I've come across some code that looks like this:
var something = this.container.Resolve<ICatManager>();
which in the web config has a mapping from ICatManager to CatManager.
However, CatManager has a constructor which takes 2 parameters, and no default constructor.
How does unity manage to create an instance of it?
Unity, and almost all other service container / service resolvers / service locators, work by analyzing the constructor(s) available, finding the "best one", then injecting parameters.
So, where does these parameters come from? From the service container itself.
For instance, if you have this service:
interface IService { ... }
class ServiceImplementation : IService
{
public ServiceImplementation(IOtherService os, IThirdService ts) { ... }
}
then when you resolve IService Unity will try to also resolve IOtherService and IThirdService recursively. If the actual classes that implement those services also require other services, it does this resolution recursively until everything is OK.
So basically you could think of the resolution call like this:
var os = container.Resolve<IOtherService>();
var ts = container.Resolve<IThirdService>();
return new ServiceImplementation(os, ts);
Related
I am reading about DI pattern in ASP.NET. I know it can create a instance inside another class. For example, we have class HomeController need to have service instance like this:
class HomeController{
private IService service;
public HomeController(IService s){
this.service = s;
}
}
IService is implemented by WaterService class.
And we have code to register class which can be created instance, the instance can be type of transient, scope or singleton:
using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IService , WaterService>();
var app = builder.Build();
Then I realize, if IService is implemented by both class WaterService and ElectricService, I have some situation, for example:
Call api to url .../service/waterService: show infomation of waterService.
Call api to url .../service/electricService: show inffomation of electricServic.
how can we register one of these class instance base on situation?
I had some problem but resolved by help of The Answer was given by Shahar Shokrani
Let me know if still facing to implement DI.
I have IDependency dependency, that is used in a huge amount of services.
There are two implementations of this dependency: DefaultDependency and CustomDependency.
DefaultDependency in most of services. CustomDependency should be used in small amount of services.
Code example that is not working because of several factories:
var container = new Container();
container.Register<IDependency, DefaultDependency>(Reuse.ScopedOrSingleton);
container.Register<IService, Service>(Reuse.ScopedOrSingleton, setup: Setup.With(openResolutionScope: true));
container.Register<IDependency, CustomDependency>(Reuse.ScopedTo<IService>());
var service = (Service)container.Resolve<IService>(); // Throws Error.ExpectedSingleDefaultFactory
Is it possible to increase priority of scoped to factory for CustomDependency or something like that? Or the only way to achieve it is to register DefaultDependency as ScopedTo to all services that should use it?
Dotnet fiddle: https://dotnetfiddle.net/wPA19s
UPDATE:
I was able to make it work with FactoryMethod, but maybe there is some cleaner way:
container.Register<CustomDependency>(Reuse.ScopedOrSingleton);
container.Register<IService, Service>(made: Made.Of(
factoryMethod: r => FactoryMethod.Of(typeof(Service).GetConstructorOrNull(args: new[] { typeof(IDependency) })),
parameters: Parameters.Of.Type<IDependency>(requiredServiceType: typeof(CustomDependency))));
Dotnet fiddle with working resolving of CustomDependency: https://dotnetfiddle.net/Znps9L
You may use the dependency condition from this answer
https://stackoverflow.com/a/34613963/2492669
Make the constructors of those that require CustomDependency take a ICustomDependency instead of IDependency.
interface ICustomDependency : IDependency {}
container.Register<IDependency, DefaultDependency>(Reuse.ScopedOrSingleton);
container.Register<ICustomDependency, CustomDependency>(Reuse.ScopedTo<IService>());
class ThatRequiresCustomDependency
{
public ThatRequiresCustomDependency(ICustomDependency cd) {}
}
I am working on a webapi project and using Unity as our IOC container. I have a set of layered dependencies something like the following:
unityContainer.RegisterType<BaseProvider, CaseProvider>(new HierarchicalLifetimeManager());
unityContainer.RegisterType<IRulesEngine, RulesEngine>();
unityContainer.RegisterType<IQuestionController, QuestionController>();
unityContainer.RegisterType<IAPIThing, WebAPIThing>();
Now the constructor for BaseProvider accepts an int as a parameter which is the Case identifier. WebAPIThing takes a BaseProvider in its constructor. Normally in a non web scenario I would inject the case id using something like:
public static IAPIThing GetIAPIThing(int caseId)
{
return CreateUnityContainer().Resolve<IAPIThing >(new ParameterOverride("caseId", caseId).OnType<CaseProvider>());
}
But that only works when I explicitly call that method. In a Web API scenario I am using a
config.DependencyResolver = new UnityDependencyResolver(unityContainer); to resolve my api controllers.
I would guess I will still need to influence how the DependencyResolver resolves that BaseProvider object at runtime.
Anyone had to do something similar?
EDIT 1
I have tried using the following which appears to work:
unityContainer.RegisterType<BaseProvider>(
new HierarchicalLifetimeManager()
, new InjectionFactory(x =>
new CaseProvider(SessionManager.GetCaseID())));
You are trying to inject a runtime value (the case id) into the object graph, which means you are complicating configuration, building, and verification of the object graph.
What you should do is promote that primitive value to its own abstraction. This might sound silly at first, but such abstraction will do a much better job in describing its functionality. In your case for instance, the abstraction should probably be named ICaseContext:
public interface ICaseContext
{
int CurrentCaseId { get; }
}
By hiding the int behind this abstraction we effectively:
Made the role of this int very explicit.
Removed any redundancy with any other values of type int that your application might need.
Delayed the resolving of this int till after the object graph has been built.
You can define this ICaseContext in a core layer of your application and everybody can depend on it. In your Web API project you can define a Web API-specific implementation of this ICaseContext abstraction. For instance:
public class WebApiCaseContext : ICaseContext
{
public int CurrentCaseId
{
get { return (int)HttpContext.Current.Session["CaseId"];
}
}
This implementation can be registered as follows:
unityContainer.RegisterType<ICaseContext, WebApiCaseContext>();
UPDATE
Do note that your own new CaseProvider(SessionManager.GetCaseID()) configuration does not solve all problems, because this means that there must be a session available when verifying the object graph, which will neither be the case during application startup and inside a unit/integration test.
Using SimpleInjector, I am trying to register an entity that depends on values retrieved from another registered entity. For example:
Settings - Reads settings values that indicate the type of SomeOtherService the app needs.
SomeOtherService - Relies on a value from Settings to be instantiated (and therefore registered).
Some DI containers allow registering an object after resolution of another object. So you could do something like the pseudo code below:
container.Register<ISettings, Settings>();
var settings = container.Resolve<ISettings>();
System.Type theTypeWeWantToRegister = Type.GetType(settings.GetTheISomeOtherServiceType());
container.Register(ISomeOtherService, theTypeWeWantToRegister);
SimpleInjector does not allow registration after resolution. Is there some mechanism in SimpleInjector that allows the same architecture?
A simple way to get this requirement is to register all of the available types that may be required and have the configuration ensure that the container returns the correct type at run time ... it's not so easy to explain in English so let me demonstrate.
You can have multiple implementations of an interface but at runtime you want one of them, and the one you want is governed by a setting in a text file - a string. Here are the test classes.
public interface IOneOfMany { }
public class OneOfMany1 : IOneOfMany { }
public class OneOfMany2 : IOneOfMany { }
public class GoodSettings : ISettings
{
public string IWantThisOnePlease
{
get { return "OneOfMany2"; }
}
}
So let's go ahead and register them all:
private Container ContainerFactory()
{
var container = new Container();
container.Register<ISettings, GoodSettings>();
container.RegisterAll<IOneOfMany>(this.GetAllOfThem(container));
container.Register<IOneOfMany>(() => this.GetTheOneIWant(container));
return container;
}
private IEnumerable<Type> GetAllOfThem(Container container)
{
var types = OpenGenericBatchRegistrationExtensions
.GetTypesToRegister(
container,
typeof(IOneOfMany),
AccessibilityOption.AllTypes,
typeof(IOneOfMany).Assembly);
return types;
}
The magic happens in the call to GetTheOneIWant - this is a delegate and will not get called until after the Container configuration has completed - here's the logic for the delegate:
private IOneOfMany GetTheOneIWant(Container container)
{
var settings = container.GetInstance<ISettings>();
var result = container
.GetAllInstances<IOneOfMany>()
.SingleOrDefault(i => i.GetType().Name == settings.IWantThisOnePlease);
return result;
}
A simple test will confirm it works as expected:
[Test]
public void Container_RegisterAll_ReturnsTheOneSpecifiedByTheSettings()
{
var container = this.ContainerFactory();
var result = container.GetInstance<IOneOfMany>();
Assert.That(result, Is.Not.Null);
}
As you already stated, Simple Injector does not allow mixing registration and resolving instances. When the first type is resolved from the container, the container is locked for further changes. When a call to one of the registration methods is made after that, the container will throw an exception. This design is chosen to force the user to strictly separate the two phases, and prevents all kinds of nasty concurrency issues that can easily come otherwise. This lock down however also allows performance optimizations that make Simple Injector the fastest in the field.
This does however mean that you sometimes need to think a little bit different about doing your registrations. In most cases however, the solution is rather simple.
In your example for instance, the problem would simply be solved by letting the ISomeOtherService implementation have a constructor argument of type ISettings. This would allow the settings instance to be injected into that type when it is resolved:
container.Register<ISettings, Settings>();
container.Register<ISomeOtherService, SomeOtherService>();
// Example
public class SomeOtherService : ISomeOtherService {
public SomeOtherService(ISettings settings) { ... }
}
Another solution is to register a delegate:
container.Register<ISettings, Settings>();
container.Register<ISomeOtherService>(() => new SomeOtherService(
container.GetInstance<ISettings>().Value));
Notice how container.GetInstance<ISettings>() is still called here, but it is embedded in the registered Func<ISomeOtherService> delegate. This will keep the registration and resolving separated.
Another option is to prevent having a large application Settings class in the first place. I experienced in the past that those classes tend to change quite often and can complicate your code because many classes will depend on that class/abstraction, but every class uses different properties. This is an indication of a Interface Segregation Principle violation.
Instead, you can also inject configuration values directly into classes that require it:
var conString = ConfigurationManager.ConnectionStrings["Billing"].ConnectionString;
container.Register<IConnectionFactory>(() => new SqlConnectionFactory(conString));
In the last few application's I built, I still had some sort of Settings class, but this class was internal to my Composition Root and was not injected itself, but only the configuration values it held where injected. It looked like this:
string connString = ConfigurationManager.ConnectionStrings["App"].ConnectionString;
var settings = new AppConfigurationSettings(
scopedLifestyle: new WcfOperationLifestyle(),
connectionString: connString,
sidToRoleMapping: CreateSidToRoleMapping(),
projectDirectories: ConfigurationManager.AppSettings.GetOrThrow("ProjectDirs"),
applicationAssemblies:
BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToArray());
var container = new Container();
var connectionFactory = new ConnectionFactory(settings.ConnectionString);
container.RegisterSingle<IConnectionFactory>(connectionFactory);
container.RegisterSingle<ITimeProvider, SystemClockTimeProvider>();
container.Register<IUserContext>(
() => new WcfUserContext(settings.SidToRoleMapping), settings.ScopedLifestyle);
UPDATE
About your update, if I understand correctly, you want to allow the registered type to change based on a configuration value. A simple way to do this is as follows:
var settings = new Settings();
container.RegisterSingle<ISettings>(settings);
Type theTypeWeWantToRegister = Type.GetType(settings.GetTheISomeOtherServiceType());
container.Register(typeof(ISomeOtherService), theTypeWeWantToRegister);
But please still consider not registering the Settings file at all.
Also note though that it's highly unusual to need that much flexibility that the type name must be placed in the configuration file. Usually the only time you need this is when you have a dynamic plugin model where a plugin assembly can be added to the application, without the application to change.
In most cases however, you have a fixed set of implementations that are already known at compile time. Take for instance a fake IMailSender that is used in your acceptance and staging environment and the real SmptMailSender that is used in production. Since both implementations are included during compilation, allowing to specify the complete fully qualified type name, just gives more options than you need, and means that there are more errors to make.
What you just need in that case however, is a boolean switch. Something like
<add key="IsProduction" value="true" />
And in your code, you can do this:
container.Register(typeof(IMailSender),
settings.IsProduction ? typeof(SmtpMailSender) : typeof(FakeMailSender));
This allows this configuration to have compile-time support (when the names change, the configuration still works) and it keeps the configuration file simple.
I have a host application which provides a plugin interface that can be implemented by plugins. When initializing plugins the host app passes in the Structuremap registry so the plugin can register things
public interface IAppPlugin
{
void Initialize(IRegistry configure);
}
public class CatPlugin : IAppPlugin
{
public void Initialize(IRegistry configure)
{
configure.For<IFilter<IPet>>()
.Add<CatFilter<IPet>>();
}
}
In my host app I have an implementation of IPet, FeralCat and I want to get from structuremap any filters
ObjectFactory.TryGetInstance<IFilter<FeralCat>>
I was hoping this would return me the CatFilter filter registered by my plugin, but it doesnt (which makes sense really, I havent registered a matching type)
My plugin doesnt know about the FeralCat, how can I configure structuremap to return the CatFilter ?
You should take a look at Advanced StructureMap: connecting implementations to open generic types, it might be useful in your case.
But for your specific code:
var container = new Container();
container.Configure(
x =>
{
x.For(typeof(IPet)).Use(typeof(FeralCat));
x.For(typeof(IFilter<>)).Use(typeof(CatFilter<>));
});
var instances = container.GetAllInstances<IFilter<FeralCat>>();
Will give you an instance of CatFilter<FerelCat>.