带有[FromBody]参数的Web API Custom方法,通过DataServiceContext.Execute调用

时间:2015-04-14 18:49:01

标签: .net client odata asp.net-web-api

在服务方面,我有一个非常简单的配置,通过URL传递参数时工作正常:

(片断)

builder.EntitySet<MappedAuthorizationGroup>("MappedAuthorizationGroups");
var function = builder.Function("TestMethod");
//parameter removed here, because I want to POST it ([FromBody])
//function.Parameter<string>("id"); 
function.ReturnsCollectionFromEntitySet<MappedAuthorizationGroup>("MappedAuthorizationGroups");

控制器方法装饰再次相当简单:

[HttpPost]
[ODataRoute("TestMethod")]  //(id={id})")]  // Again, parameter removed because i want to POST it
public IQueryable<MappedAuthorizationGroup> TestMethod([FromBody]string id)
{
    ... code ...
}

现在,这里有几个关于如何通过AJAX调用此问题的答案,但我已经在使用microsoft odata客户端(DataServiceContext)来处理所有&#34; normal&#34; Odata调用(CRUD操作)...所以我也想将它用于这些自定义调用(使用.Execute(),我假设?)

我非常简洁的客户代码:

var client = new Default.Container(new Uri("thecorrectURI"));

var methodURI = new Uri(client.BaseUri, "TestMethod");   

var recs = client.Execute<MappedAuthorizationGroup>(methodURI, "POST", new BodyOperationParameter("id", "C26DFAF6-8F32-429B-9DB3-2F8CF0ABBD3A"));

但是,这并没有正确填充字符串&#34; id&#34;到达服务器时应该是[FromBody]的参数。经过调查,这似乎是由于1或2个原因:

  1. 内容类型错误。但是,如果我将内容类型设置为&#34; application / x-www-form-urlencoded;字符集= UTF-8&#34;我在服务器上得到一个不同的错误,因为它期待json,我认为它应该只适用于一个原始参数。

  2. BodyOperationParameter()序列化为JSON,但由于某种原因,这在服务器端不起作用。很多帖子都提到它只与简单的&#34; = myvalue&#34;通过。它是否正确?我如何从DataServiceContext对象执行此操作?我是否必须通过更通用的方式进行此调用,例如HttpClient对象,它可以很容易地设置正确的标题和正文内容?

  3. 我想将它移动到正文而不是简单的URL的原因是这个参数实际上是一个GUID的序列化列表,可能比应该在URL中设置更多。

1 个答案:

答案 0 :(得分:0)

好的,有很多事要解决这个问题。每个人都被记录在网络上的“某个地方”,但是没有一个真正汇集在我可以在这种情况下使用的单一解决方案中(这看起来应该非常普遍......嗯)。无论如何:

方法装饰在odata控制器端是正确的,如:

[HttpPost]
[ODataRoute("TestMethod")]
public IQueryable<YourEntity> TestMethod([FromBody]string id)

(我将参数名称保留为“id”以消除创建另一条路线的需要)

在客户端/消费者方面,我需要更改原始代码。首先,我不能使用odata客户端上下文的东西,因为它没有给你足够的控制参数序列化,这是一个问题。此外,它似乎只想发送JSON,并将内容类型设置为其他东西(对于表单发布),导致另一个错误。可能是因为我们的OData服务通常适用于所有标准CRUD调用的JSON,并且似乎没有一种干净的方式来说“只考虑某些自定义调用的非JSON数据”)。同时,将主体内容参数序列化为JSON不起作用。

因此,使用HttpClient可以更好地控制请求。但是请求正文内容与格式非常相关。我发送为“= stringvalue”,UTF-8编码。

获取数据也是一个问题,因为IEnumerable似乎又包含在一个“值”对象中......因此将响应JSON反序列化为List会失败。创建一个名为“value”的List属性的类,并反序列化为该对象,最终成功。

实际让这个工作的最终客户端代码(对我而言)看起来有点像:

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://localhost/mywebsite/odata");

    // Content string *MUST* start with =
    var content = new StringContent("=C26DFAF6-8F32-429B-9DB3-2F8CF0ABBD3A", Encoding.UTF8, "application/x-www-form-urlencoded");

    HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, "http://localhost/mywebsite/odata/TestMethod");
    message.Content = content;

    // Send the request
    HttpResponseMessage response = client.SendAsync(message).Result;

    // Get the result
    string retval = response.Content.ReadAsStringAsync().Result;

    // Deserialize the response
    var jsonSerializer = new JavaScriptSerializer();

    var groups = jsonSerializer.Deserialize<TestContainer>(retval);
}

用于帮助反序列化的虚拟“容器”:

public class TestContainer
{
    public List<YourModel> value    { get; set; }
}