我的团队需要使用此框架为我们的公司和产品开发框架。 其中一个要求是可以为特定客户定制产品,但应该使用同一产品的另一个版本(不是自动)轻松更新。
我们正在使用ASP.NET MVC 4 + Web API(目前,基于我们的框架,将在明年创建桌面产品),NHibernate,使用Autofac作为DI容器和N层的IoC。
因此,在WebApp的某些方面,我们将ViewModels用作具有一个默认实现的接口,并使用Autofac链接它们,并且在期货自定义中很容易更改。
在ASP.NET MVC中,我们实现了这个实现IModelBinderProvider并创建一个自定义类来激活DefaultModelBinder:
这样的事情:
public class MyCustomMVCModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(Type modelType)
{
if (modelType.IsInterface)
return new MyCustomMVCModelBinder();
return new DefaultModelBinder();
}
}
public class MyCustomMVCModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var context = new ModelBindingContext(bindingContext);
var item = DependencyResolver.Current.GetService(bindingContext.ModelType);
Func<object> modelAccessor = () => item;
context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),
bindingContext.ModelMetadata.ContainerType, modelAccessor, item.GetType(), bindingContext.ModelName);
return base.BindModel(controllerContext, context);
}
}
在我的控制器中,我只使用接口作为参数。因此,它工作正常,因为值正确填充。
但是,如何在Web API中使用正确绑定的值进行相同操作? 我尝试实现IModelBinder并继承ModelBinderProvider。我可以获得接口实现的实例,但是没有填充值。
这是WebAPI中的尝试实现:
public class MyCustomWebAPIModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(System.Web.Http.HttpConfiguration configuration, Type modelType)
{
return new MyCustomWebAPIModelBinder();
}
}
public class MyCustomWebAPIModelBinder : IModelBinder
{
public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType.IsInterface)
{
var item = GlobalConfiguration.Configuration.DependencyResolver.GetService(bindingContext.ModelType);
if (item != null)
{
Func<object> modelAccessor = () => item;
var a = bindingContext.ModelMetadata.ContainerType;
var b = modelAccessor;
var c = item.GetType();
var d = bindingContext.ModelName;
bindingContext.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(), a, b, c, d);
bindingContext.Model = item;
return true;
}
}
return false;
}
}
我错过了什么? 是否有可能做我们想要的事情?
答案 0 :(得分:1)
使用MediaTypeFormatter的实现。
,而不是使用ModelBinder您可以覆盖方法“ReadFromStreamAsync”并将类型更改为您需要的任何类型。
在下面的示例中,通过使用MVC的DependencyResolver解析具体类型来更改类型,对于WebAPI可以正常工作。
public class CustomFormUrlEncodedMediaTypeFormatter : FormUrlEncodedMediaTypeFormatter
{
public CustomFormUrlEncodedMediaTypeFormatter() : base() { }
public override Task ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
if (type.IsInterface)
type = GetConcreteType(type);
return base.ReadFromStreamAsync(type, readStream, content, formatterLogger);
}
public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
if (type.IsInterface)
type = GetConcreteType(type);
return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
}
private Type GetConcreteType(Type type)
{
object concrete = System.Web.Mvc.DependencyResolver.Current.GetService(type);
return concrete.GetType();
}
}
如果你想用JsonFormatter做到这一点,那么为Json.NET创建一个“CustomCreationConverter”是一个更好的方法,而不是解决你的界面中所有子对象的依赖性。
public class DomainConverter : CustomCreationConverter
{
public DomainConverter() { }
public override bool CanConvert(Type objectType)
{
return objectType.IsInterface;
}
public override object Create(Type objectType)
{
return System.Web.Mvc.DependencyResolver.Current.GetService(objectType);
}
}