Reputation: 3969
I have an ASP.NET Core API that adds two headers to its response callback_uri
and redirect_uri
.
The strange thing (to me) is that in my AJAX call to the service, the headers are part of the JSON data, as a headers array, rather than the request
object itself. I cannot use jqxhr.getResponseHeader(...)
and therefore must interrogate the headers array manually within the response data.
Because the StatusCode
is also part of the data it means my AJAX success callback is always called, even when I'm testing for a 400 bad request response, which makes testing less simple.
Web API controller action:
[HttpGet, Route("Authenticate")]
public HttpResponseMessage Authenticate(string applicationId)
{
HttpResponseMessage response;
if(!_security.IsApplicationIdValid(applicationId))
{
response = new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest);
response.ReasonPhrase = ErrorMessages.INVALID_APPLICATION_ID;
return response;
}
IAuthenticationProvider authProvider = _security.GetAuthenticationProvider();
response = new HttpResponseMessage(System.Net.HttpStatusCode.Redirect);
response.Headers.Add(HeaderKeyNames.CALLBACK_URI_KEY_NAME, authProvider.GetCallbackUrl());
response.Headers.Add(HeaderKeyNames.AUTHENTICATION_SERVICE_REDIRECT_URI_KEY_NAME, authProvider.GetUrl());
return response;
}
AJAX code:
var settings = {
data: { "applicationId": applicationId },
success: successCallback, // at the moment just writes to console
error: errorCallback, // at the moment just writes to console
method: "GET"
};
$.ajax(url, settings);
Am I doing something wrong on the server-side?
Upvotes: 0
Views: 1835
Reputation: 1675
What you're doing is creating a HttpResponseMessage
object, serializing it to json and then returning it.
This is why the headers are in the json content, instead of the http response.
What you can do is someting like this:
[HttpGet, Route("Authenticate")]
public IActionResult Authenticate(string applicationId)
{
if(!_security.IsApplicationIdValid(applicationId))
{
return BadRequest(ErrorMessages.INVALID_APPLICATION_ID);
}
IAuthenticationProvider authProvider = _security.GetAuthenticationProvider();
this.Response.Headers.Add(HeaderKeyNames.CALLBACK_URI_KEY_NAME, authProvider.GetCallbackUrl());
this.Response.Headers.Add(HeaderKeyNames.AUTHENTICATION_SERVICE_REDIRECT_URI_KEY_NAME, authProvider.GetUrl());
return StatusCode(302);
}
Upvotes: 0
Reputation: 5762
You can use a combination of ResultFilters and ServiceFilterAttribute to add your custom headers. This is particularly useful because:
ServiceFilter
enables you to have DI access in your ResultFilter. Attribute
in the actions you wantPutting all together:
public class CustomHeadersResultFilter : IResultFilter
{
private readonly IMyService _myService;
public CustomHeadersResultFilter(IMyService myService)
{
_myService = myService;
}
public void OnResultExecuting(ResultExecutingContext context)
{
context.HttpContext.Response.Headers.Add("my-header", _myService.GetData());
// if under CORS, this need to be added otherwise you can't read the headers using xhr.getResponseHeader('my-header')
context.HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "my-header");
}
public void OnResultExecuted(ResultExecutedContext context)
{
// can't add headers here, since it's too late in the pipeline
}
}
Startup.ConfigureServices
services.AddTransient<IMyService, MyService>();
// our custom result filter
services.AddTransient<CustomHeadersResultFilter>();
[HttpGet("{id}")]
[ServiceFilter(typeof(CustomHeadersResultFilter))]
public ActionResult Get(string id)
{
if (id == "something-bad")
{
return BadRequest("invalid application id");
}
// return a 200 Ok. Check the other types if you want something different
return Ok();
}
Testing all of this with a separate web application, doing an ajax
request to the API, you can access the headers:
<script>
var settings = { method: "GET" };
$.ajax('http://localhost:61284/api/values/test', settings)
.done(function (data, textStatus, xhr) {
alert(xhr.getResponseHeader('my-header'));
})
.fail(function () {
alert("error");
});
</script>
Upvotes: 1
Reputation: 831
Add headers like this: (ofc change the type if needed or define your own)
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
Upvotes: 0