WebAPI CreateResponse with object as generic

时间:2016-10-20 19:05:34

标签: c# asp.net-web-api

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>

2 个答案:

答案 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);
    }
}