How to register a singleton in a child container? - structuremap

I am having trouble registering a singleton in a StructureMap child container.
The singleton has a dependecy which is registered in the same container.
When trying to resolve the singleton, it fails saying it cannot determine the dependency. Whereas I can resolve the depency manually without problem.
The following code snippet shows the issue:
[Test]
public void should_be_able_to_instantiate_root()
{
var parentContainer = new Container();
var childContainer = parentContainer.CreateChildContainer();
childContainer.Configure(x =>
{
x.ForSingletonOf<IRoot>().Use<Root>();
x.For<IDependency>().Use<Dependency>();
});
Console.WriteLine(childContainer.WhatDoIHave());
var dependency = childContainer.GetInstance<IDependency>(); // Works
var root = childContainer.GetInstance<IRoot>(); // Fails ("No default Instance is registered and cannot be automatically determined for type 'IDependency'")
}
public interface IRoot
{
}
public class Root : IRoot
{
public Root(IDependency dependency)
{
}
}
public interface IDependency
{
}
public class Dependency : IDependency
{
}
childContainer.GetInstance<IRoot>() throws the following exception:
StructureMap.StructureMapConfigurationException : No default Instance is registered and cannot be automatically determined for type 'StructureMapIssue.IDependency'
There is no configuration specified for StructureMapIssue.IDependency
1.) new Root(*Default of IDependency*)
2.) StructureMapIssue.Root
3.) Instance of StructureMapIssue.IRoot (StructureMapIssue.Root)
4.) Container.GetInstance(StructureMapIssue.IRoot)
Here is the output from childContainer.WhatDoIHave(), you can see IDependency is there:
Profile is 'DEFAULT'
========================================================================================================
PluginType Namespace Lifecycle Description Name
--------------------------------------------------------------------------------------------------------
Func<TResult> System Transient Open Generic Template for Func<> (Default)
--------------------------------------------------------------------------------------------------------
Func<T, TResult> System Transient Open Generic Template for Func<,> (Default)
--------------------------------------------------------------------------------------------------------
IContainer StructureMap Transient Object: StructureMap.Container (Default)
--------------------------------------------------------------------------------------------------------
IDependency StructureMapIssue Transient StructureMapIssue.Dependency (Default)
--------------------------------------------------------------------------------------------------------
IRoot StructureMapIssue Singleton StructureMapIssue.Root (Default)
--------------------------------------------------------------------------------------------------------
Lazy<T> System Transient Open Generic Template for Func<> (Default)
--------------------------------------------------------------------------------------------------------
Root StructureMapIssue Transient StructureMapIssue.Root (Default)
========================================================================================================
Am I doing something wrong?

It doesn't male much sense to register a singleton in a child container, considering that the default behaviour of something being instantiated in a child container is that the instance sticks around until the child container is disposed.
Additionally, a child container is not meant to stick around for a long time - at least not as long as the parent.

Related

.net framework- how to create IServiceProvider to get already registered service instance using IServiceProvider?

On .NET Framework 4.6.2 application, where there is no built-in DI container we are using LightInject DI Container to object initialization but don't know how to create 'IServiceProvider' Object in Main() so the other class implementations can get the already registered instance of service via IServiceProvider without using new keyword.
How to create IServiceProvider object? in .net framework 4.6.2 application
public class Program
{
public static void Main()
{
var container = new ServiceContainer();
// calls below extension method
container.RegisterDependencies();
}
}
public static class LightInjectDIExtension
{
/// Registers the application dependencies.
public static void RegisterDependencies(this ServiceContainer container)
{
container.Register<IBackgroundService1, BackgroundService1>();
container.Register<Service2>();
}
}
Once IServiceProvider instance is available to use, I'm intended to do the below
// This is background service app & this class will be
// instantiated once in application lifetime
public class BackgroundService1 : IBackgroundService1
{
private readonly IServiceProvider _serviceProvider;
public BackgroundService1(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Method1(string elementName)
{
// every time call to 'Method1' has to get the new instance
// of registered 'Service2' class rather than using 'new'
// keyword
var service2 = (Service2)_serviceProvider.GetService(typeof(Service2));
service2.CallMe();
}
}
Modification after Steven's suggestion
public class BackgroundService1 : IBackgroundService1
{
private readonly IServiceContainer_container;
public BackgroundService1 (IServiceContainer container)
//Exception thrown: 'System.InvalidOperationException' in LightInject.dll
{
_container = container;
}
public void Method1(string elementName)
{
// every time call to 'Method1' has to get the new instance
// of registered 'Service2' class rather than using 'new'
// keyword
var service2 = (Service2)_container.GetInstance(typeof(Service2));
service2.CallMe();
}
}
In general, injecting an IServiceProvider (or any abstraction that gives access to an unbound set of dependencies is a bad idea, because it can lead to the Service Locator anti-pattern. A discussion on this anti-pattern can be found here.
A Service Locator is something that only exists outside the Composition Root. Your BackgroundService1, however, might be part of the Composition Root, which might injecting a DI Container -or an abstraction there over- a feasible solution. Note that you should strive keeping all business logic out of the Composition Root. This ensures that BackgroundService1 purely functions as a mechanical peace of code that delegates the operation to classes that run the actual business logic.
Though, when operating inside the Composition Root, there is typically no need to use an abstraction over your DI Container, such as an IServiceProvider. The Composition Root already has intrinsic knowledge over all application's dependencies, including your DI Container.
This means that you can inject LightInject's ServiceContainer directly into the constructor of BackgroundService1; there is no need for an IServiceProvider.
If, however, you insist in using the IServiceProvider abstraction, you can create an IServiceProvider implementation that wraps ServiceContainer and forwards its GetService method to the wrapped ServiceContainer. This wrapper class can than be registered in the ServiceContainer.

ASP.NET MVC Boilerplate: Migrating from AutoFac to Unity, cannot get Services DI working again

Current project:
ASP.NET MVC 5 boilerplate (Github)
Switching Autofac out for Unity
When I switch the DI from AutoFac to Unity, I am unable to get the Services built into the boilerplate (robots.txt, sitemap.xml) back up and running. In particular, I am unable to translate the Autofac entries for these services to the appropriate Unity entries.
My HomeController default constructor is unchanged from the default, at least for robots.txt, which I am doing the litmus test on:
private readonly IRobotsService _robotsService;
public HomeController(IRobotsService robotsService) {
_robotsService = robotsService;
}
The robots.txt method in my HomeController is similarly default for the boilerplate:
[NoTrailingSlash]
[OutputCache(CacheProfile = CacheProfileName.RobotsText)]
[Route("robots.txt", Name = HomeControllerRoute.GetRobotsText)]
public ContentResult RobotsText() {
Trace.WriteLine($"robots.txt requested. User Agent:<{Request.Headers.Get("User-Agent")}>.");
var content = _robotsService.GetRobotsText();
return Content(content, ContentType.Text, Encoding.UTF8);
}
The IRobotsService and RobotsService files are also default for the boilerplate - they are completely unmodified (aside from removing comments for brevity):
namespace Project.Website.Services {
public interface IRobotsService {
string GetRobotsText();
}
}
namespace Project.Website.Services {
using Boilerplate.Web.Mvc;
using Constants;
using System.Text;
using System.Web.Mvc;
public sealed class RobotsService : IRobotsService {
private readonly UrlHelper _urlHelper;
public RobotsService(UrlHelper urlHelper) => _urlHelper = urlHelper;
public string GetRobotsText() {
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("user-agent: *");
stringBuilder.AppendLine("disallow: /error/");
stringBuilder.Append("sitemap: ");
// Commented out so it wouldn't trigger the sitemap, which is not active:
//stringBuilder.AppendLine(_urlHelper.AbsoluteRouteUrl(HomeControllerRoute.GetSitemapXml).TrimEnd('/'));
return stringBuilder.ToString();
}
}
}
The original Startup.Container.cs for Autofac is quite extensive, but the robots.txt service is injected by:
builder.RegisterType<RobotsService>().As<IRobotsService>().InstancePerRequest();
When my UnityConfig.cs file has the following:
container.RegisterType<RobotsService>(new TransientLifetimeManager());
I get
The current type, JCI_Vernon.Website.Services.IRobotsService, is an interface and cannot be constructed. Are you missing a type mapping?
Which pretty well tells me I have to include IRobotsService, but when my UnityConfig file has the following:
container.RegisterType<IRobotsService, RobotsService>(new TransientLifetimeManager());
I get
The current type, System.Web.HttpContextBase, is an abstract class and cannot be constructed. Are you missing a type mapping?
I am unsure as to where I am going wrong, as all other Unity DI in my project is configured by using one of these two variants.
Any assistance would be greatly appreciated.
Edit: Including the Unity files from my primary project (the visible website).
UnityMvcActivator.cs:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(JCI_Vernon.Website.UnityMvcActivator), nameof(JCI_Vernon.Website.UnityMvcActivator.Start))]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(JCI_Vernon.Website.UnityMvcActivator), nameof(JCI_Vernon.Website.UnityMvcActivator.Shutdown))]
namespace JCI_Vernon.Website {
using System.Linq;
using System.Web.Mvc;
using Unity.AspNet.Mvc;
/// <summary>
/// Provides the bootstrapping for integrating Unity with ASP.NET MVC.
/// </summary>
public static class UnityMvcActivator {
/// <summary>
/// Integrates Unity when the application starts.
/// </summary>
public static void Start() {
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(UnityConfig.Container));
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
// Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>
/// Disposes the Unity container when the application is shut down.
/// </summary>
public static void Shutdown() {
UnityConfig.Container.Dispose();
}
}
}
UnityConfig.cs:
namespace JCI_Vernon.Website {
using Data;
using Domain;
using Identity;
using Microsoft.AspNet.Identity;
using Services;
using Store;
using System;
using System.Web;
using System.Web.Mvc;
using Unity;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Mvc5;
public static class UnityConfig {
public static IUnityContainer Container { get; internal set; }
public static void RegisterComponents() {
var container = new UnityContainer();
container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager(), new InjectionConstructor("DefaultConnection"));
container.RegisterType<IUserStore<IdentityUser, Guid>, UserStore>(new TransientLifetimeManager());
container.RegisterType<RoleStore>(new TransientLifetimeManager());
container.RegisterInstance<HttpContextBase>(new HttpContextWrapper(HttpContext.Current), new TransientLifetimeManager());
container.RegisterType<IRobotsService, RobotsService>(new Unity.AspNet.Mvc.PerRequestLifetimeManager());
//container.RegisterType<ISitemapService, SitemapService>(new InjectionConstructor());
//container.RegisterType<ISitemapPingerService, SitemapPingerService>(new InjectionConstructor());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
}
In my UnityMvcActivator.cs, I have had that one PerRequestLifetimeManager line both commented and uncommented with every change, no difference observed. Any attempt to use PerRequestLifetimeManager within UnityConfig.cs without Unity.Mvc (as using Unity.AspNet.Mvc;) failed.
Changing UnityConfig.cs to include Unity.AspNet.Mvc caused mass borkage: while I was able to get PerRequestLifetimeManager to be accepted without obvious Intellisense error, UnityMvcActivator.cs suddenly couldn’t resolve its UnityConfig.Container entries without a very odd entry at the top of UnityConfig.cs:
public static IUnityContainer Container { get; internal set; }
And the SetResolver in UnityConfig.cs needed to explicitly state new Unity.Mvc5.UnityDependencyResolver(container) in order to not trigger Intellisense confusion.
Plus, when run, the following error occurred:
Could not load file or assembly 'Unity.Abstractions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=6d32ff45e0ccc69f' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
Why it is trying to target a v3.x of Unity despite the entire solution having been created under v5.x is causing my grey matter no end of meltdown. And yes, I did a full clean and rebuild of the entire solution, plus individual projects.
Edit 2:
May have come across an interesting wrinkle. On a lark, I decided to do a full reinstallation of all NuGet packages, a refresh of sorts. Naturally, when you do an upgrade or reinstall of Unity, it tries to overwrite your unity files, which is why you always need to have your UnityConfig.cs backed up otherwise your registrations will vanish. Happens to me with every. Single. F##cking. Project. So annoying.
So anyhow, I did a full refresh, and my UnityConfig.cs suddenly underwent a major change. Before it was as above, including all upgrades within v5, but the refresh provided me with the following (comments removed for brevity):
namespace JCI_Vernon.Website {
using System;
using Unity;
public static class UnityConfig {
#region Unity Container
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() => {
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer Container => container.Value;
#endregion
public static void RegisterTypes(IUnityContainer container) {
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
}
}
}
Ya, weird. Major change with no clue why. The old version works just fine, it just blows its cookies all over the specific type mapping this post is about.
Plus, I have to idea what to change the Global.cs entry to in order to load my type mappings, as just using the obvious (changing UnityConfig.RegisterComponents(), which cannot be found, to UnityConfig.RegisterTypes()) does not make any sense -- how do I pass in the container?
There are a couple of issues here. First of all, this line:
container.RegisterType<RobotsService>(new TransientLifetimeManager());
is not the equivalent of:
builder.RegisterType<RobotsService>().As<IRobotsService>().InstancePerRequest();
It should instead be:
container.RegisterType<IRobotsService, RobotsService>(new TransientLifetimeManager());
Keep in mind Autofac type mappings use the concrete type first, and then the interface type. This is backward from most other DI containers.
The last error message indicates you need to register HttpContextBase with Unity. You do that by wrapping HttpContext.Current with HttpContextWrapper.
container.RegisterInstance<HttpContextBase>(new HttpContextWrapper(HttpContext.Current), new TransientLifetimeManager());

How do I setup Windsor container on a console application to inject to external library

I have a console app and web API both referencing the same data layer which is a separate project.
In that data layer, I have a class that requires a repository that we are grabbing from the container when that class is instantiated.
In that class, it has a base class which we are doing the following in the constructor to setup the Repository:
IContainerAccessor containerAccessor = HttpContext.Current.ApplicationInstance as IContainerAccessor;
Repository = containerAccessor.Container.Resolve<IRepository>();
What would be the best way to set this up? This is obviously a problem for our console application as it has no HttpContext.
If I'm correct you want to setup your console app so it can inject classes from the shared data layer.
To do so, you need to create an installer for the console app and tell it to run the installers in the shared library, but to modify the life style from 'PerWebRequest' to 'Singleton' or 'Transient'.
For more information read this article:
http://blog.ploeh.dk/2010/04/26/ChangingWindsorlifestylesafterthefact/
Be aware that changing this may cause problems.
I.e.: If multiple components configured as "perWebRequest" require a 'Unit-Of-Work' to be injected, then this uow will be different for all components if you change the life style to transient.
Changing it to Singleton causes the same but opposite problem. Objects that are created now will have the same object for different requests ...
If you are okay with the problems this code should get you starting
public class ConsoleAppInstaller: IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// 1) make sure we do not use PerWebRequest life style types
var convertWebToTransient = new WebToTransientConvertor();
container.Kernel.ComponentModelBuilder.AddContributor(convertWebToTransient);
// 2) call installers on all libraries we use ...
container.Install(FromAssembly.Containing<SharedDataLayerInstaller>());
// 3) link internal services ...
container.Register(Component.For<IXxxxFactory>().AsFactory());
container.Register(Component.For<IYyyyFactory>().AsFactory());
container.Register(Classes.FromThisAssembly().Where(c => typeof(Form).IsAssignableFrom(c)).LifestyleTransient());
}
public static IWindsorContainer Bootstrap()
{
return new WindsorContainer().Install(FromAssembly.This());
}
}
/// <summary>
/// This class allows to intercept installers using PerWebRequest lifestyles and replaces them with Transient life styles.
/// <code>container.Kernel.ComponentModelBuilder.AddContributor(new WebToTransientConvertor())</code>
/// </summary>
public class WebToTransientConvertor : IContributeComponentModelConstruction
{
//http://blog.ploeh.dk/2010/04/26/ChangingWindsorlifestylesafterthefact/
public void ProcessModel(IKernel kernel, ComponentModel model)
{
if (model.LifestyleType == LifestyleType.PerWebRequest)
//model.LifestyleType = LifestyleType.Transient;
model.LifestyleType = LifestyleType.Singleton;
}
}

StructureMap Convention - Differences between Registy.AddType and Registry.For().Use()

Short question. Exists some diference between registry.AddType(pluginType, type); and registry.For(pluginType).Use(type); ?
Code:
public class BasicConvention : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (something)
registry.For(pluginType).Use(type).Singleton();
}
}
}
and
public class BasicConvention : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (something)
registry.AddType(pluginType, type);
}
}
}
Using WhatDoIHave() I can see the same:
Using AddType:
===============================================================================================================================================================================================================================================================================
PluginType Namespace Lifecycle Description Name
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession Paf.Application.Session Transient Paf.Application.Session ('Paf.Application.Session, Paf.Modules.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null') Paf.Application.Session,... (Default)
===============================================================================================================================================================================================================================================================================
Using For().Use():
===============================================================================================================================================================================================================================================================================
PluginType Namespace Lifecycle Description Name
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession Paf.Application.Session Singleton Paf.Application.Session (Default)
===============================================================================================================================================================================================================================================================================
The only difference is in the description ...
Somebody?
The call to registry.AddType(pluginType, type) is basically shorthand for chaining together For and Use as in registry.For(pluginType).Use(type).
Calling registry.AddType(pluginType, type) causes a direct call to Registry.alter.set with the plugin type and the concrete type specified together.
Calling registry.For(pluginType).Use(type) chains together For and Use. The call to For returns a new GenericFamilyExpression (the constructor calls Registry.alter.set for the interface type), and the call to Use ends up calling Registry.alter.set to make the concrete type the default for the plugin family.
See the source code for Registry.cs and GenericFamilyExpression.cs, and other classes in the StructureMap source.
The accepted answer is not entirely correct. They are not the same. Which is surprisingly is indicated at the end of an answer. Use will set default instance for plugin (type) and AddType will not. So you will not be able to use Structure map as service locator with AddType. You can have this error No default Instance is registered and cannot be automatically determined for type <type>

How to resolve types registered in other Modules in Prism?

I'm registering few modules in my Prism application using UnityBootstrapper
protected override IModuleCatalog GetModuleCatalog()
{
var catalog = new ModuleCatalog();
catalog
.AddModule(typeof(LoginModule))
.AddModule(typeof(AppModule))
.AddModule(typeof(DataTransformationModule), InitializationMode.OnDemand)
.AddModule(typeof(SyncModule), InitializationMode.OnDemand);
return catalog;
}
Later I'm loading those modules which are set to load OnDemand dynamically in response to user actions. Though I were able to load modules OnDemand from other modules, types I registered in OnDemand loading modules were not getting Resolved.
public class SyncModule : IModule
{
private readonly IUnityContainer container;
public SyncModule(IUnityContainer container)
{
this.container = container;
}
public void Initialize()
{
this.RegisterViewsAndServices();
ISyncController controller = this.container.Resolve<ISyncController>();
controller.Run();
}
protected void RegisterViewsAndServices()
{
this.container.RegisterType<ISyncController, SyncController>();
this.container.RegisterType<ISyncAnchorsRepository, SyncAnchorsRepository>();
this.container.RegisterType<ISyncService, SyncService>();
this.container.RegisterType<IView, SynchronizeView>("SynchronizeView");
this.container.RegisterType<IView, SyncTrayView>("SyncTrayView");
}
}
When I try to load any of the types registered in SyncModule (shown above) from another Module compiler throws an ResolutionFailedException since each module is . Is there anyway to inject same instance of IUnityContainer to all Modules? (Is it going to be a abuse of Prism?)
Look at the full message of the ResolutionFailedException. Altough somewhat criptic, it usually contains detailed information about what has failed. Usually this exception is thrown for a problem not on the type being resolved itself, but on one of the dependencies injected via constructor parameters.
My mistake. I was using Type.GetType without fully qualified name of the assembly to dynamically load types from other Modules. Types registered to Unity container from modules are available for resolution elsewhere.

Resources