Asp.net mvc 4 在Web API OData中手动反序列化对象内容
当使用WCF数据服务客户端与我的ODataAPI通信时,我偶尔需要使用 System.Data.Services.Client.DataServiceContext的AddRelatedObject方法 这将生成一个到端点的Asp.net mvc 4 在Web API OData中手动反序列化对象内容,asp.net-mvc-4,asp.net-web-api,odata,Asp.net Mvc 4,Asp.net Web Api,Odata,当使用WCF数据服务客户端与我的ODataAPI通信时,我偶尔需要使用 System.Data.Services.Client.DataServiceContext的AddRelatedObject方法 这将生成一个到端点的POST,如下所示: http://base_url/odata/Entity(键)/导航属性 http请求的内容是序列化的NavigationProperty实体 由于默认odata控制器中未映射到此URL的帖子,因此我编写了一个新的EntitySetRoutingConv
POST
,如下所示:
http://base_url/odata/Entity(键)/导航属性
http请求的内容是序列化的NavigationProperty
实体
由于默认odata控制器中未映射到此URL的帖子,因此我编写了一个新的EntitySetRoutingConvention类:
Public Class AddRelatedObjectRoutingConvention
Inherits EntitySetRoutingConvention
Public Overrides Function SelectAction(odataPath As Http.OData.Routing.ODataPath, controllerContext As Http.Controllers.HttpControllerContext, actionMap As ILookup(Of String, Http.Controllers.HttpActionDescriptor)) As String
If controllerContext.Request.Method = Net.Http.HttpMethod.Post Then
If odataPath.PathTemplate = "~/entityset/key/navigation" Then
If actionMap.Contains("AddRelation") Then
Return "AddRelation"
End If
End If
End If
Return Nothing
End Function
End Class
我将其添加到默认路由约定列表中,并将其传递到MapODATARoute
例程
在我的基本控制器中,我实现了AddRelation
,它被完美地调用
从中,我能够获得odatapath
,并对其进行解析以确定所需的类型和键
我遇到的问题是,一旦我知道我的父实体是一个键为1
的租户
,并且租户
实体中用户
的导航属性
是一个用户
实体,我不知道如何手动调用odatamediatypeformatter
将http内容反序列化到用户
实体中,以便将其添加到租户
用户集合中
我查看了OData源代码,试图了解如何使用Web API管道调用和反序列化实体,但无法找到OData库获取http内容并将其转换为实体的点
如果有人能给我指出正确的方向,我会继续研究并更新,如果我发现更多
更新日期2013年6月28日
多亏了拉古拉姆,我才得以靠近。我看到的问题是request.getconfiguration().formatters或odatamediatypeformatters.create似乎都创建了特定于类型的反序列化程序
调用ReadAsAsync时,我收到错误:
没有MediaTypeFormatter可用于从媒体类型为“application/atom+xml”的内容中读取“User”类型的对象
正如上面的文章所示,控制器的上下文是租户,因此我认为格式化程序是键入给租户的,因此无法反序列化用户
我尝试手动创建格式化程序,_childDefinition是来自odatapath的导航属性的EDM类型引用。在本例中,是一个用户
Dim dser As New Formatter.Deserialization.ODataEntityDeserializer(_childDefinition, New Formatter.Deserialization.DefaultODataDeserializerProvider)
Dim ser As New Formatter.Serialization.ODataEntityTypeSerializer(_childDefinition, New Formatter.Serialization.DefaultODataSerializerProvider)
Dim dprovider As New Formatter.Deserialization.DefaultODataDeserializerProvider
dprovider.SetEdmTypeDeserializer(_childDefinition, dser)
Dim sprovider As New Formatter.Serialization.DefaultODataSerializerProvider
sprovider.SetEdmTypeSerializer(_childDefinition, ser)
Dim fmt As New Formatter.ODataMediaTypeFormatter(dprovider, sprovider, New List(Of Microsoft.Data.OData.ODataPayloadKind) From {Microsoft.Data.OData.ODataPayloadKind.Entry})
fmt.SupportedEncodings.Add(System.Text.Encoding.UTF8)
fmt.SupportedEncodings.Add(System.Text.Encoding.Unicode)
fmt.SupportedMediaTypes.Add(Headers.MediaTypeHeaderValue.Parse("application/atom+xml;type=entry"))
fmt.SupportedMediaTypes.Add(New Headers.MediaTypeHeaderValue("application/atom+xml"))
然后我尝试:
request.content.ReadAsAsync(of User)(new List(of odatamediatypeformatter) from {fmt})
request.content.ReadAsAsync(of User)(request.getConfiguration().formatters)
request.content.ReadAsAsync(of User)(odatamediatypeformatters.create)
所有人都犯了同样的错误,似乎我遗漏了一些明显的东西
谢谢
Steve只需将User类型的参数添加到您的
AddRelation
操作中,您就应该很好了。Web API将自动调用OData格式化程序,从请求主体读取用户并将其绑定到您的操作参数
您可以使用此帮助器方法读取OData请求正文
private static Task<T> ReadODataContentAsAsync<T>(HttpRequestMessage request)
{
var formatters =
ODataMediaTypeFormatters.Create()
.Select(formatter => formatter.GetPerRequestFormatterInstance(typeof(T), request, request.Content.Headers.ContentType));
return request.Content.ReadAsAsync<T>(formatters);
}
private静态任务readodatacontentasync(HttpRequestMessage请求)
{
变量格式化程序=
ODataMediaTypeFormatters.Create()
.Select(formatter=>formatter.GetPerRequestFormatterInstance(typeof(T),request,request.Content.Headers.ContentType));
返回request.Content.ReadAsAsync(格式化程序);
}
像这样,
Customer addedCustomer = ReadODataContentAsAsync<Customer>(Request).Result;
Customer addedCustomer=ReadODataContentAsAsync(请求)。结果;
Hi RhaghuRam,这对我来说是可行的,除了我的基本控制器是泛型的,我的所有EntitySetControllers都从中继承。这意味着NavigationProperty类型在设计时未知。此外,在本例中,虽然我的示例用于添加用户,但我还可以使用相同的方法将相关组和部门添加到租户。因为直到运行时我才知道NavigationProperty是什么类型,所以我需要手动反序列化它。谢谢!这让我非常接近,但我现在得到了一个错误:没有MediaTypeFormatter可以从媒体类型为“application/atom+xml”的内容中读取“User”类型的对象。我尝试过手动创建格式化程序,但仍然没有成功。我将用我尝试过的内容更新我的原始问题。我忘记添加GetPerRequestFormatterInstance技巧,我们在将请求注入OData格式化程序时使用了该技巧。我现在更新了答案。非常有效!谢谢你的帮助!