2014-02-21 49 views
0

我有一个动作方法返回一个HttpResponseMessage的API,但是基于Accept头这可以返回数据的许多不同的格式。连载多个返回类型与Request.CreateResponse

这是我的那一刻,它的工作,但它不是很理想,因为我得记住,包括在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); 
    } 

它工作正常,没有if (mapped is ApiModelV1)的一部分,如果我只是连载到JSON,但如果我到串行化XML抛出异常。有没有人知道以更通用的方式做到这一点?

回答

0

OK,我已经找到了解决办法,但我不得不求助于使用反射,因为我不能”让它工作正常与已知类型的y。

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 ...)的,我想每一个连载型远更有利。

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) 
     ); 
    } 
} 
+0

谢谢,但如果我用KnownType属性,那么XML输出有使用上的一切d1p1命名空间。唯一可以让它输出内容的方法是使用自定义串行器,然后说'return Request.CreateResponse(HttpStatusCode.OK,映射为BaseModel);'然后根元素被命名为“BaseModel”。 – Tom