inject custom class into startup.cs - c#

I am trying to find a way to inject a dependency in Startup.cs, for a aspnet5 application. I am aware of the following previous question, but hopefully I can expand on my particular requirements:
Aspnet core 5.0 inject dependency in startup.cs constructor
I initially needed a way to fire a custom method after OnSignIn with MS Identity Platform (IP) within my app. After posting the following questions, I was quickly pointed in the right direction:
How to fire a custom method after OnSignIn with MS Identity Platform
In short, during ConfigureServices in StartUp.cs, I needed to configure the IP middleware service, to add my own methods to some of its available events. Works a treat!
So I initially tried:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
options.Events = new OpenIdConnectEvents
{
OnTicketReceived = async ctex =>
{
// Blah
},
});
As I say, this works great. However, to do anything serious, I need access to my existing code and the DI magic that goes with it. This is where I a hitting this problem. I need my custom logic that requires DI, during ConfigureServices, before I have configured the services for DI.
On the same post, someone pointed out that you can wrap up the configuration, and essentially inject it back in, so you can get DI back. Great! But for some reason, I can only inject the handler, either as a Singleton, or Transient. Not Scoped. I get to some extent why it can't be scoped (if it is has a dependency of its own on a transient service), but then are why both extremes ok? Why is Singleton OK? Why is Transient? It just so happens, but my DI requirements are that I would need to inject scoped services, as that is what I need. I need some of the data to persist across instances, but I can't have a single instances shared across the whole application/user base.
So then I tried:
public class AzureAdOpendIdHandler : IConfigureNamedOptions<OpenIdConnectOptions>
{
public AzureAdOpendIdHandler(Authentication.AuthenticationManager authenticationManager)
{
AuthenticationManager = authenticationManager;
}
public Authentication.AuthenticationManager AuthenticationManager { get; }
public void Configure(string name, OpenIdConnectOptions options)
{
options.Events = new OpenIdConnectEvents
{
OnTicketReceived = context =>
{
//Blah
return Task.CompletedTask;
},
};
}
}
Then called in StartUp.cs like:
services.AddScoped<Authentication.IAuthenticationManager, Authentication.AuthenticationManager>();
services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, AzureAdOpendIdHandler>();
Again, the handler works fine, and everything fires, as long as I don't try and pass "AuthenticationManager" within the constructor. I get an error saying that I can't inject a scoped service into a singleton service.
I keep getting within spitting distance of doing what I need, but there is always another block in the way.
In summary:
To override/extend MS Identity Platform, I need to make changes in ConfigureServices() in StartUp.cs
These changes require my classes to be available via DI.
The DI must allow me to pass them as scoped
So far, I can only meet the first two requirements, I can not find a way to satisfy all three.
My end requirement is to be able to add a call to my AuthenticationManager class from within the following OnTicketReceived Event:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
options.Events = new OpenIdConnectEvents
{
OnTicketReceived = async ctex =>
{
//use my AuthenticationManager class!!
},
});
I have tried the direct method, wrapping things up in a handler and injecting, but DI seems to be getting in the way now.
Any help, would be gratefully received.

Related

Best practices around async initialization before IOC registration

Perhaps I'm just using the wrong terms while searching, but I haven't found any solid guidance around how to do what I'm seeking to do.
All the guidance around DI registration follows something like the following:
builder.Services.AddSingleton<MyService>(() => new MyService("connectionString"));
But this seems too simple for me to use over here in the real world. I don't store my various credentials in my applications, but rather put them somewhere else like Azure Key Vault or authenticate using a managed identity that itself retrieves connection strings and keys.
This introduces the need then to access the credentials/connection string first, which increasingly is exposed only as an asynchronous operation and introduces the problem I regularly face: namely, asynchronous registration isn't a thing.
I could register a service that itself retrieves and exposes the credential in an async method, but now every downstream service is going to need to know about that method in order to utilize it - I can't simply abstract it away in a DI registration.
I could just use .Result or Wait(), but there's plenty of solid guidance that suggests this shouldn't be done for deadlocking reasons. Because this code may be intended for a library that's consumed by an app with a UI, that's a no-go.
So the question is: When I'm unable to synchronously provide my credentials, how do I register my services?
Real-world example
For example, let's say I've got a web app that needs to access Cosmos DB, but via a managed identity, following the instructions here. I need to store some information about the Cosmos DB instance which means a dependency on IConfiguration and I'd like to use a singleton HttpClient to retrieve the necessary keys.
I want to put this into a separate service responsible for setting up the Cosmos DB client so that downstream usages can just inject the CosmosClient, so my class looks like:
public class CosmosKeyService
{
private readonly MyCosmosOptions _cosmosOptions;
private readonly HttpClient _http;
public CosmosKeyService(IOptions<MyCosmosOptions> options, HttpClient http)
{
_cosmosOptions = options.Value;
_http = http;
}
private async Task<string> GetCosmosKey()
{
//Follow instructions at https://learn.microsoft.com/en-us/azure/cosmos-db/managed-identity-based-authentication#programmatically-access-the-azure-cosmos-db-keys
//...
var keys = await result.Content.ReadFromJsonAsync<CosmosKeys>();
return keys.PrimaryMasterKey;
}
public async Task<CosmosClient> GetCosmosClient()
{
var key = await GetCosmosKey();
return new CosmosClient(_cosmosOptions.CosmosDbEndpoint, key);
}
}
To support the DI used in this class, my registration then looks like:
builder.Services.Configure<MyCosmosOptions>(builder.Configuration.GetSection("cosmosdb"));
builder.Services.AddSingleton<HttpClient>();
And of course I'm going to need to register this service:
builder.Services.AddSingleton<CosmosKeyService>();
But now I'd also like to register the CosmosClient as created by the method in that service and this is where I start getting confused about the best way forward.
I can't retrieve an instance of the CosmosKeyService from the builder because I haven't yet built it, and after I do, I can't then register new services.
I can't use async methods in the registration itself or I could easily do something like:
builder.Services.AddSingleton<CosmosClient>(async services => {
var keyService = services.GetService<CosmosKeyService>();
return await keyService.GetCosmosClient();
});
...and downstream services could simply inject CosmosClient in their various constructors.
Again, any downstream consumer can just inject a CosmosKeyService, but now they're all going to have to "remember" to call the initialization method first so they can retrieve the CosmosClient and utilize it. I'd rather that be handled in registration so that 1) this initialization is hidden and centrally located and 2) the CosmosClient is truly a singleton and not just an artifact of every utilization.
I could create another intermediate service that injects this Key resolver service and retrieve the keys, but it too will need to have this async method that retrieves the keys since I can't just hide that initialization in a registration somewhere (for lack of async support).
For example, I could make another service:
public class CosmosBuilder
{
private readonly CosmosKeyService _keySvc;
public CosmosBuilder(CosmosKeyService keySvc)
{
_keySvc = keySvc;
}
public async Task<CosmosClient> GetCosmosClient()
{
return async _keySvc.GetCosmosClient();
}
}
But this ultimately still requires a downstream service to inject this service and call that initialization method and if that's necessary, I might as well just stick with injecting the CosmosKeyService and call the method there.
What I'd ideally like to see is some way to hide any async initialization in the registration so that downstream consumers can simply inject CosmosClient and it works, but it's beyond me how that's intended to happen. Can anyone shed some light on this?
Edit to address comment:
I don't want to comment on a 4-year old answer, but the issue I assert with the accepted answer boils down to this part:
Move [initialization] into the Composition Root. At that point, you can create an initialize those classes before registering them in the container and feed those initialized classes into the container as part of registrations.
That's all well and good except:
I only get to "build" my container a single time. I can't build it, then utilize the registrations to accomplish the initialization, then append still more registrations to it for later use.
In my example above, I explicitly utilize elements registered in DI by ASP.NET Core itself (namely IConfiguration), so there's simply no way to even access these except via DI (which, per #1, precludes me from being able to initialize and later supplement my registrations with more implementations).

.NET Core Singleton Creation is called multiple times

I'm registering a service as a singleton in .NET Core. Yet I'm seeing the constructor for the singleton called multiple times.
services.AddSingleton<DbAuthorizationOptions, ContextAuthorizationOptions>();
My context authorization options is just Dictionary of Entity Types to IValidators, The context authorization options are passed into the DBContext, to automatically run validations.
During the registration of my services, I also register dynamic Validators with my container registered in DI.
var useDynamicValidator = serviceOption.ValidatorOptions != null;
if(useDynamicValidator)
{
//TODO: Extract this to before the register service no sense in building the provider each time
//TODO: Make this cleaner don't be dependent on Authorization options
var provider = services.BuildServiceProvider();
var authOptions = provider.GetService<DbAuthorizationOptions>();
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
I notice that when I call GetService on the provider I receive a new singleton instead of the existing one. Does building the provider create a new container so all of the services get re-registered?
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the service container is built?
Does building the provider create a new container so all of the services get reregistered?
Yes. See the source code.
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the servicecontainer is built?
I'm not really understanding why this is a problem. You should be registering all of your services one time at application startup in the Composition Root.
The DI container is then responsible for resolving the object graphs of the application. The application itself shouldn't have a dependency on it, nor be required to update it.
You should be injecting DbAuthorizationOptions in the place where you need to use it.
public class Foo : IFoo
{
private readonly DbAuthorizationOptions authOptions;
public Foo(DbAuthorizationOptions authOptions) // <-- Inject parameters
{
this.authOptions = authOptions ??
throw new ArgumentNullException(nameof(authOptions));
}
public void DoSomething()
{
// TODO: Inject the type that has the BuildDynamicValidatorFactory
// method and the serviceOption (whatever type that is) here
// either as a method parameter of this method, or a constructor
// parameter of this class.
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
// Now we have an instance of authOptions that can be used
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
}
Note that the DI container automatically provides the DbAuthorizationOptions if injected into another type that is also resolved through DI (such as a controller or filter).
NOTE: It isn't very clear from your question where you need to do this. You mention that you want it to happen once, which usually means to put it at application startup. But users cannot interact with code that runs at startup. So, maybe you could use a filter. It really all depends on where in the lifecycle of the application it has to happen.
You can declare a dependency on IServiceProvider -- don't build it, inject it.
public class SomeController
{
DbAuthorizationOptions authOptions;
public SomeController(IServiceProvider provider)
{
authOptions = provider.GetSerivce<DbAuthorizationOptions>();
}
}
But this is the service locator anti-pattern. As I commented on NightOwl888's post after you gave more details, a factory is probably a better approach.

Simple Injector Account Controller dependencies issue in Asp.Net Web API [duplicate]

I am having a configuration setup for Simple Injector where I have moved all of my registrations to OWIN pipeline.
Now the problem is I have a controller AccountController which actually takes parameters as
public AccountController(
AngularAppUserManager userManager,
AngularAppSignInManager signinManager,
IAuthenticationManager authenticationManager)
{
this._userManager = userManager;
this._signInManager = signinManager;
this._authenticationManager = authenticationManager;
}
Now my Owin Pipeline configurations looks something like this
public void Configure(IAppBuilder app)
{
_container = new Container();
ConfigureOwinSecurity(app);
ConfigureWebApi(app);
ConfigureSimpleinjector(_container);
app.Use(async (context, next) =>
{
_container.Register<IOwinContext>(() => context);
await next();
});
_container.Register<IAuthenticationManager>(
() => _container.GetInstance<IOwinContext>().Authentication);
_container.Register<SignInManager<Users, Guid>, AngularAppSignInManager>();
}
private static void ConfigureOwinSecurity(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = "AppNgCookie",
//LoginPath = new PathString("/Account/Login")
});
}
private static void ConfigureWebApi(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
private static void ConfigureSimpleinjector(Container container)
{
SimpleInjectorInitializer.Initialize(container);
}
And Simple Injector Initializer looks something like this
private static void InitializeContainer(Container container)
{
container.Register<DbContext, AngularAppContext>();
container.Register<IUserStore<Users, Guid>, AngularAppUserStore>();
container.Register<IRoleStore<Roles, Guid>, AngularAppRoleStore>();
container.Register<UserManager<Users, Guid>, AngularAppUserManager>();
container.Register<RoleManager<Roles, Guid>, AngularAppRoleManager>();
//container.RegisterPerWebRequest<SignInManager<Users, Guid>, AngularAppSignInManager>();
container.Register<IdentityFactoryOptions<AngularAppUserManager>, IdentityFactoryOptions<AngularAppUserManager>>();
//container.Register<IAuthenticationManager>(() => HttpContext.Current.GetOwinContext().Authentication);
//container.Register<SignInManager<Users, Guid>, AngularAppSignInManager>();
// For instance:
// container.Register<IUserRepository, SqlUserRepository>();
}
Now the problem is The controller is not able to register IAuthenticationManager. I tried using
container.Register<IAuthenticationManager>(
() => HttpContext.Current.GetOwinContext().Authentication);
But that Leaves me with Exception as:
System.InvalidOperationException: No owin.Environment item was found
in the context.
In this line
container.Register<IAuthenticationManager>(
() => HttpContext.Current.GetOwinContext().Authentication);
I also tried instead of using HttpContext.Current.GetOwinContext().Authentication with the configuration mentioned above in public void Configure(app) method to register using app.Use(). And then later resolve it via container to get the IAuthenticationManager. But every possibilities have left me failed.
What am I missing here? Why HttpContext.Current.GetOwinContext().Authentcation is failing to resolve authentcation from OwinContext?
And if thats not, why is the same configuration via app.Use also not working?
As TrailMax already mentioned, the exception you got probably got raised during the call to container.Verify(). At application start-up time there is no HttpContext, hence the exception.
Although the removal of the call to container.Verify() will 'solve' the problem, I would advise against doing this and I will suggest a better solution below.
NightOwl888 references an old article of Mark Seemann (which I highly respect for his work on DI). In that article Mark explains why he thinks that verifying the container is useless. This article however seems outdated, and conflicts with newer articles from Mark. In a newer article Mark explains that one of the big advantages of using Pure DI (that is Dependency Injection without using a DI container) is that it provides the fastest feedback about correctness that you can get. Mark, and the rest of us, obviously values both the compiler's feedback and the feedback from static code analysis tools, as rapid feedback mechanism. Both Simple Injector's .Verify() and the Diagnostic Services attempt to bring this fast feedback back. In my view, Simple Injector's .Verify() method takes on the job that the compiler would do for you when doing Pure DI and the Diagnostic Services is in a sense static code analysis tool specialized to your DI configuration.
While it is indeed not possible for a container to do a 100% verification of its configuration, verifying still proved a valuable practice to me. It would be silly to think that a simple call to .Verify() would result in a completely bug free or even a working application. If somebody may think that this is what ‘verifying’ your DI configuration means, I understand why they would argue that this functionality is worthless. Sounds like a statement of truism. There is no container out there, including Simple Injector, which pretends having such a feature.
You are off course still responsible for writing integration and/or unit tests for e.g. detecting if the order of applied decorators is correct or if all implementations of ISomeService<T> are indeed registered in the container.
I want to mention 2 specific arguments from Mark’s blog against verifying the container.
It is easy to get into the situation that the container verifies, but still breaks at runtime.
I agree with that, but I do think that the Simple Injector documentation has got some great guidance on how to approach this here.
When doing convention over configuration it's easy to get registrations that shouldn't be in the container anyway.
I never had this problem, because I think it is a sane practice to prevent getting in this situation anyway.
Back to the question:
Although one of the tips in the Simple Injector documentation is to use abstract factories, I wouldn't do that in this case. Creating a factory for something that already exists, sounds pretty weird to me. Maybe it is just a problem of correct naming, but why would an AccountController need a AuthenticationFactory or AuthenticationContext? In other words, why should the application know anything about us having problem wiring things up because of some design quirks in ASP.NET Identity?
Instead, by adjusting the registration for the IAuthenticationManager we can return an Authentication component from a newly created OwinContext at startup/verify time and return the 'normal' or configured AuthenticationManager at runtime. This will remove the need for a factory and moves the responsibility to the Composition Root where it should be. And lets you inject the IAuthenticationManager everywhere you need it, while still being able to make a call to .Verify().
The code looks like:
container.RegisterPerWebRequest<IAuthenticationManager>(() =>
AdvancedExtensions.IsVerifying(container)
? new OwinContext(new Dictionary<string, object>()).Authentication
: HttpContext.Current.GetOwinContext().Authentication);
An even more SOLID solution however would be to not depend on the IAuthenticationManager at all, because depending on this interface causes us to violate the Interface Segregation Principle, making it hard to create a proxy implementation for it that delays the creation.
You could do this by defining an abstraction which fits your needs and only your needs. Looking at the identity template calls to the IAuthenticationManager this abstraction would need nothing more than the .SignIn() and .SignOut() methods. This however would force you to completely refactor the crappy AccountController that you got 'for free' by the Visual Studio template, which can be quite an undertaking.
What you are doing with IAuthenticationManager registration worked for me with no issues. At some point I was getting the same exception as you were getting, but that was caused by line with
container.Verify();
just after the container configuration. It was trying to create all instances of registered objects, but there was no HttpContext.Current present, hence the exception.
Are you not getting any instances out of container before any HTTP request is available? If you really need them, then the only way to work around this is use Factory, as suggested by NightOwl888. If you don't need container before the HTTP request, then refactor, so it is not use outwith HTTP request.
See my answer here.
Although you are accessing a different type, the problem is the same. You cannot rely on properties of HttpContext during application startup because the application is initialized outside of the user's context. The solution is to make an abstract factory to read the values at runtime rather than at object creation and inject the factory rather than the IAuthenticationManager type into your controller.
public class AccountController
{
private readonly AngularAppUserManager _userManager;
private readonly AngularAppSignInManager _signInManager;
private readonly IAuthenticationManagerFactory _authenticationManagerFactory;
public AccountController(AngularAppUserManager userManager
, AngularAppSignInManager signinManager
, IAuthenticationManagerFactory authenticationManagerFactory)
{
this._userManager = userManager;
this._signInManager = signinManager;
this._authenticationManagerFactory = authenticationManagerFactory;
}
private IAuthenticationManager AuthenticationManager
{
get { return this._authenticationManagerFactory.Create(); }
}
private void DoSomething()
{
// Now it is safe to call into HTTP context
var manager = this.AuthenticationManger;
}
}
public interface IAuthenticationMangerFactory
{
IAuthenticationManger Create();
}
public class AuthenticationMangerFactory
{
public IAuthenticationManger Create()
{
HttpContext.Current.GetOwinContext().Authentication;
}
}
// And register your factory...
container.Register<IAuthenticationManagerFactory, AuthenticationMangerFactory>();

Multithreading issue with Autofac in WPF application

I am working with a WPF based application and using Autofac to resolve the dependency of DbContext of Entityframework. I used the below code to register my data module.
public class DataModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DataContext>()
.As<IDbContext>()
.WithParameter("nameOrConnectionString", "DefaultConnectionString")
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
}
}
This works fine while using in normal scenario but while using TPL, due to simultaneous calls to repository, it creates error stating that "ExecuteReader requires an open and available Connection. The connection's current state is open."
In web application, this can be resolved using InstancePerRequest to resolve dependency per request but in WPF I need to resolve this dependency per Thread request. Is there any way out for this?
I have review InstancePerRequest summary or autofac and it states that this method is used for Web request only:
// Summary:
// Share one instance of the component within the context of a single web/HTTP/API
// request. Only available for integration that supports per-request dependencies
// (e.g., MVC, Web API, web forms, etc.).
Update:
This is a simple async method that I used to get the data:
private async void OnLoadClientDetail()
{
long clientId = SelectedClient != null ? SelectedClient.Id : 0;
var listOfCollection = await _collectionService.GetCollectedCollectionAsync(clientId);
CollectionList = new ObservableCollection<CollectedCollection>(listOfCollection);
}
Here OnLoadClientDetail is bound to selection change event of a combobox. When user change the selection frequently then this method will be called multiple times. The _collectionService is injected in the viewmodel and has InstancePerLifetimeScope define. So how can I get different scope for all this calls?
As far as I can see, you share the _collectionService instance across the different event handlers by injecting it by Constructor Injection.
It probably better to use Method Injection here, so you'll get the instance per call, as you need, resolving it before method:
builder.Register(c =>
{
var result = new MyObjectType();
var dep = c.Resolve<TheDependency>();
result.SetTheDependency(dep);
return result;
});

Register IAuthenticationManager with Simple Injector

I am having a configuration setup for Simple Injector where I have moved all of my registrations to OWIN pipeline.
Now the problem is I have a controller AccountController which actually takes parameters as
public AccountController(
AngularAppUserManager userManager,
AngularAppSignInManager signinManager,
IAuthenticationManager authenticationManager)
{
this._userManager = userManager;
this._signInManager = signinManager;
this._authenticationManager = authenticationManager;
}
Now my Owin Pipeline configurations looks something like this
public void Configure(IAppBuilder app)
{
_container = new Container();
ConfigureOwinSecurity(app);
ConfigureWebApi(app);
ConfigureSimpleinjector(_container);
app.Use(async (context, next) =>
{
_container.Register<IOwinContext>(() => context);
await next();
});
_container.Register<IAuthenticationManager>(
() => _container.GetInstance<IOwinContext>().Authentication);
_container.Register<SignInManager<Users, Guid>, AngularAppSignInManager>();
}
private static void ConfigureOwinSecurity(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = "AppNgCookie",
//LoginPath = new PathString("/Account/Login")
});
}
private static void ConfigureWebApi(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
private static void ConfigureSimpleinjector(Container container)
{
SimpleInjectorInitializer.Initialize(container);
}
And Simple Injector Initializer looks something like this
private static void InitializeContainer(Container container)
{
container.Register<DbContext, AngularAppContext>();
container.Register<IUserStore<Users, Guid>, AngularAppUserStore>();
container.Register<IRoleStore<Roles, Guid>, AngularAppRoleStore>();
container.Register<UserManager<Users, Guid>, AngularAppUserManager>();
container.Register<RoleManager<Roles, Guid>, AngularAppRoleManager>();
//container.RegisterPerWebRequest<SignInManager<Users, Guid>, AngularAppSignInManager>();
container.Register<IdentityFactoryOptions<AngularAppUserManager>, IdentityFactoryOptions<AngularAppUserManager>>();
//container.Register<IAuthenticationManager>(() => HttpContext.Current.GetOwinContext().Authentication);
//container.Register<SignInManager<Users, Guid>, AngularAppSignInManager>();
// For instance:
// container.Register<IUserRepository, SqlUserRepository>();
}
Now the problem is The controller is not able to register IAuthenticationManager. I tried using
container.Register<IAuthenticationManager>(
() => HttpContext.Current.GetOwinContext().Authentication);
But that Leaves me with Exception as:
System.InvalidOperationException: No owin.Environment item was found
in the context.
In this line
container.Register<IAuthenticationManager>(
() => HttpContext.Current.GetOwinContext().Authentication);
I also tried instead of using HttpContext.Current.GetOwinContext().Authentication with the configuration mentioned above in public void Configure(app) method to register using app.Use(). And then later resolve it via container to get the IAuthenticationManager. But every possibilities have left me failed.
What am I missing here? Why HttpContext.Current.GetOwinContext().Authentcation is failing to resolve authentcation from OwinContext?
And if thats not, why is the same configuration via app.Use also not working?
As TrailMax already mentioned, the exception you got probably got raised during the call to container.Verify(). At application start-up time there is no HttpContext, hence the exception.
Although the removal of the call to container.Verify() will 'solve' the problem, I would advise against doing this and I will suggest a better solution below.
NightOwl888 references an old article of Mark Seemann (which I highly respect for his work on DI). In that article Mark explains why he thinks that verifying the container is useless. This article however seems outdated, and conflicts with newer articles from Mark. In a newer article Mark explains that one of the big advantages of using Pure DI (that is Dependency Injection without using a DI container) is that it provides the fastest feedback about correctness that you can get. Mark, and the rest of us, obviously values both the compiler's feedback and the feedback from static code analysis tools, as rapid feedback mechanism. Both Simple Injector's .Verify() and the Diagnostic Services attempt to bring this fast feedback back. In my view, Simple Injector's .Verify() method takes on the job that the compiler would do for you when doing Pure DI and the Diagnostic Services is in a sense static code analysis tool specialized to your DI configuration.
While it is indeed not possible for a container to do a 100% verification of its configuration, verifying still proved a valuable practice to me. It would be silly to think that a simple call to .Verify() would result in a completely bug free or even a working application. If somebody may think that this is what ‘verifying’ your DI configuration means, I understand why they would argue that this functionality is worthless. Sounds like a statement of truism. There is no container out there, including Simple Injector, which pretends having such a feature.
You are off course still responsible for writing integration and/or unit tests for e.g. detecting if the order of applied decorators is correct or if all implementations of ISomeService<T> are indeed registered in the container.
I want to mention 2 specific arguments from Mark’s blog against verifying the container.
It is easy to get into the situation that the container verifies, but still breaks at runtime.
I agree with that, but I do think that the Simple Injector documentation has got some great guidance on how to approach this here.
When doing convention over configuration it's easy to get registrations that shouldn't be in the container anyway.
I never had this problem, because I think it is a sane practice to prevent getting in this situation anyway.
Back to the question:
Although one of the tips in the Simple Injector documentation is to use abstract factories, I wouldn't do that in this case. Creating a factory for something that already exists, sounds pretty weird to me. Maybe it is just a problem of correct naming, but why would an AccountController need a AuthenticationFactory or AuthenticationContext? In other words, why should the application know anything about us having problem wiring things up because of some design quirks in ASP.NET Identity?
Instead, by adjusting the registration for the IAuthenticationManager we can return an Authentication component from a newly created OwinContext at startup/verify time and return the 'normal' or configured AuthenticationManager at runtime. This will remove the need for a factory and moves the responsibility to the Composition Root where it should be. And lets you inject the IAuthenticationManager everywhere you need it, while still being able to make a call to .Verify().
The code looks like:
container.RegisterPerWebRequest<IAuthenticationManager>(() =>
AdvancedExtensions.IsVerifying(container)
? new OwinContext(new Dictionary<string, object>()).Authentication
: HttpContext.Current.GetOwinContext().Authentication);
An even more SOLID solution however would be to not depend on the IAuthenticationManager at all, because depending on this interface causes us to violate the Interface Segregation Principle, making it hard to create a proxy implementation for it that delays the creation.
You could do this by defining an abstraction which fits your needs and only your needs. Looking at the identity template calls to the IAuthenticationManager this abstraction would need nothing more than the .SignIn() and .SignOut() methods. This however would force you to completely refactor the crappy AccountController that you got 'for free' by the Visual Studio template, which can be quite an undertaking.
What you are doing with IAuthenticationManager registration worked for me with no issues. At some point I was getting the same exception as you were getting, but that was caused by line with
container.Verify();
just after the container configuration. It was trying to create all instances of registered objects, but there was no HttpContext.Current present, hence the exception.
Are you not getting any instances out of container before any HTTP request is available? If you really need them, then the only way to work around this is use Factory, as suggested by NightOwl888. If you don't need container before the HTTP request, then refactor, so it is not use outwith HTTP request.
See my answer here.
Although you are accessing a different type, the problem is the same. You cannot rely on properties of HttpContext during application startup because the application is initialized outside of the user's context. The solution is to make an abstract factory to read the values at runtime rather than at object creation and inject the factory rather than the IAuthenticationManager type into your controller.
public class AccountController
{
private readonly AngularAppUserManager _userManager;
private readonly AngularAppSignInManager _signInManager;
private readonly IAuthenticationManagerFactory _authenticationManagerFactory;
public AccountController(AngularAppUserManager userManager
, AngularAppSignInManager signinManager
, IAuthenticationManagerFactory authenticationManagerFactory)
{
this._userManager = userManager;
this._signInManager = signinManager;
this._authenticationManagerFactory = authenticationManagerFactory;
}
private IAuthenticationManager AuthenticationManager
{
get { return this._authenticationManagerFactory.Create(); }
}
private void DoSomething()
{
// Now it is safe to call into HTTP context
var manager = this.AuthenticationManger;
}
}
public interface IAuthenticationMangerFactory
{
IAuthenticationManger Create();
}
public class AuthenticationMangerFactory
{
public IAuthenticationManger Create()
{
HttpContext.Current.GetOwinContext().Authentication;
}
}
// And register your factory...
container.Register<IAuthenticationManagerFactory, AuthenticationMangerFactory>();

Categories

Resources