In an ApiController action I need to close a connection to a database as soon as the action is finished executing.
Under a controller I override OnActionExecuted to accomplish this.
How would I accomplish this under an ApiController action?
Thanks
You could override the ExecuteAsync method:
public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
{
return base
.ExecuteAsync(controllerContext, cancellationToken)
.ContinueWith(t =>
{
// the controller action has finished executing,
// your custom code could come here ...
return t.Result;
});
}
Related
Recently, I have been getting 405 response messages logged in Application Insights from the bot framework relating to "OPTIONS" message being sent.
How should my service be responding to these?
Who is making these requests?
Sorry if you saw my previous answer; it was completely off base so I deleted it in shame.
The requests you mention are made by Azure when navigating to WebChat or the Settings tab. To allow the call, you can create a custom bot auth class:
public class CustomBotAuthenticationAttribute : BotAuthentication
{
public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
if (actionContext.Request.Method.Method == "OPTIONS") // allow OPTIONS through, and do not authenticate
return Task.CompletedTask;
return base.OnActionExecutingAsync(actionContext, cancellationToken);
}
}
Then, in the MessagesController:
[CustomBotAuthentication] // Change from [BotAuthentication]
public class MessagesController : ApiController
{
public HttpResponseMessage Options() // handle options
{
return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
}
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
I'm using Mediatr 3's new features for Pipeline Behaviors. Problem is, when I wire them into Mediatr, exceptions (System.InvalidCastException) get thrown for every .Send() call. Handlers get called fine, but when its time for the pipeline behaviors to get called, it fails.
Here's my setup:
services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t));
services.AddScoped<MultiInstanceFactory>(p => t => GetRequiredServices(p,t));
services.AddScoped(typeof( IPipelineBehavior<, >), typeof(AddSessionBehavior<, >));
services.AddMediatR();
And my Behavior:
public class AddSessionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
IHttpContextAccessor Accessor;
public AddSessionBehavior(IHttpContextAccessor anAccessor)
{
this.Accessor = anAccessor;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
var response = await next();
return response;
}
}
When I send my first message through mediator, I get:
System.InvalidCastException occurred
HResult=0x80004002
Message=Object cannot be stored in an array of this type.
Source=<Cannot evaluate the exception source>
StackTrace:
at System.Array.InternalSetValue(Void* target, Object value)
at System.Array.SetValue(Object value, Int32[] indices)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitClosedIEnumerable(ClosedIEnumerableCallSite closedIEnumerableCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at MediatR.ServiceCollectionExtensions.GetRequiredServices(IServiceProvider provider, Type serviceType)
at MediatR.Internal.RequestHandlerImpl`2.GetPipeline(TRequest request, RequestHandlerDelegate`1 invokeHandler, MultiInstanceFactory factory)
at MediatR.Internal.RequestHandlerImpl`2.Handle(IRequest`1 request, CancellationToken cancellationToken, SingleInstanceFactory singleFactory, MultiInstanceFactory multiFactory)
at MediatR.Mediator.Send[TResponse](IRequest`1 request, CancellationToken cancellationToken)
at Merlin.Web.Controllers.CourseController.Add(CourseAddVM model)
If I comment out the wiring for my behavior, my handlers get called fine. And the rest of the application seems to work.
What have I done wrong?
I figured it out.
Turns out that somewhere along the way an internal class with the same name as my behavior was created in a different namespace in my application. Probably the result of a "Generate Class definition".
Removing the generated class cleared up the issue.
In Asp.net Web Api, I want to control, request "access token" key is (which is in request header) valid or not. But I cound't decide where should I implement this kind of control. ActionFilter or controller constructor etc. etc.
How about using a DelegatingHandler? It is part if the Web Api pipeline and executes before Routing and Controller handlers.
A really simple handler for access tokens may look like this. You would implement IsValid as you see fit.
public class ValidateTokenHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var token = request.Headers.Authorization;
if (token == null or !IsValid(token))
{
return new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
return await base.SendAsync(request, cancellationToken);
}
}
I am having a difficulty to get route data, action or controller in DelegatingHandler.
public class LoggingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var routeData = request.GetRouteData();
in this example routeData is always null. Is there any way how to get the context of the Web API controllers and thus actions so I could tell what action the URL is trying to invoke?
I have four message handlers - MyHandler, MyHandler1, MyHandler2 and MyOtherHandler. I have MyHandler and MyOtherHandler added to the handlers collection, but not MyHandler1 or MyHandler2.
config.MessageHandlers.Add(new MyHandler());
config.MessageHandlers.Add(new MyOtherHandler());
I want MyHandler1 or MyHandler2 to be added to the pipeline on the fly by MyHandler, depending on some condition. I know that MyHandler1 and 2 can be added to the config.MessageHandlers collection and do nothing when their turn comes, when 'some' condition does not apply but that is not what I want. Let's say I have about 100 such handlers and I don't want all of them to run in the pipeline but only when MyHandler thinks it is appropriate.
I cannot manually insert MyHandler1 into the pipeline by setting MyHandler.InnerHandler. The chain is cached globally for all requests and I cannot modify it for something related to a specific request. Here is what I did.
I created a base handler that increases the visibility of SendAsync.
public abstract class MyBaseHandler : DelegatingHandler
{
public Task<HttpResponseMessage> WrapperSendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
return this.SendAsync(request, cancellationToken);
}
}
I derived MyHandler1 and 2 from this base.
public class MyHandler1 : MyBaseHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
// Use request
var response = await base.SendAsync(request, cancellationToken);
// Use response
return response;
}
}
Now, MyHandler can instantiate MyHandler1 or Myhandler2 based on the condition and sets the InnerHandler to its own InnerHandler and just call and return SendAsync through the wrapper.
public class MyHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
// Check condition and choose MyHandler1 or MyHandler2 or just return
// await base.SendAsync(request, cancellationToken);
var h = new MyHandler1();
h.InnerHandler = this.InnerHandler;
return await h.WrapperSendAsync(request, cancellationToken);
// When MyHandler1 and MyHandler2 is no good, I just want
// to do nothing and let the other handlers do their job
// return await base.SendAsync(request, cancellationToken);
}
}
It does work but I'm not sure if I'm breaking something by doing this. Am I overlooking something by taking this approach?
Your approach looks good. I'm pretty sure it should work just fine.