我正在使用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容器创建一个自定义模型绑定器来解析它们实现的接口。 / p>
但是,经过一些调查后,我遇到How Web API does parameter binding并发现Web API使用格式化程序而不是复杂类型的模型绑定程序。链接的博客文章建议在我的操作参数上使用ModelBinderAttribute,但该属性仅接受类型作为参数。但是,我的自定义模型绑定器不包含空构造函数(它需要一个统一容器),因此我需要传递它的实例。
我能想到的另一种方法是为格式化程序使用依赖注入。不幸的是,我不熟悉它们,因为我以前从未使用它们。
哪种方式正确?我该怎么做?
答案 0 :(得分: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));
}
答案 1 :(得分:2)
我建议你看一下服务栈 http://www.servicestack.net/
它的设计与asp.net-WebApi完全相同,但它有像IOC一样的好东西。
服务堆栈上有一个惊人的系列 http://pluralsight.com/training/Courses/TableOfContents/service-stack