asp.net core constructor injection with inheritance - c#

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.

Related

Polymorphic Abstract class with a lot of DI paramters

I'm constantly running into the problem of having an abstract class that does all the heavy lifting and then I have a lot of polymorphic classes that customize the abstract to a specific need. The abstract generally needs a lot of parameters, so they all have to be passed from all polymorphic classes
public class FooComplex : AbstractFoo {
public FooComplex(IBarAwesome awesome, IBarCool cool, ...) : base(IBarAwesome awesome, IBarCool cool, ...) { }
...a lot of overriding abstracts
}
public class FooSimple : AbstractFoo
{
public FooSimple(IBarAwesome awesome, IBarCool cool, ...) : base(IBarAwesome awesome, IBarCool cool, ...) { }
...little bit of overriding abstracts
}
public class AbstractFoo
{
public AbstractFoo(IBarAwesome awesome, IBarCool cool, ...)
...heavy lifting
}
Is there anything I can do to not pass all these things, but be able to unit test them? I've always been taught that doing
var awesome = container.Resolve<IBarAwesome>();
In like say the constructor is bad practice.
The reason I would like to find a solution to this, is it makes it harder and hard to pass anything new into the abstract class as I have to copy and pass the same parameters into many polymorphic subclasses.
I believe this is similar to what #C.Evenhuis mentioned in the comments by abstracting your constructor parameters into a common interface so they can be passed as single constructor parameter as well as being easily tested.
Concrete Classes:
public class FooComplex : AbstractFoo
{
public FooComplex(ComplexParam complexParam) : base(complexParam)
{}
}
public class FooSimple : AbstractFoo
{
public FooSimple(SimpleParam simpleParam) : base(simpleParam)
{}
}
Single Generic Concrete Class (Optional)
With this class, you could pass any type into the constructor which inherits IParams and potentially remove the need for FooComplex and FooSimple.
public class Foo<T> : AbstractFoo where T : IParam
{
public Foo(T param) : base(param)
{ }
}
Base Abstract Class:
public abstract class AbstractFoo
{
protected AbstractFoo(IParam parameter) { }
}
Interfaces:
public interface IBarCool : IBar
{}
public interface IBarAwesome : IBar
{}
public interface IBar
{}
public interface IParam
{
IEnumerable<IBar> Param { get; }
}
Reusable Concrete Parameters:
I personally don't like this method below because of the repetition but I suppose if each of the classes have their own separate implementation then it's okay. Another option would be to just have a class called ParameterHolder and two instances of the class named appropriately e.g. var complex = new ParameterHolder() and pass to the Generic Foo<T>.
public class ComplexParam : IParam
{
public IEnumerable<IBar> Param { get; }
public ComplexParam(IEnumerable<IBar> complexParam)
{
Param = complexParam;
}
}
public class SimpleParam : IParam
{
public IEnumerable<IBar> Param { get; }
public SimpleParam(IEnumerable<IBar> simpleParam)
{
Param = simpleParam;
}
}
All that needs to happen is:
public interface IAbstractParams
{
IBarAwesome awesome { get; }
IBarCool cool { get; }
...
}
public class FooComplex : AbstractFoo
{
public FooComplex(IAbstractParams params) : base(params) { }
...a lot of overriding abstracts
}
public class FooSimple : AbstractFoo
{
public FooSimple(IAbstractParams params) : base(params) { }
...little bit of overriding abstracts
}
public class AbstractFoo
{
protected readonly IBarAwesome _awesome;
protected readonly IBarCool _cool;
public AbstractFoo(IAbstractParams params)
{
_awesome = params.awesome;
_cool = params.cool;
}
...heavy lifting
}
then you need to add the nuget package Autofac.Extras.AggregateService and add this line to your builder:
builder.RegisterAggregateService<IAbstractParams>();
Thank you to #Travis Illig and #C.Evenhuis for helping me come up with this solution.
For more complex solutions to this same problem please look at #Kitson88

How to downcast this to the base class?

I have this class hierarchy:
public abstract class AClass : SomeFrameworkClass {
[WorkOnThisProperty(With.Some.Context)]
private MyObject MyProperty { get; set; }
public override void OnSomethingHappened() {
ExternalFramework.WorkOn(this);
}
}
public class BClass : AClass {
// ... Snip ...
}
ExternalFramework is operating on this: an instance of BClass but i need it to operate on this as an instance of AClass because ExternalFramework only works on the type of the object passed in and does not go up the inheritance hierarchy. How can i downcast this into AClass so ExternalFramework can actually detect MyProperty?
I've tried casting this to object and then to AClass, and casting it directly to AClass but as the cast is unnecessary it doesn't seem to run. What can i do about this?
EDIT: ExternalFramework is Cheeseknife. I am trying to inject a couple views into a base fragment class that has all the reusable logic while child fragment classes implement some specific behaviour tuning.
The problem is that all private members of a class can only be accessed inside of the same class.
With this code:
class A { private string Property { get; set; } }
class B : A { public string Proxy => Property; }
We'll get compilation error because class B cannot access private property from class A, but if change keyword to protected :
class A { protected string Property { get; set; } }
It should work.

Reducing generic parameters

I'm trying to get an inheritance hierarchy of generics working, and I'm running into a bit of a problem.
Here's an example:
interface IFoo {}
interface IFoo<T> : IFoo
{
T Data { get; }
}
class Foo : IFoo<int> { public int Data { get; set; } }
interface IBar {}
class Bar : IBar { }
abstract class LayerOne<T_FOO, T_BAR> where T_FOO : IFoo where T_BAR : IBar {}
abstract class LayerTwo<T_FOO> : LayerOne<T_FOO, Bar> where T_FOO : IFoo, new()
{
protected T_FOO _foo = new T_FOO();
public void Test1() { _foo.Data.Dump();} // Compiler error
}
class LayerThree : LayerTwo<Foo>
{
public void Test2() { _foo.Data.Dump();}
}
I'm trying to get access to .Data in the LayerTwo class. Clearly, since IFoo doesn't have that property, it's going to error. However, if I change they type of T_FOO to IFoo<T>, then I have to define it and LayerThree as:
abstract class LayerTwo<T_FOO, T> : LayerOne<T_FOO, Bar> where T_FOO : IFoo<T>, new()
{
protected T_FOO _foo = new T_FOO();
public void Test1() { _foo.Data.Dump();}
}
class LayerThree : LayerTwo<Foo, int>
{
public void Test2() { _foo.Data.Dump();}
}
But the intent of the concrete Foo implementation is that it already knows it's implementing IFoo<int>. Is there any way I can get LayerTwo to know about the Data property without requiring it to be looked up from Foo and added to LayerThree's definition?
What I'd love is:
class LayerThree : LayerTwo<Foo> // Automatically realizes that the second generic is int
{
public void Test2() { _foo.Data.Dump();}
}
Update: As it turns out, I was actually trying to implement two contradictory things in my code. The actual LayerTwo was trying to keep T_FOO generic, but also created an (abstract) method which required a specific type from IFoo<T>.
So the solution I'm going with is just to use an interface which inherits from IFoo<T> and specifies the type, but I'm accepting Ondrej Tucny's answer, since it did solve the problem I asked about.
This is exactly the same situation as with IEnumerable / IEnumerable<T>. Your weakly typed interface IFoo needs to provide a weakly typed Data:
public interface IFoo
{
object Data { get; }
}
public interface IFoo<T> : IFoo
{
new T Data { get; }
}
then in the implementation one of the will be explicit to favor strongly typed access:
public class IntFoo : IFoo<int>
{
public int Data { get { return -1; } }
object IFoo.Data { get { return Data; } }
}
Now you have access to Data in either case, although when the actual type T is unknown, you have to live with an object.

How to mock an object that extends a class and implements an interface?

I have this class:
public class BaseFoo
{
public bool BoolProp { get; set; }
}
public interface IFoo {
void Method();
}
public class FooClass : BaseFoo, IFoo
{
public void Method()
{
// DoSomething
}
}
public class MyClass
{
IFoo foo; //
public MyClass(IFoo foo)
{
this.foo = foo;
}
public void DoSomething()
{
if (((FooClass)foo).BoolProp)
{
// yeah
}
else
{
//bad
}
}
}
My scenario is:
void main()
{
MyClass obj = new MyClass(new FooClass());
obj.DoSomething();
}
I'd like to create a mock object for the IFoo interface that allows me to mock the BaseFoo class too because I need to always avoid running the "else" branch of the "if (((FooClass)foo).BoolProp)" in the MyClass.DoSomething() method.
So, how can I create a mock object that allows me to mock the behaviour of BaseFoo.BoolProp used in MyClass (that will take a mock object of IFoo)?
I did that without any result because the "BoolProp" is not virtual and I can't change it as it is part of a .NET Framework class:
var cMock = new Mock<BaseFoo>();
var iMock = cMock.As<IFoo>();
cMock.Setup(c => c.BaseProp).Returns(true);
MyClass myClass = new MyClass(iMock.Object);
What your design is really saying is that your class MyClass does not have a dependency on IFoo, it has a dependency on a class instance derived from BaseFoo and implementing IFoo. In this case it is probably best that you introduce a unifying interface which you can then use as a dependency and mock:
interface IFooBar
{
bool BoolProp { get; set; }
void Method();
}
How about declaring an abstract class (BaseFooFoo?) that derives from BaseFoo and implements IFoo. Then you could show BaseFooFoo to moq.

MEF Constructor Parameters with Multiple Constructors

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.

Categories