Asp.net mvc 在单元测试中使用自定义ModelMetadataProvider

Asp.net mvc 在单元测试中使用自定义ModelMetadataProvider,asp.net-mvc,unit-testing,asp.net-mvc-4,moq,modelmetadataprovider,Asp.net Mvc,Unit Testing,Asp.net Mvc 4,Moq,Modelmetadataprovider,对于MVC来说,这是一个非常新的问题,希望这是一个简单的问题 我编写了一个自定义绑定属性,需要访问httpContext。为了在单元测试期间注入模拟的httpContext,我编写了一个InjectingMetadataProvider,它填充我的任何自定义属性上的Context属性 在以下测试中,我成功地实现了这一点: [TestMethod] public void Marker_ShouldBind_Id() { // Arrange var formCollection

对于MVC来说,这是一个非常新的问题,希望这是一个简单的问题

我编写了一个自定义绑定属性,需要访问
httpContext
。为了在单元测试期间注入模拟的
httpContext
,我编写了一个
InjectingMetadataProvider
,它填充我的任何自定义属性上的
Context
属性

在以下测试中,我成功地实现了这一点:

[TestMethod]
public void Marker_ShouldBind_Id()
{
    // Arrange
    var formCollection = new NameValueCollection 
    { 
        { "id", "2" }
    };

    var context = new Mock<HttpContextBase>();
    context.Setup(c => c.User).Returns((IPrincipal)null); 

    var metaProvider = new InjectingMetadataProvider(context.Object);
    ModelMetadataProviders.Current = metaProvider;  //why do I need this?

    var bindingContext = new ModelBindingContext
    {
        ModelName     = string.Empty,
        ValueProvider = new NameValueCollectionValueProvider(formCollection, null),
        ModelMetadata = metaProvider.GetMetadataForType(null, typeof(Marker)),
    };

    var binder = new DefaultModelBinder();

    // Act
    var marker = (Marker)binder.BindModel(new ControllerContext(), bindingContext);

    // Assert
    marker.Id.Should().Be(2);
}
[TestMethod]
公共无效标记\u ShouldBind\u Id()
{
//安排
var formCollection=新名称valuecollection
{ 
{“id”,“2”}
};
var context=newmock();
Setup(c=>c.User).返回((IPrincipal)null);
var metaProvider=新的InjectingMetadataProvider(context.Object);
ModelMetadataProviders.Current=metaProvider;//我为什么需要这个?
var bindingContext=新模型bindingContext
{
ModelName=string.Empty,
ValueProvider=新名称ValueCollectionValueProvider(formCollection,null),
ModelMetadata=metaProvider.GetMetadataForType(null,typeof(Marker)),
};
var binder=新的DefaultModelBinder();
//表演
var marker=(marker)binder.BindModel(新的ControllerContext(),bindingContext);
//断言
marker.Id.Should()为(2);
}
但是,如果我注释掉将my
InjectingMetadataProvider
设置为
ModelMetadataProviders.Current
的行,则my
InjectingMetadataProvider.CreateMatadata()
override将获得一个属性的空白列表,因此测试失败,因为我的自定义属性没有获得其上下文集

当我显式地使用它时,为什么我需要将它设置为
Current
?我不想在测试中设置静态内容


我可能在做一些愚蠢的事情,因为我对框架不熟悉,现在有点摸不着头脑。

在DefaultModelBinder中,调用BindCompleteXelementalModel时会创建一个新的绑定上下文。注意,它从ModelMetadataProviders.Current获取元数据,而不是从自定义模型元数据提供程序获取元数据

  internal ModelBindingContext CreateComplexElementalModelBindingContext(ControllerContext controllerContext, ModelBindingContext bindingContext, object model) {
        BindAttribute bindAttr = (BindAttribute)GetTypeDescriptor(controllerContext, bindingContext).GetAttributes()[typeof(BindAttribute)];
        Predicate<string> newPropertyFilter = (bindAttr != null)
            ? propertyName => bindAttr.IsPropertyAllowed(propertyName) && bindingContext.PropertyFilter(propertyName)
            : bindingContext.PropertyFilter;

        ModelBindingContext newBindingContext = new ModelBindingContext() {
            ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, bindingContext.ModelType),
            ModelName = bindingContext.ModelName,
            ModelState = bindingContext.ModelState,
            PropertyFilter = newPropertyFilter,
            ValueProvider = bindingContext.ValueProvider
        };

        return newBindingContext;
    }
内部ModelBindingContext CreateComplexElementalModelBindingContext(ControllerContext ControllerContext,ModelBindingContext bindingContext,对象模型){
BindAttribute bindAttr=(BindAttribute)GetTypeDescriptor(controllerContext,bindingContext).GetAttributes()[typeof(BindAttribute)];
谓词newPropertyFilter=(bindAttr!=null)
?propertyName=>bindAttr.IsPropertyAllowed(propertyName)和&bindingContext.PropertyFilter(propertyName)
:bindingContext.PropertyFilter;
ModelBindingContext newBindingContext=新ModelBindingContext(){
ModelMetadata=ModelMetadataProviders.Current.GetMetadataForType(()=>model,bindingContext.ModelType),
ModelName=bindingContext.ModelName,
ModelState=bindingContext.ModelState,
PropertyFilter=新建PropertyFilter,
ValueProvider=bindingContext.ValueProvider
};
返回新绑定上下文;
}

在DefaultModelBinder中,调用BindComplexElementalModel时会创建一个新的绑定上下文。注意,它从ModelMetadataProviders.Current获取元数据,而不是从自定义模型元数据提供程序获取元数据

  internal ModelBindingContext CreateComplexElementalModelBindingContext(ControllerContext controllerContext, ModelBindingContext bindingContext, object model) {
        BindAttribute bindAttr = (BindAttribute)GetTypeDescriptor(controllerContext, bindingContext).GetAttributes()[typeof(BindAttribute)];
        Predicate<string> newPropertyFilter = (bindAttr != null)
            ? propertyName => bindAttr.IsPropertyAllowed(propertyName) && bindingContext.PropertyFilter(propertyName)
            : bindingContext.PropertyFilter;

        ModelBindingContext newBindingContext = new ModelBindingContext() {
            ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, bindingContext.ModelType),
            ModelName = bindingContext.ModelName,
            ModelState = bindingContext.ModelState,
            PropertyFilter = newPropertyFilter,
            ValueProvider = bindingContext.ValueProvider
        };

        return newBindingContext;
    }
内部ModelBindingContext CreateComplexElementalModelBindingContext(ControllerContext ControllerContext,ModelBindingContext bindingContext,对象模型){
BindAttribute bindAttr=(BindAttribute)GetTypeDescriptor(controllerContext,bindingContext).GetAttributes()[typeof(BindAttribute)];
谓词newPropertyFilter=(bindAttr!=null)
?propertyName=>bindAttr.IsPropertyAllowed(propertyName)和&bindingContext.PropertyFilter(propertyName)
:bindingContext.PropertyFilter;
ModelBindingContext newBindingContext=新ModelBindingContext(){
ModelMetadata=ModelMetadataProviders.Current.GetMetadataForType(()=>model,bindingContext.ModelType),
ModelName=bindingContext.ModelName,
ModelState=bindingContext.ModelState,
PropertyFilter=新建PropertyFilter,
ValueProvider=bindingContext.ValueProvider
};
返回新绑定上下文;
}

下面的代码是否解释了为什么必须指定ModelMetadataProviders.Current?您可以在上下文中看到此方法。下面的代码是否解释了为什么必须指定ModelMetadataProviders.Current?您可以在上下文中看到此方法。