我在发布时很难让自定义模型绑定正常工作x-www-form-urlencoded
数据。我已经尝试了所有我能想到的方法,但似乎没有任何方法能产生预期的结果。请注意,发布 JSON 数据时,我的 JsonConverters 等都工作正常。当我发帖时x-www-form-urlencoded
系统似乎无法弄清楚如何绑定我的模型。
我的测试用例是我想绑定一个 TimeZoneInfo 对象作为我的模型的一部分。
这是我的模型活页夹:
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;
}
}
}
这是我正在使用的基类:
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);
}
我使用这样的基类来简化创建其他自定义模型绑定程序的过程。
这是我的模型活页夹提供商。请注意,这是从我的 IoC 容器中正确调用的,因此我不会费心去展示我的代码的这方面。
public class SystemizerModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
if(modelType == typeof(TimeZoneInfo))
return new TimeZoneModelBinder();
return null;
}
}
最后,这是操作方法和模型类:
[DataContract)]
public class TestModel
{
[DataMember]
public TimeZoneInfo TimeZone { get; set; }
}
[HttpPost]
public HttpResponseMessage Test(TestModel model)
{
return Request.CreateResponse(HttpStatusCode.OK, model);
}
对于操作方法,我尝试过:
public HttpResponseMessage Test([FromBody] TestModel model)
这会调用FormUrlEncodedMediaFormatter
,这似乎完全忽略了我的自定义模型绑定器。
public HttpResponseMessage Test([ModelBinder] TestModel model)
正如预期的那样,这会调用我的自定义模型绑定器,但它只提供 ValueProvidersRouteData
and QueryString
并且由于某种原因不提供任何内容。见下文:
我也尝试过用以下方式装饰班级本身ModelBinder(typeof(SystemizerModelBinderProvider))
为什么模型绑定仅在我使用 [ModelBinder] 属性时发生,为什么它仅尝试读取路由和查询字符串值并忽略正文内容?为什么FromBody
忽略我的自定义模型绑定器提供程序?
如何创建一个可以接收 POSTED 的场景x-www-form-urlencoded
数据并使用自定义逻辑成功绑定模型属性?