我有一个API的动作方法,它返回一个HttpResponseMessage,但是根据Accept标头,它可以返回许多不同格式的数据。
这就是我目前所做的,它确实有效,但它不是很理想,因为我必须记住在MappedItem方法中包含任何新类,并且会有很多。
[HttpGet]
public HttpResponseMessage Get(int id)
{
var result = _builder.Build(id);
return MappedItem(result);
}
protected HttpResponseMessage MappedItem<T>(T item)
{
// Maps the class to the media type defined in the Accept header
var destinationType = GetDestinationType();
var type = typeof(T);
var mapped = Mapper.Map(item, type, destinationType);
if (mapped is ApiModelV1) {
return Request.CreateResponse(HttpStatusCode.OK, mapped as ApiModelV1);
}
return Request.CreateResponse(HttpStatusCode.OK, mapped);
}
如果我只是序列化为JSON,它在没有if (mapped is ApiModelV1)
部分的情况下工作正常,但如果我序列化为XML则抛出异常。有没有人知道以更通用的方式做到这一点的方法?
答案 0 :(得分:1)
一种可能性是使用KnownType
属性装饰您的基类,并列出所有可能的派生类,以向XML序列化程序指示这些类型的存在:
[KnownType(typeof(ApiModelV1))]
[KnownType(typeof(ApiModelV2))]
public class BaseClass
{
...
}
或者,如果您不想使用此类属性污染模型,则可以使用自定义XML序列化程序并指明已知类型:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var knownTypes = new Type[]
{
typeof(ApiModelV1),
typeof(ApiModelV2),
};
config.Formatters.XmlFormatter.SetSerializer<BaseClass>(
new DataContractSerializer(typeof(BaseClass), knownTypes)
);
}
}
答案 1 :(得分:0)
好的,我找到了一个解决方案,虽然我不得不求助于使用反射,因为我无法使用已知类型正常工作。
protected HttpResponseMessage MappedItem<T>(T item)
{
var destinationType = GetDestinationType();
var type = typeof(T);
var mapped = Mapper.Map(item, type, destinationType);
MethodInfo method = this.GetType().GetMethod("CreateResponse", BindingFlags.Public | BindingFlags.Instance);
method = method.MakeGenericMethod(mapped.GetType());
return (HttpResponseMessage)method.Invoke(this, new[] {mapped});
}
public HttpResponseMessage CreateResponse<T>(T obj)
{
return Request.CreateResponse(HttpStatusCode.OK, obj);
}
它并不理想,但它比我想要序列化的每种类型都有很多if (mapped is ...)
要好得多。