依赖注入的ASP.NET Web API操作方法参数 [英] Dependency injection for ASP.NET Web API action method parameters

查看:261
本文介绍了依赖注入的ASP.NET Web API操作方法参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on an ASP.NET Web API project in C# for a JSON interface to a mobile application. My idea was to create interfaces for all requests and then only use these interfaces in the Web API code.

我结束了这样的事情:

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

我的控制器看起来是这样的:

My controller looks like this:

public class MyApiController : ApiController
{

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

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

My Web API project also contains implementations of these interfaces.

我认为网页API项目中使用的模型像MVC项目结合做的,所以我创建了一个<一个href=\"http://www.matthidinger.com/archive/2011/08/16/An-inheritance-aware-ModelBinderProvider-in-MVC-3.aspx\">inheritance意识到ModelBinderProvider 使用一个统一的容器接口解析为其实现提供所有IApiObjects粘结剂和自定义模型粘合剂。

I assumed Web API projects use model binding like MVC projects do, so I created an inheritance aware ModelBinderProvider for providing a binder for all IApiObjects and a custom model binder using a Unity container to resolve the interfaces to their implementations.

不过,经过一番更多的调查,我碰到的网络API如何参数绑定并发现该Web API使用格式化,而不是为复杂类型的模型粘合剂。链接的博客文章建议使用我的行动参数ModelBinderAttribute,但该属性只接受一个类型作为参数。我的自定义模型粘合剂没有,但不包含一个空的构造(它需要一个统一的容器),所以我需要通过它的一个实例。

However, after some more investigation, I came across How Web API does parameter binding and found out that Web API uses formatters instead of model binders for complex types. The linked blog post recommends using a ModelBinderAttribute on my action parameters, but that attribute only accepts a type as a parameter. My custom model binder does, however, not contain an empty constructor (it needs a unity container), so I would need to pass an instance of it.

我能想到的是使用依赖注入的格式化的其他方式。不幸的是,我不熟悉他们,因为我从来没有使用过他们。

The other way I can think of is using dependency injection for the formatters. Unfortunately, I am unfamiliar with them as I have never used them before.

这是正确的方式去?而我怎么办呢?

Which is the right way to go? And how do I do it?

推荐答案

这是我想出现在和它的作品。

This is what I came up with now and it works.

我决定创建一个自定义的格式由它来统一调用和使用转发的解决类型的所有进一步的操作到其他格式。它看起来像一个很多code,但这仅仅是因为所有的方法需要被覆盖,所以类型总是可以解决的。

I decided to create a custom formatter which does the unity calls and forwards all further operations to another formatter using the resolved type. It looks like a lot of code, but that is only because all the methods need to be overwritten so the type can always be resolved.

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)自定义格式化。我选择我自定义的实例,以替代目前所有的格式化,所以我得到反映所有数据类型。

Finally, register our custom formatter in the application config (Global.asax Application_Start). I chose to replace all current formatters with an instance of my custom one, so I get reflection for all data types.

// 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));
}

这篇关于依赖注入的ASP.NET Web API操作方法参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆