How to inject a service dependent on IOwinContext into custom OAuthAuthorizationServerProvider - c#

Having an issue injecting IOwinContext into my OAuthAuthorizationServerProvider.
Inside my Startup.cs i have the line:
public static IContainer ConfigureContainer(Type mvcApplication, HttpConfiguration configuration = null)
{
var builder = new ContainerBuilder();
//other stuff
builder
.Register(ctx=>HttpContext.Current.GetOwinContext())
.As<IOwinContext>();
//other stuff
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(configuration);
app.UseWebApi(configuration);
}
In my provider I do:
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider{
public ApplicationOAuthProvider(IComponentContext context)
{
_ccontext = context;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var logger = _ccontext.Resolve<EventLoggerService>();
}
}
The line above crashes because I have an injectable that needs IOwinContext. The error is:
: Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Assistant.Framework.Services.CurrentUserService' can be invoked with the available services and parameters:
Cannot resolve parameter 'Microsoft.Owin.IOwinContext context' of constructor 'Void .ctor(Microsoft.Owin.IOwinContext)'.

Short version
You don't need to register IOwinContext in the container yourself if you use Autofac and Web API integration using OWIN.
The integration package Autofac.WebApi2.Owin does it for you. All you have to do is inject IOwinContext wherever you want it to be injected and it will work out of the box, as you can see on this repo on GitHub
Longer version, a.k.a. "how does this happen?"
The reason is that when using the OWIN integration package for Autofac, the IOwinContext is automatically registered in every per-request lifetime scope. The magic happens when you call app.UseAutofac(container) in this file, and here's an excerpt of the code:
private static IAppBuilder RegisterAutofacLifetimeScopeInjector(this IAppBuilder app, ILifetimeScope container)
{
app.Use(async (context, next) =>
{
using (var lifetimeScope = container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag,
b => b.RegisterInstance(context).As<IOwinContext>()))
{
context.Set(Constants.OwinLifetimeScopeKey, lifetimeScope);
await next();
}
});
app.Properties[InjectorRegisteredKey] = true;
return app;
}
An anonymous middleware is registered in the OWIN pipeline, which does 3 things:
Creates a new lifetime scope for the current HTTP request
Registers the current IOwinContext in that new lifetime scope
Stores the current lifetime scope in the IOwinContext
All this means that the lifetime scope that resolves your services in your Web API application already knows how to inject IOwinService, so no additional work is required on your side.

Related

How to inject ClaimsPrincipal in Nancy

I have a Nancy module and a decorator class that needs to know the ClaimsPrincipal in order to retrieve the user's email address. So I have declared a constructor as
public EmailDecorator(IDbConnectionFactory connectionFactory,
IPrincipal principal,
IEmailClient emailClient) : base(connectionFactory)
What I'm struggling to figure out is how to inject the principal into the constructor. I'm using Simple Injector for DI and it has been very effective. But if I override the ConfigureRequestContainer() method, which has as a parameter for the NancyContext, to instantiate IPrincipal I get an exception
protected override void ConfigureRequestContainer(
TinyIoCContainer container, NancyContext context)
{
container.Register<IPrincipal>((c, o) => context.CurrentUser);
base.ConfigureRequestContainer(container, context);
}
The exception indicates Simple Injector doesn't know about IPrincipal which is registered in the default TinyIOC container.
The configuration is invalid. Creating the instance for type InvoiceModule failed. The constructor of type EmailDecorator contains the parameter with name 'principal' and type IPrincipal that is not registered. Please ensure IPrincipal is registered, or change the constructor of EmailDecorator.
Edit
I've spent way too long trying to resolve this and I suspect the answer is to stop trying to do it this way. In my original example, I'm trying to inject IPrincipal into the decorator constructor which is incorrect. Instead I need to inject some form of service that allows me to derive IPrincipal when one of the methods in the decorator is called, e.g. Func<IPrincipal>. Nancy provides an override-able method ConfigureRequestContainer() that is called for each request, so could potentially be used:
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
container.Register<Func<IPrincipal>>((c, o) =>
{
return () => context.CurrentUser;
});
}
Except that the request container is a TinyIoCContainer and I'm using SimpleInjector. So, maybe I can add a SimpleInjector registration that offloads resolution to the request container?
_container.RegisterSingleton<Func<IPrincipal>>(() => nancy.Resolve<Func<IPrincipal>>());
Actually no, nancy is not the same container as the request container. So maybe somewhere there is a container that can successfully resolve IPrincipal but I do not know how to access it. The objective of the exercise was to avoid having to modify the method signatures of the repo code to include the ClaimsPrincipal, kind of like the old days when it was possible to call Thread.CurrentPrincipal. Still looking for a clue but will start modifying the method signature to include a ClaimsPrincipal.
The answer is to use IHttpContextAccessor. In Startup.cs add a new service definition in the ConfigureServices() method:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IAppSettings>(settings);
services.AddSingleton<IHttpContextAccessor>(new HttpContextAccessor());
…
}
Then pass app.ApplicationServices as a parameter to the bootstrapper:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAppSettings settings)
{
var log = ConfigureLogger(settings);
app.UseOwin(buildFunc =>
{
buildFunc.UseMonitoringAndLogging(log, HealthCheckAsync);
buildFunc.UseNancy(cfg =>
cfg.Bootstrapper = new Bootstrapper(env, log, app.ApplicationServices));
});
}
In the Bootstrapper class ApplicationStartup() method, register the service in the Simple Injector container:
public Bootstrapper(IHostingEnvironment env, ILogger log, IServiceProvider services)
{
_env = env;
_log = log;
_services = services;
}
…
_container.Register<IHttpContextAccessor>(() =>
(IHttpContextAccessor) _services.GetService(typeof(IHttpContextAccessor)));
Then in the decorator class, add IHttpContextAccessor to the constructor:
public EmailDecorator(IDbConnectionFactory connectionFactory,
ILogger log,
IHttpContextAccessor httpContextAccessor,
IEmailClient emailClient) : base(connectionFactory, log)
{
_emailClient = emailClient;
_httpContextAccessor = httpContextAccessor;
}
The ClaimsPrincipal can be accessed from the _httpContextAccessor.HttpContext property.

Resolving Hangfire dependencies/HttpContext in .NET Core Startup

I've installed and configured Hangfire in my .NET Core web application's Startup class as follows (with a lot of the non-Hangfire code removed):
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseHangfireServer();
//app.UseHangfireDashboard();
//RecurringJob.AddOrUpdate(() => DailyJob(), Cron.Daily);
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<AppSettings>(Configuration);
services.AddSingleton<IConfiguration>(Configuration);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IPrincipal>((sp) => sp.GetService<IHttpContextAccessor>().HttpContext.User);
services.AddScoped<IScheduledTaskService, ScheduledTaskService>();
services.AddHangfire(x => x.UseSqlServerStorage(connectionString));
this.ApplicationContainer = getWebAppContainer(services);
return new AutofacServiceProvider(this.ApplicationContainer);
}
}
public interface IScheduledTaskService
{
void OverduePlasmidOrdersTask();
}
public class ScheduledTaskService : IScheduledTaskService
{
public void DailyJob()
{
var container = getJobContainer();
using (var scope = container.BeginLifetimeScope())
{
IScheduledTaskManager scheduledTaskManager = scope.Resolve<IScheduledTaskManager>();
scheduledTaskManager.ProcessDailyJob();
}
}
private IContainer getJobContainer()
{
var builder = new ContainerBuilder();
builder.RegisterModule(new BusinessBindingsModule());
builder.RegisterModule(new DataAccessBindingsModule());
return builder.Build();
}
}
As you can see, I'm using Autofac for DI. I've set things up to inject a new container each time the Hangfire job executes.
Currently, I have UseHangfireDashboard() as well as the call to add my recurring job commented out and I'm receiving the following error on the line referencing IPrincipal:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
I understand that Hangfire does not have an HttpContext. I'm not really sure why it's even firing that line of code for the Hangfire thread. I'm ultimately going to need to resolve a service account for my IPrincipal dependency.
How can I address my issue with Hangfire and HttpContext?
The main problem I'm having now is when I add UseHangfireServer, I
then need to resolve HttpContext too
Found here Using IoC containers
HttpContext is not available
Request information is not available during the instantiation of a
target type. If you register your dependencies in a request scope
(InstancePerHttpRequest in Autofac, InRequestScope in Ninject and so
on), an exception will be thrown during the job activation process.
So, the entire dependency graph should be available. Either register
additional services without using the request scope, or use separate
instance of container if your IoC container does not support
dependency registrations for multiple scopes.
resolving scoped dependencies in .net core would require a request which is not available during startup when registering and activating jobs. Therefore make sure that your service required for activation during startup are not registered using scoped lifetimes.
services.AddTransient<IScheduledTaskManager, ScheduledTaskManageImplementation>();
All that is left now is to configure the application to use that service with the recurring job,
public class Startup {
public IContainer ApplicationContainer { get; private set; }
public Startup(IHostingEnvironment env) {
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void Configuration(IApplicationBuilder app) {
// app.AddLogger...
//add hangfire features
app.UseHangfireServer();
app.UseHangfireDashboard();
//Add the recurring job
RecurringJob.AddOrUpdate<IScheduledTaskManager>(task => task.ProcessDailyJob(), Cron.Daily);
//app.UseMvc...
//...other code
}
public IServiceProvider ConfigureServices(IServiceCollection services) {
// Adding custom services
services.AddTransient<IScheduledTaskManager, ScheduledTaskManageImplementation>();
//add other dependencies...
// add hangfire services
services.AddHangfire(x => x.UseSqlServerStorage("<connection string>"));
//configure Autofac
this.ApplicationContainer = getWebAppContainer(services);
//get service provider
return new AutofacServiceProvider(this.ApplicationContainer);
}
IContainer getWebAppContainer(IServiceCollection service) {
var builder = new ContainerBuilder();
builder.RegisterModule(new BusinessBindingsModule());
builder.RegisterModule(new DataAccessBindingsModule());
builder.Populate(services);
return builder.Build();
}
//...other code
}
References
Hangfire 1.6.0
Integrate HangFire With ASP.NET Core
Using IoC containers
Why is Hangfire trying to resolve the .NET Core Startup class?
Hangfire doesn't store lambda expressions in the database, it stores the type and method being called. Then when the scheduled task is due to run, it resolves the type from the container and calls the method.
In your case, the method is on Startup.
You can register Startup with Autofac if you want, but it's probably easiest to have a scheduled task service:
AddOrUpdate<IScheduledTaskService>(x => x.DailyTask(), Cron.Daily);
I'm not sure of the type for jobmanager off the top of my head, but you can resolve the dependency from the container using a scope. You'll want to resolve from the scope in a using statement to prevent memory leaks. See the Autofac Docs
// not sure what type "jobManager" is
TYPE jobManager;
using(var scope = ApplicationContainer.BeginLifetimeScope())
{
jobManager = scope.Resolve<TYPE>();
}
RecurringJob.AddOrUpdate( ... );

Instanciate new AuthorizationServerProvider when per http request using dependency injection

I have a web api 2 project and I am using Asp.net Identity and Entity framework.
I have discovered that when I change the password, the old one still works but the new one give me error (invalid grant).
I am sure the change password works correctly... Infact in the database the value of the (hashed) password changes correctly.
UPDATE
I have understood why. The authorizationServerProvider (or the user manager I use inside it) is not instanciated per http request. It seems it is a singleton. The problem is that it is instanciated on startup and stop, so it's like it continue to use data of the first login, that are cached (by Entity framework).
Here how I configure my authorizationServerProvider class:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
OAuthAuthorizationServerOptions oauthServerOptions = new OAuthAuthorizationServerOptions
{
//...,
Provider = new TokenBasedAuthorizationServerProvider(),
RefreshTokenProvider = new RefreshTokenProvider()
};
app.UseOAuthAuthorizationServer(oauthServerOptions);
}
How can avoid the login use the cached data?
Thank you
You can try to:
Disable Tracking using AsNoTracking()
Throw away the DbContext and create a new one
Call GetDatabaseValues() to get updated values for single entity
I had the same problem with UseOAuthAuthorizationServer and DI. Last time I faced with this when using Autofac but this is relevant to other DI frameworks. The problem is we have static instance of OAuthAuthorizationServerProvider stored by middleware so no DI involved.
My solution was to get dependencies in OAuthAuthorizationServerProvider in each methods like this:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var scope = context.OwinContext.GetAutofacLifetimeScope();
var userManager = scope.Resolve<ApplicationUserManager>();
.........
}
My container initialization:
public static IContainer Configure(IAppBuilder appBuilder, HttpConfiguration config)
{
var containerBuilder = new ContainerBuilder();
.... registrations here ....
var container = containerBuilder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
appBuilder.UseAutofacMiddleware(container);
appBuilder.UseAutofacWebApi(config);
return container;
}
You can do something like this using other DI containers as well.

Resolve Autofac service within InstancePerLifetimeScope on Owin Startup

I cannot figure out a correct way to resolve a service via Autofac that is used while constructing the Owin context and also disposed at the request end.
Since the OwinContext is still under construction at this point, the LifetimeScope cannot be found by calling HttpContext.Current.GetOwinContext().GetAutofacLifetimeScope(). The OwinContext is not available here yet.
In my code the IAdfsAuthorizationProvider service is resolved directly at the Container, but isn't disposed after a request and lives much longer.
I could create a new LifeTimeScope by calling container.BeginLifetimeScope(), but now the LifeTime is separated of the request and will possibly resolve different instances in the same request. And there is no way to dispose the lifeTimeScope myself at the correct time.
public void Configure(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterType<AdfsAuthorizationProvider>().As<IAdfsAuthorizationProvider>().InstancePerLifetimeScope();
var container = builder.Build();
app.UseAutofacMiddleware(container);
// **Service that's not binding to the request lifetime.**
var service = container.Resolve<IAdfsAuthorizationProvider>();
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
Provider = new AuthorizationServerProvider(service),
});
}
Does anyone has a suggestion?
The OAuthAuthorizationServerProvider is a singleton that call methods for all requests.
This class has not been designed to be injected. If you want to resolve a dependency for one request you will have to resolve it manually using the owinContext provided with each method
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override Task GrantAuthorizationCode(
OAuthGrantAuthorizationCodeContext context)
{
IAdfsAuthorizationProvider authorizationProvider =
context.OwinContext
.GetAutofacLifetimeScope()
.Resolve<IAdfsAuthorizationProvider>();
return base.GrantAuthorizationCode(context);
}
}

using IOC container with IdentityFactory Middleware

I am trying to understand the UserManagerFactory middleware explained here per request lifetime management for usermanager.
I created this class which I am calling from the Startup Configuration method
public class CustomUserManagerProvider
{
public static CustomUserStore<CustomUser> CreateCustomUserStore()
{
return new CustomUserStore<CustomUser>(/*Need to inject dependencies here*/);
}
public static CustomUserManager CreateCustomUserManager(IdentityFactoryOptions<CustomUserManager> options,
IOwinContext context)
{
return new CustomUserManager(context.Get<CustomUserStore<CustomUser>>());
}
}
And the Startup Configuration
public void Configuration(IAppBuilder app)
{
app.CreatePerOwinContext(CustomUserManagerProvider.CreateCustomUserStore);
app.CreatePerOwinContext<IngramUserManager>(CustomUserManagerProvider.CreateCustomUserManager);
////....Other things
}
Now, My CustomUserStore has some dependencies which I want to inject in the constructor.
The composition root of the IOC container knows how to resolve these dependencies.
How do I make the CustomUserManagerProvider DI container aware(If that makes sense)...
Although this works
public static CustomUserStore<CustomUser> CreateCustomUserStore()
{
var dependency = DependencyResolver.Current.GetService<ISomeDependency>();
return new CustomUserStore<CustomUser>(dependency);
}
But, I was trying to avoid the service locator (anti)pattern. Is this my only option, Is this even right??
I am using Ninject.
Cant I just create a UserManager in requestScope in the composition root and inject into the controllers, wont that be the same thing?
In a web app, is CreatePerOwinContext same as creating InRequestScope?
Yes, you can inject the UserManager into your controllers a different way if you like, there's nothing that requires using the CreatePerOwinContext/IdentityFactoryMiddleware.

Categories