How to pass a parameter indirectly in Autofac - c#

I have a dependency being injected via Func<Owned<OwnedDependency>>. One of its dependencies requires a parameter that I will only have at the point of constructing OwnedDependency.
public class OwnedDependency
{
public OwnedDependency(IDependency1 dependency)
{
}
}
public interface IDependency1
{
}
public class Dependency1 : IDependency1
{
public Dependency1(MyParameter parameter)
{
}
}
public class MyClass
{
private readonly Func<Owned<OwnedDependency>> m_ownedDependencyFactory;
public MyClass(Func<Owned<OwnedDependency>> ownedDependencyFactory)
{
m_ownedDependencyFactory = ownedDependencyFactory;
}
public void CreateOwnedDependency()
{
var parameter = new MyParameter(...);
// ** how to setup parameter with the container? **
using (var ownedDependency = m_ownedDependencyFactory())
{
}
}
}
I can't work out a clean way of setting up the instance of MyParameter.
One approach I have explored is to inject ILifetimeScope into MyClass and then do something like:
var parameter = new MyParameter(...);
using (var newScope = m_lifetimeScope.BeginLifetimeScope())
{
newScope.Resolve<IDependency1>(new TypedParameter(typeof(MyParameter), parameter));
var ownedDependency = newScope.Resolve<OwnedDependency>();
// ...
}
but the container is becoming unnecessarily intrusive. Ideally what I would like to do is inject Func<IDependency1, Owned<OwnedDependency>> and the container be willing to use parameters passed in to satisfy any necessary dependency, not just the ones on OwnedDependency.

What about doing the resolution in two steps with using another factory for IDependency1:
public class MyClass
{
private Func<MyParameter, IDependency1> dependency1Factory;
private Func<IDependency1, Owned<OwnedDependency>> ownedDependencyFactory;
public MyClass(
Func<MyParameter, IDependency1> dependency1Factory,
Func<IDependency1, Owned<OwnedDependency>> ownedDependencyFactory)
{
this.dependency1Factory = dependency1Factory;
this.ownedDependencyFactory = ownedDependencyFactory;
}
public void CreateOwnedDependency()
{
var parameter = new MyParameter();
using (var owned = ownedDependencyFactory(dependency1Factory(parameter)))
{
}
}
}

Related

Unity Container resolve calling same parameterized constructor twice

I'm using a unity container and I'm trying to resolve by passing the object to the parameterized constructor, I noticed the same constructor is called twice, the first time it takes appropriate values, and not sure why it is calling again and it overrides with a blank object, can someone help me what is happening over here, not able to solve it.
//////////////////////////////////////////////////////////////////////
if (container == null)
{
container = new UnityContainer().AddExtension(new Diagnostic());
container.RegisterType<ISubscribeService,OOrderProc.Common.SubscribeService.SubscribeService>();
container.RegisterType<IBaseOrderProcessing, BaseSubscribe>("Subscribe");
}
SubscribeDetails m = new SubscribeDetails();
m.SubscribeType = SubscribeType.ACTIVATE;
m.SubscribeName = "TEST";
var b = container.Resolve<IBaseOrderProcessing>("Subscribe",new DependencyOverride<BaseSubscribe>(new OOrderProc.Common.SubscribeService.SubscribeService(m)));
//////////////////////////////////////////////////////////////////////
public interface IBaseOrderProcessing
{
void ProcessOrder();
}
public interface ISubscribeService
{
SubscribeType SubscribeType { get; set; }
void ActivateSubscribe();
void UpgradeSubscribe();
}
// Strategy Pattern 1 => Subscribe is one of the "if" condition
public class BaseSubscribe : IBaseOrderProcessing
{
private ISubscribeService _SubscribeService = null;
public BaseSubscribe(ISubscribeService SubscribeService)
{
_SubscribeService = SubscribeService;
}
public void ProcessOrder()
{
if (_SubscribeService.SubscribeType == SubscribeType.ACTIVATE)
_SubscribeService.ActivateSubscription();
if (_SubscribeService.SubscribeType == SubscribeType.UPGRADE)
_SubscribeService.UpgradeSubscription();
}
}
// Writing another class to simplify is correct ?????
public class SubscribeService : ISubscribeService
{
private SubscribeDetails _Subscribedetails = null;
public SubscribeType SubscribeType { get; set; }
public SubscribeService(SubscribeDetails Subscribedetails)
{
_Subscribedetails = Subscribedetails;
SubscribeType = Subscribedetails.SubscribeType;
}
public void ActivateSubscription()
{
// Code to save the Subscribe details in the database
Console.WriteLine($"\n\nSubscribe {_Subscribedetails.SubscribeId} for {_Subscribedetails.SubscribeName} activated for order Id: {_Subscribedetails.OrderId}" +
$" from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");
}
public void UpgradeSubscription()
{
// Code to upgrade the Subscribe details in the database
Console.WriteLine($"\n\nSubscribe {_Subscribedetails.SubscribeId} for {_Subscribedetails.SubscribeName} upgraded for order Id: {_Subscribedetails.OrderId}" +
$" from {_Subscribedetails.SubscribeStartDate} to {_Subscribedetails.SubscribeEndDate}");
}
}
I resolved using below code:
container.RegisterType<IBaseOrderProcessing, BaseSubscribe>("Subscribe", new InjectionConstructor(new OOrderProc.Common.SubscribeService.SubscribeService((SubscribeDetails)obj)));
return container.Resolve<IBaseOrderProcessing>("Subscribe");

Circular reference in dependency injection

I am creating a RESTful api in Net 5, according to the instructions I must create repositories and services that make use of them. The logic must be in the services.
The Services I have are:
SubGroupService
GroupsService
The problem I have is that I generated a circular reference since in GroupsService I need a method of SubGroupsService and SubGroupsService i need a method of GroupsService .
Injecting the GroupsService service into SubGroupsService there is no problem, but injecting SubGroupsService into GroupsService generates the circular reference.
Please can you tell me how to solve this type of problem, since I don't have much experience with dependency injection.
SubGroupService
public class SubGroupService: ISubGroupService
{
private readonly ISubGroupRepository _SubGroupRepository;
private readonly IGroupService _GroupService;
public SubGroupService(
ISubGroupRepository SubGroupRepository,
IGroupService GroupService
{
_SubGroupRepository = SubGroupRepository;
_GroupService = GroupService;
}
public async Task InsertSubGroupService(Subgroup subgroup)
{
var group = await _GroupService.GetGroupService(subgroup.idgroup);
if (group != null)
{
await _SubGroupRepository.InsertSubGroupRepository(subgroup);
}
else
{
throw new BusinessException("This group not exists");
}
}
public async Task<Subgroups> GetSubGroupService(int idgroup)
{
return await _SubGroupRepository.GetSubGroupRepository(idgroup);
}
}
Group Service
public class GroupService : IGroupService
{
private readonly ISubGroupService _SubGroupService;
private readonly IGroupRepository _GroupRepository;
public GroupService(
ISubGroupService SubGroupService,
IGroupRepository GroupRepository)
{
_SubGroupService = SubGroupService;
_GroupRepository = GroupRepository;
}
public async Task<bool> DeleteGroupService(int Idgroup)
{
var existsSubGroup = await _SubGroupRepository(Idgroup);
if(existsSubGroup == null)
{
return await _GroupRepository.DeleteGroupRepository(Idgroup);
}
}
public async Task<Groups> GetGroupService(int Idgroup)
{
return await _GroupRepository.GetGroupRepository(Idgroup);
}
}
Interfaces:
public interface IGroupService
{
Task<Groups> GetGroupsService(int Idgroup);
Task<bool> DeleteGroupService(int Idgroup);
}
public interface ISubGroupService
{
Task<Subgroups> GetSubGroupService(int idsubgrupo);
Task InsertSubgroupService(Subgroup subgroup);
}
You can't use constructor injection in that case. You can switch to property injection:
public class SubGroupService: ISubGroupService
{
private readonly ISubGroupRepository _SubGroupRepository;
public IGroupService GroupService { get; set; }
public SubGroupService(
ISubGroupRepository SubGroupRepository)
{
_SubGroupRepository = SubGroupRepository;
}
// methods of the class
}
public class GroupService : IGroupService
{
public ISubGroupService SubGroupService {get; set;}
private readonly IGroupRepository _GroupRepository;
public GroupService(
IGroupRepository GroupRepository)
{
_GroupRepository = GroupRepository;
}
// methods of the class
}
You'll have to create the objects like this:
IGroupRepository groupRepository = new GroupRepository();
IGroupService groupService = new GroupService(groupRepository);
ISubGroupService subGroupService = new SubGroupService(groupRepository);
groupService.SubGroupSerivce = subGroupService;
subGroupService.GroupService = groupService;
Of course, creation of the objects is now much more complicated. You might put the creation into a facotry method to avoid errors:
public (IGroupService,ISubGroupService) CreateGroupAndSubGroupService()
{
// code from above
}
And it is also advisable to add null checks, because someone might create the objects without initializing the service correctly.

Supply typed parameter to nested dependencies in Autofac

I was under the impression that the TypedParameter could be used to supply values during resolution in Autofac.
However, it seems that these parameters are used on the explicit type being resolved only, and does not propagate down the dependency chain.
Is there a way to accomplish this?
public interface IDepA { }
public interface IDepB { }
public interface IDepC { }
public class DepA : IDepA
{
public DepA(IDepB depB) { }
}
public class DepB : IDepB
{
public DepB(IDepC depC) { }
}
public class DepC : IDepC { }
[TestMethod]
public void AutofacResolutionTest()
{
var builder = new ContainerBuilder();
builder.RegisterType<DepA>().As<IDepA>();
builder.RegisterType<DepB>().As<IDepB>();
var container = builder.Build();
// Works
var b = container.Resolve<IDepB>(new TypedParameter(typeof(IDepC), new DepC()));
// Does not work
var a = container.Resolve<IDepA>(new TypedParameter(typeof(IDepC), new DepC()));
}
Short answer: You can't pass a parameter to something in the middle of a resolve chain.
This is an FAQ in the Autofac docs.

Constructor dependency injection via unity with parameters from HttpContext

We're using domain to customize how our application behaves. I'll illustrate it on example:
// default behavior
public class CoreService : IService {
public virtual string Hello { get { return "Hello"; } }
public virtual string FavouriteDrink { get { return "Water"; } }
}
// german.site.com
public class GermanService : CoreService {
public override string Hello { get { return "Gutten tag"; } }
public override string FavouriteDrink { get { return "Beer"; } }
}
// usa.site.com
public class UsaService : CoreService {
public override string FavouriteDrink { get { return "Cofee"; } }
}
Services are bootstrapped as follow:
var container = new UnityContainer();
container.RegisterType<IService, CoreService>();
container.RegisterType<IService, GermanService>("german.site.com");
container.RegisterType<IService, UsaService>("usa.site.com");
I use Unity to bootstrap mvc controllers. IE:
public class HomeController : Controller {
private IService m_Service;
// contructor dependency injection magic - this resolves into "CoreService"
public HomeController([Dependency]IService service) {
if (service == null) {
throw new ArgumentNullException("service");
}
m_Service = service;
}
}
Is there a way how to change unity resolution so it'll take domain into account ? Right now I ended up with
public class HomeController : Controller {
private IService m_Service;
// contructor dependency injection magic - a lot less magical
public HomeController() {
m_Service = DomainServiceLocator.Retrieve<IService>();
}
}
Support classes:
public static class DomainServiceLocator {
private static UnityContainerAdapter adapter;
public static T Retrieve<T>() {
string domain = HttpContext.Current.Request.Url.Host;
if (adapter.IsServiceRegistered(typeof(T), domain)) {
return adapter.Resolve<T>(domain);
}
return adapter.Resolve<T>();
}
}
public class QueryableContainerExtension : UnityContainerExtension {
private List<RegisterInstanceEventArgs> registeredInstances = new List<RegisterInstanceEventArgs>();
private List<RegisterEventArgs> registeredTypes = new List<RegisterEventArgs>();
protected override void Initialize() {
this.Context.Registering += (sender, e) => { this.registeredTypes.Add(e); };
this.Context.RegisteringInstance += (sender, e) => { this.registeredInstances.Add(e); };
}
public bool IsServiceRegistered(Type service, string name) {
return registeredTypes.FirstOrDefault(e => e.TypeFrom == service && e.Name == name) != null
|| registeredInstances.FirstOrDefault(e => e.RegisteredType == service && e.Name == name) != null;
}
}
public class UnityContainerAdapter {
private readonly QueryableContainerExtension queryableContainerExtension;
private readonly IUnityContainer unityContainer;
public UnityContainerAdapter()
: this(new UnityContainer()) {
}
public UnityContainerAdapter(IUnityContainer unityContainer) {
this.unityContainer = unityContainer;
// adding extensions to unity container
this.queryableContainerExtension = new QueryableContainerExtension();
unityContainer.AddExtension(this.queryableContainerExtension);
}
public T Resolve<T>(string name) {
return unityContainer.Resolve<T>(name);
}
public T Resolve<T>() {
return unityContainer.Resolve<T>();
}
public bool IsServiceRegistered(Type service, string name) {
return this.queryableContainerExtension.IsServiceRegistered(service, name);
}
}
I like to use an injection factory in these scenarios when resolving something at runtime. Essentially you're resolving your type via the domain name:
So in your composition root you could register like this:
container.RegisterType<Func<string, IService>>
(
new InjectionFactory(c => new Func<string, IService>(name => c.Resolve<IService>(name)))
);
Then in your HomeController you can inject the delegate
public class HomeController
{
private readonly Func<string,IService> _serviceFactory;
public HomeController(Func<string, IService> serviceFactory)
{
if(serviceFactory==null)
throw new ArgumentNullException("serviceFactory");
this._serviceFactory= serviceFactory;
}
public void DoSomethingWithTheService()
{
var domain = this.HttpContext.Uri.Host;
var service = this._serviceFactory(domain);
var greeting = service.Hello;
}
}
```
This is then still unit testable and you have not leaked the DI contain implementation outside of "composition root".
Also.. should CoreService be abstract to avoid direct instantiation of it?
Below is the solution I ended up with - it is based on #Spencer idea. I've created a factory, default implementation to the factory has a reference to DI container itself (IUnityContainer in my case), so it can perform the resolution based on domain once it is asked to. It is also more "modern friendly" since in current generation of ASP.NET (ASP.NET CORE) there is no such thing as magic singleton providing current HttpContext and DI is hard coded into the framework.
public interface IFactory<T>
{
T Retrieve(string domain);
}
internal sealed class Factory<T> : IFactory<T>
{
private readonly IUnityContainer _container;
public Factory(IUnityContainer container)
{
_container = container;
}
public T Resolve(string domain)
{
// this is actually more complex - we have chain inheritance here
// for simplicity assume service is either registered for given
// domain or it throws an error
return _container.Resolve<T>(domain);
}
}
// bootstrapper
var container = new UnityContainer();
container.RegisterType<IService, CoreService>();
container.RegisterType<IService, GermanService>("german.site.com");
container.RegisterType<IService, UsaService>("usa.site.com");
container.RegisterInstance<IFactory<IService>>(new Factory<IService>(container));
And the home controller looks like
public class HomeController : Controller {
private IFactory<IService> m_Factory;
public HomeController(IFactory<IService> factory) {
m_Factory = factory;
}
private void FooBar() {
var service = m_Factory.Retrieve(this.HttpContext.Uri.Host);
var hello = service.Hello;
}
}
Its also a worth mentioning that - as I'm lazy - I've build a system of decorative attributes like
[Domain("german.site.com")]
public class GermanService : IService { ... }
[DomainRoot]
public class CoreService : IService { ... }
[Domain("usa.site.com")]
public class UsaService : CoreService { ... }
So the bootstrapping is done automatically across all types in given assembly. But that part is a bit lengthy - if anyone is interested I can post it on github.

How to export parts from an object not instantiated by the MEF container

Introduction
Class SessionModel is a service locator providing several services (I am going to elaborate my system architecture in the future, but for now I need to do it that way).
Code
I edited the following code part to be a Short, Self Contained, Correct (Compilable), Example (SSCCE):
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var sessionModel = new SessionModel(3);
// first case (see text down below):
var compositionContainer = new CompositionContainer();
// second case (see text down below):
//var typeCatalog = new TypeCatalog(typeof (SessionModel));
//var compositionContainer = new CompositionContainer(typeCatalog);
compositionContainer.ComposeExportedValue(sessionModel);
var someService = compositionContainer.GetExportedValue<ISomeService>();
someService.DoSomething();
}
}
public class SessionModel
{
private int AValue { get; set; }
[Export]
public ISomeService SomeService { get; private set; }
public SessionModel(int aValue)
{
AValue = aValue;
// of course, there is much more to do here in reality:
SomeService = new SomeService();
}
}
public interface ISomeService
{
void DoSomething();
}
public class SomeService : ISomeService
{
public void DoSomething()
{
Console.WriteLine("DoSomething called");
}
}
}
Problem
I would like MEF to consider the parts (i.e. SomeService) exported by the service locator when composing other parts, but unfortunately this does not work.
First Case
When I try to get the exported value for ISomeService there is a System.ComponentModel.Composition.ImportCardinalityMismatchException telling me there are no exports with this contract name and required type identity (ConsoleApplication1.ISomeService).
Second Case
If I create the CompositionContainer using the TypeCatalog the exception is slightly different. It is a System.ComponentModel.Composition.CompositionException telling me MEF doesn't find a way to create a ConsoleApplication1.SessionModel (which is right and the reason why I am doing it myself).
Additional Information
mefx says for both cases:
[Part] ConsoleApplication1.SessionModel from: DirectoryCatalog (Path=".")
[Export] ConsoleApplication1.SessionModel.SomeService (ContractName="ConsoleApplication1.ISomeService")
[Part] ConsoleApplication1.SessionModel from: AssemblyCatalog (Assembly="ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
[Export] ConsoleApplication1.SessionModel.SomeService (ContractName="ConsoleApplication1.ISomeService")
What do I have to do? Is this possible with MEF or do I have to use Unity or StructureMap, or something else? Can this be done implementing an ExportProvider?
OK, that's how I did it:
I implemented my own SessionModelExportProvider finding exports in my SessionModel (see code below). Class SessionModelExport is just for holding the export data and – instead of creating an instance of a service – returning the value of the property of the SessionModel.
public class SessionModelExportProvider : ExportProvider
{
private List<Export> Exports { get; set; }
public SessionModelExportProvider(SessionModel sessionModel)
{
// get all the properties of the session model having an Export attribute
var typeOfSessionModel = typeof (SessionModel);
PropertyInfo[] properties = typeOfSessionModel.GetProperties();
var propertiesHavingAnExportAttribute =
from p in properties
let exportAttributes = p.GetCustomAttributes(typeof (ExportAttribute), false)
where exportAttributes.Length > 0
select new
{
PropertyInfo = p,
ExportAttributes = exportAttributes
};
// creating Export objects for each export
var exports = new List<Export>();
foreach (var propertyHavingAnExportAttribute in propertiesHavingAnExportAttribute)
{
var propertyInfo = propertyHavingAnExportAttribute.PropertyInfo;
foreach (ExportAttribute exportAttribute in propertyHavingAnExportAttribute.ExportAttributes)
{
string contractName = exportAttribute.ContractName;
if (string.IsNullOrEmpty(contractName))
{
Type contractType = exportAttribute.ContractType ?? propertyInfo.PropertyType;
contractName = contractType.FullName;
}
var metadata = new Dictionary<string, object>
{
{CompositionConstants.ExportTypeIdentityMetadataName, contractName},
{CompositionConstants.PartCreationPolicyMetadataName, CreationPolicy.Shared}
};
var exportDefinition = new ExportDefinition(contractName, metadata);
var export = new SessionModelExport(sessionModel, propertyInfo, exportDefinition);
exports.Add(export);
}
}
Exports = exports;
}
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
AtomicComposition atomicComposition)
{
return Exports.Where(e => definition.IsConstraintSatisfiedBy(e.Definition));
}
}
public class SessionModelExport : Export
{
private readonly SessionModel sessionModel;
private readonly PropertyInfo propertyInfo;
private readonly ExportDefinition definition;
public SessionModelExport(SessionModel sessionModel, PropertyInfo propertyInfo, ExportDefinition definition)
{
this.sessionModel = sessionModel;
this.propertyInfo = propertyInfo;
this.definition = definition;
}
public override ExportDefinition Definition
{
get { return definition; }
}
protected override object GetExportedValueCore()
{
var value = propertyInfo.GetValue(sessionModel, null);
return value;
}
}
The problem is that the SomeService is an instance property. You could have several SessionModel objects in your system, and MEF would have no way of knowing which SessionModel is returning the ISomeService instance that is supposed to be matched to an import.
Instead, just make SessionModel a static class and SomeService a static property. Alternatively, make SessionModel a singleton. The SomeService property would still be static, but would export the service from the one-and-only instance of SessionModel.
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Reflection;
using System.Linq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var catalogs = new AggregateCatalog();
var catalog = new System.ComponentModel.Composition.Hosting.AssemblyCatalog(Assembly.GetExecutingAssembly());
catalogs.Catalogs.Add(catalog);
var sessionModel = new SessionModel(3);
var container = new CompositionContainer(catalog);
ISomeService someService = container.GetExportedValueOrDefault<ISomeService>(sessionModel.cname);
if (someService != null)
{
someService.DoSomething();
}
}
}
public class SessionModel
{
private int AValue { get; set; }
//[Import("One",typeof(ISomeService))]
//public ISomeService SomeService { get; private set; }
public SessionModel(int aValue)
{
AValue = aValue;
// of course, there is much more to do here in reality:
}
public string cname { get { return "One"; } }
}
public class SessionModel1
{
private int AValue { get; set; }
//[Import("Two",typeof(ISomeService))]
//public ISomeService SomeService { get; private set; }
public SessionModel1(int aValue)
{
AValue = aValue;
}
public string cname { get { return "Two"; } }
}
public interface ISomeService
{
void DoSomething();
}
[Export("One",typeof(ISomeService))]
public class SomeService : ISomeService
{
public SomeService()
{
Console.WriteLine("Some Service Called");
}
public void DoSomething()
{
Console.WriteLine("DoSomething called");
Console.ReadKey();
}
}
[Export("Two",typeof(ISomeService))]
public class SomeService1 : ISomeService
{
public SomeService1()
{
Console.WriteLine("Some Service1 Called");
}
public void DoSomething()
{
Console.WriteLine("DoSomething called 1");
Console.ReadKey();
}
}
}
First case: By passing sessionModel to ComposeExportedValue you add a part of type SessionModel and not of ISomeService. To make this case work you nee to pass the service to ComposeExportedValue.
compositionContainer.ComposeExportedValue(sessionModel.SomeService);
Second case: In this case you leave the creation of parts to the container. The container can create new parts if there is either a parameter-less constructor or a constructor with parameters decorated with the ImportingConstructorAttribute. This most probably means that you will need to change your design a bit.
Personally I would go with the first case, but try to keep this to a minimum. After all the normal (and suggested) usage of MEF is letting the container create and handle parts.

Categories

Resources