How to create OWIN middleware per request - asp.net-mvc

I am implementing a custom owin middleware to add CSP header (content security policy) in response header. For CSP to work, the middleware needs to create a unique nonce value per request. So i have NonceService which creates nonce value. The custom OWIN middleware has dependency on NonceService.
However my problem is i'm not able to register custom middleware per request.
When i debug i noticed OWIN is NOT creating new instance of custom middleware per request and because of that same nonce value is being used for all the requests.
Below is my code
Nonce Service
public interface INonceService
{
string GetNonce();
}
public class NonceService : INonceService
{
private static readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
private readonly string _nonce;
public NonceService(int nonceByteAmount = 32)
{
var nonceBytes = new byte[nonceByteAmount];
_rng.GetBytes(nonceBytes);
_nonce = Convert.ToBase64String(nonceBytes);
}
public string GetNonce()
{
return _nonce;
}
}
OWIN Middleware & Extension
public class SecurityHeaderMiddleware : OwinMiddleware
{
private readonly INonceService _nonceService = null;
public SecurityHeaderMiddleware(OwinMiddleware next, INonceService nonceService) : base(next)
{
_nonceService = nonceService;
}
public override async Task Invoke(IOwinContext context)
{
await Next.Invoke(context);
var nonce = _nonceService.GetNonce();
var csp = BuildCSPHeader(nonce);
context.Response.Headers.Add(key, csp);
}
}
public static class OwinExtensions
{
private const string SecurityHeaderRegistrationKey = "SecurityHeaders";
public static IAppBuilder UseSecurityHeader(this IAppBuilder app, INonceService nonceService)
{
if (app == null)
throw new ArgumentNullException("app");
if (app.Properties.ContainsKey(SecurityHeaderRegistrationKey))
return app;
app.Use<SecurityHeaderMiddleware>(nonceService);
app.Properties.Add(SecurityHeaderRegistrationKey, true);
return app;
}
}
I am using Unity as conatiner, so i register INonceService using PerRequestLifetimeManager
container.RegisterType<INonceService, NonceService>(new PerRequestLifetimeManager(), new InjectionConstructor(32));
and i register my custom middleware with OWIN in startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var nonceService = ServiceLocator.Current.GetInstance<INonceService>();
app.UseSecurityHeader(nonceService);
}
}
Note
If creating per request OWIN middleware is not possible then at least how should i pass per request new instance of NonceService to middleware.

Looking at the stack trace upon a null reference exception for HttpContext that I received, it seems that middleware is constructed in BuildWebHost from Main.
I'm using Unity too, so I changed my constructor dependency from...
IUserRepository userRepository
to
Func<IUserRepository> userRepositoryFactory
and my method call from...
userRepository.FetchLoggedInUser(userIdentifier);
to
userRepositoryFactory().FetchLoggedInUser(userIdentifier);
Conveniently, Unity automatically generates a factory, so there's no need to edit the registrations.

Related

Configure/register depdency injection scoped service from within the scope

I have a stateless service in Azure Service Fabric, and I'm using Microsoft.Extensions.DependencyInjection, although the same issue exists for any other DI frameworks. In my Program.cs, I create a ServiceCollection, add all (but one) of my registrations, create the service provider, and pass it to my service's constructor. Any service method with external entry will create a new service scope and call the main business logic class. The issue is that one of the classes I want to have scoped lifetime needs a value that is an input parameter on the request itself. Here's a code snippet of what I would like to achieve.
internal sealed class MyService : StatelessService, IMyService
{
private IServiceProvider _serviceProvider;
private IServiceScopeFactory _scopeFactory;
public MyService(StatelessServiceContext context, IServiceProvider serviceProvider)
: base(context)
{
_serviceProvider = serviceProvider;
_scopeFactory = _serviceProvider.GetRequiredService<IServiceScopeFactory>();
}
public async Task<MyResponse> ProcessAsync(MyRequest request, string correlationId, CancellationToken cancellationToken)
{
using (var scope = _scopeFactory.CreateScope())
{
var requestContext = new RequestContext(correlationId);
//IServiceCollection serviceCollection = ??;
//serviceCollection.AddScoped<RequestContext>(di => requestContext);
var businessLogic = scope.ServiceProvider.GetRequiredService<BusinessLogic>();
return await businessLogic.ProcessAsync(request, cancellationToken);
}
}
}
The cancellation token is already passed around everywhere, including to classes that don't use it directly, just so it can be passed to dependencies that do use it, and I want to avoid doing the same with the request context.
The same issue exists in my MVC APIs. I can create middle-ware which will extract the correlation id from the HTTP headers, so the API controller doesn't need to deal with it like my service fabric service does. One way I can make it work is by giving RequestContext a default constructor, and have a mutable correlation id. However, it's absolutely critical that the correlation id doesn't get changed during a request, so I'd really like the safety of having get-only property on the context class.
My best idea at the moment is to have a scoped RequestContextFactory which has a SetCorrelationId method, and the RequestContext registration simply calls the factory to get an instance. The factory can throw an exception if a new instance is requested before the id is set, to ensure no id-less contexts are created, but it doesn't feel like a good solution.
How can I cleanly register read-only objects with a dependency injection framework, where the value depends on the incoming request?
I only had the idea for a RequestContextFactory as I was writing the original question, and I finally made time to test the idea out. It actually was less code than I expected, and worked well, so this will be my go-to solution now. But, the name factory is wrong. I'm not sure what to call it though.
First, define the context and factory classes. I even added some validation checks into the factory to ensure it worked the way I expect:
public class RequestContext
{
public RequestContext(string correlationId)
{
CorrelationId = correlationId;
}
public string CorrelationId { get; }
}
public class RequestContextFactory
{
private RequestContext _requestContext;
private bool _used = false;
public void SetContext(RequestContext requestContext)
{
if (_requestContext != null || requestContext == null)
{
throw new InvalidOperationException();
}
_requestContext = requestContext;
}
public RequestContext GetContext()
{
if (_used || _requestContext == null)
{
throw new InvalidOperationException();
}
_used = true;
return _requestContext;
}
}
Then, add registrations to your DI container:
services.AddScoped<RequestContextFactory>();
services.AddScoped<RequestContext>(di => di.GetRequiredService<RequestContextFactory>().GetContext());
Finally, the Service Fabric service method looks something like this
public async Task<MyResponse> ProcessAsync(MyRequest request, string correlationId, CancellationToken cancellationToken)
{
using (var scope = _scopeFactory.CreateScope())
{
var requestContext = new RequestContext(correlationId);
var requestContextFactory = scope.ServiceProvider.GetRequiredService<RequestContextFactory>();
requestContextFactory.SetContext(requestContext);
var businessLogic = scope.ServiceProvider.GetRequiredService<BusinessLogic>();
return await businessLogic.ProcessAsync(request, cancellationToken);
}
}
Kestrel middleware could look something like this
public async Task Invoke(HttpContext httpContext)
{
RequestContext requestContext = new RequestContext(Guid.NewGuid().ToString());
var factory = httpContext.RequestServices.GetRequiredService<RequestContextFactory>();
factory.SetContext(requestContext);
httpContext.Response.Headers["X-CorrelationId"] = requestContext.CorrelationId;
await _next(httpContext);
}
Then just do the normal thing and add a RequestContext parameter to the constructor of any class that needs to get the correlation id (or any other info you put in the request context)

Configure Unity container per-request in OWIN middleware

I'm wanting to configure registrations in a Unity container being used by ASP.NET Web API 2 based on properties of a HTTP request. For example, a request to /api/database1/values should result in a Unity container configuration with an IDbContext configured for database1, while a request to /api/database4/values will get an IDbContext configured for database4.
I've gotten so far as using UnityHierarchicalDependencyResolver as the dependency resolver, so types registered with HierarchicalLifetimeManager last only for the lifetime of the request. This works well for getting types resolved per request. But how to get them registered per request using OWIN middleware is beyond me.
In my middleware, a call to System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUnityContainer)) gets an instance of IUnityContainer, but it's the same container for all requests, including any registrations from previous requests.
By encapsulating UnityHierarchicalDependencyResolver with my own implementation of IDependencyResolver I can see that IDependencyResolver.BeginScope isn't called until much later in the process. So the problem would seem to be that the child container isn't created until Web API wakes up, long after my middleware calls Next(..).
Is there a way I can get the scope of my dependency resolver to start sooner? Is there some other strategy that I'm missing. In case it makes any difference, I'm hosting in IIS, but favouring the OWIN middleware approach.
Update
This isn't an answer, and it's too big for a comment, but after struggling to solve this with Unity I decided to switch to Autofac and it all just fell into place.
The Autofac OWIN packages (Autofac.Mvc5.Owin, Autofac.Owin, Autofac.WebApi2.Owin) make it dead easy to use Autofac within the OWIN pipeline and ensure appropriate lifetime management in ASP.NET MVC and Web API. This was the missing link.
I couldn't find a way to reconfigure the container per-request, but it did at least make it possible to configure a factory per-request (so yes, #Haukinger and #alltej, you were right to push in that direction.
So I register a factory like:
builder.RegisterType<DataDependencyFactory>().InstancePerRequest();
And register the create method of that factory like:
builder
.Register(c => c.Resolve<DataDependencyFactory>().CreateDataDependency())
.As<IDataDependency>()
.InstancePerRequest();
Registering the factory this way is particularly useful, because downstream dependents don't need to be aware of the factory. I like this because my dependents don't need a factory, they need an instance. The container bends to the needs of my dependents, not the other way around :)
Then, in a piece of OWIN middleware, I resolve the factory, and set a property on it according to the properties of the request. Subsequent resolution of IDataDependency in an MVC or Web API controller, or anything else later in the OWIN pipeline, will get an instance configured according to the property on the factory.
Based on your api URL ("/api/database4/values"), I suggest that you create a filter attribute(e.g. DbIdFilter) so that you can reuse the filter attribute to other controller methods that follow similar url path/segment like this below:
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/values")]
public IHttpActionResult GetValues()
{
return Ok();
}
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/products")]
public IHttpActionResult GetProducts()
{
return Ok();
}
First, create the filter attribute:
public class DbIdFilterAttribute : ActionFilterAttribute
{
private readonly string _routeDataId;
private const string defaultRouteName = "databaseId";
public DbIdFilterAttribute():this(defaultRouteName)
{}
public DbIdFilterAttribute(string routeDataId)
{
_routeDataId = routeDataId;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var routeData = actionContext.Request.GetRouteData();
var dbId = routeData.Values[_routeDataId] as string;
//here we create the db instance at the filter level.
DbInstanceFactory.RegisterDbInstance(dbId);
}
}
Next, create an instance factory that will register/resolve the db instance during runtime:
public class DbInstanceFactory : IDbInstanceFactory
{
public static IDbInstance RegisterDbInstance(string databaseId)
{
var factory = UnityConfig.GetConfiguredContainer().Resolve<IDbInstanceFactory>();
return factory.CreateInstance(databaseId);
}
public IDbInstance CreateInstance(string databaseId)
{
var container = UnityConfig.GetConfiguredContainer();
//container.RegisterType<IDbInstance, DbInstance>();
container.RegisterType<IDbInstance, DbInstance>(new InjectionConstructor(databaseId));
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
public IDbInstance GetInstance()
{
var container = UnityConfig.GetConfiguredContainer();
var dbInstance = container.Resolve<IDbInstance>();
return dbInstance;
}
}
public interface IDbInstanceFactory
{
IDbInstance CreateInstance(string databaseId);
IDbInstance GetInstance();
}
Register this factory class in UnityConfig.cs (or wherever you currently register the types):
container.RegisterType<IDbInstanceFactory, DbInstanceFactory>
(new ContainerControlledLifetimeManager());
It's registered ContainerControlledLifetimeManager since this factory does not have to be a per request.
So just a basic DbInstance class below(for clarity) that takes a parameter in the constructor (this parameter can be your connection string or a named connection):
public class DbInstance : IDbInstance
{
public string DbId { get; }
public DbInstance(string databaseId)
{
DbId = databaseId;
}
}
public interface IDbInstance
{
string DbId { get; }
}
In controller class, you can use it like this:
....
private IDbInstanceFactory _dbFactory;
public MyController(IDbInstanceFactory dbFactory)
{
_dbFactory = dbFactory;
}
// Alternate, if you want to use property injection instead of constructor injection
//[Dependency]
//public IDbInstanceFactory DbFactory { get; set; }
[HttpGet]
[DbIdFilter]
[Route("{databaseId}/test")]
public IHttpActionResult Test()
{
var db = _dbFactory.GetInstance();
return Ok(db.DbId);
}
...

LightInject - No scope when calling WebApi OWIN Identity TokenEndpointPath

I have a very basic WebAPI setup with token authentication.
In the application start I do:
protected void Application_Start()
{
DependencyConfig.RegisterDependecis();
//...
//...
}
Which calls:
public class DependencyConfig
{
private static ServiceContainer _LightInjectContainer;
public static ServiceContainer LightInjectContainer
{
get { return _LightInjectContainer; }
}
public static void RegisterDependecis()
{
var container = new LightInject.ServiceContainer();
container.RegisterApiControllers();
container.ScopeManagerProvider = new PerLogicalCallContextScopeManagerProvider();
container.EnableWebApi(GlobalConfiguration.Configuration);
container.Register<IRegistrationManager, RegistrationManager>(new PerScopeLifetime());
_LightInjectContainer = container;
}
}
Now, when the client invokes the token endpoint (requests a token), the provider I defined here:
OAuthOptions = new OAuthAuthorizationServerOptions
{
//...
//...
Provider = new SimpleAuthorizationServerProvider()
//...
//...
};
Is being used with this method:
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
//...
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
//...
// Here I get the exception!
var registrationManager = DependencyConfig.LightInjectContainer.GetInstance<IRegistrationManager>();
//...
}
//...
}
And when I try to get the instance the following error:
Attempt to create a scoped instance without a current scope.
I know the LightInject has a concept of Start/End scope for each request and It's actually telling me that no scope was started. But I can't seem to figure what exactly is broken and needs to be fixed.
By reading on of the last answers in this question, I came up with this solution: (Starting a scope manually)
using(DependencyConfig.LightInjectContainer.BeginScope())
{
IRegistrationManager manager = DependencyConfig.LightInjectContainer.GetInstance<IRegistrationManager>();
}
Technicaly it works, but I not sure if it's the right solution regarding whats happening behind the scenes.
I am the author of LightInject
Can you try this inside your handler(SimpleAuthorizationServerProvider)
request.GetDependencyScope().GetService(typeof(IRegistrationManager)) as IRegistrationManager;
There is actually no reason that you should expose the container as a static public member as this makes it very easy to start using the service locator anti-pattern.
Take a look at this blog post for more information.
http://www.strathweb.com/2012/11/asp-net-web-api-and-dependencies-in-request-scope/

Autofac register generic with multiple paramters?

Here are the classes and interfaces I'm dealing with.
public interface IAccountService
{
//omitted for brevity...
}
public abstract class UserClientBase<T> : ClientBase<T> where T : class
{
protected UserClientBase(Binding binding, EndpointAddress remoteAddress, string userName, string password)
: base(binding, remoteAddress)
{
if (ClientCredentials == null) return;
ClientCredentials.UserName.UserName = userName;
ClientCredentials.UserName.Password = password;
}
}
public class AccountProxy : UserClientBase<IAccountService>, IAccountService
{
private static readonly WSHttpBinding Binding = WcfHelpers.ConfigureWsHttpBinding();
private static readonly EndpointAddress EndpointAddress =
new EndpointAddress(#"https://server.project.local/Project/Account/AccountService.svc");
public AccountProxy(string userName, string password)
: base(Binding, EndpointAddress, userName, password)
{
}
//omitted for brevity
}
public interface ISafeClient<out TService> : IDisposable where TService : class
{
//omitted for brevity...
}
public class SafeClient<TClient, TService> : ISafeClient<TService>
where TClient : UserClientBase<TService>, TService
where TService : class
{
//omitted for brevity...
}
public AccountController(ISafeClient<IAccountService> accountProxy)
{
_accountProxy = accountProxy;
}
I'm using Asp.net MVC 5 with Autofac integration, here are the registrations in my Global.asax Application_Start method.
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<AccountProxy>().As<IAccountService>().InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(SafeClient<,>)).As(typeof(ISafeClient<>)).InstancePerLifetimeScope();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
Now when I try to browse to a page handled by the AccountController, I get the following exception in the URL.
None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'MyMvcApp.Controllers.AccountController' can be invoked with the
available services and parameters: Cannot resolve parameter
'Project.Client.Proxies.ISafeClient`1[Project.Client.Contracts.Service.IAccountService]
accountProxy' of constructor 'Void
I'm not sure what I'm missing here. When I look in the container's ComponentRegistry at runtime I see the Controllers and the AccountProxy. Thanks in advance.
Update:
I can inject an IAccountService successfully if I register it like this instead:
builder.Register(a => new AccountProxy("userName", "password")).As<IAccountService>();
However when I try to inject the ISafeClient I still get an exception. I think I have a larger problem here. Essentially, I'm trying to wrap a ClientBase to include safe disposing and retry logic. It handles communication and message exceptions, faulted channel states, etc. Every time I execute a method on my SafeClient, the ClientBase is re-instantiated, then automatically disposed of. If this is the case, should I even be injecting it? Ugghh.. I'm confused.
Update 2:
Looks like I can just register like this.
builder.RegisterType<SafeClient<AccountProxy, IAccountService>>().As<ISafeClient<IAccountService>>().InstancePerLifetimeScope();
Then my AccountController changes to this:
private readonly ISafeClient<IAccountService> _accountProxy;
public AccountController(ISafeClient<IAccountService> accountProxy)
{
_accountProxy = accountProxy;
}
Is there any downside to doing it this way, other than the obvious which is having to register teach safe client individually?

Response is not available in this context when creation cookie's

hi i defined one class to create cookie by received parameter's from user. when i want to add cookie to context i receive an exception.
My Class
public static class ManageCookies
{
public static void Create(string name, string value)
{
HttpCookie cookie = new HttpCookie(name);
cookie.Value = value;
cookie.Expires = DateTime.Now.AddYears(1);
HttpContext.Current.Response.Cookies.Add(cookie);
}
}
Occured Exception: Response is not available in this context.
i know it is connected with the context within the current sub is executing.
i whould suggest my function to pass the current HttpResponse as a parametter to that!
public static class ManageCookies
{
public static void Create(string name, string value, HttpResponse response)
{
HttpCookie cookie = new HttpCookie(name);
cookie.Value = value;
cookie.Expires = DateTime.Now.AddYears(1);
response.Cookies.Add(cookie);
}
public static void PrePareForApplicationStart()
{
Create("somecookie", "somevalue", _context);
}
}
this is correct way? why? and are you have another way?
UPDATE: Oppps! using this way still have First Exception! :(( Help Help
ManageCookies manager = new ManageCookies(this.Context);
manager.PrePareForApplicationStart();
i use above code to send HTTPContext object to defined class. it called from Application_Start event.
and ManageCookies class updated as below:
public class ManageCookies
{
private HttpContext _context;
public ManageCookies(HttpContext context)
{
this._context = context;
}
}
i use this variable (_context) to adding cookies!
The code you provided is not a problem the problem is where you call it from. If you call it after the response is flushed or from a thread other than the one assigned to process your request - you can get all sorts of problems
In response to Sadegh clarification:
This is exactly the point. Application Start happens only once during application lifetime. And I guess you want this cookie to be delivered as a part of every response. In other words on ApplicationStart is not the right place to do it. You can do it at any moment during page lifecycle BEFORE the end of the PreRender

Resources