Punktzeichen '.' in MVC Web API 2 für Anforderungen wie api / people / STAFF.45287


106

Die URL, die ich arbeiten lassen möchte, lautet wie folgt : http://somedomain.com/api/people/staff.33311 (genau wie Websites wie LAST.FM alle Arten von Zeichen in ihren RESTFul- und WebPage-URLs zulassen Beispiel: " http://www.last.fm/artist/psy'aviah " ist eine gültige URL für LAST.FM.

Was funktioniert, sind folgende Szenarien: - http://somedomain.com/api/people/ - das alle Personen zurückgibt - http://somedomain.com/api/people/staff33311 - würde auch funktionieren, aber es ist nicht das, was ich ' m nachdem ich möchte, dass die URL einen "Punkt" akzeptiert, wie im folgenden Beispiel - http://somedomain.com/api/people/staff.33311 - aber dies gibt mir einen

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

Ich habe folgende Dinge eingerichtet:

  1. Der 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. Die 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 }
        );
    }

Ich habe bereits versucht , nach all den Spitzen dieser Blogpost http://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspx aber es wird immer noch nicht .. Ich denke auch , es ist ziemlich langweilig , und ich frage mich , ob es nicht eine andere ist, besserer und sicherer Weg.

Wir haben unsere IDs intern so, also müssen wir eine Lösung finden, um den Punkt auf die eine oder andere Weise anzupassen, vorzugsweise im Stil von "." aber ich bin offen für alternative Vorschläge für URLs, wenn nötig ...


10
Keine Antwort, aber warum Sie eine 404 für somedomain.com/api/people/staff.33311 erhalten - Standardmäßig überprüft IIS diese URL und sieht die. als Dateierweiterung und ruft den statischen Dateihandler unter Umgehung Ihrer MVC-API auf. Die Antwort, die Sie akzeptiert haben (alle verwalteten Module für alle Anforderungen ausführen), funktioniert, weil Sie jede Anforderung an IIS zwingen, die ASP.NET-Pipeline (daher Ihre Controller) zu durchlaufen
Henry C

Eng verwandter Beitrag hier .
RBT

Antworten:


104

Die folgende Einstellung in Ihrer web.configDatei sollte Ihr Problem beheben:

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

4
Es hat den Trick gemacht. Gibt es jedoch Schwachstellen, wenn Sie diese Option festlegen? Warum ist das nicht das Standardverhalten?
Yves Schelpe

2
Ok, für jedermanns Interesse: Ich sehe, dass meine obige Frage hier auf die zum Zeitpunkt des Schreibens akzeptierte Antwort beantwortet wird (Antwort von Kapil Khandelwal): stackoverflow.com/questions/11048863/…
Yves Schelpe

2
Ja, es hat funktioniert, Bus andere, ich möchte wissen, welches Modul erforderlich ist, damit diese Funktionalität funktioniert?
Greg Z.

3
Wenn ich das versuchte, würde es nur funktionieren, wenn ich ein '/' am Ende des Pfades setze. Irgendwelche Vorschläge, warum das so ist? Nebenbei bemerkt hat die Antwort unten, die speziell das 'UrlRoutingModule' hinzufügt, anstatt alle Module auszuführen, auch für mich funktioniert, obwohl immer noch das Problem besteht, dass am Ende ein '/' erforderlich ist, um zu funktionieren.
Nikolaj Dam Larsen

10
stackoverflow.com/a/12151501/167018 ist einen Blick wert, wenn Sie (und zu Recht) über die Auswirkungen der Aktivierung von runAllManagedModulesForAllRequests auf die Leistung besorgt sind.
Henry C

140

Suffix die URL mit einem Schrägstrich zB http://somedomain.com/api/people/staff.33311/statt http://somedomain.com/api/people/staff.33311.


3
@AgustinMeriles Meine Antwort könnte eher als Problemumgehung als als tatsächliche Antwort angesehen werden. Dies hängt von Ihrer Interpretation der Frage ab.
Danny Varod

5
Dies funktioniert jedoch nicht, wenn sich der Punkt am Ende des URL-Abschnitts wie in / people / member befindet.
eYe

2
Nein, was ist, wenn ich am Ende keinen Schrägstrich will?! Es sollte nicht erforderlich sein.
Josh M.

1
@ JoshM. Dies ist eine Problemumgehung. Ich habe ASP.NET nicht geschrieben. Der Schrägstrich wirkt sich auch nicht auf die Anforderung aus. Es ist jedoch helfen , Ihre Absichten deutlicher als in machen google.com/my query goes here/vs. google.com/subDomain my query goes here.
Danny Varod

1
Ja, dies ist das Beste, was Sie nicht benötigen sollten, um die web.config zu ändern.
Timothy Gonzalez

35

Ich habe festgestellt, dass das Hinzufügen von Folgendem vor dem Standard ExtensionlessUrlHandlerdas Problem für mich löst:

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

Ich denke nicht, dass der Name wirklich so wichtig ist, außer es hilft wahrscheinlich, wenn Ihre IDE (in meinem Fall Visual Studio) Ihre Site-Konfiguration verwaltet.

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


Ich habe es 'nach' der Standardzeile hinzugefügt und es hat auch gut funktioniert.
Jalal El-Shaer

Dies sollte die akzeptierte Antwort sein.
Benötigt

2
Danke für das VORHER, denn es hat danach nicht funktioniert!
Mese

Ich glaube, die Module werden in der Reihenfolge der Deklaration ausgeführt. Stellen Sie daher immer spezifischere (oder wichtigere) Module vor allgemeinere.
BrianS

24

Ich weiß nicht, was ich wirklich tue, aber nachdem ich ein bisschen mit der vorherigen Antwort gespielt habe, habe ich eine andere, vielleicht passendere Lösung gefunden:

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

Danke, ich weiß auch nicht, was es tut, aber es sieht besser aus als die andere Lösung.
Thomas

1
scheint das URL-Routing-Modul (was darauf hindeutet, dass die Anforderung eine Erweiterung enthält und dann versucht, sie als Datei zu behandeln) an das Ende der Liste der Module zu verschieben, was ausreicht, um es nach dem Modul zu platzieren, das die API-Anforderung verarbeitet . IMHO, dies ist die beste Problemumgehung von denen, die ich auf SO gesehen habe, zumindest ATTOW
James Manning

1
Es ist nicht die Verlagerung an das Ende der Liste, sondern das Entfernen der Standardvoraussetzung, dass dieses Modul nur für verwaltete Handler ausgeführt wird. Die Standardkonfiguration verwendet dieses Format:<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler" />
Theta-Fisch

Danke - das würde das Verhalten erklären.
Greg Z.

8

Ich stellte fest, dass ich mehr tun musste, als nur das runAllManagedModulesForAllRequestsAttribut auf zu setzen true. Ich musste auch sicherstellen, dass der URL-Handler ohne Erweiterung so konfiguriert war, dass alle Pfade angezeigt werden. Darüber hinaus können Sie eine weitere Bonuskonfigurationseinstellung hinzufügen, die in einigen Fällen hilfreich ist. Hier ist meine funktionierende 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>

Beachten Sie , speziell, dass die ExtensionlessUrlHandler-Integrated-4.0ITS - pathAttribut auf , *im Gegensatz zu *.(zum Beispiel).


Ich bin gerade von der gebissen worden path="*.". Nur neugierig, was ist der Grund, warum die Leute das eingestellt haben path="*."?
JustinP8

Eigentlich habe ich es geändert path="*"und hatte ein Problem, weil wir eine Dokumentationssite neben unserer WebAPI hosten und diese Site Probleme mit .jpg, .png und anderen Dateien mit Erweiterungen hatte.
JustinP8

@ JustinP8 Hast du auch gesetzt <modules runAllManagedModulesForAllRequests="true" />? Dadurch sollte .NET diese statischen Dateien verarbeiten können.
Josh M.

1
Ja. Ich habe das getan. Das gefällt mir allerdings nicht wirklich, da jetzt alle statischen Dateien die .NET-Pipeline durchlaufen. Da es sich um einen WebAPI-Dienst handelt, sind zum Glück nur die Inhalte Swagger und Swashbuckle für die API-Dokumente / Hilfeseite betroffen.
JustinP8

Ich fand, dass dies alle statischen Dateianforderungen brach. Fehler 500. Ich hatte runAllManaged ... auf true gesetzt.
Sam

2

Ich blieb in dieser Situation stecken, aber das Anhängen / am Ende der URL sah für mich nicht sauber aus.

Fügen handlers Sie einfach unten im web.config- Tag hinzu, und schon kann es losgehen.

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

Können Sie erklären, was Nancy ist und ob es sich um eine Bibliothek handelt, die in das Projekt aufgenommen werden soll? Vielen Dank!
bläulich

1

Ich habe festgestellt, dass beides für mich funktioniert: entweder runAllManagedModulesForAllRequests auf true setzen oder ExtentionlessUrlHandler wie folgt hinzufügen. Schließlich habe ich mich entschieden, extensionUrLHandler hinzuzufügen, da runAllManagedModulesForAllRequests Auswirkungen auf die Leistung der Site haben.

<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>

1

Ich würde dies in der Datei Web.config verwenden:

<add name="ManagedSpecialNames" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

vor dem Standard "ExtensionlessUrlHandler".

Zum Beispiel in meinem Fall habe ich es hier ausgedrückt:

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

Sie erzwingen also, dass URLs eines solchen Musters von Ihnen verwaltet werden, anstatt die Standardverwaltung als Dateien im Anwendungsverzeichnisbaum.


0

Ich hatte das gleiche Problem und die Umstände, unter denen ich nicht mit IIS- und Website-Konfigurationseinstellungen spielen sollte. Ich musste es also zum Laufen bringen, indem ich Änderungen nur auf Codeebene vornahm.

Der einfache Punkt ist, dass der häufigste Fall, in dem die URL ein Punktzeichen enthält, darin besteht, dass Sie Eingaben vom Benutzer erhalten und diese als Abfragezeichenfolge oder URL-Fragment übergeben, um ein Argument an die Parameter in der Aktionsmethode zu übergeben Ihres Controllers.

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

Schauen Sie sich die folgende URL an, unter der der Benutzer seine Benutzer-ID eingibt, um seine persönlichen Daten abzurufen:

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

Da Sie einfach einige Daten vom Server abrufen müssen, verwenden wir das http- GETVerb. Während der Verwendung von GETAufrufen können alle Eingabeparameter nur in den URL-Fragmenten übergeben werden.

Um mein Problem zu lösen, habe ich das http-Verb meiner Aktion in geändert POST. Das HTTP- POSTVerb bietet die Möglichkeit, auch Benutzer- oder Nichtbenutzereingaben im Text zu übergeben. Also habe ich JSON-Daten erstellt und an den Hauptteil der http- POSTAnforderung übergeben:

{
  "userid" : "foo.bar"
}

Ändern Sie Ihre Methodendefinition wie folgt:

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

Hinweis : Hier erfahren Sie mehr darüber, wann GETund wann POSTVerb verwendet werden soll .


Keine geeignete Lösung, wenn Sie eine REST-API erstellen.
Mustafa Ozturk
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.