使用WCF数据服务客户端与我的OData API进行通信时,我偶尔需要使用 System.Data.Services.Client.DataServiceContext的AddRelatedObject方法
这会为端点生成POST
,如下所示:
http://base_url/odata/Entity(key)/NavigationProperty
http请求的内容是序列化的NavigationProperty
实体。
由于此URL的帖子在默认的odata控制器中未映射,我编写了一个新的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
,并解析它以确定所需的类型和密钥。
我遇到的问题是,一旦我知道我的父实体是Tenant
,密钥为1
,NavigationProperty
为Users
in { Tenant
实体是User
实体,我无法弄清楚如何手动调用odatamediatypeformatter
将http内容反序列化为User
实体,以便我可以添加它是Tenants
Users
集合。
我已经查看了OData源代码,以了解如何对Web-API管道调用和反序列化实体,但是无法找到OData库获取http内容并将其转换为实体的点
如果有人有想法指出我正确的方向,如果我想出更多的话,我会继续研究和更新。
更新06/28/2013 感谢RaghuRam,我已经能够靠近了。我看到的问题是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)
所有人都给出了同样的错误,似乎我错过了一些明显的东西。
谢谢!
史蒂夫
答案 0 :(得分:1)
只需在您的AddRelation
操作中添加User类型的参数即可。 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);
}
像这样,
Customer addedCustomer = ReadODataContentAsAsync<Customer>(Request).Result;