Asp.net mvc 4 使用Web API和RavenDB进行继承的自定义模型绑定器
我正在开发一个简单的web应用程序,需要绑定所有类型和特定类型的接口。我的接口只有一个这样的属性Asp.net mvc 4 使用Web API和RavenDB进行继承的自定义模型绑定器,asp.net-mvc-4,asp.net-web-api,ravendb,model-binding,Asp.net Mvc 4,Asp.net Web Api,Ravendb,Model Binding,我正在开发一个简单的web应用程序,需要绑定所有类型和特定类型的接口。我的接口只有一个这样的属性 public interface IContent { string Id { get;set; } } public class Article : IContent { public string Id { get;set; } public string Heading { get;set; } } public void Put(string id, [Syste
public interface IContent {
string Id { get;set; }
}
public class Article : IContent {
public string Id { get;set; }
public string Heading { get;set; }
}
public void Put(string id, [System.Web.Http.ModelBinding.ModelBinder(typeof(ContentModelBinder))] IContent value)
{
// Store the updated object in ravendb
}
使用此接口的公共类如下所示
public interface IContent {
string Id { get;set; }
}
public class Article : IContent {
public string Id { get;set; }
public string Heading { get;set; }
}
public void Put(string id, [System.Web.Http.ModelBinding.ModelBinder(typeof(ContentModelBinder))] IContent value)
{
// Store the updated object in ravendb
}
这里需要说明的是,article类只是实现IContent的许多不同类中的一个,因此我需要一种存储和更新这些类型的通用方法
所以在我的控制器中,我有这样的put方法
public interface IContent {
string Id { get;set; }
}
public class Article : IContent {
public string Id { get;set; }
public string Heading { get;set; }
}
public void Put(string id, [System.Web.Http.ModelBinding.ModelBinder(typeof(ContentModelBinder))] IContent value)
{
// Store the updated object in ravendb
}
还有ContentBinder
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;
}
}
公共类ContentModelBinder:System.Web.Http.ModelBinding.IModelBinder{
public bool BindModel(HttpActionContext actionContext,ModelBindingContext bindingContext){
actionContext.ControllerContext.Request.Content.ReadAsAsync().ContinueWith(任务=>
{
文章模型=任务。结果;
bindingContext.Model=Model;
});
返回true;
}
}
上面的代码不起作用,因为即使我使用默认的模型绑定器,它也无法正确绑定标题属性
因此,在BindModel方法中,我想我需要根据Id从ravendb加载正确的对象,然后使用某种默认的模型绑定器来更新复杂对象?这就是我需要帮助的地方。我使用了@kiran challa解决方案,并在Json媒体类型格式化程序的SerializerSettings上添加了TypeNameHandling。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;
}
}
}
使用Newtonsoft.Json;
使用制度;
使用System.Collections.Generic;
Net系统;
使用System.Net.Http;
使用System.Net.Http.Formatting;
使用System.Net.Http.Header;
使用System.Runtime.Serialization;
使用System.Web.Http;
使用System.Web.Http.SelfHost;
命名空间服务
{
班级服务
{
私有静态HttpSelfHostServer服务器=null;
私有静态字符串baseAddress=string.Format(“http://{0}:9095/”,Environment.MachineName);
静态void Main(字符串[]参数)
{
HttpSelfHostConfiguration配置=新的HttpSelfHostConfiguration(基本地址);
config.Routes.MapHttpRoute(“默认”、“api/{controller}/{id}”、新的{id=RouteParameter.Optional});
config.IncludeErrorDetailPolicy=IncludeErrorDetailPolicy.Always;
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling=TypeNameHandling.Objects;
尝试
{
服务器=新的HttpSelfHostServer(配置);
server.OpenAsync().Wait();
WriteLine(“服务在:{0}…”上侦听,baseAddress);
使用HttpClient(“应用程序/xml”)进行测试;
使用HttpClient(“应用程序/json”)进行测试;
Console.ReadLine();
}
捕获(例外情况除外)
{
WriteLine(“异常详细信息:\n{0}”,例如ToString());
}
最后
{
如果(服务器!=null)
{
server.CloseAsync().Wait();
}
}
}
HttpClient专用静态void测试(字符串mediaType)
{
HttpClient=新的HttpClient();
MediaTypeFormatter格式化程序=null;
//注意:以下格式化程序上的任何设置都应匹配
//服务的格式化程序具有的设置。
if(mediaType==“应用程序/xml”)
{
formatter=新的XmlMediaTypeFormatter();
}
else if(mediaType==“应用程序/json”)
{
JsonMediaTypeFormatter jsonFormatter=新的JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling=TypeNameHandling.Objects;
formatter=jsonFormatter;
}
HttpRequestMessage请求=新建HttpRequestMessage();
request.RequestUri=新Uri(baseAddress+“api/students”);
request.Method=HttpMethod.Get;
request.Headers.Accept.Add(新MediaTypeWithQualityHeaderValue(mediaType));
HttpResponseMessage response=client.SendAsync(request.Result);
Student std=response.Content.ReadAsAsync().Result;
WriteLine(“以“{0}”格式获取数据”,mediaType);
if(StudentsController.CONSTANT_STUDENT.Equals(std))
{
Console.WriteLine(“两者相等”);
}
client=新的HttpClient();
请求=新的HttpRequestMessage();
request.RequestUri=新Uri(baseAddress+“api/students”);
request.Method=HttpMethod.Post;
request.Content=newObjectContent(StudentsController.CONSTANT\u学生,格式化程序);
request.Headers.Accept.Add(新MediaTypeWithQualityHeaderValue(mediaType));
Student std1=client.SendAsync(request.Result.Content.ReadAsAsync().Result;
WriteLine(“以“{0}”格式发布和接收数据”,mediaType);
if(StudentsController.CONSTANT_STUDENT.Equals(std1))
{
Console.WriteLine(“两者相等”);
}
}
}
公共类学生控制器:ApiController
{
public static readonly Student CONSTANT_Student=new Student(){Id=1,Name=“John”,Enrolled courses=new List(){“数学”,“物理”};
公众人物
{
学生返回常数;
}
//注意:此处不需要指定FromBody。默认情况下,complextypes是绑定的
//通过读取正文的格式化程序
公众人物职位([FromBody]个人)
{
如果(!ModelState.IsValid)
{
抛出新的HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest,this.ModelState));
}
返回p