Add custom header to all responses in Web API - c#

Simple question, and I am sure it has a simple answer but I can't find it.
I am using WebAPI and I would like to send back a custom header to all responses (server date/time requested by a dev for syncing purposes).
I am currently struggling to find a clear example of how, in one place (via the global.asax or another central location) I can get a custom header to appear for all responses.
Answer accepted, here is my filter (pretty much the same) and the line i added to the Register function of the WebApi config.
NOTE: The DateTime stuff is NodaTime, no real reason just was interested in looking at it.
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Content.Headers.Add("ServerTime", Instant.FromDateTimeUtc(DateTime.Now.ToUniversalTime()).ToString());
}
Config Line:
config.Filters.Add(new ServerTimeHeaderFilter());

For that you can use a custom ActionFilter (System.Web.Http.Filters)
public class AddCustomHeaderFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Headers.Add("customHeader", "custom value date time");
}
}
You can then apply the filter to all your controller's actions by adding this in the configuration in Global.asax for example :
GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderFilter());
You can also apply the filter attribute to the action that you want without the global cofiguration line.

Previous answers to this question don't address what to do if your controller action throws an exception. There are two basic ways to get that to work:
Add an exception filter:
using System.Net;
using System.Net.Http;
using System.Web.Http.Filters;
public class HeaderAdderExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Response == null)
context.Response = context.Request.CreateErrorResponse(
HttpStatusCode.InternalServerError, context.Exception);
context.Response.Content.Headers.Add("header", "value");
}
}
and in your WebApi setup:
configuration.Filters.Add(new HeaderAdderExceptionFilter());
This approach works because WebApi's default exception handler will send the HttpResponseMessage created in a filter instead of building its own.
Replace the default exception handler:
using System.Net;
using System.Net.Http;
using System.Web.Http.ExceptionHandling;
using System.Web.Http.Results;
public class HeaderAdderExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
HttpResponseMessage response = context.Request.CreateErrorResponse(
HttpStatusCode.InternalServerError, context.Exception);
response.Headers.Add("header", "value");
context.Result = new ResponseMessageResult(response);
}
}
and in your WebApi setup:
configuration.Services.Replace(typeof(IExceptionHandler), new HeaderAdderExceptionHandler());
You can't use both of these together. Okay, well, you can, but the handler will never do anything because the filter already converted the exception into a response.
Super important to note that as written, this code will send all the exception details to the client. You probably don't want to do this in production, so check out all the available overloads on CreateErrorResponse() and pick which one suits your needs.

Julian's answer led me to have to create the filter but only using the the System.Web (v4) and System.Web.Http (v5) namespace (MVC packages were not part of this particular project this was used on.)
using System.Web;
using System.Web.Http.Filters;
...
public class AddCustomHeaderActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
actionExecutedContext.ActionContext.Response.Headers.Add("name", "value");
}
}
And add it to the global.asax to have it used on every controller/action
GlobalConfiguration.Configuration.Filters.Add(new AddCustomHeaderActionFilterAttribute());

Neither of the above two solutions worked for me. They wouldn't even compile. Here's what I did. Added:
filters.Add(new AddCustomHeaderFilter());
to RegisterGlobalFilters(GlobalFilterCollection filters) method in FiltersConfig.cs and then added
public class AddCustomHeaderFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
actionExecutedContext.HttpContext.Response.Headers.Add("ServerTime", DateTime.Now.ToString());
}
}

It can be done by the messagehandler easily, it will handle both ok response and exception case.
public class CustomHeaderHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// add header to request if you want
var response = await base.SendAsync(request, cancellationToken);
response.Headers.Add("cutomKey", "cutomValue");
return response;
}
}
Add it in the config
config.MessageHandlers.Add(new CustomHeaderHandler());

According to my requirement, below single line of code serves the purpose.
System.Web.HttpContext.Current.Response.Headers.Add("Key", "Value")

I combined the normal and exception path in one class:
public class CustomHeaderAttribute : FilterAttribute, IActionFilter, IExceptionFilter
{
private static string HEADER_KEY { get { return "X-CustomHeader"; } }
private static string HEADER_VALUE { get { return "Custom header value"; } }
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
return (new CustomHeaderAction() as IActionFilter).ExecuteActionFilterAsync(actionContext, cancellationToken, continuation);
}
public Task ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{
return (new CustomHeaderException() as IExceptionFilter).ExecuteExceptionFilterAsync(actionExecutedContext, cancellationToken);
}
private class CustomHeaderAction: ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Response != null)
{
actionExecutedContext.Response.Content.Headers.Add(HEADER_KEY, HEADER_VALUE);
}
}
}
private class CustomHeaderException : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Response == null)
{
context.Response = context.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, context.Exception);
}
context.Response.Content.Headers.Add(HEADER_KEY, HEADER_VALUE);
}
}
}
Nothing fancy but at least it gives me one place to control my additional headers. For now it's just static content but you could always hook it up to some sort of dictionary generator/factory.

I had the same problem while trying to add a new header to the whole controller, just add "services.AddHttpContextAccessor();" to startup.cs then create your controller
public class EnController : Controller{
public EnController(IHttpContextAccessor myHttpAccessor)
{
myHttpAccessor.HttpContext.Response.Headers.Add("Content-Language", "en-US");
}
... more methods here...
}

Related

MinimalAPI Action filter never get executed

I am working on a minimal API and I am trying to make an actionfilter for authentication works with it.
I tried to add my action filter directly on the endpoint registration likeso:
app.MapGet("/Users/{userId}", [ServiceFilter(typeof(CustomAuthorizationAttribute))] async (IMediator mediator, string userId) =>
{
//SomeCode
});
I also tried with the attribute directly.
app.MapGet("/Users/{userId}", [CustomAuthorizationAttribute()] async (IMediator mediator, string userId) =>
{
//SomeCode
});
At first I tried to make an extension to add it in a more elegant way and it didn't work either.
public static TBuilder AddCustomAuthorizationAttribute<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.Add(endpointBuilder =>
{
endpointBuilder.Metadata.Add(new CustomAuthorizationAttribute());
});
return builder;
}
There is my simple ActionFilter. I am placing my breakpoint under the onActionExecuting code to intercept when the attribute get called but it never get called.
public class CustomAuthorizationAttribute : ActionFilterAttribute, IAsyncActionFilter
{
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context); //BreakPoint
}
public override Task OnActionExecutionAsync(ActionExecutingContext context,ActionExecutionDelegate actionExecutionDelegate)
{
return base.OnActionExecutionAsync(context, actionExecutionDelegate); //BreakPoint
}
}
Action filters are part of ASP.NET Core MVC pipeline and are not applicable (at least at the moment of writing) to Minimal APIs.
UPD
Starting .NET 7 Minimal API's will have similar feature allowing to use AddFilter method. See also issue1 issue2, PR, and IRouteHandlerFilter interface.

How to await method in PropertyValidator's overridden IsValid?

I'm trying to use my Data Repository in PropertyValidator class. The problem is that method in the Repository is async... and I can't see IsValidAsync to override.
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentValidation.Validators;
using AccountApi.Domain.Repositories;
namespace AccountApi.Domain.Validators
{
public class UserInputValidator<TElement> : PropertyValidator
{
private IUserRepository _userRepository;
public UserInputValidator(IUserRepository userRepository)
: base("{Message}.")
{
_userRepository = userRepository;
}
protected override bool IsValid(PropertyValidatorContext context)
{
var id = (int)context.PropertyValue;
var user = await _userRepository.GetById(id); // <--- HERE is the problem
// .....
return true;
}
}
}
I tried to change to this:
protected override async Task<bool> IsValidAsync(PropertyValidatorContext context)
... but it doesn't work as well. There is no IsValidAsync to override.
Is it possible to use async methods inside PropertyValidator?
You're sort of on the right track.
Yes, you do overload the PropertyValidator method protected virtual async Task<bool> IsValidAsync(PropertyValidatorContext context, CancellationToken cancellation)
However you need to use the validator.ValidateAsync(objectToValidate) method to use it.
If your validator contains asynchronous validators or asynchronous
conditions, it’s important that you always call ValidateAsync on your
validator and never Validate. If you call Validate, then your
asynchronous rules will be run synchronously, which is not desirable.
Source
Additionally refer to the following issue where Jeremy suggests:
Also overloading the ShouldValidateAsync method; or better still
Use the AsyncValidatorBase rather than PropertyValidator which handles the ShouldValidateAsync overload for you
See the following if you want to see a working solution of an async property validator.
Is it possible to use async methods inside PropertyValidator?
You could press F12 on PropertyValidator in vs to see its methods.
public abstract class PropertyValidator : IPropertyValidator
{
protected PropertyValidator(IStringSource errorMessageSource);
protected PropertyValidator(string errorMessage);
[Obsolete("This constructor will be removed in FluentValidation 9.0. Use the overload that takes an IStringSource instead, passing in a LazyStringSource: PropertyValidator(new LazyStringSource(ctx => MyResourceClass.MyResourceName))")]
protected PropertyValidator(string errorMessageResourceName, Type errorMessageResourceType);
public PropertyValidatorOptions Options { get; }
public virtual bool ShouldValidateAsync(ValidationContext context);
public virtual IEnumerable<ValidationFailure> Validate(PropertyValidatorContext context);
[AsyncStateMachine(typeof(<ValidateAsync>d__7))]
public virtual Task<IEnumerable<ValidationFailure>> ValidateAsync(PropertyValidatorContext context, CancellationToken cancellation);
//
// Summary:
// Creates an error validation result for this validator.
//
// Parameters:
// context:
// The validator context
//
// Returns:
// Returns an error validation result.
protected virtual ValidationFailure CreateValidationError(PropertyValidatorContext context);
protected abstract bool IsValid(PropertyValidatorContext context);
[AsyncStateMachine(typeof(<IsValidAsync>d__10))]
protected virtual Task<bool> IsValidAsync(PropertyValidatorContext context, CancellationToken cancellation);
//
// Summary:
// Prepares the FluentValidation.Internal.MessageFormatter of context for an upcoming
// FluentValidation.Results.ValidationFailure.
//
// Parameters:
// context:
// The validator context
protected virtual void PrepareMessageFormatterForValidationError(PropertyValidatorContext context);
}
So,try to use
protected override async Task<bool> IsValidAsync(PropertyValidatorContext context, CancellationToken cancellation)
It is simple. Just use "AsyncPropertyValidator" or "AsyncPropertyValidator<T, type>"
In your case it will be like
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentValidation.Validators;
using AccountApi.Domain.Repositories;
namespace AccountApi.Domain.Validators
{
public class UserInputValidator<TElement> : AsyncPropertyValidator
{
private IUserRepository _userRepository;
public UserInputValidator(IUserRepository userRepository)
: base("{Message}.")
{
_userRepository = userRepository;
}
public override async Task<bool> IsValidAsync(PropertyValidatorContext context)
{
var id = (int)context.PropertyValue;
var user = await _userRepository.GetById(id);
// ..
return true;
}
}
}

Intercept webapi json formatting errors

I'd like to have a way to intercept the exception that occurs when you send in malformed json to a webapi endpoint, so that I can return a semantic error code as opposed to just 500. (e.g. "Fix your broken JSON or go to hell")
You can create your custom validation filter attribute by deriving from ActionFilterAttribute:
public class ValidationFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = actionContext
.Request
.CreateErrorResponse(HttpStatusCode.BadRequest,
actionContext.ModelState);
}
}
}
Now, you may either decorate your actions with it:
[HttpGet]
[ValidationFilter()]
public string DoSomethingCool()
or register it globally via your config:
config.Filters.Add(new ValidationFilterAttribute());

How do I return NotFound() IHttpActionResult with an error message or exception?

I am returning a NotFound IHttpActionResult, when something is not found in my WebApi GET action. Along with this response, I want to send a custom message and/or the exception message (if any). The current ApiController's NotFound() method does not provide an overload to pass a message.
Is there any way of doing this? or I will have to write my own custom IHttpActionResult?
Here's a one-liner for returning a IHttpActionResult NotFound with a simple message:
return Content(HttpStatusCode.NotFound, "Foo does not exist.");
You'd need to write your own action result if you want to customize the response message shape.
We wanted to provide the most common response message shapes out of the box for things like simple empty 404s, but we also wanted to keep these results as simple as possible; one of the main advantages of using action results is that it makes your action method much easier to unit test. The more properties we put on action results, the more things your unit test needs to consider to make sure the action method is doing what you'd expect.
I often want the ability to provide a custom message as well, so feel free to log a bug for us to consider supporting that action result in a future release:
https://aspnetwebstack.codeplex.com/workitem/list/advanced
One nice thing about action results, though, is that you can always write your own fairly easily if you want to do something slightly different. Here's how you might do it in your case (assuming you want the error message in text/plain; if you want JSON, you'd do something slightly different with the content):
public class NotFoundTextPlainActionResult : IHttpActionResult
{
public NotFoundTextPlainActionResult(string message, HttpRequestMessage request)
{
if (message == null)
{
throw new ArgumentNullException("message");
}
if (request == null)
{
throw new ArgumentNullException("request");
}
Message = message;
Request = request;
}
public string Message { get; private set; }
public HttpRequestMessage Request { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Execute());
}
public HttpResponseMessage Execute()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NotFound);
response.Content = new StringContent(Message); // Put the message in the response body (text/plain content).
response.RequestMessage = Request;
return response;
}
}
public static class ApiControllerExtensions
{
public static NotFoundTextPlainActionResult NotFound(this ApiController controller, string message)
{
return new NotFoundTextPlainActionResult(message, controller.Request);
}
}
Then, in your action method, you can just do something like this:
public class TestController : ApiController
{
public IHttpActionResult Get()
{
return this.NotFound("These are not the droids you're looking for.");
}
}
If you used a custom controller base class (instead of directly inheriting from ApiController), you could also eliminate the "this." part (which is unfortunately required when calling an extension method):
public class CustomApiController : ApiController
{
protected NotFoundTextPlainActionResult NotFound(string message)
{
return new NotFoundTextPlainActionResult(message, Request);
}
}
public class TestController : CustomApiController
{
public IHttpActionResult Get()
{
return NotFound("These are not the droids you're looking for.");
}
}
You could use ResponseMessageResult if you like:
var myCustomMessage = "your custom message which would be sent as a content-negotiated response";
return ResponseMessage(
Request.CreateResponse(
HttpStatusCode.NotFound,
myCustomMessage
)
);
yeah, if you need much shorter versions, then I guess you need to implement your custom action result.
You may use ReasonPhrase property of HttpResponseMessage class
catch (Exception exception)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound)
{
ReasonPhrase = exception.Message
});
}
You can create a custom negotiated content result as d3m3t3er suggested. However I would inherit from. Also, if you need it only for returning NotFound, you don't need to initialize the http status from constructor.
public class NotFoundNegotiatedContentResult<T> : NegotiatedContentResult<T>
{
public NotFoundNegotiatedContentResult(T content, ApiController controller)
: base(HttpStatusCode.NotFound, content, controller)
{
}
public override Task<HttpResponseMessage> ExecuteAsync(
CancellationToken cancellationToken)
{
return base.ExecuteAsync(cancellationToken).ContinueWith(
task => task.Result, cancellationToken);
}
}
one line code in asp.net core:
Return StatusCode(404, "Not a valid request.");
I solved it by simply deriving from OkNegotiatedContentResult and overriding the HTTP code in the resulting response message. This class allows you to return the content body with any HTTP response code.
public class CustomNegotiatedContentResult<T> : OkNegotiatedContentResult<T>
{
public HttpStatusCode HttpStatusCode;
public CustomNegotiatedContentResult(
HttpStatusCode httpStatusCode, T content, ApiController controller)
: base(content, controller)
{
HttpStatusCode = httpStatusCode;
}
public override Task<HttpResponseMessage> ExecuteAsync(
CancellationToken cancellationToken)
{
return base.ExecuteAsync(cancellationToken).ContinueWith(
task => {
// override OK HTTP status code with our own
task.Result.StatusCode = HttpStatusCode;
return task.Result;
},
cancellationToken);
}
}
I was needing to create an IHttpActionResult instance in the body of an IExceptionHandler class, in order to set the ExceptionHandlerContext.Result property. However I also wanted to set a custom ReasonPhrase.
I found that a ResponseMessageResult could wrap a HttpResponseMessage (which allows ReasonPhrase to be set easily).
For Example:
public class MyExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
var ex = context.Exception as IRecordNotFoundException;
if (ex != null)
{
context.Result = new ResponseMessageResult(new HttpResponseMessage(HttpStatusCode.NotFound) { ReasonPhrase = $"{ex.EntityName} not found" });
}
}
}
If you inherit from the base NegotitatedContentResult<T>, as mentioned, and you don't need to transform your content (e.g. you just want to return a string), then you don't need to override the ExecuteAsync method.
All you need to do is provide an appropriate type definition and a constructor that tells the base which HTTP Status Code to return. Everything else just works.
Here are examples for both NotFound and InternalServerError:
public class NotFoundNegotiatedContentResult : NegotiatedContentResult<string>
{
public NotFoundNegotiatedContentResult(string content, ApiController controller)
: base(HttpStatusCode.NotFound, content, controller) { }
}
public class InternalServerErrorNegotiatedContentResult : NegotiatedContentResult<string>
{
public InternalServerErrorNegotiatedContentResult(string content, ApiController controller)
: base(HttpStatusCode.InternalServerError, content, controller) { }
}
And then you can create corresponding extension methods for ApiController (or do it in a base class if you have one):
public static NotFoundNegotiatedContentResult NotFound(this ApiController controller, string message)
{
return new NotFoundNegotiatedContentResult(message, controller);
}
public static InternalServerErrorNegotiatedContentResult InternalServerError(this ApiController controller, string message)
{
return new InternalServerErrorNegotiatedContentResult(message, controller);
}
And then they work just like the built-in methods. You can either call the existing NotFound() or you can call your new custom NotFound(myErrorMessage).
And of course, you can get rid of the "hard-coded" string types in the custom type definitions and leave it generic if you want, but then you may have to worry about the ExecuteAsync stuff, depending on what your <T> actually is.
You can look over the source code for NegotiatedContentResult<T> to see all it does. There isn't much to it.
Iknow PO asked with a message text, but another option to just return a 404 is making the method return a IHttpActionResult and use the StatusCode function
public async Task<IHttpActionResult> Get([FromUri]string id)
{
var item = await _service.GetItem(id);
if(item == null)
{
StatusCode(HttpStatusCode.NotFound);
}
return Ok(item);
}
Answers here are missing a little developer story problem. The ApiController class is still exposing a NotFound() method that developers may use. This would cause some 404 response to contain a uncontrolled result body.
I present here a few parts of code "better ApiController NotFound method" that will provide a less error-prone method that does not require developers to know "the better way of sending a 404".
create a class inheriting from ApiController called ApiController
I use this technique to prevent developers from using the original class
override its NotFound method to let devs use the first available api
if you want to discourage this, mark this as [Obsolete("Use overload instead")]
add an extra protected NotFoundResult NotFound(string message) that you want to encourage
problem: the result does not support responding with a body. solution: inherit and use NegotiatedContentResult. see attached better NotFoundResult class.
Another nice possibility is to use a different built-in result type: NotFoundObjectResult(message).
Needed to return the error message for 404 Not Found and I am using Dot Net 6.0.
This is the code
Problem(statusCode: 404, detail: "Put your detailed error message here");
Where Problem is a method present in ControllerBase class.

Terminate the execution of web api request in Initialize function

I am working on some Restful APIs in .net web api . All the API controllers that I am working on inherit from a base API controller. It has some logic in the Initialize function.
protected override void Initialize(HttpControllerContext controllerContext)
{
// some logic
}
There is a new product requirement comes in and I want to return the response to the client in the Initialize function depending on some criteria.
e.g.
protected override void Initialize(HttpControllerContext controllerContext)
{
// some logic
controllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "error");
}
however it seems like that the .net pipeline still moves on even I return the response already.
Is there anyway to return the response inside that function and stop the execution? Or I have to refactor the existing code to do it in another way?
Here is a hacky way of accomplishing what you want. Throw an exception like so.
protected override void Initialize(HttpControllerContext controllerContext)
{
// some logic
if(youhavetosend401)
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
The cleaner way, assuming what you are trying to do is all about authorization is to create an authorization filter like so.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext context)
{
// Do your stuff and determine if the request can proceed further or not
// If not, return false
return true;
}
}
Apply the filter on the action method or controller or even globally.
[MyAuthorize]
public HttpResponseMessage Get(int id)
{
return null;
}
Use HttpResponseException to send the HttpResponseMessage created for Error.
protected override void Initialize(System.Web.Http.Controllers.HttpControllerContext controllerContext)
{
//Your Logic
throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.Unauthorized, "error"));
base.Initialize(controllerContext);
}
Use
Application.CompleteRequest()
it will fire the EndRequest event.

Categories

Resources