Mam wiele problemów z uzyskaniem niestandardowego wiązania modelu do pracy po opublikowaniu danych x-www-form-urlencoded
. Próbowałem na każdy sposób, jaki przychodzi mi do głowy, i nic nie wydaje się przynosić pożądanego rezultatu. Uwaga podczas publikowania danych JSON, moje JsonConverters i tak dalej wszystko działa dobrze. Kiedy publikuję jako x-www-form-urlencoded
, system nie może wymyślić, jak powiązać mój model.Niestandardowe powiązanie modelu ASP.Net Web API z danymi opublikowanymi przez x-www-urlencoded - nic nie wydaje się działać
Mój przypadek testowy polega na tym, że chciałbym związać obiekt TimeZoneInfo jako część mojego modelu.
Oto mój model spoiwo:
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;
}
}
}
Oto klasa bazowa Używam:
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);
}
użyłem klasy bazowej tak, aby w prosty sposób tworzyć dodatkowe niestandardowy model spoiw.
Oto mój dostawca segregatorów. Zauważ, że jest to poprawnie wywoływane z mojego kontenera IoC, więc nie będę zawracał sobie głowy pokazywaniem tego aspektu mojego kodu.
public class SystemizerModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
if(modelType == typeof(TimeZoneInfo))
return new TimeZoneModelBinder();
return null;
}
}
Wreszcie, oto sposób działania i model klasy:
[DataContract)]
public class TestModel
{
[DataMember]
public TimeZoneInfo TimeZone { get; set; }
}
[HttpPost]
public HttpResponseMessage Test(TestModel model)
{
return Request.CreateResponse(HttpStatusCode.OK, model);
}
Dla metody działania, próbowałem:
public HttpResponseMessage Test([FromBody] TestModel model)
wywoływany jest FormUrlEncodedMediaFormatter
, który wydaje się ignorować moje niestandardowy model spoiwa w ogóle.
public HttpResponseMessage Test([ModelBinder] TestModel model)
Stawia to pod moim model niestandardowy spoiwem, jak się spodziewano, ale to tylko zapewnia ValueProviders dla RouteData
i QueryString
iz jakiegoś powodu nie zapewnia niczego dla zawartości ciała. Patrz poniżej:
Próbowałem zostały również dekorowanie samej klasy z ModelBinder(typeof(SystemizerModelBinderProvider))
Dlaczego wiążący jedyny model wystąpić podczas korzystania z [ModelBinder] atrybut, a dlaczego to jedynie próbować odczytać trasa i wartości zapytania oraz ignorowanie treści ciała? Dlaczego FromBody
ignoruje mojego dostawcę niestandardowego modelu wiązania?
Jak utworzyć scenariusz, w którym mogę odbierać dane POSTED x-www-form-urlencoded
i pomyślnie powiązać właściwości modelu za pomocą niestandardowej logiki?
prostu ciekawi, używacie ReSharper? –