我的团队需要使用此框架为我们的公司和产品开发框架.
其中一个要求是可以为特定客户定制产品,但应该使用同一产品的其他版本(不是自动)轻松更新.
其中一个要求是可以为特定客户定制产品,但应该使用同一产品的其他版本(不是自动)轻松更新.
我们正在使用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; } }
我错过了什么?
有可能做我们想要的吗?
解决方法
而不是使用ModelBinder,使用MediaTypeFormatter的实现.
您可以覆盖方法“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,TransportContext transportContext) { if (type.IsInterface) type = GetConcreteType(type); return base.WriteToStreamAsync(type,value,writeStream,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); } }