Within ConfigureServices I'm setting up a number of services (this works). In the same method I'm trying to configure a custom file provider (for Razor). It looks like this:
services.AddMvc()
.AddRazorOptions(options =>
{
options.FileProvider = new CustomFileProvider(???);
});
CustomFileProvider has a few dependencies (that are all configured), but how can I ask the DI to give me an instance of CustomFileProvider right after all the services have been configured?
From what I can see the DI only injects in constructors, but in my case I need a "please give me an instance of CustomFileProvider right here" option.
If you want to be able to resolve services from the container while configuring some options, you need to leverage the IConfigureOptions<TOption> infrastructure, which most of MVC uses to set up the option defaults. See RazorViewEngineOptionsSetup for an example.
First, add the services you need to the collection:
services.AddSingleton<IDependency1, Dependency1>();
services.AddSingleton<IDependency2, Dependency2>();
Then, implement the setup class:
public class CustomFileProviderRazorViewEngineOptionsSetup : ConfigureOptions<RazorViewEngineOptions>
{
public CustomFileProviderRazorViewEngineOptionsSetup(IServiceProvider serviceProvider)
: base(options => ConfigureRazor(options, serviceProvider))
{
}
private static void ConfigureRazor(RazorViewEngineOptions options, IServiceProvider serviceProvider)
{
// Alternative 1 - Resolve each service and new up the instance.
var dependency1 = serviceProvider.GetService<IDependency1>();
var dependency2 = serviceProvider.GetService<IDependency2>();
options.FileProviders.Add(new CustomFileProvider(dependency1, dependency2));
// Alternative 2 - Same as alternative 1, but with moar magic ;)
options.FileProviders.Add(ActivatorUtilities.CreateInstance<CustomFileProvider>(serviceProvider));
// Alternative 3 - Just resolve CustomFileProvider from the service provider.
// This requires it to be registered first, of course.
options.FileProviders.Add(serviceProvider.GetService<CustomFileProvider>());
}
}
This is resolved from the container, so it'll allow you to inject an IServiceProvider, which can again be used to resolve the services you need. You could optionally add the CustomFileProvider to the container and resolve that directly instead, like in alternative 3.
Finally, add the setup class to the service collection:
services.TryAddEnumerable(
ServiceDescriptor.Transient<
IConfigureOptions<RazorViewEngineOptions>,
CustomFileProviderRazorViewEngineOptionsSetup>());
This will add the setup to the options builder pipeline, which means it'll run with the other registered instances of IConfigureOptions<RazorViewEngineOptions> to setup the options object.
Related
I have been using Proto.Actor and specifically the ActorFactory to spawn actors. To be able to use these features I need to add services.AddProtoActor() to the ConfigureServices method of my startup class.
However, now I want to transition to using StructureMap as my IoC container, but the two do not appear to play nicely together - when I add the following code from guides I have found online:
public IServiceProvider ConfigureIoC(IServiceCollection services)
{
// static class method that scans assemblies
IContainer container = IocContainer.SetupContainer();
container.Configure(config =>
{
config.Populate(services);
});
return container.GetInstance<IServiceProvider>();
}
When it tries to run config.Populate I get the following error:
System.ArgumentOutOfRangeException: Specified argument was out of the
range of valid values. Parameter name: EventStream must have at
least one public constructor to be plugged in by StructureMap
Does anyone have any ideas how to get the IActorFactory created correctly as a singleton in StructureMap (or have a workaround)?
In the end, using StructureMap removes the need I had for the ActorFactory itself. So instead of getting the actor's PID from the factory I have two lines:
var props = Actor.FromProducer(() => container.GetInstance<MyActorType>());
var pid = Actor.Spawn(props);
I am trying to find out how I can pass the StructrueMap container to a class that I wrote that inherits from another (MS-Class).
namespace TheNamespace
{
public class DatabaseIssuerNameRegistry : ValidatingIssuerNameRegistry
{
/* **This can't be done**
public DatabaseIssuerNameRegistry(IPortalTenantManager portalTenantManager)
{
_someField= portalTenantManager;
}*/
protected override bool IsThumbprintValid(string thumbprint, string issuer)
{
//How does it work ???????????
var portalTenantManager = container.GetInstance<IPortalTenantManager>();
//Do something with the portalTenantManager
}
}
I need portalTenantManager to be the Instance that I have defined in my container in the Global.asax.
My Global Assax has these things setup:
protected void Application_Start()
{
var container = new Container();
container.Configure(x =>
{ ....
....
x.For<IPortalTenantManager>().Use<PortalTenantManager>();
});
...
...
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory(container));
...
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapApiControllerFactory(container);
...
}
Edit:
Because of the comments of #NightOwl888 I'll explain a bit further what this class does. (Hopefully explaining so why my hands are tied)
My application is able to authenticate a user with Azure Active Directory and is Multi-tenant capable. In the authentication pipeline I have the possibility to store the validation endpoints in my database instead of the default way on the web.config file. See MSDN
and this, which actually is explaining exactly what I'm doing.
So I registered my class in the web.config under the Tag issuerNameRegistry. At some point of the validation pipeline my class is instantiated and the overriden method IsThumbprintValid is beeing called. The problem is that the class registered in issuerNameRegistry expects a parameterless constructor (there it is! the constrained construction!), therefore I cannot create a constructor that would solve my problem.
Thanks for your help
It turns out that this question has been asked before on MSDN, the answer of which was provided by Travis Spencer in 2 different posts.
it is typical in my experience to have a single container and use that service- or Web-side-wide. In the startup of the service or Web app, you can create the container, register the dependencies, new up an instance of your SecurityTokenServiceConfiguration class, resolve your dependencies, use it to punch out a SecurityTokenService object, and host it.
After the first beta, we really pushed for DI support. We got a little hook in beta 2. You can now create a custom SecurityTokenServiceConfiguration class that overrides the virtual CreateSecurityTokenService method. The implementation in Microsoft's SecurityTokenServiceConfiguration does Activator.CreateInstance; yours can do IoC. This can include the resolution of an IssuerNameRegistiry. Something like this perhaps:
RequestSecurityTokenResponse Issue(IClaimsPrincipal principal, RequestSecurityToken request)
{
SecurityTokenServiceConfiguration config = new MyGoodSecurityTokenServiceConfiguration();
SecurityTokenService sts = config.CreateSecurityTokenService();
RequestSecurityTokenResponse rstr = sts.Issue(principal, request);
return rstr;
}
public class MyGoodSecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration
{
public override SecurityTokenService CreateSecurityTokenService()
{
IssuerNameRegistry = IoC.Resolve<IssuerNameRegistry>();
var sts = IoC.Reslove<SecurityTokenService>();
return sts;
}
}
Of course, this means that you need to create a static instance of your DI container so it is accessible to your SecurityTokenServiceConfiguration class. Personally, I don't like that idea because it makes your DI container accessible throughout the application, which can lead to abuse of the DI container as a service locator.
Ideally, there would be a way in any DI friendly framework to pass the container into an abstract factory in order to resolve service dependencies. However, since I am not familiar with WIF it is unclear whether that can be done - perhaps the class where the Issue method exists could have a constructor added? The trick is to keep walking up the chain until you find the first place in the framework where you can intervene and do all of your DI configuration there.
I'm attempting to implement Dependency Injection into my architecture (MVC, DDD - Domain Model, Repository). And my architecture includes ASP.NET Identity 2.0.
At this stage, I don't want DI controlling any of the Identity 2.0 objects (UserAdminController, RolesAdminController...). I'd prefer the security objects outside of DI. At this stage, integrating the Identity objects in DI looks very difficult. I had a good look to see if someone has already done this, so I could read and learn how to do this. I couldn't find anything. (Found one post which came close, but no resolution).
Anyway, I've followed the Simple Injector MVC implementation (see standard code below), and trying many things, I believe the problem lies in me calling RegisterMvcControllers.
Correct me if I'm wrong, but this statement will pickup all controllers with their name post-fixed with "controller".
Question: How can I select which controllers get registered with Simple Injector? (Is this called manually registering?)
Any help would be greatly appreciated, as I've spent most of today trying to get my head around all this, and proceed to the next step, i.e. have DI implemented, and instantiating my objects.
...
...
... called from Application_Start()
// Create a Simple Injector container
var container = new Container();
// Configure the container
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
// Verify the container's configuration
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
private static void InitializeContainer(Container container)
{
container.Register<MyService1>();
container.Register<IMyRepositoryA, MyRepositoryA>();
// Trying to include Identity into Simple Injector - please ignore
container.Register<IUserStore<ApplicationUser>>(() => new UserStore<ApplicationUser>(new ApplicationDbContext()));
}
The RegisterMvcControllers has the following constraints on the types it registers:
The type must be public
The type must implement System.Web.Mvc.IController
The type must not be abstract
The type must not be a generic type definition
Its name must end with "Controller"
You can see what happens here in the source code.
The RegisterMvcControllers extension method calls into the SimpleInjectorMvcExtensions.GetControllerTypesToRegister method to get the list of controllers to register. You can call that method yourself to see what is registered as follows:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly())
So instead of calling RegisterMvcControllers you can register the controllers yourself by calling the GetControllerTypesToRegister method:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly());
foreach (var controllerType in registeredControllerTypes)
{
container.Register(controllerType, controllerType, Lifestyle.Transient);
}
This way you can filter out any controller you want to register manually:
var registeredControllerTypes =
SimpleInjectorMvcExtensions.GetControllerTypesToRegister(
container, Assembly.GetExecutingAssembly())
.Where(type => type.Name != "UserStore`1");
foreach (var controllerType in registeredControllerTypes)
{
container.Register(controllerType, controllerType, Lifestyle.Transient);
}
Another option is to override the registration:
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Options.AllowOverridingRegistrations = true;
container.Register<IUserStore<ApplicationUser>>(
() => new UserStore<ApplicationUser>(new ApplicationDbContext()))
// Always set the option back to false ASAP to prevent configuration errors.
container.Options.AllowOverridingRegistrations = false;
I've got a ConfigurationReader class that I'm trying to wire up using StructureMap or AutoFac (I haven't settled on which container I'm using).
public class ConfigurationReader {
private string _filePath;
public ConfigurationReader(string filePath){
this._filePath = filePath;
}
public IList<Baz> ListStuff(){
//do something with _filePath;
}
}
There will be 1..n to instances of this class based on how the app is configured (web.config will contain a delimited list of files). I'm looking for an extension point in either IoC container that would allow me to leverage them to create instances of ConfigurationReader.
Well, in AutoFac you can just register each one in the Container (during Application_Start for example).
Whenever you need to read all configurations you can add a dependency to IEnumerable<ConfigurationReader> (or IConfigurationReader if you decide to extract an interface) and it will provide you with all of them.
Something like this:
var builder = new ContainerBuilder();
foreach(var file in ConfigurationManager.AppSettings[yourKey].Split(','))
{
var fileName = file;
builder.Register(c => new ConfigurationReader(fileName));
}
DependencyResolver.SetResolver(new AutofacDependencyResolver(builder.Build()));
If you extract interfaces, then you may want to register by adding the .AsImplementedInterfaces() or .As<IConfigurationReader>() at end as well.
I want to replace the default IDataBus implementation (which writes to the filesystem) with one which writes to a db (so it can run on AWS). To this end I have a config extension:
public static class ConfigureSqlServerDataBus
{
public static Configure SqlServerDataBus(this Configure config)
{
var dataBus = new SqlServerDataBus();
config.Configurer.RegisterSingleton<IDataBus>(dataBus);
return config;
}
}
to allow me to configure the bus. But obviously my SqlServerDataBus has a dependency on something which tells it where to write (An IRepository implementation in this case).
Usually I would ask for the dependency through the constructor, but as the config of the service bus is done through the IWantCustomInitialization which will use Activator to create the instance I can't. My understanding is that NServiceBus will use property injection to satisfy the dependencies but it doesn't seem to do this. I have a couple of calls like this after my configuration is done:
Configure
.With()
.DefineEndpointName("SomeName")
.DefaultBuilder()
.DBSubcriptionStorage()
.XmlSerializer()
.SqlServerDataBus()
.MsmqTransport()
.IsTransactional(true)
.UnicastBus()
.LoadMessageHandlers()
.CreateBus()
.Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
Configure.Instance.Configurer.ConfigureComponent<RepositoryImplementation>(ComponentCallModelEnum.None);
Configure.Instance.Configurer.ConfigureComponent<SqlServerDataBus>(ComponentCallModelEnum.None);
but my setters for the SqlServerDataBus are never called, although the Put method is.
Can someone point out what I'm doing wrong?
You can't change the configuration after the bus has already been started. To move your config calls into the fluent initialization code, use the RunCustomAction method.
Alternatively, you can write a new class which implements INeedInitialization and make your config calls in there. This class will be invoked at the right time.