ASP.Net Web-API benutzerdefinierte Modell-Bindung mit x-www-form-urlencoded Daten gepostet - nichts scheint zu funktionieren
Ich bin eine Menge ärger bekommen custom-Modell der Bindung zu arbeiten, wenn die Buchung x-www-form-urlencoded
Daten. Ich habe versucht, jeden Weg, den ich denken kann, und nichts scheint zu produzieren das gewünschte Ergebnis. Beachten Sie beim veröffentlichen von JSON-Daten, meine JsonConverters und so weiter alle gut funktionieren. Es ist, wenn ich den post als x-www-form-urlencoded
dass das system kann nicht scheinen, um herauszufinden, wie zu binden, meinem Modell.
Meinem test-Fall ist, dass ich möchte, zu binden, ein TimeZoneInfo-Objekt als Teil von meinem Modell.
Hier mein binder Modell:
public class TimeZoneModelBinder : SystemizerModelBinder
{
protected override object BindModel(string attemptedValue, Action<string> addModelError)
{
try
{
return TimeZoneInfo.FindSystemTimeZoneById(attemptedValue);
}
catch(TimeZoneNotFoundException)
{
addModelError("The value was not a valid time zone ID. See the GetSupportedTimeZones Api call for a list of valid time zone IDs.");
return null;
}
}
}
Hier ist die Basis-Klasse, die ich verwende:
public abstract class SystemizerModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var name = GetModelName(bindingContext.ModelName);
var valueProviderResult = bindingContext.ValueProvider.GetValue(name);
if(valueProviderResult == null || string.IsNullOrWhiteSpace(valueProviderResult.AttemptedValue))
return false;
var success = true;
var value = BindModel(valueProviderResult.AttemptedValue, s =>
{
success = false;
bindingContext.ModelState.AddModelError(name, s);
});
bindingContext.Model = value;
bindingContext.ModelState.SetModelValue(name, new System.Web.Http.ValueProviders.ValueProviderResult(value, valueProviderResult.AttemptedValue, valueProviderResult.Culture));
return success;
}
private string GetModelName(string name)
{
var n = name.LastIndexOf(".", StringComparison.Ordinal);
return n < 0 || n >= name.Length - 1 ? name : name.Substring(n + 1);
}
protected abstract object BindModel(string attemptedValue, Action<string> addModelError);
}
Habe ich eine Basisklasse wie diese machen es einfach zu erstellen Sie zusätzliche benutzerdefinierte Modell Mappen.
Hier mein Modell von binder-Anbieter. Beachten Sie, dass dieser immer aufgerufen wird korrekt von meinem IoC-container, damit ich nicht die Mühe zu zeigen, dass die Aspekt meinem code.
public class SystemizerModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
if(modelType == typeof(TimeZoneInfo))
return new TimeZoneModelBinder();
return null;
}
}
Schließlich, hier ist die action-Methode und Modell-Klasse:
[DataContract)]
public class TestModel
{
[DataMember]
public TimeZoneInfo TimeZone { get; set; }
}
[HttpPost]
public HttpResponseMessage Test(TestModel model)
{
return Request.CreateResponse(HttpStatusCode.OK, model);
}
Für die action-Methode, die ich versucht habe:
public HttpResponseMessage Test([FromBody] TestModel model)
Dieser ruft die FormUrlEncodedMediaFormatter
ist, scheint zu ignorieren, mein custom Modell binder zusammen.
public HttpResponseMessage Test([ModelBinder] TestModel model)
Diese Anrufe in mein custom Modell binder, wie erwartet, aber dann es stellt nur ValueProviders für RouteData
und QueryString
und aus irgendeinem Grund nicht bieten alles, was für den Körper Inhalt. Siehe unten:
Ich habe auch versucht die Dekoration der Klasse selbst mit ModelBinder(typeof(SystemizerModelBinderProvider))
Warum muss das model NUR verbindlich auftreten, wenn ich den [ModelBinder] - Attribut, und warum es NUR versuchen zu Lesen, route und querystring-Werten und ignorieren der Inhalt? Warum FromBody
ignorieren meine custom-Modell von binder-Anbieter?
Wie erstelle ich ein Szenario, in dem ich empfangen kann GEBUCHT x-www-form-urlencoded
Daten und erfolgreich binden-Modell-Eigenschaften mithilfe von benutzerdefinierten Logik?
InformationsquelleAutor Nathan Ridley | 2013-02-13
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich würde Ihnen empfehlen, Lesen Sie die
folgenden blog-post
, in der Mike Stall erklärt im Detail, wie Modell-Bindung funktioniert in der Web-API:Also, wenn die Quelle der Daten ist das request-body, dann können Sie erstellen eine benutzerdefinierte MediaTypeFormatter eher als ein Modell binder.
Die
FormUrlEncodedMediaTypeFormatter
liest die Anfrage und verwendet einen benutzerdefinierten parser zum Parsen derapplication/x-www-form-urlencoded
Anfrage eine Sammlung vonKeyValuePair<string, string>
die dann zum Bau des Modells.Welches Attribut haben Sie auf Ihrer action-Methode mit dem MediaTypeFormatter,
[ModelBinder]
,[FromBody]
oder[ModelBinder(typeof(x))]
?InformationsquelleAutor Darin Dimitrov
ModelBinder scheint relativ besser zu bedienen als MediaTypeFormatter. Sie müssen sich nicht registrieren es weltweit.
Fand ich eine alternative stellen die Modell-Bindemittel zu binden komplexe Objekt-Typen in Web-API. Im Modell-binder, I am reading request-body als string und dann mit JSON.NET Deserialisieren es zum gewünschten Objekt-Typ. Es kann verwendet werden, um map-array von komplexen Objekttypen.
Habe ich ein Modell binder wie folgt:
Und dann verwende ich es in der Web-API-controller wie folgt:
JSON.NET bietet einige Validierung mit JsonProoperty-Attribut (newtonsoft.com/json/help/html/...). Können Sie "Erforderlich" - Eigenschaft ist Erforderlich, AllowNull etc.
InformationsquelleAutor Tushar Kesare