I'm starting to use MEF, and I have a class with multiple constructors, like this:
[Export(typeof(ifoo))]
class foo : ifoo {
void foo() { ... }
[ImportingConstructor]
void foo(object par1) { ... }
}
I am using catalog.ComposeExportedValue() when composing to supply the par1
value to second constructor:
...
catalog.ComposeExportedValue(par1Value);
catalog.ComposeParts(this);
...
To hold the components I'm using:
[ImportMany(typeof(ifoo))]
public List<Lazy<ifoo, ifoometadata>> FooList { get; set; }
And to create the foo instance I'm using the value property, FooList[0].Value.
Everthing works fine, except that the second constructor of the foo class is never called. What's wrong?
How do I select the constructor I want to use when MEF instantiates the class?
MEF should use the constructor you put the ImportingConstructorAttribute on. I'm not sure what is happening for you, I wasn't able to reproduce the issue. Here is a test which shows using an ImportingConstructor on a class that also has a default constructor:
[TestClass]
public class MefTest
{
public const string ConstructorParameterContract = "FooConstructorParameterContract";
[TestMethod]
public void TestConstructorInjectionWithMultipleConstructors()
{
string ExpectedConstructorParameterValue = "42";
var catalog = new TypeCatalog(typeof(Foo), typeof(FooImporter));
var container = new CompositionContainer(catalog);
container.ComposeExportedValue<string>(ConstructorParameterContract, ExpectedConstructorParameterValue);
var fooImporter = container.GetExportedValue<FooImporter>();
Assert.AreEqual(1, fooImporter.FooList.Count, "Expect a single IFoo import in the list");
Assert.AreEqual(ExpectedConstructorParameterValue, fooImporter.FooList[0].Value.ConstructorParameter, "Expected foo's ConstructorParameter to have the correct value.");
}
}
public interface IFoo
{
string ConstructorParameter { get; }
}
[Export(typeof(IFoo))]
public class Foo : IFoo
{
public Foo()
{
ConstructorParameter = null;
}
[ImportingConstructor]
public Foo([Import(MefTest.ConstructorParameterContract)]string constructorParameter)
{
this.ConstructorParameter = constructorParameter;
}
public string ConstructorParameter { get; private set; }
}
[Export]
public class FooImporter
{
[ImportMany]
public List<Lazy<IFoo>> FooList { get; set; }
}
Are you passing an instance of the foo class into the ComposeExportedValue method? In that case the object has already been constructed and the constructor can't be called again, so MEF will ignore the constructor imports.
Related
First, let's take a look in the code:
using System;
using Autofac;
namespace PropertyInjectionAutofacPoC
{
public interface IInterfaceA { }
public interface IInterfaceB
{
IInterfaceA ClassA { get; set; }
}
public class ClassA : IInterfaceA { }
public class ClassB : IInterfaceB
{
public IInterfaceA ClassA { get; set; } // this is injected properly //
}
public class Z { }
public interface IInterfaceC<T> { }
public interface IInterfaceD<T>
{
IInterfaceA ClassA { get; set; }
IInterfaceC<T> ClassC { get; set; }
}
public interface IInterfaceCZ : IInterfaceC<Z> { }
public abstract class ClassD<T> : IInterfaceD<T>
{
public IInterfaceA ClassA { get; set; } // this is not injected, it's always null //
public IInterfaceC<T> ClassC { get; set; } // this is not injected, it's always null //
}
public abstract class ClassC<T> : IInterfaceC<T> { }
public sealed class ClassCZ : ClassC<Z>, IInterfaceCZ { }
public interface IRepositoryZ : IInterfaceD<Z> { }
public sealed class RepositoryZ : ClassD<Z>, IRepositoryZ { }
internal class Program
{
private static IContainer _container;
private static void Main()
{
try
{
RegisterServices();
// it works //
var a = _container.Resolve<IInterfaceB>();
// it doesn't work //
var b = _container.Resolve<IRepositoryZ>(); // ClassC property is null
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
DisposeServices();
}
}
private static void RegisterServices()
{
var builder = new ContainerBuilder();
builder.RegisterType<ClassA>().As<IInterfaceA>();
builder.RegisterType<ClassB>().As<IInterfaceB>().PropertiesAutowired(); // works like a charm //
builder.RegisterGeneric(typeof(ClassC<>)).As(typeof(IInterfaceC<>)).PropertiesAutowired();
builder.RegisterGeneric(typeof(ClassD<>)).As(typeof(IInterfaceD<>)).PropertiesAutowired(); // it doesn't work //
builder.RegisterType<ClassCZ>().As<IInterfaceCZ>();
builder.RegisterType<RepositoryZ>().As<IRepositoryZ>();
_container = builder.Build();
}
private static void DisposeServices()
{
if (_container != null &&
_container is IDisposable disposable)
disposable.Dispose();
}
}
}
If I change everything to constructors, it works perfectly like a charm but, the main idea for using injected properties here is to avoid the constructor hell.
In the code snippet above, there's some comments where I mentioned what works and what doesn't. The properties injection works properly when there's no generics in use.
So, I'm asking you guys, what am I doing wrong here and what my code is missing to work?
Thanks so much!
The problem you have here is mostly about where you've specified PropertiesAutowired vs what you are resolving.
I've updated your RegisterServices method with some additional comments.
private static void RegisterServices()
{
var builder = new ContainerBuilder();
builder.RegisterType<ClassA>().As<IInterfaceA>();
builder.RegisterType<ClassB>().As<IInterfaceB>().PropertiesAutowired();
// These registrations aren't really valid. You would never be able to
// resolve IInterfaceC<> or IInterfaceD<>, because they are abstract classes, so cannot be constructed.
// You'll always get a NoConstructorsFoundException.
builder.RegisterGeneric(typeof(ClassC<>)).As(typeof(IInterfaceC<>)).PropertiesAutowired();
builder.RegisterGeneric(typeof(ClassD<>)).As(typeof(IInterfaceD<>)).PropertiesAutowired();
builder.RegisterType<ClassCZ>().As<IInterfaceCZ>();
// When I resolve IRepositoryZ, this is the registration that gets provided. So this is where you need PropertiesAutowired.
// Just because RepositoryZ derives from ClassD<Z> does not mean it inherits any of its component registration information,
// which I think is what you may have been expecting.
//
// However, the resolve of IRepositoryZ will now throw a NoConstructorFoundException, because when it goes to inject IInterfaceC<Z>
// onto the property, it hits the invalid registration problem above.
builder.RegisterType<RepositoryZ>().As<IRepositoryZ>().PropertiesAutowired();
_container = builder.Build();
}
Fundamentally, I think you may need to rejig some of your generic class vs concrete class inheritance. I don't think there's a straightforward way to make a generic service be supplied by a concrete registration as you have tried to do here.
In my asp.net core application I have dependency classes which are injected to almost all services. So I want to build a base service class to get these dependencies to properties and my services inherit this base service class.
public abstract class BaseService
{
protected Foo Foo { get; set; }
protected Bar Bar { get; set; }
public BaseService(Foo foo, Bar bar)
{
Foo = foo;
Bar = bar;
}
}
public class Service : BaseService
{
public Service(IOtherDependency otherDependency) { }
public void Method()
{
var value = Bar.value;
Foo.Do(value);
}
}
So with the given code it warns me to call base constructor with supplied parameters, however they are the parameters that will be injected on runtime, I don't want it. If I add a parameterless constructor it will not call my parameterized constructor which I need.
I don't want to call or define any class that injected in base service(Foo and Bar) inside my inherited service, how can I do that ?
By the way Foo and Bar classes are injected as singleton to container in case their lifetime are important.
This is what I was looking for.
I modified my code for my controller base as indicated above post.
For my service side which I was asking in my question; as they do not make use of HttpContext like built-in Controller base class, I only inject IServiceProvider class to my BaseService, so whatever I need in all my services, I get it to property via provider.GetService().
public abstract class BaseService
{
protected Foo Foo { get; set; }
protected Bar Bar { get; set; }
public BaseService(IServiceProvider provider)
{
Foo = provider.GetService<Foo>();
Bar = provider.GetService<Bar>();
}
}
public class Service : BaseService, IService
{
public Service(IOtherDependency otherDependency, IServiceProvider provider) : base(provider) { }
public void Method()
{
var value = Bar.value;
Foo.Do(value);
}
}
public class SomeController : BaseController
{
private readonly IService _service;
public SomeController(IService service)
{
_service = service;
}
public IActionResult Index()
{
//call method
_service.Method();
}
}
Good. Let us have the base class BaseService with a constructor passing its dependencies as parameters:
public abstract class BaseService
{
protected IFoo Foo { get; private set; }
protected IBar Bar { get; private set; }
public BaseService(IFoo foo, IBar bar)
{
Foo = foo;
Bar = bar;
}
}
public class Service : BaseService
{
protected IOtherDependency otherDependency { get; private set; }
public Service(IOtherDependency otherDependency, IFoo foo, IBar bar)
: base(foo, bar)
{
OtherDependency = otherDependency;
}
}
What can the developer of the BaseService class now do when they find out that some of its functionality should be outsourced to an external service on which that class should depend?
Adding another INewDependency parameter to the BaseService class constructor is a violation of the contract with the derived class developers, because they call the BaseService class constructor explicitly and expect only two parameters, so when upgrading to the new version, the corresponding signature constructor is not found and compilation fails. In my opinion, the requirement to repeat the list of base class dependencies in the code of derived classes is a violation of the Single Source Of Truth principle, and the compilation failure after allocating part of the base class functionality into the dependency is a consequence of this violation.
As a workaround, I suggest concentrating all the dependencies of the base class into the properties of the designated sealed class, register this class by ConfigureServices, and pass it in the constructor parameter.
Do the same for a derived class. The developer registers each of these classes with the IServicesCollection.
public abstract class BaseService
{
protected IFoo Foo { get; private set; }
protected IBar Bar { get; private set; }
public BaseService(Dependencies dependencies)
{
Foo = dependencies.Foo;
Bar = dependencies.Bar;
}
public sealed class Dependencies
{
internal IFoo Foo { get; private set; }
internal IBar Bar { get; private set; }
public Dependencies(IFoo foo, IBar bar)
{
Foo = foo;
Bar = bar;
}
}
}
An object with parent class dependencies will be referenced by a class property that provides child class dependencies. However, the code of the derived class completely abstracts from the list of dependencies of the parent class, which is encapsulated in the BaseService.Dependencies type:
public class Service : BaseService
{
protected IOtherDependency OtherDependency { get; private set; }
public Service(Dependencies dependencies) : base(dependencies.BaseDependencies)
{
OtherDependency = dependencies.OtherDependency;
}
public new sealed class Dependencies
{
internal IOtherDependency OtherDependency { get; private set; }
internal BaseService.Depencencies BaseDependencies { get; private set; }
public Dependencies(IOtherDependency otherDependency, BaseService.Dependencies baseDependencies)
{
OtherDependency = otherDependency;
BaseDependencies = baseDependencies;
}
}
}
In this design, the constructor of each class has a single parameter, an instance of the sealed class with its dependencies, with inherited dependencies being passed as a property. The list of class dependencies is encapsulated in the Dependencies class, which is provided to consumers along with the class and default IServiceCollection registrations.
If a BaseClass developer decides to outsource some functionality to a new dependency, all necessary changes will be made within the supplied package, while its consumers do not have to change anything in their code.
Here is the simplest way by using the generic Base Controller class:
public abstract class BaseController<T> : Controller
{
private IFoo _fooInstance;
private IBar _barInstance;
protected IFoo _foo => _fooInstance ??= HttpContext.RequestServices.GetService<IFoo>();
protected IBar _bar => _barInstance ??= HttpContext.RequestServices.GetService<IBar>();
}
and if you are using Razor pages:
class BasePageModel<T> : PageModel where T : class
{
private IFoo _fooInstance;
private IBar _barInstance;
protected IFoo _foo => _fooInstance ??= HttpContext.RequestServices.GetService<IFoo>();
protected IBar _bar => _barInstance ??= HttpContext.RequestServices.GetService<IBar>();
}
You can't do it that way.
If you derive from a base class that does not have a default constructor then you must pass the parameters to the derived class constructor and call the base class constructor with them e.g.
public abstract class BaseService
{
protected Foo Foo { get; set; }
protected Bar Bar { get; set; }
public BaseService(Foo foo, Bar bar)
{
Foo = foo;
Bar = bar;
}
}
public class Service : BaseService
{
public Service(IOtherDependency otherDependency, Foo foo, Bar bar) : base(foo, bar) { }
}
The compiler wants to create the base class but needs the parameters to do so. Image the scenario if you have 2 constructors on your base class
public abstract class BaseService
{
public BaseService(Foo foo)
{
...
}
public BaseService(Bar bar)
{
...
}
}
In this scenario which base class constructor does the compiler call from the derived class? You need to be explicit with parameterized constructors so you need to pass them to any derived constructors as well.
I have these interfaces
public interface Interface1 { Interface2 Items {get;} }
public interface Interface2 { Guid? ApplicationTypeId { get; } }
public interface Interface3 { Class1 Item {get;} }
public interface Interface4 { Guid? ApplicationId { get; set; } }
A class inherits the first interface
public class Class1 : Interface1 {
public Interface2 Items { get; }
}
Another class which consists of few guids
public static class ContentTypeIds
{
public static Guid ContentGuid1 => new Guid("{11798e9d-a167-4cfc-8cfa-9a24fd6caf25}");
public static Guid ContentGuid2 => new Guid("{7d22f5bb-37fd-445a-b322-2fa1b108d260}");
}
I need to unit test the following property
private readonly Interface3 _interface3;
public Ticket Current
{
get
{
//This line is very complicated
Interface4 itemByContentType = _interface3.Item?.Items.GetItemByContentType(ContentTypeIds.ContentGuid2);
if ( itemByContentType?.ContentId != null )
return Get(itemByContentType.ContentId.Value);
return null;
}
}
My test class goes here
[Test]
public class TestClass {
var mock1 = new Mock<Interface1>();
var mock2 = new Mock<Interface2>();
var mock3 = new Mock<Interface3>();
mock1.SetupAllProperties();
mock2.SetupAllProperties();
mock3.SetupAllProperties();
}
The value for 'itemByContentType' goes null.
Could anyone help me to make it simple and testable as it is getting complicated to test this property? I'm using Moq. I will appreciate any help.
Thanks
I'm not an expert on Moq, but it looks like its SetupAllProperties method simply sets up all the properties to act like properties (i.e. the object it creates has a persistent member which can support GET/SET operation). If this isn't done, then as I understand it, the properties will still be available, but they'll always resolve to null. This is very handy when preparing the Mock objects, but on its own, though, that doesn't setup the properties with any sort of value.
I think what you should be doing is using Moq's SetupGet in conjunction with the Returns method to prepare the GET of the Items property with a specific value.
Here is some (simplified) sample code, to demonstrate this:
public interface IFoo { Guid? ApplicationId { get; set; } }
public interface IBar { IFoo Items { get; } }
class Program
{
static void Main(string[] args)
{
// SETUP
// Prepare mocks
Mock<IFoo> MockFoo = new Mock<IFoo>();
Mock<IBar> MockBar = new Mock<IBar>();
// Seting up properties allows us read/write Foo's ApplicationId
MockFoo.SetupAllProperties();
// The mocked Foo object should be what's returned when Items is requested
var expectedFoo = MockFoo.Object;
// Setup the Bar object to return that mocked Foo
MockBar.SetupGet(x => x.Items).Returns(expectedFoo);
// The value written here will be persistent due to SetupAllProperties
expectedFoo.ApplicationId = new Guid("{7d22f5bb-37fd-445a-b322-2fa1b108d260}");
// ACTION
// When the "Items" property is accessed, the IFoo we get should be what we mocked...
var actualFoo = MockBar.Object.Items;
// ... and we can read the value set to Foo's ApplicationId
var actualAppId = actualFoo.ApplicationId;
}
}
I have a base class with many descendants. In the base class a parameter-less constructor is declared. Descendants may declare specialized constructors.
public class A
{
public A()
{
}
}
public class B : A
{
string Stuff { get; set; }
public B(string stuff)
{
Stuff = stuff;
}
}
At some point I want to instantiate a B using the Activator. This instance needs no initialization of it's "Stuff". So I want to use the A's default constructor:
public object InstantiateType(Type type)
{
return Activator.CreateInstance(
type,
BindingFlags.CreateInstance |
BindingFlags.Public |
BindingFlags.NonPublic
);
}
This sample call results in an exception as many other variations on this theme, is it at all possible, and if so how do I instruct the Activator to do so?
At some point I want to instantiate a B using ... A's default constructor
You can't. Constructors aren't inherited, and there is no parameterless constructor for B that you can use. You will need to create a constructur that passes through to the base constructor:
public class B : A
{
string Stuff{get;set}
public B(string stuff)
{
Stuff = stuff;
}
public B() : base() // technically the ": base()" is redundant since A only has one constructor
{
}
}
You could also change your CreateInstance call to pass in null as the string parameter.
Here is a workaround for you:
public class A {
///<summary>Creates an instance of A, or of a subclass of A</summary>
public static A Create<T>() where T : A {
A result = (A)FormatterServices.GetUninitializedObject(typeof(T));
result.defaultInit();
return result;
}
public A() {
defaultInit();
}
private void defaultInit() {
// field assignments ...
// default constructor code ...
}
}
public class B : A {
string Stuff { get; set; }
public B(string stuff) {
Stuff = stuff;
}
}
I'm using the Unity dependency injection framework.
I have two classes, that each take the same delegate parameter in the constructor. Each class should get a different method when resolved.
Can I set this up without using attributes ? If not how would you do it with attributes?
Yep, you can decorate properties or constructor parameters with the [Dependency] attribute.
This example isn't using delegates, it's just using an interface instead, but it shows two of the same interface being registered with different names, and a class requesting a particular one in its constructor:
[TestClass]
public class NamedCI
{
internal interface ITestInterface
{
int GetValue();
}
internal class TestClassOne : ITestInterface
{
public int GetValue()
{
return 1;
}
}
internal class TestClassTwo : ITestInterface
{
public int GetValue()
{
return 2;
}
}
internal class ClassToResolve
{
public int Value { get; private set; }
public ClassToResolve([Dependency("ClassTwo")]ITestInterface testClass)
{
Value = testClass.GetValue();
}
}
[TestMethod]
public void Resolve_NamedCtorDependencyRegisteredLast_InjectsCorrectInstance()
{
using (IUnityContainer container = new UnityContainer())
{
container.RegisterType<ITestInterface, TestClassOne>("ClassOne");
container.RegisterType<ITestInterface, TestClassTwo>("ClassTwo");
container.RegisterType<ClassToResolve>();
var resolvedClass = container.Resolve<ClassToResolve>();
Assert.AreEqual<int>(2, resolvedClass.Value);
}
}
[TestMethod]
public void Resolve_NamedCtorDependencyRegisteredFirst_InjectsCorrectInstance()
{
using (IUnityContainer container = new UnityContainer())
{
container.RegisterType<ITestInterface, TestClassTwo>("ClassTwo");
container.RegisterType<ITestInterface, TestClassOne>("ClassOne");
container.RegisterType<ClassToResolve>();
var resolvedClass = container.Resolve<ClassToResolve>();
Assert.AreEqual<int>(2, resolvedClass.Value);
}
}
}
Instead, you could try passing a factory in on the constructor of the objects. That way you can guarantee (and test) in code exactly what objects are created.