0

在使用 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, 并对其进行解析以确定所需的类型和键。

我遇到的问题是,一旦我知道我的父实体是 aTenant的键1,并且实体中的NavigationPropertyofUsersTenant一个User实体,我无法弄清楚如何手动调用 anodatamediatypeformatter将 http 内容反序列化为User实体,以便我可以将其添加到Tenants Users集合中。

我已经查看了 OData 源,以了解 Web-API 管道如何调用和反序列化实体,但无法找到 OData 库获取 http 内容并将其转换为实体的点。

如果有人有想法为我指明正确的方向,如果我发现更多,我将继续研究和更新。

更新2013 年 6 月 28 日 多亏了 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)

都给出了同样的错误,似乎我错过了一些明显的东西。

谢谢!

史蒂夫

4

1 回答 1

1

只需将 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);
}

像这样,

Customer addedCustomer = ReadODataContentAsAsync<Customer>(Request).Result;
于 2013-06-27T18:38:43.500 回答