asp.net-mvc-4 – 用于继承类型的WebApi模型绑定

前端之家收集整理的这篇文章主要介绍了asp.net-mvc-4 – 用于继承类型的WebApi模型绑定前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在寻找在WebApi中继承类型的模型绑定,而我真正想要做的是使用默认模型绑定来处理绑定(除了选择不能这样做的类型),但是我遗漏一些根本的东西

所以说我有类型:

  1. public abstract class ModuleVM
  2. {
  3. public abstract ModuleType ModuleType { get; }
  4. }
  5.  
  6. public class ConcreteVM : ModuleVM
  7. {
  8.  
  9. }

使用MVC控制器,我会这样做:

  1. public class ModuleMvcBinder : DefaultModelBinder
  2. {
  3. protected override object CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType)
  4. {
  5. if (modelType == typeof(ModuleVM))
  6. {
  7. // Just hardcoding the type for simplicity
  8. Type instantiationType = typeof(ConcreteVM);
  9. var obj = Activator.CreateInstance(instantiationType);
  10. bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null,instantiationType);
  11. bindingContext.ModelMetadata.Model = obj;
  12. return obj;
  13. }
  14. return base.CreateModel(controllerContext,bindingContext,modelType);
  15. }
  16.  
  17. }
  18.  
  19. [AttributeUsage( AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Struct | AttributeTargets.Property,AllowMultiple = false,Inherited = false)]
  20. public class ModuleMvcBinderAttribute : CustomModelBinderAttribute
  21. {
  22. public override IModelBinder GetBinder()
  23. {
  24. return new ModuleMvcBinder();
  25. }
  26. }

然后使用控制器上的属性,一切都很好,我正在利用DefaultModelBinder进行实际工作,我基本上只是提供正确的对象实例化.

那么如何为WebApi版本做同样的呢?

如果我使用自定义模型绑定器(例如Error implementing a Custom Model Binder in Asp.Net Web API),我的问题是(我相信)在BindModel方法中,我没有找到在实例化对象之后使用“标准”http绑定的好方法.我可以专门针对其他帖子中提到的JSON(Deserialising Json to derived types in Asp.Net Web API)或XML(Getting my Custom Model bound to my POST controller)进行处理,但在我看来,这是因为web api应该分离出来,而是 – 它只是不知道如何确定方式. (所有具体类型自然处理得很好.)

我是否忽略了一些明显的事情,我应该在实例化对象后引导BindModel调用

解决方法

以下是我在我的类型中继承的一个示例,并且在某些设置(如使用KnownType属性装饰,Xml格式化程序的datacontractserializer需要)和TypeNameHandling设置之后,我们可以期待两个xml / json请求的一致行为.
  1. using Newtonsoft.Json;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Net;
  5. using System.Net.Http;
  6. using System.Net.Http.Formatting;
  7. using System.Net.Http.Headers;
  8. using System.Runtime.Serialization;
  9. using System.Web.Http;
  10. using System.Web.Http.SelfHost;
  11.  
  12. namespace Service
  13. {
  14. class Service
  15. {
  16. private static HttpSelfHostServer server = null;
  17. private static string baseAddress = string.Format("http://{0}:9095/",Environment.MachineName);
  18.  
  19. static void Main(string[] args)
  20. {
  21. HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
  22. config.Routes.MapHttpRoute("Default","api/{controller}/{id}",new { id = RouteParameter.Optional });
  23. config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
  24. config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
  25.  
  26. try
  27. {
  28. server = new HttpSelfHostServer(config);
  29. server.OpenAsync().Wait();
  30.  
  31. Console.WriteLine("Service listenting at: {0} ...",baseAddress);
  32.  
  33. TestWithHttpClient("application/xml");
  34.  
  35. TestWithHttpClient("application/json");
  36.  
  37. Console.ReadLine();
  38. }
  39. catch (Exception ex)
  40. {
  41. Console.WriteLine("Exception Details:\n{0}",ex.ToString());
  42. }
  43. finally
  44. {
  45. if (server != null)
  46. {
  47. server.CloseAsync().Wait();
  48. }
  49. }
  50. }
  51.  
  52. private static void TestWithHttpClient(string mediaType)
  53. {
  54. HttpClient client = new HttpClient();
  55.  
  56. MediaTypeFormatter formatter = null;
  57.  
  58. // NOTE: following any settings on the following formatters should match
  59. // to the settings that the service's formatters have.
  60. if (mediaType == "application/xml")
  61. {
  62. formatter = new XmlMediaTypeFormatter();
  63. }
  64. else if (mediaType == "application/json")
  65. {
  66. JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
  67. jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
  68.  
  69. formatter = jsonFormatter;
  70. }
  71.  
  72. HttpRequestMessage request = new HttpRequestMessage();
  73. request.RequestUri = new Uri(baseAddress + "api/students");
  74. request.Method = HttpMethod.Get;
  75. request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
  76. HttpResponseMessage response = client.SendAsync(request).Result;
  77. Student std = response.Content.ReadAsAsync<Student>().Result;
  78.  
  79. Console.WriteLine("GET data in '{0}' format",mediaType);
  80. if (StudentsController.CONSTANT_STUDENT.Equals(std))
  81. {
  82. Console.WriteLine("both are equal");
  83. }
  84.  
  85. client = new HttpClient();
  86. request = new HttpRequestMessage();
  87. request.RequestUri = new Uri(baseAddress + "api/students");
  88. request.Method = HttpMethod.Post;
  89. request.Content = new ObjectContent<Person>(StudentsController.CONSTANT_STUDENT,formatter);
  90. request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
  91. Student std1 = client.SendAsync(request).Result.Content.ReadAsAsync<Student>().Result;
  92.  
  93. Console.WriteLine("POST and receive data in '{0}' format",mediaType);
  94. if (StudentsController.CONSTANT_STUDENT.Equals(std1))
  95. {
  96. Console.WriteLine("both are equal");
  97. }
  98. }
  99. }
  100.  
  101. public class StudentsController : ApiController
  102. {
  103. public static readonly Student CONSTANT_STUDENT = new Student() { Id = 1,Name = "John",EnrolledCourses = new List<string>() { "maths","physics" } };
  104.  
  105. public Person Get()
  106. {
  107. return CONSTANT_STUDENT;
  108. }
  109.  
  110. // NOTE: specifying FromBody here is not required. By default complextypes are bound
  111. // by formatters which read the body
  112. public Person Post([FromBody] Person person)
  113. {
  114. if (!ModelState.IsValid)
  115. {
  116. throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest,this.ModelState));
  117. }
  118.  
  119. return person;
  120. }
  121. }
  122.  
  123. [DataContract]
  124. [KnownType(typeof(Student))]
  125. public abstract class Person : IEquatable<Person>
  126. {
  127. [DataMember]
  128. public int Id { get; set; }
  129.  
  130. [DataMember]
  131. public string Name { get; set; }
  132.  
  133. public bool Equals(Person other)
  134. {
  135. if (other == null)
  136. return false;
  137.  
  138. if (ReferenceEquals(this,other))
  139. return true;
  140.  
  141. if (this.Id != other.Id)
  142. return false;
  143.  
  144. if (this.Name != other.Name)
  145. return false;
  146.  
  147. return true;
  148. }
  149. }
  150.  
  151. [DataContract]
  152. public class Student : Person,IEquatable<Student>
  153. {
  154. [DataMember]
  155. public List<string> EnrolledCourses { get; set; }
  156.  
  157. public bool Equals(Student other)
  158. {
  159. if (!base.Equals(other))
  160. {
  161. return false;
  162. }
  163.  
  164. if (this.EnrolledCourses == null && other.EnrolledCourses == null)
  165. {
  166. return true;
  167. }
  168.  
  169. if ((this.EnrolledCourses == null && other.EnrolledCourses != null) ||
  170. (this.EnrolledCourses != null && other.EnrolledCourses == null))
  171. return false;
  172.  
  173. if (this.EnrolledCourses.Count != other.EnrolledCourses.Count)
  174. return false;
  175.  
  176. for (int i = 0; i < this.EnrolledCourses.Count; i++)
  177. {
  178. if (this.EnrolledCourses[i] != other.EnrolledCourses[i])
  179. return false;
  180. }
  181.  
  182. return true;
  183. }
  184. }
  185. }

猜你在找的asp.Net相关文章