我是MVC Web Api的新手,但我有一些使用ServiceStack框架的经验。一些web api示例看起来很像RPC,有更多的操作方法和更少的参数。事实上,大多数示例似乎将请求参数限制为id。我想使用请求/响应创建一些报告服务,因为请求对所有报告标准都非常复杂。
这是我的简化请求/响应类型:
public class PendingRequest
{
public string Id { get; set; }
public int AccountId { get; set; }
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
}
public class PendingResponse
{
public string Id { get; set; }
public IEnumerable<Pending> Data { get; set; }
}
我的大纲报告控制器:
public class ReportsController : ApiController
{
public async Task<PendingResponse> GetPending(PendingRequest request)
{
return new PendingResponse
{
Id = request.Id,
// Data = await Repo.GetPending()
};
}
public async Task<ShippedResponse> GetShipped(ShippedRequest request)
{
return new ShippedResponse
{
Id = request.Id,
// Data = await Repo.GetShipped()
};
}
public async Task<ProductsResponse> GetProducts(ProductsRequest request)
{
return new ProductsResponse
{
Id = request.Id,
// Data = await Repo.GetProducts()
};
}
}
我的自托管应用的路由和配置:
class Program
{
static void Main()
{
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute(
name: "Reports",
routeTemplate: "api/reports/{action}",
defaults: new
{
controller = "Reports"
});
using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
}
因此,通过此路由,我打算将操作作为报告的名称。注意我这里没有包含请求参数。不确定我是否应该。
问题实际上是在客户端。使用HttpClient,GetAsync方法不允许我包含JSON请求对象。我看到一个扩展方法PostAsJsonAsync但肯定这不应该是一个POST?没有GetAsJsonAsync或类似的东西,我看不到用GET包含请求的方法?
说实话,我更喜欢ServiceStack,但似乎还没有异步支持。我需要开发一些I / O密集型的高性能服务,我希望尽可能地减少阻塞。
更新
似乎Web Api将执行模型绑定,如果我不是使用请求主体,而是将模型的参数作为查询字符串的一部分包含在内。为了使其工作,Get方法需要在模型类型前加上[FromUri]属性,该属性通知模型绑定器应该从请求查询字符串构造模型。凌乱,但有效。
[ActionName("Pending")]
public async Task<PendingResponse> GetPending([FromUri] PendingRequest request)
{
return new PendingResponse
{
Id = request.Id,
// query = ...build from request params
// Data = await Repo.GetPending(query)
};
}
现在在客户端,我执行以下操作:
var result = await _httpClient.GetAsync("api/reports/pending?Id=123&AccountId=456");
result.EnsureSuccessStatusCode();
var response = await result.Content.ReadAsAsync<PendingResponse>();
对服务的调用导致使用从提供的查询字符串参数中实现的PendingRequest对象的副本调用GetPending方法。
答案 0 :(得分:3)
这里的根本问题是你试图为HTTP GET提供一个请求体,这是不允许的。好吧,您仍然可以继续使用请求正文格式化GET并提交,但这不符合规范。严格来说,HTTP规范并不禁止GET请求拥有正文,但GET请求的响应不得基于请求正文进行更改,这基本上意味着您无法在GET请求正文中使用搜索条件。您可以使用URI路径和查询字符串来指定搜索条件,如果要将它们绑定到复杂类型参数,则需要使用[FromUri]
,如下所示:public async Task<PendingResponse> GetPending([FromUri]PendingRequest request)
。
答案 1 :(得分:0)
有点猜测,但是只是对JSON请求对象进行URL编码并将其放入GET URI的查询字符串段中呢?
此外,您可能需要在操作中的请求方法参数上使用[FromUri]属性,因为它是一个复杂类型。我可能错过了一些东西,但是parameter binding上的这篇文章没有提到关于GET是复杂类型的特殊情况的任何内容,因此我认为它们总是会尝试从POST主体中读取。