WebApi2 IHttpActionResult强类型返回值

时间:2016-10-28 07:23:18

标签: c# generics asp.net-web-api2 httpresponse

这样做可能并且不理想:(一个非常简单的例子!)

[Serializable]
public class MyRecord
{
    public string key {get; set;}
    public string data {get; set;}
}

public async Task<IHttpActionResult> Get(string SomeKey)
{
    if(ExistsInDB(SomeKey))
    {
        return Ok(SomeRecordFromDB(SomeKey));  //SomeRecord() returns a POCO MyRecord.
    }
    else
    {
        //I know I can return NotFound() but not the focus of my Q
        return Ok(false);  //returns "False"
    }
}

有效地证明在返回类型上没有编译时错误检查。这个例子将返回一个JSon序列化的POCO类(JSon在我的接受头上设置)或者它将返回文本&#34; False&#34;这会给客户带来类型检查的负担。

我不会通过设计来做到这一点,但我的团队正在重构asmx / svc中的很多代码并且出现错误。当编译器帮助捕获这些类型时,我喜欢它错误而不是等待模块或单元测试。

回到使用强类型方法签名是正确的方法(避免使用IHttpActionResult和Ok(),NotFound()等辅助工具,还是有类似IHttpActionResult<T>的东西可以用来确保正在返回正确的类型?

微米。

4 个答案:

答案 0 :(得分:3)

首先,最好返回IHttpActionResult,表示相应的http status。类似的东西:

public async Task<IHttpActionResult> Get(string SomeKey)
{
    if(ExistsInDB(SomeKey))
        return Ok(SomeRecordFromDB(SomeKey));

    return NotFound();
}

但是如果你真的想要一个强类型的api,你可以做类似的事情:

 public async Task<StronglyTypeResponse> Get()
 {
     return new StronglyTypeResponse();
 }

或者,创建一个类型化的响应,并在响应中保留http状态代码等:

public class StronglyTypeResponse
{

}

public class StronglyTypedResult<T> : IHttpActionResult
{
    HttpConfiguration _configuration;
    T _content;
    HttpStatusCode _statusCode;
    HttpRequestMessage _request;

    public StronglyTypedResult(T content, HttpStatusCode statusCode, HttpRequestMessage request, HttpConfiguration configuration)
    {
        _content = content;
        _request = request;
        _configuration = configuration;
        _statusCode = statusCode;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(_statusCode)
        {
            Content = new ObjectContent<dynamic>(_content, _configuration.Formatters.JsonFormatter),
            RequestMessage = _request,
            ReasonPhrase = "some phrase"
        };

        return Task.FromResult(response);
    }
}

然后你可以创建你的方法:

public async Task<StronglyTypedResult<StronglyTypeResponse>> Get()
{
    return new StronglyTypedResult<StronglyTypeResponse>(new StronglyTypeResponse(), HttpStatusCode.OK, Request, Configuration);
}

创建自己的自定义通用IHttpActionResult

它基本相同:

public class IHttpActionResult<T> : System.Web.Http.IHttpActionResult
{
    HttpConfiguration _configuration;
    T _content;
    HttpStatusCode _statusCode;
    HttpRequestMessage _request;

    public IHttpActionResult(T content, HttpStatusCode statusCode, HttpRequestMessage request, HttpConfiguration configuration)
    {
        _content = content;
        _request = request;
        _configuration = configuration;
        _statusCode = statusCode;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(_statusCode)
        {
            Content = new ObjectContent<dynamic>(_content, _configuration.Formatters.JsonFormatter),
            RequestMessage = _request,
            ReasonPhrase = "some phrase"
        };

        return Task.FromResult(response);
    }
}

现在,您可以使用键入的IHttpActionResult

返回所需的课程
public async Task<IHttpActionResult<YourClass>> Get()
{
    var yourclass = new YourClass();

    return new IHttpActionResult<YourClass>(yourclass, HttpStatusCode.OK, Request, Configuration);
}

答案 1 :(得分:1)

使用强类型方法签名的问题是,如果请求出现问题,则无法返回“错误”对象,无论是验证错误还是未找到错误。

因此,如果您想使用强类型签名,则必须在返回类型中包含某种“错误”对象引用或显式抛出异常。

使用 HttpActionResult 的好处是您不受限于特定的返回类型。例如,您可以返回 OK(someObject) BadRequest(errorObject)。但是,由开发人员正确编写方法并仔细检查没有发生任何事情,如上面提到的示例。

答案 2 :(得分:0)

您可以通过以下方式重构代码:

public class Answer<T>
{
    public T result {get;set;}
    public bool success {get;set;}
    public string exception {get;set;}
}

public async Task<Answer<MyRecord>> Get(string SomeKey)
{
    var answer = new Answer<MyRecord>();
    try
    {     
        if(ExistsInDB(SomeKey))
        {
            answer.result = await SomeRecordFromDB(SomeKey);
            answer.success = true;
        }
    }
    catch(Exception e)
    {
        answer.exception = e.Message;            
    }
    return answer;
}

答案 3 :(得分:0)

public class ObjectResult : IHttpActionResult
{
    object _value;
    HttpRequestMessage _request;

    public ObjectResult(object value, HttpRequestMessage request)
    {
        _value = value;
        _request = request;
    }


    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        if (_value == null)
            return Task.FromResult(_request.CreateResponse(HttpStatusCode.NotFound));

        var response = _request.CreateResponse(HttpStatusCode.OK, _value);
        return Task.FromResult(response);
    }
}

   //create your method:

    public IHttpActionResult Get()
    {
        return new ObjectResult(repository.GetAll(), Request);
    }