2013-08-19 4 views
5

컨트롤러 작업을 인터페이스에 바인딩하려고하지만 여전히 기본 바인딩 동작을 유지하려고합니다.인터페이스에 웹 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 
    } 
} 

내 서비스의 소비자는 그래서 그들이 내 의견에 해킹 될 전달하는 JSON에 "$ 유형"을 추가 할 필요 CoolClass 아무것도 모른다. 서비스에서 처리 할 수 ​​있기를 바랍니다. 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에 내 대답을 체크 아웃입니다 : // http://www.google.com/support/bin/answer.py?answer=14124189/can-i-pass-an-interface-based-object-to-an-mvc-4-webapi-post/22279204#22279204). –

답변

11

다른 사람에게 도움이 될 수 있으므로 필자가 생각해 낸 해결책을 게시하겠습니다.

위에서 언급했듯이 동작 방법의 인터페이스 매개 변수는 DI를 사용하여 해결할 수 있습니다. 그러나 객체의 인터페이스 멤버는 다르게 처리해야합니다.

인터페이스 속성을 꾸미기 위해 단일 엔티티 유형과 컬렉션 유형의 두 가지 유형의 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

감사합니다. Alex. 나는 그 페이지를 보았지만 이것이 나의 DI 컨테이너로 해결 될 수 있기를 정말로 바라고 있었다. DI를 사용하여 API 작업 인터페이스 매개 변수를 해결할 수 있습니까? – chrisl91

+0

내 질문이 업데이트되었습니다. – chrisl91