3

我是 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>();

对服务的调用会导致调用 GetPending 方法,并使用从提供的查询字符串参数具体化的 PendingRequest 对象的副本。

4

2 回答 2

3

这里的根本问题是您试图向 HTTP GET 提供请求正文,这是不允许的。好吧,您仍然可以继续使用请求正文格式化 GET 并提交它,但这不符合规范。严格来说,HTTP 规范并没有禁止 GET 请求具有正文,但 GET 请求的响应不能根据请求正文而改变,这基本上意味着您不能在 GET 请求正文中使用搜索条件。您可以使用 URI 路径和查询字符串来指定搜索条件,如果要将它们绑定到复杂类型参数中,则需要[FromUri]像这样使用:public async Task<PendingResponse> GetPending([FromUri]PendingRequest request).

于 2013-08-29T13:37:58.720 回答
0

有点猜想,但是只是对 JSON 请求对象进行 URL 编码并将其放入 GET URI 的查询字符串段中呢?

此外,您可能需要在操作中的请求方法参数上使用 [FromUri] 属性,因为它是一种复杂类型。我可能遗漏了一些东西,但是这篇关于参数绑定的文章没有提到 GET 是复杂类型的特例,因此我认为他们总是会尝试从 POST 正文中读取。

于 2013-08-29T07:40:01.113 回答