Bot Framework sending OPTIONS message - botframework

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)

Related

Trying to use IPipelineBehavior with ASP.NET Core - get System.InvalidCastException

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.

Web Api and where should I contorol Request Header data

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);
}
}

Authorization Header in request is always null

I have created a Delegated Handler to do some token authentication.
public class SimpleWebTokenHandler: DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Headers.Authorization == null)
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
return await base.SendAsync(request, cancellationToken);
}
}
I am not even getting to the token validation part because the Autorization header is always null. However I can see it chrome developer tools it is being sent.
Turns out that the format of the Authorization header has to be something like
<Authorization> <Scheme> <token>="<tokenValue>"
I was missing the quotes.

Adding message handler on the fly

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.

Autofac and Web API self host

I get the error:
"The request lifetime scope cannot be created because the HttpContext
is not available."
if I try to setup my web api.
HttpContext is not available in System.Web.Http.SelfHost but is there an alternative?
Example with my AuthenticationHandler:
public class AuthenticationHandler : DelegatingHandler
{
private const string m_AuthenticationScheme = "Basic";
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
AuthenticationHeaderValue authenticationHeader = request.Headers.Authorization; //get the authorization header
if (authenticationHeader != null && authenticationHeader.Scheme == m_AuthenticationScheme)
{
Credentials credentials = authenticationHeader.ParseAuthenticationHeader();
if (credentials != null)
{
IMyClass procadCredentials = DependencyResolver.Current.GetService<IMyClass>(); //thows the InvalidOperationException if I use self-hosting
//tried: "Autofac.Integration.Mvc.AutofacDependencyResolver.Current.RequestLifetimeScope.Resolve<IMyClass>();" too.
I got the InvalidOperationException with the message:
The request lifetime scope cannot be created because the HttpContext
is not available.
IMyClass is registeres in global.asax like this:
m_builder.Register<IMyClass>((c, p) =>
{
//...
//return ...
}
While IIS-Hosting, it works fine, but using self-hosting, IoC with AutoFac fails.
You are using Autofac's MVC integration package with Web API, while you should really be using Autofac.WebApi http://nuget.org/packages/Autofac.WebApi
You can read more about it here - http://alexmg.com/post/2012/09/01/New-features-in-the-Autofac-MVC-4-and-Web-API-(Beta)-Integrations.aspx

Resources