带有[FromBody]参数的Web API自定义方法,通过DataServiceContext调用.执行



在服务端,我有一个非常简单的配置,当通过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)进行所有"正常"的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"));

但是,这并不能正确填充到达服务器时应为[FromBody]的字符串"id"参数。经过调查,这似乎是因为1或2个原因:

  1. 内容类型错误。然而,如果我将内容类型设置为"application/x-www-form-urlencoded;charset=utf-8",我会在服务器上得到一个不同的错误,因为它需要json,我认为这只适用于单个基元参数。

  2. BodyOperationParameter()串行化为JSON,但由于某些原因,这在服务器端不起作用。许多帖子提到它只与简单的"=myvalue"传递兼容。这是正确的吗?如何从DataServiceContext对象执行此操作?我是否必须从更通用的东西进行调用,比如HttpClient对象,在那里可以很容易地设置正确的头和正文内容?

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

好的,需要做很多事情来解决这个问题。每一个都被记录在网络上的"某个地方",但没有一个真正整合在一个单一的解决方案中,我可以在这个场景中使用(这似乎非常常见…嗯)。无论如何:

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; }
}

最新更新