Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to return HttpResponseMessage as IActionResult in .Net Core 2.2

In .Net Core 2.2. I am creating a API Controller that routes the request to another Http endpoint based on payload.

  [Route("api/v1")]   public class RoutesController : Controller   {       [HttpPost]       [Route("routes")]       public async Task<IActionResult> Routes([FromBody]JObject request)       {                           var httpClient = new HttpClient();          // here based on request httpCLient will make `POST` or `GET` or `PUT` request         // and returns `Task<HttpResponseMessage>`. Lets assume its making `GET`          // call         Task<HttpResponseMessage> response = await          httpClient.GetAsync(request["resource"]);                     /*  ??? what is the correct way to return response as `IActionResult`*/       }           } 

based on SO post i can do this

        return StatusCode((int)response.StatusCode, response); 

However i am not sure sending HttpResponseMessage as ObjectResult is correct way.

I also want to make sure content negotiation will work.

like image 309
LP13 Avatar asked Jan 10 '19 20:01

LP13


People also ask

How do I return HttpResponseMessage?

Depending on which of these is returned, Web API uses a different mechanism to create the HTTP response. Convert directly to an HTTP response message. Call ExecuteAsync to create an HttpResponseMessage, then convert to an HTTP response message. Write the serialized return value into the response body; return 200 (OK).

What is IActionResult in .NET core?

The IActionResult return type is appropriate when multiple ActionResult return types are possible in an action. The ActionResult types represent various HTTP status codes. Any non-abstract class deriving from ActionResult qualifies as a valid return type.


2 Answers

public class HttpResponseMessageResult : IActionResult {     private readonly HttpResponseMessage _responseMessage;      public HttpResponseMessageResult(HttpResponseMessage responseMessage)     {         _responseMessage = responseMessage; // could add throw if null     }      public async Task ExecuteResultAsync(ActionContext context)     {         var response = context.HttpContext.Response;           if (_responseMessage == null)         {             var message = "Response message cannot be null";              throw new InvalidOperationException(message);         }          using (_responseMessage)         {             response.StatusCode = (int)_responseMessage.StatusCode;              var responseFeature = context.HttpContext.Features.Get<IHttpResponseFeature>();             if (responseFeature != null)             {                 responseFeature.ReasonPhrase = _responseMessage.ReasonPhrase;             }              var responseHeaders = _responseMessage.Headers;              // Ignore the Transfer-Encoding header if it is just "chunked".             // We let the host decide about whether the response should be chunked or not.             if (responseHeaders.TransferEncodingChunked == true &&                 responseHeaders.TransferEncoding.Count == 1)             {                 responseHeaders.TransferEncoding.Clear();             }              foreach (var header in responseHeaders)             {                 response.Headers.Append(header.Key, header.Value.ToArray());             }              if (_responseMessage.Content != null)             {                 var contentHeaders = _responseMessage.Content.Headers;                  // Copy the response content headers only after ensuring they are complete.                 // We ask for Content-Length first because HttpContent lazily computes this                 // and only afterwards writes the value into the content headers.                 var unused = contentHeaders.ContentLength;                  foreach (var header in contentHeaders)                 {                     response.Headers.Append(header.Key, header.Value.ToArray());                 }                  await _responseMessage.Content.CopyToAsync(response.Body);             }         }     } 
like image 106
LP13 Avatar answered Oct 06 '22 14:10

LP13


You can create a custom IActionResult that will wrap transfere logic.

public async Task<IActionResult> Routes([FromBody]JObject request) {     var httpClient = new HttpClient();      HttpResponseMessage response = await httpClient.GetAsync("");      // Here we ask the framework to dispose the response object a the end of the user resquest     this.HttpContext.Response.RegisterForDispose(response);      return new HttpResponseMessageResult(response); }  public class HttpResponseMessageResult : IActionResult {     private readonly HttpResponseMessage _responseMessage;      public HttpResponseMessageResult(HttpResponseMessage responseMessage)     {         _responseMessage = responseMessage; // could add throw if null     }      public async Task ExecuteResultAsync(ActionContext context)     {         context.HttpContext.Response.StatusCode = (int)_responseMessage.StatusCode;          foreach (var header in _responseMessage.Headers)         {             context.HttpContext.Response.Headers.TryAdd(header.Key, new StringValues(header.Value.ToArray()));         }          if(_responseMessage.Content != null)         {             using (var stream = await _responseMessage.Content.ReadAsStreamAsync())             {                 await stream.CopyToAsync(context.HttpContext.Response.Body);                 await context.HttpContext.Response.Body.FlushAsync();             }         }     } } 
like image 42
Kalten Avatar answered Oct 06 '22 13:10

Kalten