StructureMap not possible to use injected instance for setter injection - c#

I am having a problem with injecting an instance into structuremap for my tests.
My objects graph looks like this
internal class ConfigurationManager : IConfigurationManager : IManager
{
public ISomeManager SomeManager { get; set; }
}
internal class SomeManager : ISomeManager : IManager
{
public IConfigurationManager ConfigurationManager { get; set; }
}
1) first i create the container and add all found registries
_container = new Container(c => c.Scan(s =>
{
s.TheCallingAssembly();
s.LookForRegistries();
}));
one of these scanned assemblies contains the following registration
x.For<IConfigurationManager>().Singleton.Use<ConfigurationManager>();
2) then i want to inject a special mock object for this managers
_configurationManagerStub = MockRepository.GenerateStub<IConfigurationManager>();
_container.Inject(_configurationManagerStub);
3) Then the manager instances are created without setter injection configured (to avoid circular dependencies)
foreach (Type pluginType in AllManagers())
{
managerInstances.Add(_container.GetInstance(pluginType));
}
4) at last I use the BuildUp method to set the Properties of type IManager.
_container.Configure(x => x.SetAllProperties(c =>
{
// configure the property injection for all managers
c.Matching(prop => typeof(IManager).IsAssignableFrom(prop.PropertyType));
}));
// push in dependencies -> EXCEPTION
managerInstances.ForEach(x => _container.BuildUp(x));
Unfortunatly in the last line of code i get the following exception.
StructureMap.StructureMapException : StructureMap Exception Code: 245
Error while trying to create an InstanceBuilder for
IConfigurationManagerProxyd079980359cf491b821a3afb15be8a86,
DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null ----> System.ArgumentException : Expression of
type 'System.Object' cannot be used for parameter of type
'System.String' of method 'Castle.Core.Interceptor.IInterceptor[]
GetIInterceptor[]'
Why does structuremap try to use an InstanceBuilder when I did inject the instance?
Br,
David

The issue is with StructureMap support of Castle DynamicProxy (Rhino Mocks and Moq uses it) generated stubs when used in BuildUp.
Specifically Castle generates a constructor with 2 parameters for requested proxy type and those parameters don't have names. ConstructorFunctionBuilder within StructureMap fails to create proper lambda expression in such case (null is treated as System.Object where System.String is expected). Thats not even needed when you just want to setup property setters, but there is no way to control this.
The "Inject" will work with non-dynamically generated stubs, but you might wanna look for a different solution.

Related

Injecting dependencies into dynamically loaded .dll (.net core)

Similar to How to Inject Dependencies to Dynamically Loaded Assemblies, I want to inject dependencies into classes from dynamically loaded assemblies. Is this possible with the .NET 6.0 DI Container? If so, how? If not, is there a light-weight IOC container that can you might recommend? (Not adding a 2nd IOC system to the project would be preferred.)
(Note: there will be only 2-4 maximum possible dependencies to inject, so a fake injection system with if/switch statements could be acceptable.)
One challenge: ILogger<> typically expects a type, but the loading .dll has no compile-time knowledge of the types in the dynamically loaded assemblies, and vice-versa. I could use the non-generic ILogger interface, but am not sure if that works with DI.
EDIT:
Expanding example, as requested:
Given: All potential dependencies to inject come from the Microsoft.Extensions.Hosting nuget package. The two we initially expect to use are ILogging<> and IConfiguration.
Type desiredClass = <Type found in the dynamically loaded assembly>;
//The below line does not inject dependencies. I am trying to find out what will.
object classInstace = Activator.CreateInstance(desiredClass);
MethodInfo selectedMethod = desiredClass.GetMethods
.Single(m=>m.Name=="Execute" && m.GetParameters().All(p=>p.IsOptional));
//Schedule the method in HangFire
RecurringJob.AddOrUpdate(
() => selectedMethod!.Invoke(
ClassInstance,
Array.Empty<object?>(),
scheduleForThisTask);
I found a very ugly way to get this done, and very much hope there is a cleaner way to accomplish this. (Please let there be a built-in way to do this that I have missed.)
Create an extension method GetInjectedObject for IService Provider:
public static object GetInjectedObject(this IServiceProvider serviceProvider, Type type)
{
//Dependency injection the ugly way
//Find the constructor that asks for the most injected parameters
var constructor = type.GetConstructors().Where(cn =>
cn.GetParameters().All(par => serviceProvider.GetServices(par.ParameterType).Any()))
.OrderByDescending(cn => cn.GetParameters().Length).FirstOrDefault();
if (null == constructor)
throw new Exception($"Type {type.Name} does not have a constructor without non-injectible parameters.");
//Get the needed parameters from the IServiceProvider
var constructorParameters =
constructor.GetParameters().Select(par => serviceProvider.GetService(par.ParameterType)).ToArray();
//Create the object with the parameters
var classInstance = Activator.CreateInstance(type, constructorParameters);
return classInstance;
}
and then create the objects like this:
_classInstance = serviceProvider.GetInjectedObject(Class);
Perhaps I misunderstood the problem, might it work for you to:
Have an assembly shared by the loading assembly (i.e. your Composition Root) and the dynamically loaded assembly? This assembly could contain an interface that dynamically loaded types must implement. (you might already have a shared assembly)
Load the dynamically loaded assembly at startup at the point that you're still wiring the DI Container?
In that case I expect an interface similar to:
namespace MySharedAssembly
{
public interface ITask
{
void Execute(TaskSchedule schedule);
}
public class TaskSchedule { ... }
}
In the dynamically loaded assembly:
namespace MyDynamicAssembly
{
public class HelloWorldTask : ITask
{
public void Execute(TaskSchedule schedule)
{
Console.WriteLine("Hello world!");
}
}
}
By doing so, you can:
Easily find all types in the dynamically loaded assembly by the ITask interface.
Register them by their concrete type in the DI Container.
Resolve them by their concrete type when needed, while their dependencies are injected by the DI Container.
For instance:
string dynamicallyLoadedAssemblyPath = "c:\\...\etc\etc\myAssembly.dll";
// Load plugin assembly
Assembly assembly =
Assembly.Load(AssemblyName.GetAssemblyName(dynamicallyLoadedAssemblyPath));
// Load plugin types
Type plugins = assembly.GetExportedTypes().Where(typeof(ITask).IsAssignableFrom);
// Register plugins in DI Container
foreach (var plugin in plugins)
{
services.AddTransient(plugin, plugin);
}
// Add jobs after container was constructed
IServiceProvider provider = ...
foreach (var plugin in plugins)
{
var scheduleForThisTask = GetSchedule(plugin);
RecurringJob.AddOrUpdate(() =>
{
// It might be important to execute each task in its own scope.
using (var scope = provider.CreateScope())
{
var task = (ITask)scope.ServiceProvider.GetRequiredService(plugin);
task.Execute(scheduleForThisTask);
}
}
}

Inject an IEnumerable of interface in controller using Dependency Injection

I want to resolve the dependency for the IEnumerable collections of the multiple class inheriting the Interface on the controller.
I want to resolve the following dependency during the application startup:
var notificationStrategy = new NotificationStrategy(
new INotificationService[]
{
new TextNotificationService(), // <-- inject any dependencies here
new EmailNotificationService() // <-- inject any dependencies here
});
NotificationStragey
public class NotificationStrategy : INotificatonStrategy
{
private readonly IEnumerable<INotificationService> notificationServices;
public NotificationStrategy(IEnumerable<INotificationService> notificationServices)
{
this.notificationServices = notificationServices ?? throw new ArgumentNullException(nameof(notificationServices));
}
}
What is the best way of dependency injection of IEnumerable types of objects in the asp.net core without using any external dependency or library?
Register all the types with the service collection at the composite root
//...
services.AddScoped<INotificationService, TextNotificationService>();
services.AddScoped<INotificationService, EmailNotificationService>();
services.AddScoped<INotificatonStrategy, NotificationStrategy>();
//...
and all dependencies should be injected when resolving the desired type since the constructor already has IEnumerable<INotificationService> as a constructor parameter
Reference Dependency injection in ASP.NET Core

Is there a way to eagerly resolve all components registered with Windsor IoC container?

I have C# application where I register a few dozen interfaces with their implementation classes in the Windsor container. All these implementation classes are resolved as singletons by Windsor. The question is can I somehow make Windsor manually resolve all these stuff and wire them to create a object graph? Rather than lazy resolving that Windsor does by default when some component is request, I need to resolve them all at once for some debugging and testing purposes. Ideally I'd like to get the array of instances for all registered types. Is this possible?
The dependency graph is available through the GraphNodes property. Here's a simple demonstration:
[Test]
public void Get1()
{
var container = new WindsorContainer();
container.Register(Component.For<SomeClass>().LifestyleSingleton());
container.Register(Component.For<Dependency>().LifestyleSingleton());
var graphNodes = container.Kernel.GraphNodes;
Assert.That(graphNodes.Length, Is.EqualTo(2));
Assert.That(graphNodes[0].Dependents[0].ToString(), Is.EqualTo(typeof(Dependency).Name));
Assert.That(graphNodes[1].Dependents.Length, Is.EqualTo(0));
}
You should easily be able to establish which types are "root" types by filtering out any types that are a dependency ...
UPDATE
One of the ways to create an instance from a GraphNode is to cast the GraphNode to Castle.Core.ComponentModel
[Test]
public void Resolve1()
{
var container = new WindsorContainer();
container.Register(Component.For<SomeClass>().LifestyleSingleton());
container.Register(Component.For<Dependency>().LifestyleSingleton());
var graphNodes = container.Kernel.GraphNodes;
var name = (graphNodes[0] as ComponentModel).ComponentName.ToString();
var type = Type.GetType(name);
dynamic instance1 = container.Resolve(type);
Assert.That(instance1, Is.Not.Null);
}
Usually for debugging and testing the container you may use the component handler instead of resolving the component itself.
Said so, Simon is right: when you Resolve a component, windsor creates the real instance and all its dependencies. Nothing is "deferred" unless you mean "late dependency" achived through a (typed) factory, but that's somenthing else...
The solution that uses ComponentName doesn't work. ComponentModel.Services should be used instead. Tested with version 3.3
container.Kernel.GraphNodes
.Cast<ComponentModel>()
.ToList()
.ForEach(component =>
{
component.Services
.ToList()
.ForEach(type =>
{
var instance = container.Resolve(type);
Assert.IsNotNull(instance);
});
});

Orchard CMS, Autofac Relationship

I am trying to create a "A(UserManager) needs to create instances of B(UserClient)" relationship (http://code.google.com/p/autofac/wiki/RelationshipTypes) where B(UserClient) needs a HttpSessionStateBase..
UserClient
public class UserClient : IUserClient
{
public UserClient(HttpSessionStateBase session)
{
//...
}
//...
}
UserManager
public class UserManager : IUserManager
{
private readonly Func<IUserClient> userClientPerRequest;
private IUserClient UserClient
{
get
{
return userClientPerRequest();
}
}
public UserManager(Func<IUserClient> userClientPerRequest)
{
this.userClientPerRequest = userClientPerRequest;
}
public void DoStuff()
{
UserClient.DoStuff();
}
This is where is register autofac stuff
public class MyModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<UserManager>().As<IUserManager>().SingleInstance();
builder.RegisterType<UserClient>().As<IUserClient>().InstancePerHttpRequest();
builder.RegisterModule(new AutofacWebTypesModule());
//If i try this, i get Error 1 (printing errors after this code-block)
builder.Register<Func<IUserClient>>(c => c.Resolve<IUserClient>);
//If i try this, i get Error 2
builder.Register<Func<IUserClient>>(c => {
var ctx = c.Resolve<IComponentContext>();
return ctx.Resolve<IUserClient>;
});
//If i try this, well i always get null from GetService..
builder.Register<Func<IUserClient>>(c =>
DependencyResolver.Current.GetService<IUserClient>);
}
Looking at Autofac: Reference from a SingleInstance'd type to a HttpRequestScoped , they use some RequestContainer but i can find no such thing. :)
Error 1
This resolve operation has already ended. When registering components using lambdas, the IComponentContext 'c' parameter to the lambda cannot be stored. Instead, either resolve IComponentContext again from 'c', or resolve a Func<> based factory to create subsequent components from.
Error 2
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being reqested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I have tried switching .InstancePerHttpRequest() to .InstancePerLifetimeScope() and a whole other different stuff.. Anyone have any ideas?
Thanks
When adding Autofac registrations manually in Orchard, use InstancePerMatchingLifetimeScope("shell"), if you need a singleton or InstancePerMatchingLifetimeScope("work"), if you need per-request instance.
I'm not sure if HttpSessionStateBase ctor argument can actually be resolved from the container. You could put IHttpContextAccessor there instead and use it to access the session state object inside IUserClient implementation.
And as Jim Bolla suggested - Func<IUserClient> (factory) is already available out of the box.
I don't think you need to do either of those registrations. Because of Relationship Types, Func<IUserClient> should already be available to you.

Unity IoC resolving a Generic Service plus Generic repository

When using ASP.NET MVC plus Entity Framework, and trying to implement a generic repository and a generic service, and have everything resolved by Unity Ioc:
I am trying to get Unity Ioc to inject a generic service into the controller using parameter injection, but the type resolving is failing with this this error message:
Activation error occured while trying to get instance of type
ISupplierService The current build operation (build key Build
Key[MyApp.Services.Implementation.SupplierService, null]) failed:
Activation error occured while trying to get instance of type
IGenericRepository1, key \"\" Resolution of the dependency failed:
The current type,
MyApp.Repository.Interfaces.IGenericRepository1[Entities.Supplier],
is an interface and cannot be constructed. Are you missing a type
mapping? (Strategy type BuildPlanStrategy, index 3)
I can understand that the error message means that it is trying to create an instance of IGenericRepository when instead I am actually trying to get it to create an instance of SupplierService, but I do not see why it is resolving this way. As per initial answers it could be because the types are not registered
The controller's service injection is:
public class SupplierController : Controller
{
private readonly ISupplierService _service;
public SupplierController() : this (null) { }
public SupplierController(ISupplierService service)
{
_service = service;
}
// .. injection fails, service is NULL
}
Supplier service is an empty interface plus empty class (which could have custom methods added later if needed)
public partial interface ISupplierService : IGenericService<Supplier> {}
IGenericService simply resurfaces the IGenericRepository's methods:
public interface IGenericService<T> : IDisposable where T : BaseEntity {}
In Global.asax.cs the IoC container is created by
var container = new UnityContainer();
var uri = new Uri(Assembly.GetExecutingAssembly().CodeBase);
string path = System.IO.Path.GetDirectoryName(uri.AbsolutePath);
var assemblyPaths = new List<string>
{
Path.Combine(path, "MyApp.Repository.Interfaces.dll"),
Path.Combine(path, "MyApp.Repository.Implementation.dll"),
Path.Combine(path, "MyApp.Services.Interfaces.dll"),
Path.Combine(path, "MyApp.Services.Implementation.dll")
};
container
.ConfigureAutoRegistration()
.LoadAssembliesFrom(assemblyPaths)
.ExcludeSystemAssemblies()
.Include(If.Any, Then.Register())
.ApplyAutoRegistration();
var serviceLocator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);
experimented with UnityAutoRegistration while the latest release was still "fresh" and I was not happy with it. The TecX project on codeplex contains a port of the StructureMap config engine which gives you support for conventions that should make your life a lot easier.
Something like
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.Scan(s =>
{
s.AssembliesFromApplicationBaseDirectory();
s.With(new ImplementsIInterfaceNameConvention());
}
var container = new UnityContainer();
container.AddExtension(builder);
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<>));
var serviceLocator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);
should register all of your Interface/Service and Interface/Repository pairs. The convention registers SupplierService as the implementation of ISupplierService etc.
The additional call to RegisterType with the two open generic types (IGenericRepositoy<> and GenericRepository) maps your generic repository interface to the generic repository class. Unity will close the type definition automatically for you (i.e. IGenericRepository<Supplier> will be mapped to GenericRepository<Supplier>).

Categories