2013-08-29 36 views
3

我是MVC Web Api的新手,但是我有一些使用ServiceStack框架的经验。一些web api示例看起来很像RPC,它具有更多的操作方法和更少的参数。实际上,大多数示例似乎将请求参数限制为一个id。我想创建一些使用请求/响应的报告服务,因为请求对于所有报告条件都非常复杂。如何使用Web Api实现请求/响应模式?

这里是我的简单的请求/响应类型:

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密集型的高性能服务,并尽可能减少阻塞。

UPDATE:

看来网络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对象的副本从所提供的查询字符串物化参数。

回答

3

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

+0

这很有趣。如果语句“...但GET请求的响应不能根据请求主体改变”是真的,那么我不能使用GET,因为即使没有任何标准,对/ api/reports/pending的请求很可能会产生不同时间的结果也许那时我们真的在谈论做一个POST。我应该认为这是CreatePendingReport(请求请求)或其他内容中的创建... –

+0

响应随时间而改变与使用请求主体发送不同响应完全不同。可能是我不清楚。检查了这一点 - http://stackoverflow.com/questions/978061/http-get-with-request-body。 – Badri

+0

谢谢巴德里。最初的答案是正确的,我已经用示例客户端调用更新了我的帖子。现在我只需要一个好的对象 - >查询字符串映射器。 –

0

这是一个猜测的位,但是如何才能对JSON请求对象进行URL编码并将其放入GET URI的查询字符串段中?

另外,您可能需要操作中的请求方法参数的[FromUri]属性,因为它是一种复杂类型。我可能错过了一些东西,但parameter binding上的这篇文章没有提到任何有关GET作为复杂类型的特例的内容,因此我认为他们总是会尝试从POST主体读取数据。

相关问题