C# 测试webapi模型绑定
我有一个Web Api模型活页夹,看起来是这样的:C# 测试webapi模型绑定,c#,asp.net-mvc,unit-testing,asp.net-web-api,model-binding,C#,Asp.net Mvc,Unit Testing,Asp.net Web Api,Model Binding,我有一个Web Api模型活页夹,看起来是这样的: public class KeyModelBinder : IModelBinder { public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { //... } } 我正试图写一个规则,使它更容易测试。我发现了一个与MVC的模型绑定器一起工作的函数: 但是,当尝试转换为使用we
public class KeyModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
//...
}
}
我正试图写一个规则,使它更容易测试。我发现了一个与MVC的模型绑定器一起工作的函数:
但是,当尝试转换为使用webApi时,我不知道如何填充值提供程序
public TModel BindModel<TBinder, TModel>(NameValueCollection formCollection, TBinder binder)
where TBinder : IModelBinder
{
var valueProvider = new NameValueCollectionValueProvider(formCollection, null);
var dataProvider = new DataAnnotationsModelMetadataProvider();
var modelMetadata = dataProvider.GetMetadataForType(null, typeof(TModel));
var bindingContext = new ModelBindingContext
{
ModelName = typeof(TModel).Name,
ValueProvider = valueProvider,
ModelMetadata = modelMetadata
};
binder.BindModel(null, bindingContext);
return (TModel)bindingContext.ModelMetadata.Model;
}
公共TModel BindModel(NameValueCollection formCollection,TBinder binder)
其中TBinder:IModelBinder
{
var valueProvider=新名称ValueCollectionValueProvider(formCollection,null);
var dataProvider=新的DataAnnotationsModelMetadataProvider();
var modelMetadata=dataProvider.GetMetadataForType(null,typeof(TModel));
var bindingContext=新模型bindingContext
{
ModelName=typeof(TModel).Name,
ValueProvider=ValueProvider,
ModelMetadata=ModelMetadata
};
binder.BindModel(null,bindingContext);
返回(TModel)bindingContext.ModelMetadata.Model;
}
NameValueCollection仅存在于MVC中,如何为Web Api创建一个值提供程序?如果不使用默认值提供程序,则测试模型绑定器是不可能的。因此,我根据预期的规则编写了绑定模型。在这种情况下,我只需要测试GET
public TModel BindModelFromGet<TBinder, TModel>(string modelName, string queryString, TBinder binder)
where TBinder : IModelBinder
{
var httpControllerContext = new HttpControllerContext();
httpControllerContext.Request = new HttpRequestMessage(HttpMethod.Get, MOCK_URL + queryString);
var bindingContext = new ModelBindingContext();
var dataProvider = new DataAnnotationsModelMetadataProvider();
var modelMetadata = dataProvider.GetMetadataForType(null, typeof(TModel));
var httpActionContext = new HttpActionContext();
httpActionContext.ControllerContext = httpControllerContext;
var provider = new QueryStringValueProvider(httpActionContext, CultureInfo.InvariantCulture);
bindingContext.ModelMetadata = modelMetadata;
bindingContext.ValueProvider = provider;
bindingContext.ModelName = modelName;
if (binder.BindModel(httpActionContext, bindingContext))
{
return (TModel)bindingContext.Model;
}
throw new Exception("Model was not bindable");
}
publictmodelbindmodelfromget(字符串modelName、字符串queryString、TBinder binder)
其中TBinder:IModelBinder
{
var httpControllerContext=新的httpControllerContext();
httpControllerContext.Request=新的HttpRequestMessage(HttpMethod.Get,MOCK_URL+queryString);
var bindingContext=新的ModelBindingContext();
var dataProvider=新的DataAnnotationsModelMetadataProvider();
var modelMetadata=dataProvider.GetMetadataForType(null,typeof(TModel));
var httpActionContext=新的httpActionContext();
httpActionContext.ControllerContext=httpControllerContext;
var provider=新的QueryStringValueProvider(httpActionContext,CultureInfo.InvariantCulture);
bindingContext.ModelMetadata=ModelMetadata;
bindingContext.ValueProvider=提供程序;
bindingContext.ModelName=ModelName;
if(binder.BindModel(httpActionContext,bindingContext))
{
return(TModel)bindingContext.Model;
}
抛出新异常(“模型不可绑定”);
}
如果您想让这一点在post中起作用,请输入一个jsonValues字符串,修改httpControllerContext,如下所示:
httpControllerContext.Request = new HttpRequestMessage(HttpMethod.Post, "");
httpControllerContext.Request.Content = new ObjectContent<object>(jsonValues, new JsonMediaTypeFormatter());
httpControllerContext.Request=newhttprequestmessage(HttpMethod.Post,”);
httpControllerContext.Request.Content=新的ObjectContent(jsonValues,新的JsonMediaTypeFormatter());
然后你只需要使用合适的ValueProvider(我没有研究如何使用它,因为我不需要它)。johnny 5的答案是正确的,但是,至少对我来说,很难理解如何使用它。。。所以考虑这个问题的答案,它介绍了一个我们想进行单元测试的绑定器: 这只是将所有日期时间转换为DateTimeKind.Utc。为了对其进行单元测试,我们需要一些假URI(不一定是真的): 然后使用BindModelFromGet方法进行单元测试,如下所示:
[Test]
public void should_convert_datetime_to_utc()
{
var bar = new UtcDateTimeModelBinder();
var dateTime = BindModelFromGet<UtcDateTimeModelBinder, DateTime>
("fred", "?fred=2019-08-12 00:00:00Z", bar);
Assert.That(dateTime.Kind, Is.EqualTo(DateTimeKind.Utc));
}
并进行如下测试:
[Test]
public void should_handle_bad_dates()
{
var bar = new UtcDateTimeModelBinder();
var ex = Assert.Throws<Exception>(() => BindModelFromGet<UtcDateTimeModelBinder, DateTime>
("fred", "?fred=NotADate", bar));
Assert.That(ex.Message, Is.EqualTo("Cannot convert value to Utc DateTime"));
}
[测试]
public void应该处理错误日期()
{
var bar=新的UtcDateTimeModelBinder();
var ex=Assert.Throws(()=>BindModelFromGet
(“弗雷德”,“弗雷德=NotADate”,bar));
Assert.That(例如Message,Is.EqualTo(“无法将值转换为Utc日期时间”);
}
这将处理简单的验证问题,但请注意,如果活页夹添加了多个错误,或者通常不能像简单的日期转换器那样工作,您需要做更多的工作。Nice,+1用于澄清
throw new Exception(bindingContext.ModelState[modelName].Errors[0].ErrorMessage);
[Test]
public void should_handle_bad_dates()
{
var bar = new UtcDateTimeModelBinder();
var ex = Assert.Throws<Exception>(() => BindModelFromGet<UtcDateTimeModelBinder, DateTime>
("fred", "?fred=NotADate", bar));
Assert.That(ex.Message, Is.EqualTo("Cannot convert value to Utc DateTime"));
}