2013-03-16 2 views
2

구현하고있는 모든 유형의 유형과 특정 유형의 인터페이스를 바인딩해야하는 간단한 웹 앱을 개발 중입니다. 내 인터페이스는 문서 클래스 IContent 그래서 그에 대한 구현하는 많은 다른 클래스의 한 여기에 깨끗이웹 API 및 RavenDB를 사용하여 상속 된 사용자 정의 모델 바인더

public class Article : IContent { 
    public string Id { get;set; } 
    public string Heading { get;set; } 
} 

과 같을 것이다,이 인터페이스를 사용하여이

public interface IContent { 
    string Id { get;set; } 
} 

일반적인 클래스처럼 하나의 속성이 있습니다 이러한 유형을 저장하고 업데이트하는 일반적인 방법이 필요합니다.

그래서 내 컨트롤러에 내가 가진이

public void Put(string id, [System.Web.Http.ModelBinding.ModelBinder(typeof(ContentModelBinder))] IContent value) 
{ 
    // Store the updated object in ravendb 
} 

와 ContentBinder 같은 put 메소드

public class ContentModelBinder : System.Web.Http.ModelBinding.IModelBinder { 
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { 

     actionContext.ControllerContext.Request.Content.ReadAsAsync<Article>().ContinueWith(task => 
     { 
      Article model = task.Result; 
      bindingContext.Model = model; 
     }); 

     return true; 
    } 

} 

는 제목 특성 잡아 보이지 않기 때문에 위의 코드는 작동하지 않습니다 기본 모델 바인더를 사용하더라도 제목을 올바르게 바인딩합니다.

그래서 BindModel 메서드에서 id를 기반으로 ravendb에서 올바른 개체를로드 한 다음 일종의 기본 모델 바인더를 사용하여 복잡한 개체를 업데이트해야 할 것 같습니까? 이것은 내가 도움이 필요한 곳입니다.

+0

@ matt-johnson 실제로 모델을 업데이트하는 방법은 없지만 일부 코드로 내 질문을 업데이트했지만 시행 착오 일뿐입니다. – Marcus

+0

@MattJohnson HttpContent.ReadAsAsync 또는 뭔가를 사용하여 특정 유형의 json을 deserialize 할 수 있습니까? – Marcus

+0

@ matt-johnson ReadAsAsync로 코드를 업데이트했지만 왜 작동하지 않는지 알 수 없습니다. – Marcus

답변

0

@ kiran-challa 솔루션을 사용하고 Json 미디어 유형 포매터의 SerializerSettings에 TypeNameHandling을 추가했습니다.

2

Marcus는 다음과 같은 Json 및 Xml 포맷터에서 잘 작동하는 예제입니다.

using Newtonsoft.Json; 
using System; 
using System.Collections.Generic; 
using System.Net; 
using System.Net.Http; 
using System.Net.Http.Formatting; 
using System.Net.Http.Headers; 
using System.Runtime.Serialization; 
using System.Web.Http; 
using System.Web.Http.SelfHost; 

namespace Service 
{ 
    class Service 
    { 
     private static HttpSelfHostServer server = null; 
     private static string baseAddress = string.Format("http://{0}:9095/", Environment.MachineName); 

     static void Main(string[] args) 
     { 
      HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress); 
      config.Routes.MapHttpRoute("Default", "api/{controller}/{id}", new { id = RouteParameter.Optional }); 
      config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always; 
      config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects; 

      try 
      { 
       server = new HttpSelfHostServer(config); 
       server.OpenAsync().Wait(); 

       Console.WriteLine("Service listenting at: {0} ...", baseAddress); 

       TestWithHttpClient("application/xml"); 

       TestWithHttpClient("application/json"); 

       Console.ReadLine(); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("Exception Details:\n{0}", ex.ToString()); 
      } 
      finally 
      { 
       if (server != null) 
       { 
        server.CloseAsync().Wait(); 
       } 
      } 
     } 

     private static void TestWithHttpClient(string mediaType) 
     { 
      HttpClient client = new HttpClient(); 

      MediaTypeFormatter formatter = null; 

      // NOTE: following any settings on the following formatters should match 
      // to the settings that the service's formatters have. 
      if (mediaType == "application/xml") 
      { 
       formatter = new XmlMediaTypeFormatter(); 
      } 
      else if (mediaType == "application/json") 
      { 
       JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter(); 
       jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects; 

       formatter = jsonFormatter; 
      } 

      HttpRequestMessage request = new HttpRequestMessage(); 
      request.RequestUri = new Uri(baseAddress + "api/students"); 
      request.Method = HttpMethod.Get; 
      request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType)); 
      HttpResponseMessage response = client.SendAsync(request).Result; 
      Student std = response.Content.ReadAsAsync<Student>().Result; 

      Console.WriteLine("GET data in '{0}' format", mediaType); 
      if (StudentsController.CONSTANT_STUDENT.Equals(std)) 
      { 
       Console.WriteLine("both are equal"); 
      } 

      client = new HttpClient(); 
      request = new HttpRequestMessage(); 
      request.RequestUri = new Uri(baseAddress + "api/students"); 
      request.Method = HttpMethod.Post; 
      request.Content = new ObjectContent<Person>(StudentsController.CONSTANT_STUDENT, formatter); 
      request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType)); 
      Student std1 = client.SendAsync(request).Result.Content.ReadAsAsync<Student>().Result; 

      Console.WriteLine("POST and receive data in '{0}' format", mediaType); 
      if (StudentsController.CONSTANT_STUDENT.Equals(std1)) 
      { 
       Console.WriteLine("both are equal"); 
      } 
     } 
    } 

    public class StudentsController : ApiController 
    { 
     public static readonly Student CONSTANT_STUDENT = new Student() { Id = 1, Name = "John", EnrolledCourses = new List<string>() { "maths", "physics" } }; 

     public Person Get() 
     { 
      return CONSTANT_STUDENT; 
     } 

     // NOTE: specifying FromBody here is not required. By default complextypes are bound 
     // by formatters which read the body 
     public Person Post([FromBody] Person person) 
     { 
      if (!ModelState.IsValid) 
      { 
       throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, this.ModelState)); 
      } 

      return person; 
     } 
    } 

    [DataContract] 
    [KnownType(typeof(Student))] 
    public abstract class Person : IEquatable<Person> 
    { 
     [DataMember] 
     public int Id { get; set; } 

     [DataMember] 
     public string Name { get; set; } 

     // this is ignored 
     public DateTime DateOfBirth { get; set; } 

     public bool Equals(Person other) 
     { 
      if (other == null) 
       return false; 

      if (ReferenceEquals(this, other)) 
       return true; 

      if (this.Id != other.Id) 
       return false; 

      if (this.Name != other.Name) 
       return false; 

      return true; 
     } 
    } 

    [DataContract] 
    public class Student : Person, IEquatable<Student> 
    { 
     [DataMember] 
     public List<string> EnrolledCourses { get; set; } 

     public bool Equals(Student other) 
     { 
      if (!base.Equals(other)) 
      { 
       return false; 
      } 

      if (this.EnrolledCourses == null && other.EnrolledCourses == null) 
      { 
       return true; 
      } 

      if ((this.EnrolledCourses == null && other.EnrolledCourses != null) || 
       (this.EnrolledCourses != null && other.EnrolledCourses == null)) 
       return false; 

      if (this.EnrolledCourses.Count != other.EnrolledCourses.Count) 
       return false; 

      for (int i = 0; i < this.EnrolledCourses.Count; i++) 
      { 
       if (this.EnrolledCourses[i] != other.EnrolledCourses[i]) 
        return false; 
      } 

      return true; 
     } 
    } 
}