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);
}
但是,如果我注释掉将InjectingMetadataProvider
设置为ModelMetadataProviders.Current
的行,那么我的InjectingMetadataProvider.CreateMetadata()
覆盖会获得一个空白的属性列表,因此测试失败,因为我的自定义属性不会设置其上下文。
为什么我在显式使用它时需要将其设置为Current
?我不想在我的测试中设置静态内容。
我可能会做一些愚蠢的事情,因为由于我对框架的不熟悉,我现在感觉自己处于黑暗状态。
答案 0 :(得分:1)
在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;
}