Asp.net mvc 3 如何使用ModelMetadata对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

如何对自定义ModelBinder进行单元测试

这是密码

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()”将防止崩溃。