Reputation: 3048
I have a .NET Web API controller that contains the following login method:
[HttpPost]
[AllowAnonymous]
[Route("api/account/login")]
//Web API Controller method
public virtual async Task<IHttpActionResult> Login(LoginViewModel model)
{
SignInStatus response = await this.SignInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, shouldLockout: true);
if (response == SignInStatus.Success)
return Ok();
return BadRequest();
}
The method returns an HttpResponseMessage
that contains a number of Headers including Set-Cookie
.
What I need to do is to call this Web API controller from a controller written in .NET Core 3.1 and return the HttpResponseMessage
unaltered. This what I currently have:
[HttpPost]
[Route("[action]")]
//.NET Core Controller method
public async Task<ActionResult> Login(LoginViewModel model)
{
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.PostAsync(WebApiControllerURI, new JsonContent(model));
return Ok(response);
}
However, in the response from the .NET Core the Set-Cookie
is not a header but is contained in the response body:
{
"Key": "Set-Cookie",
"Value": [
".AspNet.ApplicationCookie=...."
]
},
I get the same result when I try to return the HttpResponseMessage
explicitly:
[HttpPost]
[Route("[action]")]
public async Task<HttpResponseMessage> Login(LoginViewModel model)
{
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.PostAsync(serverUrl + LoginUri, new JsonContent(model));
return response;
}
How can I return the response from the Web API controller through the .NET Core controller and retain the headers in the Headers
property?
Upvotes: 1
Views: 3280
Reputation: 2598
If you want to add a cookie to your API request, then there are two ways:
Used with static cookies.
// Method 1 - In Startup
app.Use(async (context, next) =>
{
var cookieOptions = new CookieOptions()
{
Path = "/",
Expires = DateTimeOffset.UtcNow.AddHours(1),
IsEssential = true,
HttpOnly = false,
Secure = false,
};
context.Response.Cookies.Append("MyCookie", "TheValue", cookieOptions);
await next();
});
Used when you have a cookie with changing values:
[HttpPost("TestCookie")]
public async Task TestCookie(string cookieName, string cookieValue)
{
// Method 2 - Add to current context
var context = HttpContext;
var cookieOptions = new CookieOptions()
{
Path = "/",
Expires = DateTimeOffset.UtcNow.AddHours(1),
IsEssential = true,
HttpOnly = false,
Secure = false,
};
context.Response.Cookies.Append(cookieName, cookieValue, cookieOptions);
}
The context is always returned, even if you don't have a return statement. So you just have to set the cookie header in the context and it will automatically get returned.
Upvotes: 2
Reputation: 1003
When you use return Ok(response)
or just return response
the framework takes the HttpResponse
object and serializes it to json.
To proxy the response, take a look at this stack overflow question Creating a proxy to another web api with Asp.net core
The code would be something like this:
/* Copied from the linked stack overflow answer. Only part of the code since the linked question was about a full proxy. */
public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage)
{
if (responseMessage == null)
{
throw new ArgumentNullException(nameof(responseMessage));
}
var response = context.Response;
response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers)
{
response.Headers[header.Key] = header.Value.ToArray();
}
foreach (var header in responseMessage.Content.Headers)
{
response.Headers[header.Key] = header.Value.ToArray();
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
response.Headers.Remove("transfer-encoding");
using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(response.Body, _streamCopyBufferSize, context.RequestAborted);
}
}
[HttpPost]
[Route("[action]")]
//.NET Core Controller method
public async Task<ActionResult> Login(LoginViewModel model)
{
HttpResponseMessage response = await httpClient.PostAsync(WebApiControllerURI, new JsonContent(model));
await HttpContext.CopyProxyHttpResponse(response);
return Ok();
}
another option would be a library like AspNetCore.Proxy depending on how much you need to proxy.
Upvotes: 1