Dot character '.' in MVC Web API 2 for req

2019-01-02 20:54发布

问题:

The URL I'm trying to let work is one in the style of: http://somedomain.com/api/people/staff.33311 (just like sites as LAST.FM allow all sort of signs in their RESTFul & WebPage urls, for example "http://www.last.fm/artist/psy'aviah" is a valid url for LAST.FM).

What works are following scenarios: - http://somedomain.com/api/people/ - which returns all people - http://somedomain.com/api/people/staff33311 - would work as well, but it's not what I'm after I'd want the url to accept a "dot", like the example below - http://somedomain.com/api/people/staff.33311 - but this gives me a

HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

I've set up following things:

  1. The controller "PeopleController"

    public IEnumerable<Person> GetAllPeople()
    {
        return _people;
    }
    
    public IHttpActionResult GetPerson(string id)
    {
        var person = _people.FirstOrDefault(p => p.Id.ToLower().Equals(id.ToLower()));
        if (person == null)
            return NotFound();
    
        return Ok(person);
    }    
    
  2. The WebApiConfig.cs

    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
    
        // Web API routes
        config.MapHttpAttributeRoutes();
    
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
    

I already tried following all the tips of this blogpost http://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspx but it still won't work.. I also think it's quite tedious and I wonder if there isn't another, better and more secure way.

We have our Id's internally like this, so we're going to have to find a solution to fit the dot in one way or another, preferably in the style of "." but I'm open to alternative suggestions for urls if need be...

回答1:

Following setting in your web.config file should fix your issue:

<configuration>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />


回答2:

Suffix the URL with a slash e.g. http://somedomain.com/api/people/staff.33311/ instead of http://somedomain.com/api/people/staff.33311.



回答3:

I've found that adding the following before the standard ExtensionlessUrlHandler solves the issue for me:

<add name="ExtensionlessUrlHandler-Integrated-4.0-ForApi"
     path="api/*"
     verb="*"
     type="System.Web.Handlers.TransferRequestHandler"
     preCondition="integratedMode,runtimeVersionv4.0" />

I don't think the name actually matters all that much except it probably helps if your IDE (Visual Studio in my case) is managing your site configuration.

H/T to https://stackoverflow.com/a/15802305/264628



回答4:

I don't know what I am doing really, but after playing with the previous answer a bit I came up with another, perhaps more appropriate, solution:

<system.webServer>
<modules>
    <remove name="UrlRoutingModule-4.0" />
    <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
</modules>
</system.webServer>


回答5:

I found that I needed to do more than just set the runAllManagedModulesForAllRequests attribute to true. I also had to ensure that the extensionless URL handler was configured to look at all paths. In addition, there is one more bonus configuration setting you can add which will help in some cases. Here is my working Web.config:

<system.web>
    <httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <handlers>
        <remove name="WebDAV" />
        <remove name="OPTIONSVerbHandler" />
        <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
        <add name="ExtensionlessUrlHandler-Integrated-4.0"  path="*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>

Note, specifically, that the ExtensionlessUrlHandler-Integrated-4.0 has its path attribute set to * as opposed to *. (for instance).



回答6:

I got stuck in this situation but appending / at the end of URL wasn't look clean for me.

so just add below in web.config handlers tag and you will be good to go.

<add name="Nancy" path="api" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" allowPathInfo="true" />


回答7:

I found that both way works for me: either setting runAllManagedModulesForAllRequests to true or add ExtentionlessUrlHandler as following. Finally i choose to add extensionUrLHandler since runAllManagedModulesForAllRequests do have performance impact to the site.

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <remove name="WebDAV" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" 
       type="System.Web.Handlers.TransferRequestHandler" 
       preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>


回答8:

I faced the very same issue and the circumstances I was in where I was not supposed to play with IIS and website config related settings. So I had to make it working by making changes at the code level only.

The simple point is that the most common case where you would end up having dot character in the URL is when you get some input from the user and pass it as a query string or url fragment to pass some argument to the parameters in the action method of your controller.

public class GetuserdetailsbyuseridController : ApiController
{
     string getuserdetailsbyuserid(string userId)
     {
        //some code to get user details
     }
}

Have a look at below URL where user enters his user id to get his personal details:

http://mywebsite:8080/getuserdetailsbyuserid/foo.bar

Since you have to simply fetch some data from the server we use http GET verb. While using GET calls any input parameters can be passed only in the URL fragments.

So to solve my problem I changed the http verb of my action to POST. Http POST verb has the facility of passing any user or non-user input in body also. So I created a JSON data and passed it into the body of the http POST request:

{
  "userid" : "foo.bar"
}

Change your method definition as below:

public class GetuserdetailsbyuseridController : ApiController
{
     [Post]
     string getuserdetailsbyuserid([FromBody] string userId)
     {
        //some code to get user details
     }
}

Note: More on when to use GET verb and when to use POST verb here.



标签: