wake-up-neo.com

Abfragezeichenfolge funktioniert bei Verwendung des Attributroutings nicht

Ich verwende System.Web.Http.RouteAttribute Und System.Web.Http.RoutePrefixAttribute, Um saubere URLs für meine Web API 2-Anwendung zu aktivieren. Für die meisten meiner Anfragen kann ich Routing verwenden (z. B. Controller/param1/param2) Oder Abfragezeichenfolgen (z. B. Controller?param1=bob&param2=mary).

Leider schlägt dies mit einem meiner Controller (und nur einem) fehl. Hier ist mein Controller:

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

    [HttpGet]
    [Route("{name}/{sport}/{drink}")]
    public List<int> Get(string name, string sport, string drink)
    {
        // Code removed...
    }

    [HttpGet]
    [Route("{name}/{drink}")]
    public List<int> Get(string name, string drink)
    {
        // Code removed...
    }
}

Wenn ich eine Anfrage an einen der beiden Router stelle, funktionieren beide einwandfrei. Wenn ich jedoch eine Abfragezeichenfolge verwende, schlägt diese fehl und teilt mir mit, dass dieser Pfad nicht vorhanden ist.

Ich habe versucht, meiner WebApiConfig.cs - Klasse 'Register(HttpConfiguration config) function (vor und nach der Standardroute) Folgendes hinzuzufügen, aber es hat nichts bewirkt:

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });

Aus Gründen der Klarheit möchte ich in der Lage sein, beides zu tun:

localhost:12345/1/Names/Ted/rugby/coke
localhost:12345/1/Names/Ted/coke

und,

localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke
localhost:12345/1/Names?name=Ted&drink=coke

aber leider funktionieren die Query-String-Versionen nicht! :(

aktualisiert

Ich habe die zweite Aktion vollständig entfernt und versuche nun, nur eine einzelne Aktion mit optionalen Parametern zu verwenden. Ich habe mein Routenattribut in [Route("{name}/{drink}/{sport?}")] geändert, als Tony vorschlug, den Sport auf null zu setzen, aber dies verhindert nun aus irgendeinem Grund, dass localhost:12345/1/Names/Ted/coke Eine gültige Route ist. Abfragezeichenfolgen verhalten sich wie zuvor.

pdate 2 Ich habe jetzt eine singuläre Aktion in meinem Controller:

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

    [HttpGet]
    [Route("{name}/{drink}/{sport?}")]
    public List<int> Get(string name, string drink, string sport = "")
    {
        // Code removed...
    }
}

bei Verwendung von Abfragezeichenfolgen wird jedoch kein geeigneter Pfad gefunden, während dies bei Verwendung der Routing-Methode der Fall ist.

59
Chris Paton

Nach viel mühevollem Fummeln und Googeln habe ich mir eine "Lösung" ausgedacht. Ich weiß nicht, ob dies ideal ist/die beste Vorgehensweise/einfach falsch, aber es löst mein Problem.

Ich habe nur [Route("")] zusätzlich zu den Routenattributen hinzugefügt, die ich bereits verwendet habe. Auf diese Weise kann das Web API 2-Routing Abfragezeichenfolgen zulassen, da dies nun eine gültige Route ist.

Ein Beispiel wäre jetzt:

[HttpGet]
[Route("")]
[Route("{name}/{drink}/{sport?}")]
public List<int> Get(string name, string drink, string sport = "")
{
    // Code removed...
}

Dies macht sowohl localhost:12345/1/Names/Ted/coke und localhost:12345/1/Names?name=Ted&drink=coke gültig.

41
Chris Paton

Beim Versuch, eine Web-API für mein aktuelles Projekt zu erstellen, stellte sich das gleiche Problem wie beim Einschließen von Suchparametern als Abfragezeichenfolge. Nach dem Googeln funktioniert für mich Folgendes:

API-Controller-Aktion:

[HttpGet, Route("search/{categoryid=categoryid}/{ordercode=ordercode}")]

public Task<IHttpActionResult> GetProducts(string categoryId, string orderCode)
{

}

Die URL habe ich über Postbote ausprobiert:

http://localhost/PD/search?categoryid=all-products&ordercode=star-1932

http://localhost/PD is my hosted api
59

Beim Attribut-Routing müssen Sie Standardwerte angeben, damit diese optional sind.

[Route("{name}/{sport=Football}/{drink=Coke}")]

Wenn Sie einen Wert zuweisen, kann dieser optional sein, sodass Sie ihn nicht einschließen müssen, und der angegebene Wert wird übergeben.

Ich habe die Abfragezeichenfolge dafür nicht getestet, aber es sollte genauso funktionieren.

Ich lese die Frage einfach noch einmal und sehe, dass Sie 2 Verben mit dem gleichen Pfad haben. Ich glaube, dies würde zu Konflikten führen, da das Routing nicht weiß, welchen man verwenden soll. Vielleicht hilft die Verwendung der optionalen Parameter. Sie können auch angeben, dass eins null sein darf, und in der Methode überprüfen, wie fortgefahren werden soll.

[Route("{name}/{sport?}/{drink?}")]

Überprüfen Sie dann die Variablen in der Methode, um festzustellen, ob sie null sind, und behandeln Sie sie nach Bedarf.

Hoffe das hilft einiges? lol

Wenn dies nicht der Fall ist, enthält diese Site weitere Details zum Attribut-Routing.

http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

Clip von dieser Seite:

Optionale Parameter und Standardwerte Sie können festlegen, dass ein Parameter optional ist, indem Sie dem Parameter ein Fragezeichen hinzufügen.

[Route("countries/{name?}")]
public Country GetCountry(string name = "USA") { }

Derzeit muss für den optionalen Parameter ein Standardwert angegeben werden, damit die Aktionsauswahl erfolgreich ist. Wir können jedoch untersuchen, wie diese Einschränkung aufgehoben wird. (Bitte lassen Sie uns wissen, ob dies wichtig ist.)

Standardwerte können auf ähnliche Weise angegeben werden:

[Route("countries/{name=USA}")]
public Country GetCountry(string name) { }

Der optionale Parameter '?' und die Standardwerte müssen nach Inline-Einschränkungen in der Parameterdefinition erscheinen.

17
Tony

Nur eine Randnotiz von meiner Seite. Damit queryString-Parameter funktionieren, müssen Sie ein Standardwert für die Methodenparameter, damit sie optional sind angeben. Genau wie beim normalen Aufrufen einer C # -Methode.

[RoutePrefix("api/v1/profile")]
public class ProfileController : ApiController
{

   ...

   [HttpGet]
   [Route("{profileUid}")]
   public IHttpActionResult GetProfile(string profileUid, long? someOtherId) 
   {
      // ...
   }

   ...

}

Auf diese Weise kann ich den Endpunkt folgendermaßen aufrufen:

/api/v1/profile/someUid
/api/v1/profile/someUid?someOtherId=123
10
Juri

Hier ist eine kleine Abweichung von @ bhargav kishore mummadireddy's Antwort, aber eine wichtige Abweichung. Bei seiner Antwort werden die Abfragezeichenfolgewerte standardmäßig auf einen tatsächlichen nicht leeren Wert gesetzt. Diese Antwort wird standardmäßig leer sein.

Sie können den Controller über das Pfadrouting oder über den Querystring aufrufen. Im Wesentlichen setzt es den Standardwert des Querystrings auf leer, was bedeutet, dass es immer weitergeleitet wird.

Dies war für mich wichtig, da ich 400 (Bad Request) zurückgeben möchte, wenn kein Querystring angegeben ist, anstatt ASP.NET den Fehler "Diese Methode konnte auf diesem Controller nicht gefunden werden" zurückgeben zu lassen.

[RoutePrefix("api/AppUsageReporting")]
public class AppUsageReportingController : ApiController
    {
        [HttpGet]
        // Specify default routing parameters if the parameters aren't specified
        [Route("UsageAggregationDaily/{userId=}/{startDate=}/{endDate=}")]
        public async Task<HttpResponseMessage> UsageAggregationDaily(string userId, DateTime? startDate, DateTime? endDate)
        {
            if (String.IsNullOrEmpty(userId))
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(userId)} was not specified.");
            }

            if (!startDate.HasValue)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(startDate)} was not specified.");
            }

            if (!endDate.HasValue)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(endDate)} was not specified.");
            }
        }
    }
4
contactmatt

Mit Route("search/{categoryid=categoryid}/{ordercode=ordercode}") können Sie sowohl Querystringe als auch Inline-Routenparameter verwenden, wie von mosharaf hossain beantwortet. Schreiben Sie diese Antwort, da dies die beste Antwort und der beste Weg sein sollte. Die Verwendung von Route("") verursacht Probleme, wenn Sie mehrere Gets/Puts/Posts/Deletes haben.

Da Sie [Route("{name}/{drink}/{sport?}")] als Attributrouting haben, wird dieser Code niemals getroffen.

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });

Hier wird also nur das Attribut route [Route("{name}/{drink}/{sport?}")] berücksichtigt. Da Ihre Anfrage localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke Keinen Namen, keine Sportart oder kein Getränk in der URL enthält, stimmt sie nicht mit dieser Attributroute überein. Die Parameter der Abfragezeichenfolge werden beim Abgleichen der Routen nicht berücksichtigt.

Um dies zu lösen, müssen Sie alle 3 in Ihrer Attributroute optional machen. Dann wird es der Anfrage entsprechen.

1
mugdhak

Ich benutze FromUri-Attribut als Lösung

[Route("UsageAggregationDaily")]
public async Task<HttpResponseMessage> UsageAggregationDaily([FromUri] string userId = null, [FromUri] DateTime? startDate = null, [FromUri] DateTime? endDate = null)
0