WebApi2 IHttpActionResult 强类型 return 值
WebApi2 IHttpActionResult strongly typed return values
这样做是可能的,但并不理想:(一个大大简化的例子!)
[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"
}
}
有效地演示了 return 类型没有编译时错误检查。此示例将 return JSon 序列化 POCO class(JSon 在我的接受 header 上设置)或者它将 return 文本 "False" 这将类型检查的负担放在客户端上。
我不会故意这样做,但我的团队正在重构 asmx/svc 中的 很多 代码并且错误逐渐出现。当编译器提供帮助时,我喜欢它捕获这些类型的错误,而不是等待模块或单元测试。
是回到使用强类型方法签名的正确方法吗(避免 IHttpActionResult 和 Ok()、NotFound() 等帮助程序,或者是否有类似 IHttpActionResult<T>
的东西可用于确保 returned?
的类型正确
男.
您可以这样重构您的代码:
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;
}
使用强类型方法签名的问题在于,如果请求出现问题,无论是验证错误还是未发现错误,您都无法 return 一个 "error" 对象.
因此,如果您想使用强类型签名,那么您要么必须在 return 类型中包含某种 "error" 对象引用,要么显式抛出异常..
使用 HttpActionResult 的好处是您不会受限于特定的 return 类型。例如,您可以 return OK(someObject) 或 BadRequest(errorObject)。但是,由开发人员正确编写方法并仔细检查是否没有像您上面提到的示例那样发生任何事情。
首先,最好是returnIHttpActionResult
,说明相应的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);
}
}
现在您可以 return 您想要的 class 输入 IHttpActionResult
:
public async Task<IHttpActionResult<YourClass>> Get()
{
var yourclass = new YourClass();
return new IHttpActionResult<YourClass>(yourclass, HttpStatusCode.OK, Request, Configuration);
}
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);
}
这样做是可能的,但并不理想:(一个大大简化的例子!)
[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"
}
}
有效地演示了 return 类型没有编译时错误检查。此示例将 return JSon 序列化 POCO class(JSon 在我的接受 header 上设置)或者它将 return 文本 "False" 这将类型检查的负担放在客户端上。
我不会故意这样做,但我的团队正在重构 asmx/svc 中的 很多 代码并且错误逐渐出现。当编译器提供帮助时,我喜欢它捕获这些类型的错误,而不是等待模块或单元测试。
是回到使用强类型方法签名的正确方法吗(避免 IHttpActionResult 和 Ok()、NotFound() 等帮助程序,或者是否有类似 IHttpActionResult<T>
的东西可用于确保 returned?
男.
您可以这样重构您的代码:
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;
}
使用强类型方法签名的问题在于,如果请求出现问题,无论是验证错误还是未发现错误,您都无法 return 一个 "error" 对象.
因此,如果您想使用强类型签名,那么您要么必须在 return 类型中包含某种 "error" 对象引用,要么显式抛出异常..
使用 HttpActionResult 的好处是您不会受限于特定的 return 类型。例如,您可以 return OK(someObject) 或 BadRequest(errorObject)。但是,由开发人员正确编写方法并仔细检查是否没有像您上面提到的示例那样发生任何事情。
首先,最好是returnIHttpActionResult
,说明相应的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);
}
}
现在您可以 return 您想要的 class 输入 IHttpActionResult
:
public async Task<IHttpActionResult<YourClass>> Get()
{
var yourclass = new YourClass();
return new IHttpActionResult<YourClass>(yourclass, HttpStatusCode.OK, Request, Configuration);
}
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);
}