Unity named mapping issue - c#

I have two implementations of IEmailService, one for testing and one for live (is-A). And I have a BusinessService that has-A IEmailService reference.
BusinessService
IEmailService (has-A)
IEmailService
TestEmailService (is-A)
LiveEmailService (is-A)
In unity config, I register the two IEmailService implementations as follows.
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="DataAccess.IEmailService, DataAccess"
mapTo="DataAccess.LiveEmailService, DataAccess"
name="Live">
<lifetime type="singleton" />
</register>
<register type="DataAccess.IEmailService, DataAccess"
mapTo="DataAccess.TestEmailService, DataAccess"
name="Test">
<lifetime type="singleton" />
</register>
<container>
</unity>
Based on the appSetting for IEmailService I want Unity to pick the correct implementation. This will help while testing.
<appSettings>
<add key="IEmailService" value="Test"/>
</appSettings>
The issue is when unity resolves BusinessService, it tries to resolve (none) named mapping of IEmailService instead of Live or Test and throws an ResolutionFailedException.
container.Resolve<BusinessService>(); throws below exception:
BusinessServices.Test.BusinessServiceTest_Integration.Test103:
Microsoft.Practices.Unity.ResolutionFailedException : Resolution of the dependency failed, type = "BusinessServices.BusinessService", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, DataAccess.IEmailService, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:
Resolving BusinessServices.BusinessService,(none)
Resolving parameter "emailService" of constructor BusinessServices.BusinessService(DataAccess.IEmailService emailService)
Resolving DataAccess.IEmailService,(none)
----> System.InvalidOperationException : The current type, DataAccess.IEmailService, is an interface and cannot be constructed. Are you missing a type mapping?
The workaround I came up with is to specify the registrations in code as well and have a wrapper method around container.RegisterType to register IEmailService with (none) named mapping as well based on the appSetting value.
IUnityContainer container;
// registering unity
static void Load()
{
container = new UnityContainer().LoadConfiguration();
RegisterType<IEmailService, TestEmailService>("Test");
RegisterType<IEmailService, LiveEmailService>("Live");
}
// register the `Test` or `Live` implementation with `(none)` named mapping as per appSetting
static void RegisterType<TFrom, TTo>(string name)
where TTo : TFrom
{
var tFromAppSetting= ConfigurationManager.AppSettings[typeof(TFrom).Name];
if (!string.IsNullOrEmpty(tFromAppSetting) && tFromAppSetting == name)
container.RegisterType<TFrom, TTo>();
}
This works, but I end up specifying the registrations in two places - config as well as code. Is there a better way for doing this?
Update
I actually had got it correct by code. I do not need the unity config at all. The RegisterType<TFrom, TTo>(string name) registers either the Test or Live implementation as (none) named mapping depending on appSetting value. BusinessService is also resolved without exception.
As there is no unity config, I do not have load the configuration.
container = new UnityContainer();

In my opinion the only point of having registrations in config is to not have them in code and being able to replace implementation without recompilation. So you are write in trying to remove it form code. What I don't understand is why you want to have both registrations in config in the first place. Simply remove the Live one from config for tests and the Test from config for application and register them both without name.
So for instance in application app.config:
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="DataAccess.IEmailService, DataAccess"
mapTo="DataAccess.LiveEmailService, DataAccess">
<lifetime type="singleton" />
</register>
Since you really are determent to do it your way:
The other way around this is to register in code only a way of determining which instance is the default one:
container.RegisterType<IEmailService>(new InjectionFactory((c)=>
{
var name = GetImplementationsNameFromAppSettings();
return c.Resolve<IEmailService>(name);
});

Related

FW: Unexpected result upon unnamed registration of the same mapTo with different mapFrom with injectedProperties

We are seeing unexpected behavior from Unity when registering the same concrete class to different unnamed instances. In this scenario, the registrations appear to interfere with each other in unexpected ways.
We provide a framework to other applications where we want to inject
different interfaces (i.e. different views on a common concept) with
potentially the same class that may be initialized in different ways,
either with different injected parameters and/or different values.
When the framework uses the class via one interface it can expect
potentially different behavior than when it uses the class via a
different interface.We therefore register two interfaces with the
same mapTo class with different initializations (and potentially
lifetimes).It is logical to expect that when we register type by
different interfaces in Unity that they do not interfere with each
other. This is true for named instances, but not for unnamed
instances.
There are three logical outcomes of attempting to
register different interfaces mapped to the same class:
Exception: during the second registration exception should be throwing. The exception is only expected if we believe this is misuse of the framework; we don’t believe this to be true.
Overwrite: the overwrite could make sense, but the internal representation of the current implementation seems to imply it is not designed to overwrite due to the augmentation of the parameters for the mapTo type. In the example code below we are registering 2 different interfaces mapped to the same class and each of them inject 2 properties. We can see that the value of container.policies.policies( of type ObjectBuilder.SpecifiedPropertiesSelectorPolicy) propertiesAndValues , contains 4 injected properties. In the case of overwriting, we are expecting would expect to see 2 injected properties initialized with values from the second registration. Outcome of this behavior in case of registering several different types mapped to the same type and will inject in each of them some properties with values and some of them not (expecting to be not initialized) , the resolved instance will not have proper initialization of any registered types.
Independent registrations: all registration will be resolved properly , each of them will be injected with correct property values.
The independent registrations are what we expect, but does not work. It appears that the mapTo types are not managed based on the registered type but rather only on the mapTo type and the registered name. We would like to understand what the expected behavior is, and if the current behavior is expected, and if there is a clean way to achieve independent registrations.
Note that we have seen suggestions to name the registrations, but we don’t want to change our framework since it is in use, and generally we don’t want to force applications to conform to named instances for no logical reason.
The code attached demonstrates the unexpected behavior.
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
namespace TestUnity
{
public interface IBaseInterface
{
string BaseString { set; get; }
}
public interface IChildInterface : IBaseInterface
{
string ChildString { set; get; }
}
public class ChildClass : IChildInterface
{
public string BaseString { set; get; }
public string ChildString { set; get; }
}
public class ContainerClass
{
public IBaseInterface impl { set; get; }
}
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.LoadConfiguration();
// the expected result BaseString ="IBaseInterface_BaseString" & ChildString ="IBaseInterface_ChildString"
// the result is BaseString ="IChildInterface_BaseString" & ChildString ="IChildInterface_ChildString"
var iBaseInterface = container.Resolve<IBaseInterface>();
// the expected result BaseString ="IChildInterface_BaseString" & ChildString ="IChildInterface_ChildString"
var iChildInterface = container.Resolve<IChildInterface>();
//We expect test class will be initialize with BaseString ="IBaseInterface_BaseString" & ChildString ="IBaseInterface_ChildString"
//but the result is the expected result BaseString ="IChildInterface_BaseString" & ChildString ="IChildInterface_ChildString"
var testClass = container.Resolve<ContainerClass>("Test");
//The container.Registrations include both regestered types(IBaseInterface & IChildInterface)
foreach (var registration in container.Registrations)
{
Console.WriteLine(#"RegisteredType :{0} ,MappedToType :{1}", registration.RegisteredType, registration.MappedToType);
}
Console.ReadLine();
}
}
}
App.config
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IBaseInterface" type="TestUnity.IBaseInterface, TestUnity" />
<alias alias="IChildInterface" type="TestUnity.IChildInterface, TestUnity" />
<alias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity"/>
<container>
<register type="IBaseInterface" mapTo="TestUnity.ChildClass, TestUnity">
<lifetime type="transient"/>
<property name="BaseString" value="IBaseInterface_BaseString" />
<property name="ChildString" value="IBaseInterface_ChildString" />
</register>
<register type="IChildInterface" mapTo="TestUnity.ChildClass, TestUnity">
<lifetime type="transient" />
<property name="BaseString" value="IChildInterface_BaseString" />
<property name="ChildString" value="IChildInterface_ChildString" />
</register>
<register name="Test" type="TestUnity.ContainerClass, TestUnity" mapTo="TestUnity.ContainerClass, TestUnity">
<lifetime type="transient" />
<property name="impl" dependencyType="IBaseInterface" />
</register>
</container>
</unity>
</configuration>
TL;DR - Sorry, but this looks to be a limitation to Unity.
I'm not a member of the team that built Unity, so I can only speculate on the expected behavior as it is not explicitly documented for this specific scenario. But going by precedence with the other behaviors of Unity, I would have expected it to overwrite the previous registration's InjectionProperty.
You are correct that the object builder does not consider the registered type when looking up the policies for building up an instance of the object requested to be resolved. The object builder key is composed of the mapTo type and the name (see NamedTypeBuildKey). The way this key is created is integral to the internals of Unity's Object Builder. Attempting to add the registered type to this key in the pipeline would be much more customization than you would want to tackle. And I can't think of another way to introduce your desired behavior of independent registration based on the registered type (besides different concrete classes or multiple named registrations).

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'

When I try to set a PARAMETER using the Xml Configuration I get the following error:
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'LM.AM.Core.Services.EmailService' can be invoked with the available
services and parameters: Cannot resolve parameter 'System.String
testSmtp' of constructor 'Void .ctor(System.String)'.
Here are the relevant files:
web.config
<configSections>
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration" />
</configSections>
<autofac>
<components>
<component type="LM.AM.Core.Services.EmailService , LM.AM.Core" service="LM.AM.Core.Infrastructure.Services.IEmailService , LM.AM.Core.Infrastructure">
<parameters>
<parameter name="testSmtp" value="abc" />
</parameters>
</component>
</components>
</autofac>
Service Class
public class EmailService : IEmailService
{
public string _testSmtp;
public EmailService (string testSmtp)
{
_testSmtp = testSmtp;
}
}
Registration
builder.RegisterType<EmailService>().As<IEmailService>().SingleInstance();
Global.asax
var builder = new ContainerBuilder();
builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
builder.RegisterModule<Core.ModuleInstaller>();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
AutofacContainer.Container = builder.Build();
var emailSvc = AutofacContainer.Container.Resolve<IEmailService>();
I've checked the container is aware of the xml parameter and I've followed the Wiki as close as I can, but for some reason the parameter is not resolving on the only constructor and I'm receiving the above error.
This should be pretty simple to get going. Can anyone provide some suggestions on what I
can try to get this working?
You have regiestered your EmailService two times.
Once in the web.config and once with
builder.RegisterType<EmailService>().As<IEmailService>().SingleInstance();
If you have the line above in the Core.ModuleInstaller then it will override the web.config configuration. And because here you haven't specified the parameter Autofac throws an exception.
So to solve this just remove the EmailService registration from the Core.ModuleInstaller module.
If you use the Core.ModuleInstaller multiple places and you need to have the EmailService registration there then you need to change the order of the Module loading:
var builder = new ContainerBuilder();
builder.RegisterModule<Core.ModuleInstaller>();
builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
or tell Autofac to not override the registration of EmailService if it already exists with PreserveExistingDefaults:
builder.RegisterType<EmailService>().As<IEmailService>()
.SingleInstance().PreserveExistingDefaults();
I had created a constructor where there was none before and made it private, therefore there was default constructor so I got this error. Had to make my constructor public.
My registrations were all good, but I had referenced the concrete class instead of the interface in my constructor - Missed the 'I'.
Hope this answer helps someone save 5 minutes of effort one day.
Adding the service with appropriate scope(Singleton,Scoped,Transient) to the specified IServiceCollection instance helped to resolve this issue.
Something like below:
public static IServiceCollection YourServiceCollectionExtensionMethod(this IServiceCollection services)
{
services.AddTransient<IEmailService, EmailService>();
}
Hope this helps!

UNity Framework: Cannot find extension methods

I am trying to use container.LoadConfiguration and I dont see it in the intellisense. Do I need to install or download something?
Config
<unity>
<containers>
<container>
<types>
<type type="IMyInterface, someAssembly"
mapTo="MyObject, someAssembly" />
</types>
</container>
</containers>
code
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension.Configuration;
...
IUnityContainer _container = new UnityContainer();
UnityConfigurationSection section = (UnityConfigurationSection)System.
Configuration.ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(_container);
IEnumerable<IMyInterface> serviceList = _container.ResolveAll<IMyInterface>();
foreach (IMyInterface item in serviceList)
{
Console.Write("tet");
}
It does not go into the loop. It seems to configure ok. no errors.
If I understand your problem correctly, LoadConfiguration is not showing up in Intellisense.
I would try two things:
First makes sure you have included the Microsoft.Practices.Unity.Configuration assembly
Add an using statement for Microsoft.Practices.Unity.Configuration
LoadConfiguration is an extension method defined there.

Dependency injection with EF DbContext that implements 2 interfaces

Given a DbContext that implements 2 interfaces like so:
public interface IQueryEntities
{
IQueryable<User> Users { get; }
IQueryable<Computer> Computers { get; }
// other IQueryable<T> get properties
}
public interface IUnitOfWork
{
int SaveChanges();
}
public class MyContext : DbContext, IQueryEntities, IUnitOfWork
{
// implement interfaces using EF
}
First question, is it a bad idea to separate out the query aspects of DbContext (IDbSets) from the command aspects (SaveChanges)? I am exploring a refactor to the above because there are a lot of cases where we just need to query data, without saving anything.
The problem I'm running into involves unity DI, which currently injects MyDbContext using a singleton-per-http-context lifetime for the IUnitOfWork interface. I'm not sure how to go about setting up injection for the IQueryEntities interface so that it will reuse an existing DbContext instance that may have already been injected against the IUnitOfWork interface. Or vice versa. Is this even possible?
Here is the current lifetime manager that reuses previously-injected instances of IUnitOfWork in the same http context:
public class UnityHttpContextLifetimeManager : LifetimeManager
{
private const string KeyFormat = "SingletonPerCallContext_{0}";
private readonly string _key;
public UnityHttpContextLifetimeManager()
{
_key = string.Format(KeyFormat, Guid.NewGuid());
}
public override object GetValue()
{
return HttpContext.Current.Items[_key];
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[_key] = newValue;
}
public override void RemoveValue()
{
HttpContext.Current.Items.Remove(_key);
}
}
By the way if there is a way to do this, I would prefer to do it in unity web.config section rather than compiled c# bootstrapper.
Update
With help from onof I was able to get this working, however my config looks different from what he suggested. Am I doing something wrong? When I don't give each interface the lifetime manager, one HttpContext ends up with multiple instances of the DbContext. Only when I give all 3 the lifetime manager does it reuse the same DbContext instance across a single request for both interfaces. Is something wrong with this config?
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<namespace name="MyApp.MyNameSpace" />
<assembly name="MyApp" />
<alias alias="singleton-per-http-context"
type="MyApp.MyNameSpace.UnityHttpContextLifetimeManager, MyApp" />
<container>
<register type="MyContext">
<lifetime type="singleton-per-http-context" />
</register>
<register type="IUnitOfWork" mapTo="MyContext">
<lifetime type="singleton-per-http-context" />
</register>
<register type="IQueryEntities" mapTo="MyContext">
<lifetime type="singleton-per-http-context" />
</register>
...
</container>
is it a bad idea to separate out the query aspects of DbContext
(IDbSets) from the command aspects (SaveChanges)?
I think it's a good idea, because of Interface Segregation Principle, which states that each client should see only the interface it needs to do its work.
To register, i would do:
container.RegisterType<MyContext>(new UnityHttpContextLifetimeManager());
container.RegisterType<IQueryEntities, MyContext>();
container.RegisterType<IUnitOfWork, MyContext>();
AFAIK it's the only way to share the same instance, once the object created.
To do it at design-time (in web.config), it's straightforward:
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<namespace name="MyApp.MyNameSpace" />
<assembly name="MyApp" />
<container>
<register type="MyContext" >
<lifetime type="UnityHttpContextLifetimeManager" />
</register>
<register type="IQueryEntities" mapTo="MyContext" />
<register type="IUnitOfWork" mapTo="MyContext" />
</container>
You need to register one interface as singleton and the other will automatically follow.
container.RegisterType<IQueryEntities, MyContext>(new UnityHttpContextLifetimeManager());
container.RegisterType<IUnitOfWork, MyContext>();
Assuming that your LifetimeManager works correctly this would scope the lifetime of a instance of MyContext to the HttpContext and the mapping from IUnitOfWork would reuse the same instance as the target of the mapping is the same.

Unity Dependency Injection using a config file - cant resolve dependency

I'm using my app.config to tell Unity my interface to type mappings...
<unity>
<containers>
<container>
<types>
<type type="UnityDAL.Interfaces.IDataContextFactory, UnityDAL"
mapTo="UnityDAL.UnityDemoDataContextFactory, UnityDAL" />
<type type="UnityDAL.Interfaces.IProductRepository, UnityDAL"
mapTo="UnityDAL.ProductRepository, UnityDAL" />
<type name="productRepo"
type="UnityDAL.Interfaces.IProductRepository, UnityDAL"
mapTo="UnityDAL.ProductRepository, UnityDAL" />
and so on...
using this code
var wrapper = UnityWrapper.Create();
var productRepository =
wrapper.Container.Resolve<IProductRepository>("productRepo");
var productsBO = new ProductBO(productRepository);
var products = productsBO.GetAllProducts();
Here is the constructor for the wrapper object...
public UnityWrapper()
{
_container = new UnityContainer();
var section =
(UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(_container);
}
but I get an exception that says...
{"Resolution of the dependency failed, type = \"IProductRepository\",
name = \"productRepo\". Exception message is: The current build operation
(build key Build Key[UnityDAL.ProductRepository, productRepo]) failed:
The parameter dataContextFactory could not be resolved when attempting
to call constructor UnityDAL.ProductRepository(UnityDAL.Interfaces.
IDataContextFactory dataContextFactory). (Strategy type
Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy, index 2)"}
I thought this node was wiring that up
<type type="UnityDAL.Interfaces.IDataContextFactory, UnityDAL"
mapTo="UnityDAL.UnityDemoDataContextFactory, UnityDAL" />
The idea here was originally to create a nice dependency chain. Any idea what I'm doing wrong? If you have any advice or tips on how I can correct the problem, I would like to hear them. Thanks for any help.
Cheers,
~ck in San Diego
This is a mapping problem.
Trying to resolve the UnityDAL.Interfaces.IProductRepository you need to first resolve UnityDAL.Interfaces.IDataContextFactory. Next trying to resolve UnityDAL.UnityDemoDataContextFactory you miss some mapping. Probably the ctor of the UnityDAL.UnityDemoDataContextFactory requires something that has being not registered.
By the way: what you do here is using
a service location. I avoid this
practice if possible but if you
absolutely need this then try to
expose the common service
locator. This dll ships with Unity
and provides a simple service locator
ONLY interface.

Categories