First of all sorry for so much code but i belive it will be easier to find an issue here. I am using SimpleInjector and getting error inside Program class on container.Verify(); line, it says as below. I was trying to investigate throug docs website but still cannot figoure out how to fix that.
SimpleInjector.DiagnosticVerificationException: 'The configuration is
invalid. The following diagnostic warnings were reported:
-[Disposable Transient Component] FrmLogin is registered as transient, but implements IDisposable. See the Error property for detailed
information about the warnings. Please see
https://simpleinjector.org/diagnostics how to fix problems and how to
suppress individual warnings.'
Full code:
static class Program
{
private static Container container;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(container.GetInstance<FrmLogin>());
}
private static void Bootstrap()
{
// Create the container as usual.
container = new Container();
container.Register<IRepositoryDal<User>, UserRepositoryDal>();
container.Register<IRepositoryDal<Order>, OrderRepositoryDal>();
container.Register<IDbManager>(() => new DbManager("sqlserver"));
container.Register<IGenericBal<User>, UserBal>();
container.Register<IGenericBal<Order>, OrderBal>();
container.Register<FrmLogin>();
container.Verify();
}
}
public partial class FrmLogin : Form
{
private readonly IGenericBal<User> _userBal;
private readonly IGenericBal<Order> _orderBal;
public FrmLogin(IGenericBal<User> userBal, IGenericBal<Order> orderBal)
{
InitializeComponent();
_userBal = userBal;
_orderBal = orderBal;
}
}
public interface IGenericBal<out T> where T : IEntity
{
IEnumerable<T> SearchByName(string name);
}
public class UserBal : IGenericBal<User>
{
private readonly IRepositoryDal<User> _userRepositoryDal;
public UserBal(IRepositoryDal<User> userRepositoryDal)
{
_userRepositoryDal = userRepositoryDal ?? throw new ArgumentNullException(nameof(userRepositoryDal));
}
public IEnumerable<User> SearchByName(string name)
{
return _userRepositoryDal.SearchByName(name);
}
}
public interface IEntity
{
int Id { get; set; }
int DoSomething(string one, int two);
}
public interface IRepositoryDal<T> where T : IEntity
{
IEnumerable<T> SearchByName(string username);
T SearchById(string id);
void Update(T entity);
void Remove(T entity);
void Add(T entity);
}
public class UserRepositoryDal: IRepositoryDal<User>
{
private readonly IDbManager _dbManager;
public UserRepositoryDal(IDbManager dbManager)
{
//read from either singleton or configuration file !!
_dbManager = dbManager;
}
public IEnumerable<User> SearchByName(string username)
{
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("#Name", 50, username, DbType.String),
};
username = "JUSTyou";
var userDataTable = _dbManager.GetDataTable("SELECT * FROM T_Marke WHERE Name=#Name", CommandType.Text, parameters.ToArray());
foreach (DataRow dr in userDataTable.Rows)
{
var user = new User
{
Id = int.Parse(dr["Id"].ToString()),
Firstname = dr["Name"].ToString(),
};
yield return user;
}
}
public User SearchById(string id)
{
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("#Id", 50, id, DbType.Int32),
};
var userDataTable = _dbManager.GetDataTable("storedpr2", CommandType.StoredProcedure, parameters.ToArray());
return new User
{
Id = int.Parse(userDataTable.Rows[0]["Id"].ToString()),
Firstname = userDataTable.Rows[0]["Firstname"].ToString(),
Lastname = userDataTable.Rows[0]["LastName"].ToString(),
Email = userDataTable.Rows[0]["Email"].ToString()
};
}
public void Update(User entity)
{
throw new System.NotImplementedException();
}
public void Remove(User entity)
{
throw new System.NotImplementedException();
}
public void Add(User entity)
{
throw new System.NotImplementedException();
}
}
public class User : IEntity
{
public int Id { get; set; }
public int DoSomething(string one, int two)
{
throw new NotImplementedException();
}
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
The error is quite clear
A registration has been made with the Transient LifeStyle for a component that implements IDisposable.
A component that implements IDisposable would usually need deterministic clean-up but Simple Injector does not implicitly track and dispose components registered with the transient lifestyle.
One way to fix this is to make its Life Style Scoped
var container = new Container();
// Select the scoped lifestyle that is appropriate for the application
// you are building. For instance:
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
// DisposableService implements IDisposable
container.Register<FrmLogin>(Lifestyle.Scoped);
Since this is the main form you could probably ignore this warning
and dispose of it your self.
Registration registration = container.GetRegistration(typeof(FrmLogin)).Registration;
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
"Reason of suppression");
Though in my personal opinion, you should probably just give it the right Life Style and let Simple Iinjector take care of things
Additional Resources
Diagnostic Warning - Disposable Transient Components
Related
Good day. I have a problem of understanding the Dependency Injection.
So what exactly do I need is to have access from child objects to parent objects.
For example, I have my MainProgram object. This object creates another object, another object create 3-d objects and so on. Let's stop on child object #5
This child needs to have a reference to object #1.
I don't understand how to do this in a better way. But then I started to search and find something called Dependency Injection.
I really hope that this thing is the right answer for my issue (If not, please tell).
So here in my problem and example.
I'm trying to create a WEB API for one of my services. Using ASP .NET Core 6
First, I created a simple class that will be MainProgram, when Server will receive POST request with needed data, it will launch some working in multi-threading.
public class MainProgram
{
public int MaxThreads { get; set; }
public int OrderCounter { get; set; }
public AdjustableSemaphore Semaphore { get; set; }
public MainProgram(int maxThreads)
{
MaxThreads = maxThreads;
Semaphore = new AdjustableSemaphore(MaxThreads);
}
public async Task StartOperation(IApiOperation operation)
{
try
{
operation.Prepare();
operation.Start();
while (!operation.IsReady())
{
await Task.Delay(500);
}
operation.Finish();
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(e.Message);
Console.ResetColor();
}
}
public string OperationStatus(IApiOperation operation)
{
return operation.ShowDetails();
}
}
Then I added this class to Program.cs for Dependency.
builder.Services.AddSingleton(program => new MainProgram(1000));
I made a Constructor for my Controller as it was in the example I read and all worked great.
Controller create instance of MainProgram by its own.
[ApiController]
[Route("/")]
public class ApiController : ControllerBase
{
private MainProgram _mainProgram;
public ApiController(MainProgram mainProgram)
{
_mainProgram = mainProgram;
}
[HttpPost]
[Route("test")]
public string Get()
{
TestOperation to = new TestOperation(_mainProgram);
new Thread(() =>
{
var project = _mainProgram.StartOperation(to);
}).Start();
return $"Started task #{to.Id}";
}
}
The problems that I have are in this line
TestOperation to = new TestOperation(_mainProgram);
This TestOperation also has a Dependency from MainProgram. I understand that I can pass my private _mainProgram in it.
But let's pretend that TestOperation also has a child, and this child also has a child, and only the third one needs a link to MainProgram.
I thought that's where Dependency Injection helps.
Main Question is
How can I create objects that have a constructor with dependency for MainProgram,
If I cannot write new TestOperation(WITHOUT ATTRIBUTE)? It will be a syntax error.
I think you'd avoid the cycle of dependency;
If you couldn't avoid it ,you could try to inject the IServiceProvider into your services,and get the target service with provider.GetService() method,and you could try to create a Parameterservice or Static class to hold the parameter you need,
I tried as below :
Services:
interface IA {int methodA();}
interface IB { int methodB(); }
interface IC { int methodC(); }
interface IParameterService { }
public class ParameterService: IParameterService
{
public int APara;
public int BPara;
public ParameterService(int para)
{
APara = para+1;
}
}
public class A : IA
{
private readonly IServiceProvider _provider;
private readonly int Id;
public A(IServiceProvider provider)
{
_provider = provider;
Id = (provider.GetService(typeof(IParameterService)) as ParameterService).APara;
}
public int methodA()
{
return Id+1;
}
}
public class B : IB
{
private readonly IServiceProvider _provider;
public B(IServiceProvider provider)
{
_provider = provider;
}
public int methodB()
{
return (_provider.GetService(typeof(IA)) as A).methodA();
}
}
public class C : IC
{
private readonly IServiceProvider _provider;
public C(IServiceProvider provider)
{
_provider = provider;
}
public int methodC()
{
return (_provider.GetService(typeof(IB)) as B).methodB();
}
}
In startup:
services.AddTransient<IParameterService>(x => new ParameterService(1));
services.AddTransient<IA,A>();
services.AddTransient<IB,B>();
services.AddTransient<IC, C>();
in controller:
private readonly A _A;
private readonly C _C;
public SomeController(IServiceProvider provider)
{
_A = (A)provider.GetService(typeof(IA));
_C=(C)provider.GetService(typeof(IC));
}
Result:
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");
As i am learning through design pattern concept and also wanted to implement the payment modules in my project using the proper design pattern. So for that I have created some sample code.
Currently I have two concrete implementation for the payment PayPal and Credit Card. But the concrete implementation will be added further on the project.
Payment Service
public interface IPaymentService
{
void MakePayment<T>(T type) where T : class;
}
Credit Card and Pay Pal Service
public class CreditCardPayment : IPaymentService
{
public void MakePayment<T>(T type) where T : class
{
var creditCardModel = (CreditCardModel)(object)type;
//Implementation CreditCardPayment
}
}
class PayPalPayment : IPaymentService
{
public void MakePayment<T>(T type) where T : class
{
var payPalModel = (PayPalModel)(object)type;
//Further Implementation will goes here
}
}
Client Code Implementation
var obj = GetPaymentOption(payType);
obj.MakePayment<PayPalModel>(payPalModel);
Get Payment Option
private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
IPaymentService paymentService = null;
switch (paymentType)
{
case PaymentType.PayPalPayment:
paymentService = new PayPalPayment();
break;
case PaymentType.CreditCardPayment:
paymentService = new CreditCardPayment();
break;
default:
break;
}
return paymentService;
}
I thought of implementing this modules using strategy design pattern, and I got deviated from Strategy and ended up doing this way.
Is this a proper way for creating the payment modules. Is there a more better approach of solving this scenario. Is this a design pattern?
Edited:
Client Code:
static void Main(string[] args)
{
PaymentStrategy paymentStrategy = null;
paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)1));
paymentStrategy.Pay<PayPalModel>(new PayPalModel() { UserName = "", Password = "" });
paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)2));
paymentStrategy.Pay<CreditCardModel>(
new CreditCardModel()
{
CardHolderName = "Aakash"
});
Console.ReadLine();
}
Strategy:
public class PaymentStrategy
{
private readonly IPaymentService paymentService;
public PaymentStrategy(IPaymentService paymentService)
{
this.paymentService = paymentService;
}
public void Pay<T>(T type) where T : class
{
paymentService.MakePayment(type);
}
}
Does this update inlines with the Strategy Pattern?
One major drawback of using an abstract factory for this is the fact that it contains a switch case statement. That inherently means if you want to add a payment service, you have to update the code in the factory class. This is a violation of the Open-Closed Principal which states that entities should be open for extension but closed for modification.
Note that using an Enum to switch between payment providers is also problematic for the same reason. This means that the list of services would have to change every time a payment service is added or removed. Even worse, a payment service can be removed from the strategy, but still be an Enum symbol for it even though it isn't valid.
On the other hand, using a strategy pattern doesn't require a switch case statement. As a result, there are no changes to existing classes when you add or remove a payment service. This, and the fact that the number of payment options will likely be capped at a small double-digit number makes the strategy pattern a better fit for this scenario.
Interfaces
// Empty interface just to ensure that we get a compile
// error if we pass a model that does not belong to our
// payment system.
public interface IPaymentModel { }
public interface IPaymentService
{
void MakePayment<T>(T model) where T : IPaymentModel;
bool AppliesTo(Type provider);
}
public interface IPaymentStrategy
{
void MakePayment<T>(T model) where T : IPaymentModel;
}
Models
public class CreditCardModel : IPaymentModel
{
public string CardHolderName { get; set; }
public string CardNumber { get; set; }
public int ExpirtationMonth { get; set; }
public int ExpirationYear { get; set; }
}
public class PayPalModel : IPaymentModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
Payment Service Abstraction
Here is an abstract class that is used to hide the ugly details of casting to the concrete model type from the IPaymentService implementations.
public abstract class PaymentService<TModel> : IPaymentService
where TModel : IPaymentModel
{
public virtual bool AppliesTo(Type provider)
{
return typeof(TModel).Equals(provider);
}
public void MakePayment<T>(T model) where T : IPaymentModel
{
MakePayment((TModel)(object)model);
}
protected abstract void MakePayment(TModel model);
}
Payment Service Implementations
public class CreditCardPayment : PaymentService<CreditCardModel>
{
protected override void MakePayment(CreditCardModel model)
{
//Implementation CreditCardPayment
}
}
public class PayPalPayment : PaymentService<PayPalModel>
{
protected override void MakePayment(PayPalModel model)
{
//Implementation PayPalPayment
}
}
Payment Strategy
Here is the class that ties it all together. Its main purpose is to provide the selection functionality of the payment service based on the type of model passed. But unlike other examples here, it loosely couples the IPaymentService implementations so they are not directly referenced here. This means without changing the design, payment providers can be added or removed.
public class PaymentStrategy : IPaymentStrategy
{
private readonly IEnumerable<IPaymentService> paymentServices;
public PaymentStrategy(IEnumerable<IPaymentService> paymentServices)
{
this.paymentServices = paymentServices ?? throw new ArgumentNullException(nameof(paymentServices));
}
public void MakePayment<T>(T model) where T : IPaymentModel
{
GetPaymentService(model).MakePayment(model);
}
private IPaymentService GetPaymentService<T>(T model) where T : IPaymentModel
{
var result = paymentServices.FirstOrDefault(p => p.AppliesTo(model.GetType()));
if (result == null)
{
throw new InvalidOperationException(
$"Payment service for {model.GetType().ToString()} not registered.");
}
return result;
}
}
Usage
// I am showing this in code, but you would normally
// do this with your DI container in your composition
// root, and the instance would be created by injecting
// it somewhere.
var paymentStrategy = new PaymentStrategy(
new IPaymentService[]
{
new CreditCardPayment(), // <-- inject any dependencies here
new PayPalPayment() // <-- inject any dependencies here
});
// Then once it is injected, you simply do this...
var cc = new CreditCardModel() { CardHolderName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(cc);
// Or this...
var pp = new PayPalModel() { UserName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(pp);
Additional References:
Dependency Injection Unity - Conditional Resolving
Factory method with DI and IoC
This is one approach you could take. There's not a lot to go on from your source, and I'd really reconsider having MakePayment a void instead of something like an IPayResult.
public interface IPayModel { } // Worth investigating into common shared methods and properties for this
public interface IPaymentService
{
void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
void MakePayment(T payModel); // Void here? Is the status of the payment saved on the concrete pay model? Why not an IPayResult?
}
public class CreditCardModel : IPayModel
{
public string CardHolderName { get; set; }
}
public class PayPalModel : IPayModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
public class CreditCardPayment : IPaymentService<CreditCardModel>
{
public void MakePayment(CreditCardModel payModel)
{
//Implmentation CreditCardPayment
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as CreditCardModel);
}
}
public class PayPalPayment : IPaymentService<PayPalModel>
{
public void MakePayment(PayPalModel payModel)
{
//Implmentation PayPalPayment
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as PayPalModel);
}
}
public enum PaymentType
{
PayPalPayment = 1,
CreditCardPayment = 2
}
So following your implementation approach, it could look something like:
static class Program
{
static void Main(object[] args)
{
IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);
paymentStrategy.MakePayment(new PayPalModel { UserName = "", Password = "" });
paymentStrategy = GetPaymentOption((PaymentType)2);
paymentStrategy.MakePayment(new CreditCardModel { CardHolderName = "Aakash" });
Console.ReadLine();
}
private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
switch (paymentType)
{
case PaymentType.PayPalPayment:
return new PayPalPayment();
case PaymentType.CreditCardPayment:
return new CreditCardPayment();
default:
throw new NotSupportedException($"Payment Type '{paymentType.ToString()}' Not Supported");
}
}
}
I also think for a strategy/factory pattern approach, manually creating an IPayModel type doesn't make much sense. Therefore you could expand the IPaymentService as an IPayModel factory:
public interface IPaymentService
{
IPayModel CreatePayModel();
void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
new T CreatePayModel();
void MakePayment(T payModel);
}
public class CreditCardPayment : IPaymentService<CreditCardModel>
{
public CreditCardModel CreatePayModel()
{
return new CreditCardModel();
}
public void MakePayment(CreditCardModel payModel)
{
//Implmentation CreditCardPayment
}
IPayModel IPaymentService.CreatePayModel()
{
return CreatePayModel();
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as CreditCardModel);
}
}
Usage would then be:
IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);
var payModel = (PayPalModel)paymentStrategy.CreatePayModel();
payModel.UserName = "";
payModel.Password = "";
paymentStrategy.MakePayment(payModel);
Your code is basically using the factory pattern. This is a good way to handle more than one method of payment
http://www.dotnettricks.com/learn/designpatterns/factory-method-design-pattern-dotnet
Here is my try to add a Stash to the actor:
class Program
{
static void Main(string[] args)
{
var actorSystem = ActorSystem.Create("mySystem");
var container = new WindsorContainer();
container.Install(new CommonWindsorInstaller());
// ReSharper disable once ObjectCreationAsStatement
new WindsorDependencyResolver(container, actorSystem);
var rootActor = actorSystem.ActorOf(actorSystem.DI().Props<RootActor>(), typeof(RootActor).Name);
rootActor.Tell(new CreateChildMessage());
Console.ReadLine();
}
}
internal class CreateChildMessage
{
}
internal class CommonWindsorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<RootActor>().Named("RootActor").LifestyleTransient());
container.Register(Component.For<ChildActor>().Named("ChildActor").LifestyleTransient());
container.Register(Component.For<IChildActor>().ImplementedBy<ChildActor>().Named("IChildActor").LifestyleTransient());
}
}
internal class RootActor : ReceiveActor
{
public RootActor()
{
Receive<CreateChildMessage>(
m =>
{
var child = ActorHelper.CreateActor(Context, typeof(IChildActor), "child");
});
}
}
public interface IChildActor
{
}
public class ChildActor : ReceiveActor, IChildActor, IWithUnboundedStash
{
public IStash Stash { get; set; }
}
public static class ActorHelper
{
public static IActorRef CreateActor(IUntypedActorContext context, Type actorType, string name)
{
var actorName = actorType.Name + "." + name;
var actor = context.Child(actorName);
if (!actor.Equals(ActorRefs.Nobody))
{
return actor;
}
var actorProps = context.DI().Props(actorType);
actor = context.ActorOf(actorProps, actorName);
return actor;
}
}
Unfortunately, I'm getting following exception:
[ERROR][17.02.2017 9:39:19][Thread 0004][ActorSystem(mySystem)] An exception occurred while trying to apply plugin of type Akka.Actor.ActorStashPlugin to the newly created actor (Type = Akka.Stash.ChildActor, Path = akka://mySystem/user/RootActor/IChildActor.child)
Cause: System.NotSupportedException: DequeBasedMailbox required, got: Mailbox
An (unbounded) deque-based mailbox can be configured as follows:
my-custom-mailbox {
mailbox-type = "Akka.Dispatch.UnboundedDequeBasedMailbox"
}
at Akka.Actor.Internal.AbstractStash..ctor(IActorContext context, Int32 capacity)
at Akka.Actor.StashFactory.CreateStash(IActorContext context, Type actorType)
at Akka.Actor.ActorStashPlugin.AfterIncarnated(ActorBase actor, IActorContext context)
at Akka.Actor.ActorProducerPipeline.AfterActorIncarnated(ActorBase actor, IActorContext context)
EDIT
I can get rid of this error by making my IChildActor descendant of IWithUnboundedStash, i.e.
public interface IChildActor: IWithUnboundedStash
{
}
public class ChildActor : ReceiveActor, IChildActor
{
public IStash Stash { get; set; }
}
But it's not the option, I don't want to all my IChildActor implementations has a stash
EDIT 2
Here is the GitHub repository to reproduce https://github.com/bonza/Akka.Net.CastleWindsor.Stash/
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.