Asp.net mvc 3 如何使用ModelMetadata对modelbinder进行单元测试
如何对自定义ModelBinder进行单元测试 这是密码Asp.net mvc 3 如何使用ModelMetadata对modelbinder进行单元测试,asp.net-mvc-3,Asp.net Mvc 3,如何对自定义ModelBinder进行单元测试 这是密码 public class MagicBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var boundModelObject = base.Bind
public class MagicBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var boundModelObject = base.BindModel(controllerContext, bindingContext);
var properties = bindingContext.ModelType.GetProperties().Where(a => a.CanWrite);
foreach (var propertyInfo in properties)
{
object outValue = null;
bindingContext.TryGetValue(propertyInfo.Name, propertyInfo.DeclaringType, out outValue);
propertyInfo.SetValue(boundModelObject, outValue, null);
}
return boundModelObject;
}
}
这是测试脚本
[TestMethod]
public void TestFooBinding()
{
var dict = new ValueProviderDictionary(null)
{
{"Number", new ValueProviderResult("2", "2", null)},
{"Test", new ValueProviderResult("12", "12", null)},
};
var bindingContext = new ModelBindingContext() { ModelName = "foo", ValueProvider = dict};
var target = new MagicBinder();
Foo result = (Foo)target.BindModel(null, bindingContext);
}
public class Foo
{
public int Number { get; set; }
public int Test { get; set; }
}
有问题吗?在MagicBinder中,bindingContext.Model为null。如果我试着用
bindingContext.Model=new Foo()。我收到一个异常,说它已弃用,我应该设置ModelMetadata
那么,如何构建模型元数据呢?它甚至不能被嘲笑。注意:这个答案是针对ASP.NET on.NET Framework的,可能已经过时了 试着这样做:
[TestMethod]
public void TestFooBinding()
{
// arrange
var formCollection = new NameValueCollection
{
{ "Number", "2" },
{ "Test", "12" },
};
var valueProvider = new NameValueCollectionValueProvider(formCollection, null);
var metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(Foo));
var bindingContext = new ModelBindingContext
{
ModelName = "",
ValueProvider = valueProvider,
ModelMetadata = metadata
};
var controllerContext = new ControllerContext();
var sut = new MagicBinder();
// act
Foo actual = (Foo)sut.BindModel(controllerContext, bindingContext);
// assert
// TODO:
}
如果您中的任何人需要此方法来为web api工作,您可以使用此方法来测试的Get请求,您可以使用内置提供程序获得好处: 这将填充来自web的值,而不是产生奇怪的副作用,即创建提供者可能永远不会返回Null等的值
using System;
using System.Globalization;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Metadata.Providers;
using System.Web.Http.ModelBinding;
using System.Web.Http.ValueProviders.Providers;
namespace Apps.API.Web.Tests
{
public class ModelBinderTestRule
{
//This URL is just a place holder for prefixing the query string
public const string MOCK_URL = "http://localhost:8088/";
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");
}
}
}
使用系统;
利用制度全球化;
使用System.Net.Http;
使用System.Web.Http.Controller;
使用System.Web.Http.Metadata.Providers;
使用System.Web.Http.ModelBinding;
使用System.Web.Http.ValueProviders.Providers;
命名空间Apps.API.Web.Tests
{
公共类ModelBinderTestRule
{
//此URL只是一个用于作为查询字符串前缀的占位符
公共常量字符串MOCK_URL=”http://localhost:8088/";
公共TModel BindModelFromGet(字符串模型名、字符串查询字符串、TBinder绑定器)
其中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;
}
抛出新异常(“模型不可绑定”);
}
}
}
非常感谢。但是,使用ModelMetadata具体类的原因是什么?为什么他们不能实现一个接口,因为它所做的只是为一个模型类型提供“元数据”。就像任何遇到这个问题的人的参考:如果你需要访问元数据。模型,那么你必须设置访问器,它是GetMetadataForType的第一个参数,必须是一个Func,所以可以像()=>新的MyModelClass()
对于.NET Framework来说并不过时,但在.NET Core中无法工作仅供未来读者注意,TryGetValue不再可用(MVC1之后):次要问题可能重复:如果您碰巧在活页夹中使用模型验证,这将崩溃。添加“httpControllerContext.Configuration=new HttpConfiguration()”将防止崩溃。