With
HttpContext.Current.GetOwinContext()
I can recieve the current OwinContext in web applications.
With OwinContext.Set<T> and OwinContext.Get<T> I store values which should be present for a whole request.
Now I've a component which should be used inside web and console owin applications. In this component I currently don't have access to http context.
In the application I'm using threading and async features.
I also tried using the CallContext but this seems to loose data in some scenarios.
How could I access the current OwinContext? Or is there an other context where I may play my values?
I do the below with a WebApi AuthorizationFilter, also you should also be able to do this on an MVC controller and WebApi controller context if you have middleware to support it for example app.UseWebApi(app) for WebApi.
The component must support the Owin pipeline, otherwise not sure how you will get the context from for the correct thread.
So maybe you can create your own custom
OwinMiddleware
to wireup this component using the app.Use() in your Owin startup.
More Info here
My Properties Middleware
public class PropertiesMiddleware : OwinMiddleware
{
Dictionary<string, object> _properties = null;
public PropertiesMiddleware(OwinMiddleware next, Dictionary<string, object> properties)
: base(next)
{
_properties = properties;
}
public async override Task Invoke(IOwinContext context)
{
if (_properties != null)
{
foreach (var prop in _properties)
if (context.Get<object>(prop.Key) == null)
{
context.Set<object>(prop.Key, prop.Value);
}
}
await Next.Invoke(context);
}
}
Owin StartUp configuration
public void Configuration(IAppBuilder app)
{
var properties = new Dictionary<string, object>();
properties.Add("AppName", AppName);
//pass any properties through the Owin context Environment
app.Use(typeof(PropertiesMiddleware), new object[] { properties });
}
WebApi Filter
public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext context, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
var owinContext = context.Request.GetOwinContext();
var owinEnvVars = owinContext.Environment;
var appName = owinEnvVars["AppName"];
}
Happy coding!
Related
I need to get all the attribute route collections. to validate against my list of scopes configured in appsettigs whether the user has got the access.
I am trying to include the validation as part of the Authentication.
[HttpGet("test/policymethod")]
public IActionResult PolicyMethod()
{
return Ok();
}
[HttpGet("test/check")]
public IActionResult CheckWithAuthentication()
{
var services = HttpContext.RequestServices.GetAllService<IAuthenticationService>();
return Ok();
}
How would I get above Route details?. I know we can do it using "AuthorizationHandler".However, in my case I need a different approach.
Any other option to retrieve all the Route values in asp core web api 2.0?
This is something I achieved using AuthorizationHandler and action names.I need
route collection or action names without using the AuthorizationHandler.
I am trying to include the validation as part of the Authentication. Please suggest a workaround.
public class ScopeAuthorization : IAuthorizationRequirement
{
public IEnumerable<string> Scopes { get; }
public ScopeAuthorization(IEnumerable<string> scopes)
{
Scopes = scopes ?? throw new ArgumentNullException(nameof(scopes));
}
}
public class ScopeAuthorizationHandler : AuthorizationHandler<ScopeAuthorization>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ScopeAuthorization requirement)
{
var resContext = context.Resource as AuthorizationFilterContext;
if (resContext?.ActionDescriptor is ControllerActionDescriptor descriptor)
{
if (requirement.Scopes.Contains(descriptor.ActionName))
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
}
I have a self hosted Owin application that uses Nancy. In one of the NancyModules I need to get an instance of IOwinContext.
This question touches on the subject, but there's no solution in it: Get current owin context in self host mode
It says that for Nancy, you have to use NancyContext to get to the Items dictionary and look for the value corresponding to the key "OWIN_REQUEST_ENVIRONMENT".
I do have access to the NancyContext and I can see the Items dictionary and that it contains a key called "OWIN_REQUEST_ENVIRONMENT". (I could also call the NancyContext.GetOwinEnvironment() extension, which gives the same result
However, when I get that key it doesn't contain an actual IOwinContext.
It contains a lot of keys with information about Owin (some of the keys are owin.RequestPath, owin.RequestMethod, owin.CallCancelled, and more), but not an actual context object. And it is only really a dictionary with various keys, so I can't cast it to an IOwinContext either.
How can I get from a NancyContext to an IOwinContext object?
public class MyStartup
{
public void Start()
{
var options = new StartOptions()
options.Urls.Add(new Uri("http://*:8084"));
options.AppStartup(this.GetType().AssemblyQualifiedName;
var host = WebApp.Start(options, Configuration);
}
public void Configuration(IAppBuilder app)
{
app.UseNancy();
}
}
public class MyModule : NancyModule
{
Get["/", true] = async(x, ct) =>
{
var owinEnvironment = Context.GetOwinEnvironment();
// Now what?
}
}
var owinContext = new OwinContext(Context.GetOwinEnvironment());
example:
public class SecurityApi : NancyModule
{
public SecurityApi()
{
Post["api/admin/register", true] = async (_, ct) =>
{
var body = this.Bind<RegisterUserBody>();
var owinContext = new OwinContext(Context.GetOwinEnvironment());
var userManager = owinContext.GetUserManager<ApplicationUserManager>();
var user = new User {Id = Guid.NewGuid().ToString(), UserName = body.UserName, Email = body.Email};
var result = await userManager.CreateAsync(user, body.Password);
if (!result.Succeeded)
{
return this.BadRequest(string.Join(Environment.NewLine, result.Errors));
}
return HttpStatusCode.OK;
};
}
}
Actually, question that you mentioned has some tips that you probably missed.
For Nancy, you have to use NancyContext to get to the Items dictionary
and look for the value corresponding to the key
"OWIN_REQUEST_ENVIRONMENT". For SignalR, Environment property of
IRequest gives you access to OWIN environment. Once you have the OWIN
environment, you can create a new OwinContext using the environment.
So, once you called var owinEnvironment = Context.GetOwinEnvironment() and got the dictionary then you can create OwinContext (which is just wrapper for these dictionary values)
It has a constructor OwinContext(IDictionary<String, Object>) which, i guess, is what you need.
Also, you can get OwinContext from HttpContext:
// get owin context
var owinContext = HttpContext.Current.GetOwinContext();
// get user manager
var userManager = owinContext.GetUserManager<YourUserManager>();
I ended up solving this by creating new Owin middleware. In the middleware you have access to the current Owin context, which gives you access to the Owin environment.
When you have access to the Owin environment it's simply a case of adding the Owin context to the environment. When the context is in the environment you can retrieve it in the NancyModule.
After retrieving it like this I also had access to the GetUserManager() method on the context so that I could get my AspNetIdentity manager (as I mentioned in a comment to another answer). Just remember that the middleware must be added before Nancy to the Owin pipeline.
Startup
public class Startup
{
public void Start()
{
var options = new StartOptions()
options.Urls.Add(new Uri("http://*:8084"));
options.AppStartup(this.GetType().AssemblyQualifiedName;
var host = WebApp.Start(options, Configuration);
}
public void Configuration(IAppBuilder app)
{
app.Use(typeof(OwinContextMiddleware));
app.UseNancy();
}
}
Middleware
public class OwinContextMiddleware : OwinMiddleware
{
public OwinContextMiddleware(OwinMiddleware next)
: base(next)
{
}
public async override Task Invoke(IOwinContext context)
{
context.Environment.Add("Context", context);
await Next.Invoke(context);
}
}
NancyModule
public class MyModule : NancyModule
{
public MyModule()
{
Get["/", true] = async(x, ct) =>
{
IDictionary<string, object> environment = Context.GetOwinEnvironment();
IOwinContext context = (IOwinContext)environment["Context"]; // The same "Context" as added in the Middleware
}
}
Caveat
The middleware listed above is untested as the middleware I have is more complex and I haven't had the time to create a working example. I found a simple overview on how to create Owin middleware on this page.
I am trying to add logging to my app using Web Api 2 and Owin, so I started using Microsoft Owin Logging, which requires an ILogger and ILoggerFactory, that has been implemented and it works great when I need to log anything inside the STARTUP method or any of the Owin Middleware components.
For example, when I am in the Startup method I can create the logger using:
public void Configuration(IAppBuilder app)
{
// Creates configuration
var configuration = new HttpConfiguration();
// Configure WebApi Settings
WebApiConfig.Register(configuration);
app.SetLoggerFactory(new OwinLog4NetLoggerFactory("Default"));
var logger = app.CreateLogger<Startup>();
logger.WriteInformation("test log");
// Enabled WebApi in OWIN
app.UseWebApi(configuration);
}
Where "OwinLog4NetLoggerFactory" is my custom ILoggerFactory implementation.
So far, so good... but... How can I create the logger when I am in the actual web api action method?... I tried accessing the Request.GetOwinEnvironment() and the logger factory is not in the dictionary.
For example:
public class AccountController : ApiController
{
public int Get(int id)
{
// Create logger here
return id + 1;
}
}
I know I can create a static class with a reference to the Logger Factory or even Injection to add the logger to the api controller, but that seems too complicated for something that should be already there.
Any ideas would be appreciated.
I'd recommend writing your middleware so that you can handle the logging outside of the controller:
public class LoggingMiddleware : OwinMiddleware
{
public LoggingMiddleware(OwinMiddleware next)
: base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
//handle request logging
await Next.Invoke(context);
//handle response logging
}
}
Then in Startup class:
public class Startup
{
// ReSharper disable once UnusedMember.Global
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
appBuilder.Use<LoggingMiddleware>();
appBuilder.UseWebApi(config);
}
}
The request would then come in, hit the request logging code in the LoggingMiddleware, hit the controller code and then response would be logged on the LoggingMiddleware on the way back.
However, if all you are wanting to do is send an object through from middleware to the controller you can use context.Set("loggingObject", loggingObject); in the middleware and then
var loggingObject = Request.GetOwinContext().Get<LoggerClass>("loggingObject"); in the controller.
instead of adding logging code in every method, I create a MessageLoggingHandler that can be registered in Global.asax.cs once, and it then logs every Request and Response.
Here is the code that I use, you can modify as per your requirements:
First Create a MessageHandler class that inherits from DelegationHandler:
public abstract class MessageHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var corrId = Guid.NewGuid();
var requestMethod = request.Method.Method.ToString();
var requestUri = request.RequestUri.ToString();
var ipAddress = request.GetOwinContext().Request.RemoteIpAddress;
var requestMessage = await request.Content.ReadAsByteArrayAsync();
await LogMessageAsync(corrId, requestUri, ipAddress, "Request", requestMethod, request.Headers.ToString(), requestMessage, string.Empty);
var response = await base.SendAsync(request, cancellationToken);
var responseMessage = await response.Content.ReadAsByteArrayAsync();
await LogMessageAsync(corrId, requestUri, ipAddress, "Response", requestMethod, response.Headers.ToString(), responseMessage, ((int)response.StatusCode).ToString() + "-" + response.ReasonPhrase);
return response;
}
protected abstract Task LogMessageAsync(Guid CorrelationId, string APIUrl, string ClientIPAddress, string RequestResponse, string HttpMethod, string HttpHeaders, byte[] HttpMessage, string HttpStatusCode);
}
public class MessageLoggingHandler : MessageHandler
{
protected override async Task LogMessageAsync(Guid CorrelationId, string APIUrl, string ClientIPAddress, string RequestResponse, string HttpMethod, string HttpHeaders, byte[] HttpMessage, string HttpStatusCode)
{
// Create logger here
//Do your logging here
}
}
Then in your Global.asax.cs, you need to register the above created MessageLoggingHandler:
GlobalConfiguration.Configuration.MessageHandlers.Add(new MessageLoggingHandler());
Just be aware, this will log every request and response, will full message body. This can take a lot of space very quickly (depending on your API's usage). So you may need to tweak this (for example - keep records for a month or so, or ignore 200-OK responses etc)
I would recommend using the Common.Logging library in your applications, available on NuGet. Common.Logging gives you a common interface for using your preferred logging solution. It solves a lot of issues like yours. Here is an example using Common.Logging with NLog:
In your controller, you would access it like so:
public class MyController : ApiController
{
private static readonly ILog Log = LogManager.GetLogger<MyController>();
public async Task<IHttpActionResult> Get([FromUri] int id)
{
Log.Debug("Called Get with id " + id.ToString());
return Ok();
}
}
Pick up the latest Common.Logging.NLog package on NuGet (as of this writing, it should be Common.Logging.NLog41). Then in your web.config, you would configure Common.Logging to use your NLog configuration:
<common>
<logging>
<factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog41">
<arg key="configType" value="FILE" />
<arg key="configFile" value="~/NLog.config" />
</factoryAdapter>
</logging>
</common>
Here are some additional links:
https://github.com/net-commons/common-logging
https://cmatskas.com/an-introduction-to-common-logging-api-2/
Based on this article I'm trying to create an IActionFilter implementation for ASP.NET Core that can process attributes that are marked on the controller and the controller's action. Although reading the controller's attributes is easy, I'm unable to find a way to read the attributes defined on the action method.
Here's the code I have right now:
public sealed class ActionFilterDispatcher : IActionFilter
{
private readonly Func<Type, IEnumerable> container;
public ActionFilterDispatcher(Func<Type, IEnumerable> container)
{
this.container = container;
}
public void OnActionExecuting(ActionExecutingContext context)
{
var attributes = context.Controller.GetType().GetCustomAttributes(true);
attributes = attributes.Append(/* how to read attributes from action method? */);
foreach (var attribute in attributes)
{
Type filterType = typeof(IActionFilter<>).MakeGenericType(attribute.GetType());
IEnumerable filters = this.container.Invoke(filterType);
foreach (dynamic actionFilter in filters)
{
actionFilter.OnActionExecuting((dynamic)attribute, context);
}
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
throw new NotImplementedException();
}
}
My question is: how do I read the action method's attributes in ASP.NET Core MVC?
You can access the MethodInfo of the action through the ControllerActionDescriptor class:
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);
}
}
The MVC 5 ActionDescriptor class used to implement the ICustomAttributeProvider interface which gave access to the attributes. For some reason this was removed in the ASP.NET Core MVC ActionDescriptor class.
Invoking GetCustomAttributes on a method and/or class is slow(er). You should not invoke GetCustomAttributes every request since .net core 2.2, which #Henk Mollema is suggesting. (There is one exception which I will explain later)
Instead, on application startup time, the asp.net core framework will invoke GetCustomAttributes on the action method and controller for you and store the result in the EndPoint metadata.
You can then access this metadata in your asp.net core filters via the EndpointMetadata property of the ActionDescriptor class.
public class CustomFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// Get attributes on the executing action method and it's defining controller class
var attributes = context.ActionDescriptor.EndpointMetadata.OfType<MyCustomAttribute>();
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
If you do not have access to the ActionDescriptor (for example: because you are operating from a Middleware instead of an filter) from asp.net core 3.0 you can use the GetEndpoint extension method to access it's Metadata.
For more info see this github issue.
public class CustomMiddleware
{
private readonly RequestDelegate next;
public CustomMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
// Get the enpoint which is executing (asp.net core 3.0 only)
var executingEnpoint = context.GetEndpoint();
// Get attributes on the executing action method and it's defining controller class
var attributes = executingEnpoint.Metadata.OfType<MyCustomAttribute>();
await next(context);
// Get the enpoint which was executed (asp.net core 2.2 possible after call to await next(context))
var executingEnpoint2 = context.GetEndpoint();
// Get attributes on the executing action method and it's defining controller class
var attributes2 = executingEnpoint.Metadata.OfType<MyCustomAttribute>();
}
}
Like stated above, Endpoint Metadata contains the attributes for the action method and its defining controller class. This means that if you would want to explicitly IGNORE the attributes applied on either the controller class or the action method, you have to use GetCustomAttributes. This is almost never the case in asp.net core.
My custom attribute is inherit from ActionFilterAttribute. I put it on my controller but there is one action do not need it. I want to use AllowAnonymous attribute to ignore that but it not work. So I add this snippet in my custom attribute to find the AllowAnonymous and skip it. You can get other in the for loop.
public class PermissionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
foreach (var filterDescriptors in context.ActionDescriptor.FilterDescriptors)
{
if (filterDescriptors.Filter.GetType() == typeof(AllowAnonymousFilter))
{
return;
}
}
}
}
I created an extension method that mimics the original GetCustomAttributes based in Henk Mollema's solution.
public static IEnumerable<T> GetCustomAttributes<T>(this Microsoft.AspNet.Mvc.Abstractions.ActionDescriptor actionDescriptor) where T : Attribute
{
var controllerActionDescriptor = actionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
return controllerActionDescriptor.MethodInfo.GetCustomAttributes<T>();
}
return Enumerable.Empty<T>();
}
Hope it helps.
As answered by Henk Mollena
public void OnActionExecuting(ActionExecutingContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
var controllerAttributes = controllerActionDescriptor
.MethodInfo
.GetCustomAttributes(inherit: true);
}
}
is the correct way if you want to check the presence of an attribute applied to an action.
I just want to add to his answer in case if you want to check the presence of an attribute applied to the controller
public void OnActionExecuting(ActionExecutingContext context)
{
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor != null)
{
var actionAttributes = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(inherit: true);
}
}
Also you can use the overloaded function of the GetCustomAttributes functions to get your specific attribute(s)
var specificAttribute = GetCustomAttributes(typeof(YourSpecificAttribute), true).FirstOrDefault()
According to this post, it should be possible to inject per-web-request dependencies into SignalR hubs (although with some limitations like problem with OnDisconnected() method). In my case it is ASP Web API (not MVC) and it does not work for some reason.
Here are relevant parts:
container.RegisterWebApiControllers(httpConfiguration);
container.RegisterWebApiRequest<DbContext, MyDbContext>();
container.RegisterWebApiRequest<ISampleRepository, SampleRepository>(); //DbContext injected to SampleRepository
//Enable injections to SignalR Hubs
var activator = new SimpleInjectorHubActivator(container);
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => activator);
This class makes possible to inject into hubs:
public class SimpleInjectorHubActivator : IHubActivator
{
private readonly Container _container;
public SimpleInjectorHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return (IHub)_container.GetInstance(descriptor.HubType);
}
}
And Hub itself:
[HubName("sample")]
public class SampleHub : Hub
{
public ActiveBetsHub(ISampleRepository repository)
{
}
//Irrelevant methods here. OnDisconnected() NOT implemented!
}
With this setup I get exception:
No registration for type SampleHub could be found and
an implicit registration could not be made.
The ISampleRepository is registered as 'Web API Request'
lifestyle, but the instance is requested outside the context of a Web API Request.
Which is expected as I understand. However I get exactly same exception when I change Lifestyle of repository to Transient:
var transientHybrid = Lifestyle.CreateHybrid(() => HttpContext.Current != null, new WebApiRequestLifestyle(), Lifestyle.Transient);
container.Register<ISampleRepository, SampleRepository>(transientHybrid);
I suspect the problem could lie in HttpContext.Current != null check that is not working for Web API the same way as for MVC.
SignalR 2.2
Simple Injector 2.8.3
What do I miss?
UPDATE:
This is stack trace on how SignalR creates Hubs:
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.Container.GetInstance(Type serviceType)
at MyWebAbi.WebApiApplication.SimpleInjectorHubActivator.Create(HubDescriptor descriptor) in Global.asax.cs:line 108
at Microsoft.AspNet.SignalR.Hubs.DefaultHubManager.ResolveHub(String hubName)
at Microsoft.AspNet.SignalR.Hubs.HubDispatcher.CreateHub(IRequest request, HubDescriptor descriptor, String connectionId, StateChangeTracker tracker, Boolean throwIfFailedToCreate)
So the proper solution would be to use ExecutionContextScope for a Hubs but this scope needs to be explicitly closed which makes things more complicated...
Your definition of your hybrid lifestyle is incorrect. The WebApiRequestLifestyle does not depend in any way on the HttpContext so checking whether HttpContext.Current != null will not work. You will have to check if there is an active Web API request lifestyle scope (or execution context scope, which is basically the same) by calling container.GetCurrentExecutionContextScope():
var transientHybrid = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new WebApiRequestLifestyle(),
Lifestyle.Transient);
Do note however that you should be very careful composing a hybrid lifestyle of a scoped lifestyle and transient, because this will easily yield in wrong results. This is actually the default behavior of some DI libraries, but this is a design flaw IMO. I assume you very consciously registered your MyDbContext with the scoped lifestyle, because you need to make sure that the same instance is used throughout the request. Using the Transient lifestyle means that you might get multiple MyDbContext during the request. This might not be a problem, because in your hubs you might currently only have one reference to your MyDbContext, but your code might break once your object graph changes and a second reference to MyDbContext is added.
So instead, I would advice not using this combination of lifestyles. Instead, just use either the WebApiRequestLifestyle or the ExecutionContextScopeLifestyle (they are the same) and make sure that such a execution context scope is started before your hub is resolved.
And by the way, don't forget to register your hubs explicitly in Simple Injector. This allows Simple Injector to analyze the complete object graph for you including your hub classes.
Recently I faced the same problem and found the following working quite well, hope this will help someone:
public class SignalRDependencyResolver : DefaultDependencyResolver
{
public SignalRDependencyResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public override object GetService(Type serviceType)
{
return _serviceProvider.GetService(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
var #this = (IEnumerable<object>) _serviceProvider.GetService(typeof (IEnumerable<>).MakeGenericType(serviceType));
var #base = base.GetServices(serviceType);
return #this == null ? #base : #base == null ? #this : #this.Concat(#base);
}
private readonly IServiceProvider _serviceProvider;
}
public class SignalRHubDispatcher : HubDispatcher
{
public SignalRHubDispatcher(Container container, HubConfiguration configuration) : base(configuration)
{
_container = container;
}
protected override Task OnConnected(IRequest request, string connectionId)
{
return Invoke(() => base.OnConnected(request, connectionId));
}
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Invoke(() => base.OnReceived(request, connectionId, data));
}
protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
{
return Invoke(() => base.OnDisconnected(request, connectionId, stopCalled));
}
protected override Task OnReconnected(IRequest request, string connectionId)
{
return Invoke(() => base.OnReconnected(request, connectionId));
}
private async Task Invoke(Func<Task> method)
{
using (_container.BeginExecutionContextScope())
await method();
}
private readonly Container _container;
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.Register<DbContext, MyDbContext>(Lifestyle.Scoped);
container.Register<ISampleRepository, SampleRepository>(Lifestyle.Scoped);
// if you want to use the same container in WebApi don't forget to add
app.Use(async (context, next) => {
using (container.BeginExecutionContextScope())
await next();
});
// ... configure web api
var config = new HubConfiguration
{
Resolver = new SignalRDependencyResolver(container)
}
// ... configure the rest of SignalR
// pass SignalRHubDispatcher
app.MapSignalR<SignalRHubDispatcher>("/signalr", config);
}
}