3

我的团队需要使用这个框架为我们的公司和产品开发一个框架。其中一个必要条件是可以为特定客户定制产品,但它应该很容易用同一产品的另一个版本进行更新(不是自动的)。

我们正在使用 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;
    }
}

我错过了什么?有没有可能做我们想做的事?

4

1 回答 1

1

不要使用 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, 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);
            }
    }

于 2013-06-19T11:02:57.790 回答