9

我正在使用 C# 开发一个用于移动应用程序的 JSON 接口的 ASP.NET Web API 项目。我的想法是为所有请求创建接口,然后只在 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 项目一样使用模型绑定,因此我创建了一个具有继承意识的 ModelBinderProvider,用于为所有 IApiObjects 提供绑定器,并使用 Unity 容器创建自定义模型绑定器来解析其实现的接口。

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

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

哪条路是正确的?我该怎么做?

4

2 回答 2

5

这就是我现在想出的,它有效。

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

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));
}
于 2012-12-19T14:49:55.913 回答
2

我建议你看看服务堆栈 http://www.servicestack.net/

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

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

于 2012-12-19T10:47:12.540 回答