C# WebApi2 IHttpActionResult强类型返回值
这样做是可能的,但并不理想:(一个大大简化的例子!)C# WebApi2 IHttpActionResult强类型返回值,c#,generics,asp.net-web-api2,httpresponse,C#,Generics,Asp.net Web Api2,Httpresponse,这样做是可能的,但并不理想:(一个大大简化的例子!) [可序列化] 公共类MyRecord { 公共字符串密钥{get;set;} 公共字符串数据{get;set;} } 公共异步任务Get(字符串SomeKey) { if(ExistsInDB(SomeKey)) { return Ok(SomeRecordFromDB(SomeKey));//SomeRecord()返回POCO MyRecord。 } 其他的 { //我知道我可以返回NotFound(),但不能返回Q的焦点 返回Ok(fa
[可序列化]
公共类MyRecord
{
公共字符串密钥{get;set;}
公共字符串数据{get;set;}
}
公共异步任务Get(字符串SomeKey)
{
if(ExistsInDB(SomeKey))
{
return Ok(SomeRecordFromDB(SomeKey));//SomeRecord()返回POCO MyRecord。
}
其他的
{
//我知道我可以返回NotFound(),但不能返回Q的焦点
返回Ok(false);//返回“false”
}
}
有效地证明了在返回类型上没有编译时错误检查。这个示例将返回一个JSon序列化的POCO类(JSon设置在我的accept头上),或者返回文本“False”,这会给客户端带来类型检查的负担
我不会通过设计来做到这一点,但我的团队正在重构来自asmx/svc的大量代码,并且错误逐渐出现。我喜欢编译器帮助捕获这些类型的错误,而不是等待模块或单元测试
返回使用强类型方法签名(避免使用IHttpActionResult和Ok()、NotFound()等帮助程序)的正确方法,还是可以使用类似于IHttpActionResult
的方法来确保返回正确的类型
M.您可以通过以下方式重构代码:
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;
}
公共类答案
{
公共T结果{get;set;}
公共bool成功{get;set;}
公共字符串异常{get;set;}
}
公共异步任务Get(字符串SomeKey)
{
var-answer=新答案();
尝试
{
if(ExistsInDB(SomeKey))
{
answer.result=wait SomeRecordFromDB(SomeKey);
答案:成功=正确;
}
}
捕获(例外e)
{
answer.exception=e.消息;
}
返回答案;
}
使用强类型方法签名的问题是,如果请求有问题,无论是验证错误还是未找到错误,您都无法返回“错误”对象
因此,如果要使用强类型签名,则必须在返回类型中包含某种“错误”对象引用,或者显式抛出异常
使用HttpActionResult的好处在于,您不受特定返回类型的限制。因此,您可以返回OK(someObject)或BadRequest(errorObject)。但是,由开发人员正确编写方法,并仔细检查是否没有发生与上述示例类似的情况。首先,返回
IHttpActionResult
,指示相应的http状态是一种很好的做法。例如:
public async Task<IHttpActionResult> Get(string SomeKey)
{
if(ExistsInDB(SomeKey))
return Ok(SomeRecordFromDB(SomeKey));
return NotFound();
}
public async Task<StronglyTypeResponse> Get()
{
return new StronglyTypeResponse();
}
公共类ObjectResult:IHttpActionResult
{
对象值;
HttpRequestMessage\u请求;
公共对象结果(对象值,HttpRequestMessage请求)
{
_价值=价值;
_请求=请求;
}
公共任务执行同步(CancellationToken CancellationToken)
{
如果(_值==null)
返回Task.FromResult(_request.CreateResponse(HttpStatusCode.NotFound));
var response=_request.CreateResponse(HttpStatusCode.OK,_值);
返回Task.FromResult(响应);
}
}
//创建您的方法:
public IHttpActionResult Get()
{
返回新的ObjectResult(repository.GetAll(),Request);
}
我认为您考虑得太多了。您不需要返回强类型的返回值。事实上,这其实是一件好事,这并不重要。这在很大程度上是基于这样一个事实,即您的传输模式,无论是XML还是JSON,都不关心类型。当您的方法需要返回其他内容时,会发生什么,所有类型的变化毫无理由。在构建了大量web应用程序之后,这一部分应该是你最不需要考虑的事情。我看到了这种方法在许多情况下是如何工作的,并且WebAPI的灵活性在开发过程中非常好。在我的情况下,WebAPI中的API现在更多的是关于与消费者的合同,以及什么它们将响应请求而不是方便的传输机制(仍然正确)关于当一个方法需要返回其他东西时发生的事情…我们会认为对合同的一个突破性的改变并相应地采取行动以确保合同的两端可以采用这种改变。在这里没有争论你所说的是合适的。是的,我仍然认为你正在考虑它。API行动是结束了。al,只要你的数据在那一点之前是正确的,你就不应该输入结果!!你应该做的是创建集成测试来断言你的api正在生成正确的数据。我认为Slava的响应有助于解决这种情况,尽管这是以包装真实类型为代价的。我同意HttpAction的灵活性sult提供。在这样一个大型重构项目中,目的是尽量减少编译时的错误。我想我有一个简单的方法可以帮助我解决这个问题。感谢您和其他人对WebAPI灵活性的看法。我认为这将大大有助于正式联系。我想我是否可以调用StronglyTypedResultIHttpActionResult?我会试试。我想到的另一个简单方法是使用一个非常精简的WebAPI方法,所有类型检查都在.net方法中完成。因此,使用一个名为private MyRecord Get()的方法。未经检查的键入量将是WebAPI中的一行。返回Ok(Get(SomeKey));但是StronglyTypedResult是一个IHttpActionResult。如果你愿意,你甚至可以调用StronglyTypedResult IHttpActionResult,我将编辑答案以显示给你。是的-在同一页上。我们正在谈论将其命名为IHttpActionResult。这样它就表示它做了相同的事情(并提供了相同的帮助),但添加了类型。感谢您的回复
public async Task<StronglyTypeResponse> Get()
{
return new StronglyTypeResponse();
}
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);
}
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);
}
}
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);
}