2013-08-19 83 views
5

我試圖綁定一個控制器動作到接口,但仍然保持默認的綁定行爲。web api模型綁定到接口

public class CoolClass : ISomeInterface 
{ 
    public DoSomething {get;set;} // ISomeInterface 
} 

public class DosomethingController : ApiController 
{ 
    public HttpResponseMessage Post(ISomeInterface model) 
    { 
     // do something with model which should be an instance of CoolClass 
    } 
} 

我的服務的消費者知道什麼CoolClass這麼讓他們加上「$型」向他們傳遞將在我看來,一個黑客的JSON。我希望能夠在服務中處理它。如果我將CoolClass指定爲動作參數,它可以正常工作。

編輯:所以我在這裏找到了我的問題的部分解決方案Dependency injection for ASP.NET Web API action method parameters,但有一個後續問題。該解決方案不能解析接口屬性。看我下面的例子。

IConcreteClass將被解析,但ISubtype不會。

public class SubConcreteClass : ISubtype 
{ 
    // properties 
} 

public class ConcreteClass : IConcreteClass 
{ 
    public ISubtype Subtype {get;set;} 
} 

一旦媒體格式化程序發現可以解析IConcreteClass中的類型,它就會讀取整個流。所以我猜測沒有機會解決接口成員。

+0

對於另一替代方案中,檢查了我的回答一個類似的問題[_here_](HTTP:// stackoverflow.com/questions/14124189/can-i-pass-an-interface-based-object-to-an-mvc-4-webapi-post/22279204#22279204)。 –

回答

11

因此,如果這可以幫助其他人,我會繼續發佈我提出的解決方案。

正如我上面提到的,動作方法的接口參數可以使用DI解決。但是該對象的接口成員需要以不同的方式處理。

我創建了2種類型的Json轉換器,一種實體類型和一種集合類型,用於修飾接口屬性。

這裏有一個需要作爲動作接口參數解析的類。

public class CreateEnvelopeModel : ICreateEnvelopeCommand 
{ 
    [JsonConverter(typeof(EntityModelConverter<CreateEmailModel, ICreateEmailCommand>))] 
    public ICreateEmailCommand Email { get; set; } 
    [JsonConverter(typeof(CollectionEntityConverter<CreateFormModel, ICreateFormCommand>))] 
    public IList<ICreateFormCommand> Forms { get; set; } 
} 

這裏的控制器的操作方法

public HttpResponseMessage PostEnvelope(ICreateEnvelopeCommand model) 
{ 
    // do stuff 
} 

這裏是2 JSON變換器

public class EntityModelConverter<T, Tt> : JsonConverter where T : Tt 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(Tt)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return serializer.Deserialize<T>(reader); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value, typeof(T)); 
    } 
} 

public class CollectionEntityConverter<T, Tt> : JsonConverter where T : Tt 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(IList<Tt>)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     IList<Tt> items = serializer.Deserialize<List<T>>(reader).Cast<Tt>().ToList(); 
     return items; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value, typeof(IList<T>)); 
    } 
} 
+0

這是一個很好的解決方案。 – saille

+0

你最好的,它只是完美的工作。 – alsafoo

+0

這是非常簡單和有效的。使用這個與自定義模型綁定有什麼缺點嗎?關於如何在接口有多個實現類的集合(例如IAuto,Car:IAuto,Truck:IAuto)上使用類似的東西的想法? – BrianS

-1

Model Binders部分here。我認爲這是你的情況。

+0

謝謝亞歷克斯。我看到那個頁面,但我真的希望這可以通過我的DI容器來解決。用DI解析API動作接口參數是不可能的? – chrisl91

+0

更新我的問題。 – chrisl91