【问题标题】:Dependency injection for ASP.NET Web API action method parametersASP.NET Web API 操作方法参数的依赖注入
【发布时间】:2012-12-06 16:30:22
【问题描述】:

我正在开发一个 C# 中的 ASP.NET Web API 项目,用于移动应用程序的 JSON 接口。我的想法是为所有请求创建接口,然后只在 Web API 代码中使用这些接口。

我最终得到了这样的结果:

public interface IApiObject {}
public interface IApiResponse<T> : IApiObject where T : IApiObject {}
public interface IApiRegistrationRequest : IApiObject {}

我的控制器如下所示:

public class MyApiController : ApiController
{

    public IApiResponse<IApiObject> Register(IApiRegistrationRequest request) {
        // do some stuff
    }
}

我的 Web API 项目也包含这些接口的实现。

我假设 Web API 项目像 MVC 项目一样使用模型绑定,因此我创建了一个 inheritance aware ModelBinderProvider 来为所有 IApiObjects 提供绑定器,并使用 Unity 容器来自定义模型绑定器来解析其实现的接口。

但是,经过进一步调查,我发现了How Web API does parameter binding,发现 Web API 使用格式化程序而不是复杂类型的模型绑定器。链接的博客文章建议在我的操作参数上使用 ModelBinderAttribute,但该属性仅接受类型作为参数。但是,我的自定义模型绑定器不包含空构造函数(它需要一个统一容器),因此我需要传递它的一个实例。

我能想到的另一种方法是对格式化程序使用依赖注入。不幸的是,我对它们并不熟悉,因为我以前从未使用过它们。

正确的方法是什么?我该怎么做?

【问题讨论】:

    标签: c# dependency-injection asp.net-web-api


    【解决方案1】:

    这就是我现在想出的方法。

    我决定创建一个自定义格式化程序,它执行统一调用并将所有进一步的操作转发到另一个使用已解析类型的格式化程序。看起来代码很多,但那只是因为所有的方法都需要被覆盖,所以类型总是可以被解析的。

    public class UnityFormatter : MediaTypeFormatter
    {
        private MediaTypeFormatter formatter;
    
        private IUnityContainer container;
    
        public UnityFormatter(MediaTypeFormatter formatter, IUnityContainer container)
        {
            this.formatter = formatter;
            this.container = container;
    
            foreach (var supportedMediaType in this.formatter.SupportedMediaTypes)
            {
                this.SupportedMediaTypes.Add(supportedMediaType);
            }
    
            foreach (var supportedEncoding in this.formatter.SupportedEncodings)
            {
                this.SupportedEncodings.Add(supportedEncoding);
            }
    
            foreach (var mediaTypeMapping in this.MediaTypeMappings)
            {
                this.MediaTypeMappings.Add(mediaTypeMapping);
            }
    
            this.RequiredMemberSelector = this.formatter.RequiredMemberSelector;
        }
    
        private Type ResolveType(Type type)
        {
            return this.container.Registrations.Where(n => n.RegisteredType == type).Select(n => n.MappedToType).FirstOrDefault() ?? type;
        }
    
        public override bool CanReadType(Type type)
        {
            return this.formatter.CanReadType(this.ResolveType(type));
        }
    
        public override bool CanWriteType(Type type)
        {
            return this.formatter.CanWriteType(this.ResolveType(type));
        }
    
        public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
        {
            return this.formatter.GetPerRequestFormatterInstance(this.ResolveType(type), request, mediaType);
        }
    
        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            return this.formatter.ReadFromStreamAsync(this.ResolveType(type), readStream, content, formatterLogger);
        }
    
        public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
        {
            this.formatter.SetDefaultContentHeaders(this.ResolveType(type), headers, mediaType);
        }
    
        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            return this.formatter.WriteToStreamAsync(this.ResolveType(type), value, writeStream, content, transportContext);
        }
    }
    

    最后,在应用程序配置 (Global.asax Application_Start) 中注册我们的自定义格式化程序。我选择用我自定义的一个实例替换所有当前的格式化程序,所以我得到了所有数据类型的反射。

    // set up unity container, register all types
    UnityContainer container = new UnityContainer();
    container.RegisterType<IApiRegistrationRequest, ApiRegistrationRequest>();
    
    // save existing formatters and remove them from the config
    List<MediaTypeFormatter> formatters = new List<MediaTypeFormatter>(GlobalConfiguration.Configuration.Formatters);
    GlobalConfiguration.Configuration.Formatters.Clear();
    
    // create an instance of our custom formatter for each existing formatter
    foreach (MediaTypeFormatter formatter in formatters)
    {
        GlobalConfiguration.Configuration.Formatters.Add(new UnityFormatter(formatter, container));
    }
    

    【讨论】:

      【解决方案2】:

      我建议你看看 Service Stack http://www.servicestack.net/

      它的设计与 asp.net-WebApi 相同,但其中包含 IOC 之类的好东西。

      在服务堆栈上有一个惊人的系列 http://pluralsight.com/training/Courses/TableOfContents/service-stack

      【讨论】:

      • 谢谢,这看起来很有趣,但我现在不能轻易改变技术。
      猜你喜欢
      • 2017-10-22
      • 2018-03-24
      • 1970-01-01
      • 1970-01-01
      • 2015-11-08
      • 2013-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多