Remove/add MessageHandlers at runtime - asp.net-web-api

How can I add or remove message handlers at runtime?
The following example does not work:
var logHandler = GlobalConfiguration.Configuration.MessageHandlers.FirstOrDefault(a => a.GetType() == typeof(ApiLogHandler));
if (logHandler == null)
{
GlobalConfiguration.Configuration.MessageHandlers.Add(new ApiLogHandler());
}
else
{
GlobalConfiguration.Configuration.MessageHandlers.Remove(logHandler);
}
The message handler is added to the list,
but it is not called in the the next requests...

I would inject a MessageHandler into the configuration at startup that is built specifically to have a dynamic list of inner message handlers, and change the interface they use from DelegatingHandler to a custom one, e.g.
public interface ICustomMessageHandler
{
Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
}
After this, you can create a standard MessageHandler that contains a list of inner handlers:
public class DynamicMessageHandler : DelegatingHandler
{
public List<ICustomMessageHandler> InnerHandlers { get; set; }
public DynamicMessageHandler()
{
InnerHandlers = new List<ICustomMessageHandler>();
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
foreach (var innerHandler in InnerHandlers)
{
await innerHandler.SendAsync(request, cancellationToken);
}
return await base.SendAsync(request, cancellationToken);
}
}
This way youshould be able to modify the list of InnerHandlers at runtime as long as you keep a single instance of DynamicMessageHandler around.

Related

RabbitMq Consumers do Not Consume

public class RequestConsumer :
IConsumer<StartFlowCommand>,
IConsumer<List<StartAndNextCommand>>
{
readonly IWorkFlowHandler _flowHandler;
public RequestConsumer(IContainer container)
{
_flowHandler = container.Resolve<IWorkFlowHandler>();
}
public async Task Consume(ConsumeContext<StartAndNextCommand> context)
{
var result =await _flowHandler.WorkFlowStartNext(context.Message);
await context.RespondAsync(result);
}
public async Task Consume(ConsumeContext<List<StartAndNextCommand>> context)
{
var result = await Task.Run(() => _flowHandler.WorkFlowStartNextBatch(context.Message));
await context.RespondAsync(result);
}
Message type of StartAndNextCommand can consume,but type of List are unable to consume,why?
This is by design. We can only consume one message. You can have a new contract, like:
public interface StartAndNextBatch
{
IList<StartAndNextCommand> Commands { get; }
}
and then have a consumer for that message type
public async Task Consume(ConsumeContext<StartAndNextBatch> context)
but you also need to publish that message type
await bus.Publish<StartAndNextBatch>(
new { Commands = ... }
);

Simple Injector inject dependency into custom global authentication filters and OWIN middle ware OAuthAuthorizationServerProvider

I used Simple Injector as our Ioc container; we have two problems.
We want to inject into our custom authentication filter; we read the post of converting attribute to a passive attribute: Convert Attribute into a passive. But we can't convert custom authentication filter attribute into a passive.
public class BearerAuthentication : Attribute, IAuthenticationFilter
{
public async Task AuthenticateAsync(
HttpAuthenticationContext context, CancellationToken cancellationToken)
{
}
public Task ChallengeAsync(
HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
}
}
We want to inject dependency into OWin middleware OAuthAuthorizationServerProvider; we know we can use begin execution context scope, but we want an elegant solution.
using (Ioc.Container.BeginExecutionContextScope())
{
}
Updated
public interface IAuthenticationFilter<TAttribute> where TAttribute : Attribute
{
Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken);
Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken);
}
public class BearerAuthenticationFilter : Attribute, IAuthenticationFilter<BearerAuthenticationFilter>
{
private readonly IAuthenticationBusinessEngine _authenticationBusinessEngine;
private readonly IHttpContextAccessor _httpContextAccessor;
public BearerAuthenticationFilter(IAuthenticationBusinessEngine authenticationBusinessEngine, IHttpContextAccessor httpContextAccessor)
{
_authenticationBusinessEngine = authenticationBusinessEngine;
_httpContextAccessor = httpContextAccessor;
}
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
public class AuthenticationFilterDispatcher : IAuthenticationFilter
{
private readonly Func<Type, IEnumerable> _container;
public AuthenticationFilterDispatcher(Func<Type, IEnumerable> container)
{
_container = container;
}
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
var descriptor = context.ActionContext.ActionDescriptor;
var attributes = descriptor.ControllerDescriptor.GetCustomAttributes<Attribute>(true)
.Concat(descriptor.GetCustomAttributes<Attribute>(true));
foreach (var attribute in attributes)
{
var filterType = typeof(IAuthenticationFilter<>).MakeGenericType(attribute.GetType());
var filters = _container.Invoke(filterType);
foreach (dynamic actionFilter in filters)
{
await actionFilter.AuthenticateAsync(context, cancellationToken);
}
}
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public bool AllowMultiple
{
get
{
return true;
}
}
}
The equivalent code for working with IAuthenticationFilter is:
public interface IAuthenticationFilter<TAttribute> where TAttribute : Attribute
{
Task AuthenticateAsync(TAttribute attribute, HttpAuthenticationContext context);
}
public class AuthenticationFilterDispatcher : IAuthenticationFilter
{
private readonly Func<Type, IEnumerable> container;
public AuthenticationFilterDispatcher(Func<Type, IEnumerable> container) {
this.container = container;
}
public async Task AuthenticateAsync(HttpAuthenticationContext context,
CancellationToken token) {
var descriptor = context.ActionContext.ActionDescriptor;
var attributes = descriptor.ControllerDescriptor
.GetCustomAttributes<Attribute>(true)
.Concat(descriptor.GetCustomAttributes<Attribute>(true));
foreach (var attribute in attributes) {
Type filterType = typeof(IAuthenticationFilter<>)
.MakeGenericType(attribute.GetType());
IEnumerable filters = this.container.Invoke(filterType);
foreach (dynamic actionFilter in filters) {
await actionFilter.AuthenticateAsync((dynamic)attribute, context);
}
}
}
public async Task ChallengeAsync(HttpAuthenticationChallengeContext context,
CancellationToken token) { }
public bool AllowMultiple { get { return true; } }
}
Registration is done as follows:
GlobalConfiguration.Configuration.Filters.Add(
new AuthenticationFilterDispatcher(container.GetAllInstances));
// For Simple Injector 2.x:
container.RegisterManyForOpenGeneric(typeof(IAuthenticationFilter<>),
container.RegisterAll,
new[] { typeof(IAuthenticationFilter<>).Assembly });
// For Simple Injector 3.x:
container.RegisterCollection(typeof(IAuthenticationFilter<>),
new[] { typeof(IAuthenticationFilter<>).Assembly });
Now instead of making your attributes active, you can make the attribute passive and implement the required logic inside an IAuthenticationFilter<MyPassiveAttribute> implementation.
Your attribute and new component might look like this:
// NOTE: This attribute does not derive from anything Web API specific,
// just from Attribute
public class RequiresBearerAuthenticationAttribute : Attribute
{
// put here properties if required
}
public class BearerAuthenticationFilter
: IAuthenticationFilter<RequiresBearerAuthenticationAttribute>
{
private readonly IAuthenticationBusinessEngine _authenticationBusinessEngine;
private readonly IHttpContextAccessor _httpContextAccessor;
public BearerAuthenticationFilter(
IAuthenticationBusinessEngine authenticationBusinessEngine,
IHttpContextAccessor httpContextAccessor)
{
_authenticationBusinessEngine = authenticationBusinessEngine;
_httpContextAccessor = httpContextAccessor;
}
public async Task AuthenticateAsync(RequiresBearerAuthenticationAttribute attribute,
HttpAuthenticationContext context)
{
// TODO: Behavior here
}
}

Web API 2 RequireHttps allowing http connection

I have created the following action in my MVC Web API 2 controller:
[ResponseType(typeof(int))]
[RequireHttps]
public IHttpActionResult SaveLead(EcommerceLead lead)
{
}
But in my test app I am making a call to
http://localhost/api/savelead
And it is working. Is there any way to make the action to only work if it is called over https, ie return a 404 if it isn't or something?
If you are using RequireHttps from Mvc namespace, it will not work with Web API. You can write a simple filter for Web API yourself to enforce HTTPS. Since you are using Web API 2, create an authentication filter like this.
public class RequireHttpsAttribute : IAuthenticationFilter
{
public bool AllowMultiple
{
get { return true; }
}
public Task AuthenticateAsync(HttpAuthenticationContext context,
CancellationToken cancellationToken)
{
if (context.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
context.ActionContext.Response = new HttpResponseMessage(
System.Net.HttpStatusCode.Forbidden);
}
return Task.FromResult<object>(null);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context,
CancellationToken cancellationToken)
{
return Task.FromResult<object>(null);
}
}
If you are using web api older version you can use Authoriztion filter.
public class RequireHttpsAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
{
ReasonPhrase = "HTTPS Required"
};
}
else
{
base.OnAuthorization(actionContext);
}
}
}
You can use Message Handler.
public class RequireHttpsHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
return Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
{
ReasonPhrase = "HTTPS Required"
});
}
return base.SendAsync(request, cancellationToken);
}
}

Can you please tell me the Advantages and Disadvantages of IExceptionhandler?

Can Any one tell me the Advantages and Disadvantages of IExceptionhandler used in web api?
Which one is the best method to handle Exceptions in web Api?
In My below sample i am using IExceptionHandler to handle all my web api exceptions.
In HandleCore method, i am handling Httpexceptions,MyCustomerrormessages,Unhandled Exceptions.
Can any one tell me,handling all the exceptions inside my HandleCore method of IExceptionHandler is a correct way?
namespace AccessServices.EntityModel
{
/// <summary>
/// To Handle the unhandled exceptions caught by Web API.
/// </summary>
public class CustomExceptionHandler : IExceptionHandler
{
public virtual Task HandleAsync(ExceptionHandlerContext context,
CancellationToken cancellationToken)
{
if (!ShouldHandle(context))
{
return Task.FromResult(0);
}
return HandleAsyncCore(context, cancellationToken);
}
public virtual Task HandleAsyncCore(ExceptionHandlerContext context,
CancellationToken cancellationToken)
{
HandleCore(context);
return Task.FromResult(0);
}
public virtual void HandleCore(ExceptionHandlerContext context)
{
}
public virtual bool ShouldHandle(ExceptionHandlerContext context)
{
return context.ExceptionContext.CatchBlock.IsTopLevel;
}
}
/// <summary>
///Response to unhandled exceptions caught by Web API.
/// </summary>
public class OopsExceptionHandler : CustomExceptionHandler
{
public override void HandleCore(ExceptionHandlerContext context)
{
var exception = context.Exception;
if (exception is HttpException)
{
var httpException = (HttpException)exception;
context.Result = new TextPlainErrorResult
{
Request = context.ExceptionContext.Request,
Content = exception.Message,
Statuscode=(HttpStatusCode)httpException.GetHttpCode()
};
}
else if (exception is MyCustomException)
{
context.Result = new TextPlainErrorResult
{
//Request = context.ExceptionContext.Request,
Content = MyCustomException.Message,
Statuscode = MyCustomException.StatusCode
};
}
else
{
context.Result = new TextPlainErrorResult
{
Request = context.ExceptionContext.Request,
Content = "Oops! Sorry! Something went wrong." +
"Please contact Administrator",
Statuscode=HttpStatusCode.InternalServerError
};
}
}
/// <summary>
/// Sends HttpResponseMessage to the client
/// </summary>
private class TextPlainErrorResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string Content { get; set; }
public HttpStatusCode Statuscode { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(Statuscode)
{
Content = new StringContent(Content),
RequestMessage = Request
};
return Task.FromResult(response);
}
}
}
}
IExceptionHandler intention is to provide a global error handling mechanism for unhandled exceptions occurring in Web API.
ExceptionFilterAttributes can handle exceptions only from certain areas of Web APIā€¦for example, in case of any exceptions thrown from Authentication filters, Authorization filters, Action filters & Actions.
If exceptions are thrown, for example, from MessageHandlers, route matching or when writing out response, then exception filters are not invoked as they sit high up in the layered stack. So Global Error Handling feature (IExceptionLogger and IExceptionHandler) here try to provide a consistent experience throughout all the layers.

Properly Implementing IAuthorizationFilter in Web API

I'm having trouble figuring out how to implement an authorization filter in Web API using IAuthorizationFilter from System.Web.Http.Filters.
This is a simple filter I wrote to respond to all non-https requests with a 403 forbidden response:
public class HttpsFilter : IAuthorizationFilter {
public bool AllowMultiple {
get {
return false;
}
}
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync( HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation ) {
var request = actionContext.Request;
if ( request.RequestUri.Scheme != Uri.UriSchemeHttps ) {
HttpResponseMessage response = request.CreateResponse( HttpStatusCode.Forbidden );
response.Content = new StringContent( "<h1>HTTPS Required</h1>", Encoding.UTF8, "text/html" );
actionContext.Response = response;
return new Task<HttpResponseMessage>( delegate() {
return response;
} );
}
else
return continuation();
}
}
What I have written so far runs, but when I try to access the api over regular http, it just hangs and I never get a response.
For you scenario, you could simply derive from the "System.Web.Http.AuthorizeAttribute".
Example:
public class HttpsFilterAttribute : System.Web.Http.AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
//do something
}
}
You either need to save the task into a variable and call the task.Start() method before returning it, or use the Task<HttpResponseMessage>.Factory.StartNew(Action action) method to create the task.

Resources