How do I resolve an instance of a class with the new Unity 5.0.0 Resolve() method?
In Unity 4.0.1 I resolved an instances like the example given below with SettingsContext. But this no longer works.
I am thinking it is a matter of giving a second argument to Resolve, but I am not sure howto.
var _unity = UnityConfig.GetConfiguredContainer();
var _settings = _unity.Resolve<SettingsContext>();
With UnityConfig class being defined as
public class UnityConfig
{
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
public static void RegisterTypes(IUnityContainer unity)
{
//all the unity.RegisterType calls
}
}
As normal, load the container.
Next load the named section - the default is "unity", but it could be any tag you want in the config file.
Finally, have the section object configure the container.
var c = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Configure(c);
var ss = c.Resolve<IStorageSystem>();
For the app|web.config, be sure to reference the updated type definition (see assembly).
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="FileBox.IStorageSystem, FileBox" mapTo="FileBox.StorageSystem.Local.LocalFileSystem, FileBox" >
<constructor>
<param name="root">
<value value =""/>
</param>
</constructor>
</register>
</container>
Related
I have trouble to use Unity on this project.
The error is
The current type, Business.Interfaces.IPersonnelBusiness, is an
interface and cannot be constructed. Are you missing a type mapping?
I've updated the Unity to thge latest version because of stackoverflow issueand I saw that RegisterComponents has changed to lazy loaded one
here is the Global asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Unity settings
//UnityConfig.RegisterComponents();
// For logging
//SetupSemanticLoggingApplicationBlock();
}
Here is the UnityConfig file:
public static class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Configured Unity Container.
/// </summary>
public static IUnityContainer Container
{
get
{
return container.Value;
}
}
#endregion
/// <summary>
/// Registers the type mappings with the Unity container.
/// </summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>
/// There is no need to register concrete types such as controllers or
/// API controllers (unless you want to change the defaults), as Unity
/// allows resolving a concrete type even if it was not previously
/// registered.
/// </remarks>
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below.
// Make sure to add a Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
container = new UnityContainer();
// Identity managment
container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());
container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<AccountController>(new InjectionConstructor());
container.RegisterType<PersonnelController>(new InjectionConstructor());
container.RegisterType<UsersAdminController>(new InjectionConstructor());
// Business Layer
container.RegisterType<ILogBusiness, LogBusiness>();
container.RegisterType<IAnomalyBusiness, AnomalyBusiness>();
container.RegisterType<ICockpitStatBusiness, CockpitStatsBusiness>();
container.RegisterType<IDocumentBusiness, DocumentBusiness>();
container.RegisterType<IEmailBusiness, EmailBusiness>();
container.RegisterType<IMessageBusiness, MessageBusiness>();
container.RegisterType<INatureBusiness, NatureBusiness>();
container.RegisterType<IPersonnelBusiness, PersonnelBusiness>();
container.RegisterType<ISAPBusiness, SAPBusiness>();
// Set resolver
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
Thanks folks
EDIT:
here is the stack and the code where it is thrown:
StackTrace:
[ResolutionFailedException: Resolution of the dependency failed, type = 'APPI.WEB.Controllers.HomeController', name = '(none)'.
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, APPI.Business.Interfaces.IPersonnelBusiness, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:
Resolving APPI.WEB.Controllers.HomeController,(none)
Resolving parameter 'personnelRepo' of constructor APPI.WEB.Controllers.HomeController(APPI.Business.Interfaces.IPersonnelBusiness personnelRepo, APPI.Business.Interfaces.IAnomalyBusiness anomalyRepo, APPI.Business.Interfaces.IDocumentBusiness docRepo, APPI.Business.Interfaces.IMessageBusiness msgRepo, APPI.Business.Interfaces.ICockpitStatBusiness cockpitStatRepo, APPI.Business.Interfaces.INatureBusiness natureRepo)
Resolving APPI.Business.Interfaces.IPersonnelBusiness,(none)
]
Controller:
public class HomeController : BaseController
{
private readonly IPersonnelBusiness _IPersonnelBusinessRepo;
private readonly IAnomalyBusiness _IAnomalyBusinessRepo;
private readonly IDocumentBusiness _IDocumentBusinessRepo;
private readonly IMessageBusiness _IMessageBusinessRepo;
private readonly ICockpitStatBusiness _ICockpitStatBusinessRepo;
private readonly INatureBusiness _INatureBusinessRepo;
// Unity inject references
public HomeController(IPersonnelBusiness personnelRepo, IAnomalyBusiness anomalyRepo, IDocumentBusiness docRepo,
IMessageBusiness msgRepo, ICockpitStatBusiness cockpitStatRepo, INatureBusiness natureRepo)
{
_IPersonnelBusinessRepo = personnelRepo;
_IAnomalyBusinessRepo = anomalyRepo;
_IDocumentBusinessRepo = docRepo;
_IMessageBusinessRepo = msgRepo;
_ICockpitStatBusinessRepo = cockpitStatRepo;
_INatureBusinessRepo = natureRepo;
}
public HomeController()
{
}
public ActionResult Index()
{
return RedirectToActionPermanent("Cockpit", "Home");
}
There is also the UnityActivator that is called before starting app thanks to
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(APPI.WEB.UnityMvcActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(APPI.WEB.UnityMvcActivator), "Shutdown")]
UnityActivator:
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();
}
}
As pointed out in the comments, the issue is that you are instantiating 2 different containers, once in your initializer:
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer(); // <-- new container here
RegisterTypes(container);
return container;
});
And once in your RegisterTypes method:
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below.
// Make sure to add a Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
container = new UnityContainer(); // <-- new container here
...
The type mappings are added in the RegisterTypes method to a different instance than the container you are passing in as an argument.
To make it work right, you should remove the instantiation of the container in RegisterTypes so it can use the instance that is passed in the parameter.
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below.
// Make sure to add a Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
// container = new UnityContainer(); // <-- Remove this
...
I have a simple structure of classes, interfaces as follows:
public interface IMessagingClient (interface supporting service bus queue operation)
public class ServiceBusMessagingClient : IMessagingClient (real implementation)
public class MockMessagingClient : IMessagingClient (mock implementation for our unit test)
public class FailoverMessagingClient : IMessagingClient (this implementation internally uses 2 clients and switches roles b/w 2 as and when disaster in a datacenter occur)
{
private IMessagingClient PrimaryClient { get; set; }
private IMessagingClient SecondaryClient { get; set; }
}
We load unity config from web.config/app.config and use it in our product code and test code.
We want following:
For production scenario, PrimaryClient and SecondaryClient should of type ServiceBusMessagingClient
For Test scenario, PrimaryClient and SecondaryClient should of type MockMessagingClient
Our current unity config looks like:
<container name="azure">
<register type="IMessagingClient" mapTo="FailoverMessagingClient"/>
</container>
Do we have to use some interceptors to achieve this? Or by defining a ctor in FailoverMessagingClient and using ctor injection?
Some suggestions would be great!
You can do this using named registrations.
For example, given the following example set up:
namespace ConsoleApplication8
{
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
public interface IMessagingClient { }
public class ServiceBusMessagingClient : IMessagingClient { }
public class MockMessagingClient : IMessagingClient { }
public class FailoverMessagingClient : IMessagingClient
{
private readonly IMessagingClient primaryClient;
private readonly IMessagingClient secondaryClient;
public FailoverMessagingClient(IMessagingClient primaryClient, IMessagingClient secondaryClient)
{
this.primaryClient = primaryClient;
this.secondaryClient = secondaryClient;
}
}
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer().LoadConfiguration();
var failOverMessagingClient = container.Resolve<IMessagingClient>("Two");
}
}
}
you can hook up the dependencies using the app.config
<?xml version="1.0" encoding="utf-8" ?>
<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="IMessagingClient" type="ConsoleApplication8.IMessagingClient, ConsoleApplication8" />
<alias alias="ServiceBusMessagingClient" type="ConsoleApplication8.ServiceBusMessagingClient, ConsoleApplication8" />
<alias alias="MockMessagingClient" type="ConsoleApplication8.MockMessagingClient, ConsoleApplication8" />
<alias alias="FailoverMessagingClient" type="ConsoleApplication8.FailoverMessagingClient, ConsoleApplication8" />
<container>
<register type="IMessagingClient" name="One" mapTo="ServiceBusMessagingClient" />
<register type="IMessagingClient" name="Two" mapTo="FailoverMessagingClient">
<constructor>
<param name="primaryClient">
<dependency type="IMessagingClient" name="One" />
</param>
<param name="secondaryClient">
<dependency type="IMessagingClient" name="One" />
</param>
</constructor>
</register>
</container>
</unity>
</configuration>
Changing the line
<register type="IMessagingClient" name="One" mapTo="ServiceBusMessagingClient" />
to
<register type="IMessagingClient" name="One" mapTo="MockMessagingClient" />
will allow you to swap out your implementation of IMessagingClient as appropriate.
Personally, I would rather do this using the fluid syntax
var container = new UnityContainer();
container.RegisterType<IMessagingClient, ServiceBusMessagingClient>("One");
container.RegisterType<IMessagingClient, FailoverMessagingClient>("Two",
new InjectionConstructor(new ResolvedParameter<IMessagingClient>("One"), new ResolvedParameter<IMessagingClient>("One")));
var failOverMessagingClient = container.Resolve<IMessagingClient>("Two");
When using the unity container, you can override an existing registration by registering it again for a different class.
For example:
If you run this code:
container.RegisterType<IMessagingClient, ServiceBusMessagingClient>();
container.RegisterType<IMessagingClient, MockMessagingClient>();
The first registration is overridden and so IMessagingClient is mapped to MockMessagingClient. Its like the first line never executed.
You can use this fact, and in your unit test (in the arrange phase or in the setup method of your test class), simply register the IMessagingClient to the mock implementation like this (after loading the XML configuration):
container.RegisterType<IMessagingClient, MockMessagingClient>();
By the way, you might not want to use DI containers in unit tests. Take a look at this question.
What I am trying to achieve: Have Unity load the mappings from a configuration file, then in source code resolve the types which were loaded from said configuration file
App.Config
<register type="NameSpace.ITill, ExampleTightCoupled" mapTo="NameSpace.Till, NameSpace" />
<register type="NameSpace.IAnalyticLogs, NameSpace" mapTo="NameSpace.AnalyticLogs, NameSpace" />
Code
IUnityContainer container;
container = new UnityContainer();
// Read interface->type mappings from app.config
container.LoadConfiguration();
// Resolve ILogger - this works
ILogger obj = container.Resolve<ILogger>();
// Resolve IBus - this fails
IBus = container.Resolve<IBus>();
Issue: Sometimes IBus will be defined in the App.config, and sometimes it will not be there. When I try and resolve an interface/class and it does not exist I get an exception.
Can someone educate me here?
Thanks,
Andrew
What version of Unity are you using? In v2+ there is an extension method:
public static bool IsRegistered<T>(this IUnityContainer container);
so you can do
if (container.IsRegistered<IBus>())
IBus = container.Resolve<IBus>();
An extension method would make this nicer
public static class UnityExtensions
{
public static T TryResolve<T>(this IUnityContainer container)
{
if (container.IsRegistered<T>())
return container.Resolve<T>();
return default(T);
}
}
// TryResolve returns the default type (null in this case) if the type is not configured
IBus = container.TryResolve<IBus>();
Also check out this link: Is there TryResolve in Unity?
This is my dad class
public class Dad
{
public string Name
{
get;set;
}
public Dad(string name)
{
Name = name;
}
}
This is my test method
public void TestDad()
{
UnityContainer DadContainer= new UnityContainer();
Dad newdad = DadContainer.Resolve<Dad>();
newdad.Name = "chris";
Assert.AreEqual(newdad.Name,"chris");
}
This is the error I am getting
"InvalidOperationException - the type String cannot be constructed.
You must configure the container to supply this value"
How do I configure my DadContainer for this assertion to pass?
Thank you
You should provide a parameterless constructor:
public class Dad
{
public string Name { get; set; }
public Dad()
{
}
public Dad(string name)
{
Name = name;
}
}
If you can't provide a parameterless constructor, you need to configure the container to provide it, either by directly registering it with the container:
UnityContainer DadContainer = new UnityContainer();
DadContainer.RegisterType<Dad>(
new InjectionConstructor("chris"));
or through the app/web.config file:
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity>
<containers>
<container>
<register type="System.String, MyProject">
<constructor>
<param name="name" value="chris" />
</constructor>
</register >
</container>
</containers>
</unity>
I am trying to create an ASP.NET MVC application, using Spring.NET to inject dependencies. The application has three tiers: Controller, Service, and Data.
I have defined the objects in the file "~\Resources\objects.xml".
My first object, UserAccountController, requires the injecion of two Service-tier classes: UserAccountService and DepartmentService. So, the definition in objects.xml looks like this:
<object id="UserAccountController" type="App.Controllers.UserAccountController, App">
<constructor-arg index="0" ref="DepartmentService" />
<constructor-arg index="1" ref="UserAccountService" />
</object>
<object id="UserAccountService" type="App.Service.UserAccountService, App">
<property name="UserAccountDao" ref="UserAccountDao" />
</object>
<object id="UserAccountDao" type="App.Data.UserAccountDao, App" />
<object id="DepartmentService" type="App.Service.DepartmentService, App">
<property name="DepartmentDao" ref="DepartmentDao" />
</object>
<object id="DepartmentDao" type="App.Data.DepartmentDao" />
Webconfig contains this:
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="~/Resources/objects.xml" />
</context>
</spring>
I would prefer to use Property injection rather than constructor, but currently neither method is working.
Well, it turned out to be that ASP.NET MVC and Spring.NET just don't get along...
However, the MvcContrib package (actually, the Extras package) seems to have solved the issue. The package had a Spring Controller factory implementation that worked, and everything was happy.
(Kind of reminds me of trying to make Struts 1.X and Spring work on the Java side...)
in your bootstrapclass you have to load the spring container
ContextRegistry.getContext();
by the way you need to specify the assembly name for DepartmentDao
<object id="DepartmentDao" type="App.Data.DepartmentDao, App" />
Further information: I also have classes for SpringApplicationController and SpringControllerFactory:
SpringApplicationController.cs:
public static class SpringApplicationContext
{
private static IApplicationContext Context { get; set; }
/// <summary>
/// Returns a boolean value if the current application context contains an named object.
/// </summary>
/// <param name="objectName">Accepts the name of the object to check.</param>
public static bool Contains(string objectName)
{
SpringApplicationContext.EnsureContext();
return SpringApplicationContext.Context.ContainsObject(objectName);
}
/// <summary>
/// Return a instance of an object in the context by the specified name.
/// </summary>
/// <param name="objectName">Accepts a string object name.</param>
public static object Resolve(string objectName)
{
SpringApplicationContext.EnsureContext();
return SpringApplicationContext.Context.GetObject(objectName);
}
/// <summary>
/// Return a instance of an object in the context by the specified name and type.
/// </summary>
/// <typeparam name="T">Accepts the type of the object to resolve.</typeparam>
/// <param name="objectName">Accepts a string object name.</param>
public static T Resolve<T>(string objectName)
{
return (T)SpringApplicationContext.Resolve(objectName);
}
private static void EnsureContext()
{
if (SpringApplicationContext.Context == null)
{
SpringApplicationContext.Context = ContextRegistry.GetContext();
}
}
}
SpringControllerFactory.cs:
public class SpringControllerFactory : DefaultControllerFactory
{
public IController CreateController(RequestContext context, Type controllerType)
{
IResource input = new FileSystemResource(context.HttpContext.Request.MapPath("Resource\\objects.xml"));
IObjectFactory factory = new XmlObjectFactory(input);
return (IController) factory.GetObject(controllerType.Name);
}
public IController CreateController(RequestContext context, string controllerName)
{
IController controller = null;
string controllerClassName = string.Format("{0}Controller", controllerName);
if (SpringApplicationContext.Contains(controllerClassName))
{
controller = SpringApplicationContext.Resolve<IController>(controllerClassName);
this.RequestContext = context;
}
else
{
controller = base.CreateController(context, controllerName);
}
return controller;
}
public override void ReleaseController(IController controller)
{
IDisposable disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
I reference this in my Global.asax as follows:
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(typeof(App.Util.SpringControllerFactory));
RegisterRoutes(RouteTable.Routes);
}