Warum müssen wir FromBody und FromUri angeben?

157

Warum werden die Attribute FromBodyund FromUriin der ASP.NET-Web-API benötigt?

Was sind die Unterschiede zwischen der Verwendung der Attribute und der Nichtverwendung?

Rajneesh
quelle
11
Nur um einen Hinweis zu geben, wann es nützlich sein könnte, die Annotation [FromBody] zu verwenden: Es ist beispielsweise eine schlechte Praxis, statische Anmeldeinformationen wie Benutzername / Passwort als in der URL codierte Parameter zu senden. Auch wenn die SSL-Verschlüsselung möglicherweise verhindert, dass ein Dritter Lesezugriff auf die Parameter in der URL erhält, bleibt dies dennoch eine schlechte Praxis, da diese Anmeldeinformationen möglicherweise in Browserprotokollen gespeichert werden, was definitiv nicht erwünscht ist. In einem solchen Fall könnte man die Annotation [FromBody] verwenden, um die Speicherung eines Parameters im Hauptteil der HTTP-Nachricht zu erzwingen und ein High
Chris

Antworten:

193

Wenn die ASP.NET-Web-API eine Methode auf einem Controller aufruft, muss sie Werte für die Parameter festlegen, ein Prozess, der als Parameterbindung bezeichnet wird .

Standardmäßig verwendet die Web-API die folgenden Regeln, um Parameter zu binden:

  • Wenn der Parameter ein "einfacher" Typ ist , versucht die Web-API, den Wert vom URI abzurufen . Zu den einfachen Typen gehören die primitiven .NET-Typen (int, bool, double usw.) sowie TimeSpan, DateTime, Guid, decimal und string sowie alle Typen mit einem Typkonverter, der aus einer Zeichenfolge konvertiert werden kann.

  • Bei komplexen Typen versucht die Web-API, den Wert mithilfe eines Medientyp-Formatierers aus dem Nachrichtentext zu lesen .

Wenn Sie also das oben genannte Standardverhalten überschreiben und die Web-API zwingen möchten, einen komplexen Typ aus dem URI zu lesen, fügen Sie das [FromUri]Attribut dem Parameter hinzu. Fügen Sie das [FromBody]Attribut dem Parameter hinzu, um die Web-API zu zwingen, einen einfachen Typ aus dem Anforderungshauptteil zu lesen .

Um Ihre Frage zu beantworten, müssen die Attribute [FromBody]und [FromUri]in der Web-API einfach das oben beschriebene Standardverhalten überschreiben, falls erforderlich. Beachten Sie, dass Sie beide Attribute für eine Controller-Methode verwenden können, jedoch nur für verschiedene Parameter, wie hier gezeigt .

Es gibt viel mehr Informationen im Web, wenn Sie "Web-API-Parameterbindung" googeln.

Djikay
quelle
2
@ user3510527: Sie müssen diese Attribute nicht verwenden, wenn Sie nicht möchten, solange Sie dem Standardverhalten folgen. Wenn Sie das Standardverhalten ändern möchten, müssen Sie sie verwenden.
Djikay
1
Wenn es sein Standardverhalten ausführt, warum müssen wir dann übergehen und welche Vorteile erhalten wir, wenn wir dieses Attribut erwähnen?
Rajneesh
1
@ user3510527 Sie nicht brauchen , außer Kraft zu setzen. Sie können einfach das Standardverhalten verwenden. Ein Beispiel, bei dem jemand möglicherweise überschreiben möchte, ist, wenn er eine einfache Ganzzahl im Hauptteil der Anforderung angeben möchte, da standardmäßig erwartet wird, dass diese im URI gefunden wird. Grundsätzlich können Sie das Standardverhalten einfach beibehalten, wenn Sie möchten, oder Sie können es überschreiben. Dies ist nur eine Option, die Sie haben. Ich verstehe nicht, was die Verwirrung ist.
Djikay
Ich möchte nur den internen Arbeitsprozess kennen, wenn wir das Formularattribut verwenden, damit es direkt den Wert erhält und keine Uri oder Formkörper überprüft ...
Rajneesh
7
Ich frage mich, ob man ein Attribut namens JustGetIt[FromBody, FromQuery]
The Muffin Man
93

Das Standardverhalten ist:

  1. Wenn die Parameter a primitive Art ( int, bool, double, ...), Web - API versucht , den Wert von der zu bekommen URI der HTTPAnforderung.

  2. Bei komplexen Typen (z. B. Ihrem eigenen Objekt Person:) versucht die Web-API, den Wert aus dem zu lesen Hauptteil der HTTP-Anforderung.

Also, wenn Sie haben:

  • ein primitiver Typ in der URI, oder
  • ein komplexer Typ im Körper

... dann müssen Sie keine Attribute hinzufügen (auch nicht [FromBody] noch [FromUri]).

Aber wenn Sie einen primitiven Typ im Körper haben , müssen Sie ihn [FromBody]in Ihrer WebAPI-Controller-Methode vor Ihrem primitiven Typparameter hinzufügen . (Da WebAPI standardmäßig nach primitiven Typen im URI der HTTP-Anforderung sucht.)

Wenn Sie einen komplexen Typ in Ihrer URI haben , müssen Sie diesen hinzufügen[FromUri] . (Da WebAPI standardmäßig nach komplexen Typen im Hauptteil der HTTP-Anforderung sucht.)

Primitive Typen:

public class UsersController : ApiController
{
    // api/users
    public HttpResponseMessage Post([FromBody]int id)
    {

    }
    // api/users/id
    public HttpResponseMessage Post(int id)
    {

    }       
}

Komplexe Typen:

public class UsersController : ApiController
{       
    // api/users
    public HttpResponseMessage Post(User user)
    {

    }

    // api/users/user
    public HttpResponseMessage Post([FromUri]User user)
    {

    }       
}

Dies funktioniert, solange Sie nur einen Parameter in Ihrer HTTP-Anfrage senden . Wenn Sie mehrere senden , müssen Sie ein benutzerdefiniertes Modell erstellen,das alle Ihre Parameter wie folgt enthält:

public class MyModel
{
    public string MyProperty { get; set; }
    public string MyProperty2 { get; set; }
}

[Route("search")]
[HttpPost]
public async Task<dynamic> Search([FromBody] MyModel model)
{
    // model.MyProperty;
    // model.MyProperty2;
}

Aus der Microsoft-Dokumentation zur Parameterbindung in der ASP.NET-Web-API :

Wenn ein Parameter [FromBody] hat, verwendet die Web-API den Content-Type-Header, um einen Formatierer auszuwählen. In diesem Beispiel lautet der Inhaltstyp "application / json" und der Anforderungshauptteil ist eine unformatierte JSON-Zeichenfolge (kein JSON-Objekt). Es darf höchstens ein Parameter aus dem Nachrichtentext lesen.

Das sollte funktionieren:

public HttpResponseMessage Post([FromBody] string name) { ... }

Dies wird nicht funktionieren:

// Caution: This won't work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

Der Grund für diese Regel ist, dass der Anforderungshauptteil möglicherweise in einem nicht gepufferten Stream gespeichert ist, der nur einmal gelesen werden kann.

Tadej
quelle
5
"Höchstens ein Parameter darf aus dem Nachrichtentext lesen" war eine besonders hilfreiche Information
Ryan
15

Nur Ergänzung zu den obigen Antworten ..

[FromUri] kann auch verwendet werden, um komplexe Typen aus Uri-Parametern zu binden, anstatt Parameter aus Querystring zu übergeben

Zum Beispiel ..

public class GeoPoint
{
    public double Latitude { get; set; } 
    public double Longitude { get; set; }
}

[RoutePrefix("api/Values")]
public ValuesController : ApiController
{
    [Route("{Latitude}/{Longitude}")]
    public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}

Kann wie folgt aufgerufen werden:

http://localhost/api/values/47.678558/-122.130989
Utkarsh Patel
quelle
12

Wenn ein Parameter [FromBody] hat, verwendet die Web-API den Content-Type-Header, um einen Formatierer auszuwählen. In diesem Beispiel lautet der Inhaltstyp "application / json" und der Anforderungshauptteil ist eine unformatierte JSON-Zeichenfolge (kein JSON-Objekt).

Es darf höchstens ein Parameter aus dem Nachrichtentext lesen. Das wird also nicht funktionieren:

 // Caution: Will not work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

Der Grund für diese Regel ist, dass der Anforderungshauptteil möglicherweise in einem nicht gepufferten Stream gespeichert ist, der nur einmal gelesen werden kann

Weitere Informationen finden Sie auf der Website: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

user5166729
quelle