In CMS 12 you should do that in the ConfigureServices method of your Startup class instead, avoiding initialization modules when possible.
Since this is an independent module for customer's system I have planned to enclose everything in the InitializationModule, but you sugessting to register evething in Startup instead?
After adding
services.AddSingleton<IObjectInstanceCache, MemoryObjectInstanceCache>();
provider moves further but now it cannot find implememtation of EPiServer.Framework.ITimeProvider.
Why all of that is not registred in existed services.AddCms()?
No idea how to get a service I have just registred without ServiceProvider. Also ServiceLocator.Current.GetService(typeof(SomeType)) returns null.
Hi L,
I believe all the services you mention are registered by the FrameworkInitialization
(EPiServer.Framework
) initalizable module.
You should specify a dependency on it in your initializable module and see if that helps.
[InitializableModule]
[ModuleDependency(typeof(FrameworkInitialization))]
public class MyInitializationModule : IConfigurableModule {}
Perhaps try to register yours in context.ConfigurationComplete event?
context.ConfigurationComplete += (o, e) =>
{
e.Services.TryAddSingleton<blah blah blah ...
};
Quan's solution should be working, the ConfigurationComplete event should be the last thing executed during configuration. However, what I don't understand is why you register the service into container and then retrieve it immediately by forcing to create a new scope of the container? Manually invoking BuildServiceProvider could lead unexpected behaviour (e.g. intensive singleton services are being re-created). If you need to reference to the instance of your class during the registration, I recommend going with manually instantiate the object
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.Services.Configure<ProtectedModuleOptions>(pm => pm.Items.Add(new ModuleDetails { Name = "MyModule" }));
var someTypeInstance = new SomeType();
context.Services.AddSingleton<SomeType>(someTypeInstance);
}
As you already stated in your original post - you can register types whenever you want. However, in order to create a instance of that type - all dependencies for that instance needs to exist in the registry as well. As the name ConfigureContainer suggests - the purpose of this method is to set up the service provider (for example StructureMap registry) - nothing else. You should not use the service provider to create instances, because the service provider is not yet ready.
So, you need to move serviceProvider.GetService<SomeType>() (which creates the instance) to something that occurs later - for example ConfigurationComplete, as Quan mentioned. At this point, the service provider is ready to use.
Ok, now it seems to have sense. I was registering my services in the ConfigureContainer() method. Some of my classes had dependencies on Episerver stuff like EPiServer.DataAbstraction.ILanguageBranchRepository. Being still ConfigureContainer() method I needed to retrieve class that I registered and I was facing that problem with Epi part wasn't ready yet. Even after added
[ModuleDependency(typeof(FrameworkInitialization))]
I moved retrieving my service to Initialize() method and now I can use it to initialize what I need :)
Also that suggestion to extract services registration to the separate extension method seems a better idea than keeping it in the module.
Theory tells us that module has to be split into 2 parts: registration and usage.
That is the reason why we see services.AddSomething(); and app.UseSomething();. in our Startup.cs files.
So you should look for a way to split your module into registering your dependencies in phase #1 - configure container, and phase #2 - use those registered dependencies to carry out tasks during startup.
I was also struggling with this until I realize that I actually don't need that dependency yet - I can make use of it when everything is configured, the dependency container is built and the app is about to start.
Hi,
I'm implemeting InitializationModule
[InitializableModule] [ModuleDependency(typeof(InitializationModule))] public class MyInitializationModule : IConfigurableModule { public void ConfigureContainer(ServiceConfigurationContext context) { context.Services.Configure<ProtectedModuleOptions>(pm => pm.Items.Add(new ModuleDetails { Name = "MyModule" })); context.Services.AddSingleton<SomeType>(); var serviceProvider = context.Services.BuildServiceProvider(); var myType = serviceProvider.GetService<SomeType>(); //ERROR } }
Error is `System.InvalidOperationException: No constructor for type 'EPiServer.Events.Internal.RemoteCacheSynchronization' can be instantiated using services from the service container and default values.`.
Ok, RemoteCacheSynchronization type needs some IObjectInstanceCache to instantiate, but it is module job to register it? Modules could use different caches, or what?