I'm trying to figure out a way to return an object in my response while still maintaining an understandable return type.
So for starters, I know this works as expected.
public async Task<HttpResponseMessage> DoMyThing(MyObject myObject)
{
var result = await _myService.CreateMyThingAsync(myObject);
return Request.CreateResponse(HttpStatusCode.Created, result);
}
But what I really want is for this pseudo code to work... somehow.
public Task<MyObject> DoMyThing(MyObject myObject)
{
var result = _myService.CreateMyThingAsync(myObject);
return Request.CreateResponse<Task<MyObject>>(HttpStatusCode.Created, result);
// or better yet
return Request.CreateResponse<MyObject>(HttpStatusCode.Created, result);
}
Is there any magic in the framework that'll make this happen? Or are there any third party libraries that can do this?
Essentially I need to return the Task<MyObject>
instead of the Task<HttpResponseMessage>
I'm also open to other suggestions on how to return a non 200 response while still returning the Task<MyObject>
答案 0 :(得分:3)
The issue with specifying the type as the return type is that you restrict yourself to having to return that type. That may sound strange but actually there will be many cases where you need to be able to support multiple response, such as 404, 200 201 and so on.
To handle the documentation of this you can use the ResponseType attribute, like so:
[ResponseType(typeof(BookDto))]
public async Task<IHttpActionResult> GetBook(int id)
{
BookDto book = await db.Books.Include(b => b.Author)
.Where(b => b.BookId == id)
.Select(AsBookDto)
.FirstOrDefaultAsync();
if (book == null)
{
return NotFound();
}
return Ok(book);
}
Take a look here
Edit:
In Asp.Net Core you use the ProducesResponseType attribute which can be used multiple times per method
See here
Example
[ProducesResponseType(typeof(BookDto), 200)]
[ProducesResponseType(typeof(object), 201)]
public async Task<IActionResult> GetBook(int id)
{
BookDto book = await db.Books.Include(b => b.Author)
.Where(b => b.BookId == id)
.Select(AsBookDto)
.FirstOrDefaultAsync();
if (book == null)
{
return NotFound();
}
return Ok(book);
}
EDIT: Multiple response attributes prior to dot net core
You can use Swagger to help document / describe your API, they have a custom attribute called SwaggerResponse
The .Net port of Swagger is Swashbuckle, take a look here
答案 1 :(得分:0)
This would be the best pattern in WebApi.
public async Task<IHttpActionResult> DoMyThing(MyObject myObject)
{
try
{
var result = await _myService.CreateMyThingAsync(myObject);
return new JsonStreamHttpActionResult<MyObject>(Request, System.Net.HttpStatusCode.Created, result);
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
return new HttpActionResult(HttpStatusCode.InternalServerError, "An error has occured");
}
}
with a generic serializer. You can then use the "better" IHttpActionResult instead of a real return value.
public class JsonStreamHttpActionResult<T> : IHttpActionResult
{
private T responseData;
private HttpRequestMessage request;
private HttpStatusCode statusCode;
public JsonStreamHttpActionResult(HttpRequestMessage request, System.Net.HttpStatusCode code, T responseData)
{
this.responseData = responseData;
this.request = request;
this.statusCode = code;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = request.CreateResponse(statusCode);
response.Content =
new PushStreamContent((stream, content, context) =>
{
var serializer = new Newtonsoft.Json.JsonSerializer();
using (var writer = new System.IO.StreamWriter(stream))
{
serializer.Serialize(writer, responseData);
stream.Flush();
}
});
return Task.FromResult(response);
}
}