Calling a Command from a Separate Class File - c#

So I have been at it for days, and for the life of me cannot find any documentation that fits my situation exactly here.
I have essentially set up a custom navigation service and would like to call the command from my ViewModel Class directly from my User Control.
I think I'm on the edge of having it here, but my lack of experience with C# is shooting me in the foot.
Here is the section of code from my Login.xaml.cs in question:
private LoginViewModel _loginViewModel;
public Login(LoginViewModel loginViewModel)
{
_loginViewModel = loginViewModel;
}
private void GrantAccess()
{
int userAccess = Int16.Parse(User.Access);
if (userAccess == 1)
{
MessageBox.Show("The bottom man");
}
if (userAccess == 2)
{
MessageBox.Show("The little boss");
}
if (userAccess == 3)
{
MessageBox.Show("The little big boss");
}
if (userAccess == 4)
{
{
_loginViewModel.NavigateMM1Command.Execute(null);
}
}
}
and here is the command I'm trying to reference from the ViewModel:
public class LoginViewModel : BaseViewModel
{
public ICommand NavigateMM1Command { get; }
public LoginViewModel(NavigationStore navigationStore)
{
NavigateMM1Command = new NavigateCommand<MM1ViewModel>(new NavigationService<MM1ViewModel>(navigationStore, () => new MM1ViewModel(navigationStore)));
}
}
Basically I've been going through tutorial after tutorial trying to apply what they teach to what I need and its worked for the most part but now _loginViewModel is throwing a null reference exception and I'm not sure why.
I have tried:
LoginViewModel loginViewModel = new loginViewModel();
but its asking me to pass a navigationStore argument through it and that feels wrong.
Any help here will cure my temporary insanity XD

You're receiving a Null Object Reference because navigationStore is null when LoginViewModel is being constructed.
That is, you have not configured a means to instantiate the type navigationStore when constructing LoginViewModel.
Dependency Injection (DI), or Invocation of Control (IoC) is bit more comprehensive a subject to cover in this answer.
Having said that,
I'll provide code to review here. It represents a means to configure a service provider using a collection of type mappings.
In this complete, ConsoleApp example, we'll explicitly instantiate a ServiceCollection, add Service Types (specifying mapping where application), and Build the ServiceProvider; With that provider, we'll resolve and instantiate Login type using GetService -- instantiating all the types;
The Types are essentially mockups of the types you've specified, but I've modified some aspects (an made up notioned like what your Execute method and usage of NavigationStore was).
DemoNavTypes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleDemo.NavLoginDemo
{
public interface ICommand
{
void Execute(string? userName);
}
public interface INavigationStore {
public bool this[string index] { get;set; }
}
public interface INavigationService {
void GrantAccessToUser(string userName);
}
public interface INavigationViewModel { }
internal class NavigationStore : INavigationStore
{
private Dictionary<string, bool> userAccessDict;
public NavigationStore() {
userAccessDict = new Dictionary<string, bool>();
}
public bool this[string index] {
get => userAccessDict.TryGetValue(index, out var val) && val;
set => userAccessDict[index] = value;
}
}
internal class NavigationService : INavigationService
{
private readonly INavigationStore _navigationStore;
public NavigationService(INavigationStore navigationStore)
{
_navigationStore = navigationStore;
}
public void GrantAccessToUser(string? userName)
{
if (string.IsNullOrWhiteSpace(userName))
throw new ArgumentException(nameof(userName));
_navigationStore[userName!] = true;
}
}
internal class NavigationCommand : ICommand
{
private readonly INavigationService _navigationService;
public NavigationCommand(INavigationService navigationService)
{
_navigationService = navigationService;
}
public void Execute(string? userName)
{
if (userName != null)
{
_navigationService.GrantAccessToUser(userName);
}
}
}
internal class User
{
public string? Name { get; set; }
public string Access { get; set; } = "1";
}
public abstract class BaseViewModel
{
internal User User { get; set; } = new User();
protected BaseViewModel() { }
}
internal class LoginViewModel : BaseViewModel, INavigationViewModel
{
private readonly ICommand _command;
public LoginViewModel(ICommand command) : base()
{
_command = command;
}
internal ICommand NavigateMM1Command => _command;
}
internal class Login
{
private User User => _loginViewModel.User;
private readonly LoginViewModel _loginViewModel;
public Login(LoginViewModel loginViewModel)
{
_loginViewModel = loginViewModel;
}
internal void SetAccess(int access)
{
SetAccess($"{access}");
}
internal void SetAccess(string access)
{
User.Access = access;
}
internal void SetUserName(string userName) { User.Name = userName; }
internal async Task GrantAccessAsync()
{
await Task.Yield();
int userAccess = Int16.Parse(User.Access);
switch (userAccess)
{
case 1:
Console.WriteLine("The bottom man");
break;
case 2:
Console.WriteLine("The little boss");
break;
case 3:
Console.WriteLine("The little big boss");
break;
case 4:
_loginViewModel.NavigateMM1Command.Execute(User.Name);
break;
default:
throw new NotImplementedException();
}
}
}
}
Program.cs (using Microsoft.Extensions.DependencyInjection)
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Immutable;
using System.ComponentModel.Design;
using System.Linq;
using ConsoleDemo.NavLoginDemo;
internal class Program
{
private static async Task Main(string[] args)
{
var services = new ServiceCollection();
var provder = ConfigureServices(services);
var login = provder.GetService<Login>();
if (login != null)
{
await login.GrantAccessAsync();
login.SetAccess(2);
await login.GrantAccessAsync();
login.SetAccess(3);
await login.GrantAccessAsync();
login.SetUserName("James Bond");
login.SetAccess(4);
await login.GrantAccessAsync();
}
}
private static IServiceProvider ConfigureServices(IServiceCollection services)
{
return services
.AddScoped<INavigationStore, NavigationStore>()
.AddScoped<INavigationService, NavigationService>()
.AddScoped<ICommand, NavigationCommand>()
.AddScoped<LoginViewModel>()
.AddScoped<Login>()
.BuildServiceProvider();
}
}
Note
-- However,
In your application, you'll probably already have a ServiceCollection instance in your Program.cs or Startup.cs file. And the ServiceProvider (or HostProvider) will be managed over by the application; So, you probably won't need to explicitly resolve (or GetService<T>) -- just add the Service Type (mappings) in ServiceCollection. Those parameter types will be instantiated and 'injected' into the constructor of Type that is itself being instantiated.

Related

Which design pattern to use when we have classes that does similar high level functionality but the returns different types in methods?

I have an existing C# console application that takes arguments and based on the arguments
creates an instance of markets (UK, US, MX..) using dependency injection.
Each market class does a 'string GetData()', 'string ProcessData()' and 'bool ExportData()'.
The application was initially created for one eCommerce vendor's markets. Now I am told to modify it for a different vendor that does a different process. The high-level flow remains the same.
'GetData' to fetch records from DB,
'ProcessData' for any transformation or the likes
'ExportData'.
The difference is Getdata() pulls records from DB and maps to an object. I am planning to use Petapoco. 'ProcessData' might return a similar class. 'Exportdata' currently does an API call but for the new vendor, I have to write to a file.
I was reading up on patterns I am totally confused. At first, I thought I needed abstract factory pattern and now I think the factory method is what I should be using but I am not sure if I am doing it right. Need some guidance/review here. A sample cs file I created from my understanding of factory pattern. This code is based on the headfirst code samples.
using System;
using System.Collections.Generic;
using StatusExport.Models;
namespace factorymethod
{
class Program
{
static void Main(string[] args)
{
ClientFactory factory = null;
Console.WriteLine("Enter client code:");
string clientCode= Console.ReadLine();
switch (clientCode.ToLower())
{
case "costco":
factory = new CostcoFactory("accountname", "taskname");
break;
//NEw vendor might be added
//case "walmart"
//factory = new WalmartFactory("taskname", "type");
//break
default:
break;
}
bool status = factory.ProcessData();
Console.ReadKey();
}
}
abstract class Client
{
public abstract string AccountName { get; }
public abstract string Task { get; set; }
//More properties might be added. Some may not even be used by some of the new vendors. For example, Costco Might need accountname and task. Tomorrow if walmart comes, they might not need these two or may need task and a new property 'type'
public abstract List<T> GetData<T>();
public abstract List<T> ProcessData<T>();
public abstract bool ExportData();
}
class CostcoClient : Client
{
public override string AccountName { get; }
public override string Task { get; set; }
public CostcoClient(string accountName, string task)
{
AccountName = accountName;
Task = task;
}
public override List<DBRecord> GetData<DBRecord>() //DBRecord class is specific to Costco.
{
List<DBRecord> dbresult = new List<DBRecord>();
//dbresult = db return data mapped to an object DBRecord using petapoco. Another vendor might have a different class to which DB records are mapped. So the return type can be generic
return asn;
}
public override List<T> ProcessData<T>()
{
throw new NotImplementedException(); //Any data transformation or business logic. Return type might be DBRecord or a new class altogether
}
public override bool ExportData()
{
throw new NotImplementedException();//Call API or write data to file and if success send true else false
}
}
abstract class ClientFactory
{
public abstract bool ProcessData();
}
class CostcoFactory : ClientFactory
{
public string AccountName { get; }
public string Task { get; set; }
public CostcoFactory(string accountname, string task)
{
AccountName = accountname;
Task = task;
}
public override bool ProcessData()
{
CostcoClient gc = new CostcoClient(AccountName, Task);
var result = gc.GetData<DBRecord>();
return true;
}
}
}
Do you think this is the right design approach?
I also want to keep the console project independent of vendor project. So maybe 'StatusExport.Program' for the console application. DLL projects StatusExport.Common to hold the interface and abstract classes' and 'StatusExport.Client(ex:StatusExport.Costco)' for each vendor stuff.
You can create BaseClient class that will contains a basic group of properties, and if you need to add something new - just inherit it. You did right, but i think it's better to change public modifier to protected in your properties AccountName and Task, to give access to them only from child classes.
Actually, you can create a BaseClientModels (request/response) for each method if you are not sure that returning type List will be always actual.
Example:
public abstract class BaseClient
{
#region Properties : Protected
protected abstract string AccountName { get; }
protected abstract string Task { get; set; }
#endregion
#region Methods : Public
public abstract BaseGetDataResponseModel GetData(BaseGetDataRequestModel model);
public abstract BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model);
public abstract BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model);
#endregion
}
public class BaseGetDataResponseModel { }
public class BaseGetDataRequestModel { }
public class BaseProcessDataResponseModel { }
public class BaseProcessDataRequestModel { }
public class BaseExportDataResponseModel { }
public class BaseExportDataRequestModel { }
Then let's look on your class CostcoClient and how it can looks like:
public class CostcoClient : BaseClient
{
#region Properties : Protected
protected override string AccountName { get; }
protected override string Task { get; set; }
protected virtual IDataReader<BaseGetDataRequestModel, BaseGetDataResponseModel> DataReader { get; }
protected virtual IDataProcessor<CostcoClientProcessDataRequestModel, CostcoClientProcessDataResponseModel> DataProcessor { get; }
protected virtual IExportDataHandler<CostcoClientExportDataRequestModel, CostcoClientExportDataResponseModel> ExportDataHandler { get; }
#endregion
#region Constructors
public CostcoClient(string accountName, string task)
{
//set DataReader, DataProcessor, ExportDataHandler
AccountName = accountName;
Task = task;
}
#endregion
#region Methods : Public
public override BaseGetDataResponseModel GetData(BaseGetDataRequestModel model)
{
if (model is CostcoClientGetDataRequestModel clientGetDataRequestModel)
{
return DataReader.ReadData(clientGetDataRequestModel);
}
return null; //wrong type has passed
}
public override BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model)
{
if (model is CostcoClientProcessDataRequestModel clientProcessDataRequestModel)
{
return DataProcessor.ProcessData(clientProcessDataRequestModel);
}
return null;
}
public override BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model)
{
if (model is CostcoClientExportDataRequestModel clientExportDataRequestModel)
{
return ExportDataHandler.Handle(clientExportDataRequestModel);
}
return null;
}
#endregion
}
public class CostcoClientGetDataRequestModel : BaseGetDataRequestModel { }
public class CostcoClientGetDataResponseModel : BaseGetDataResponseModel { }
public class CostcoClientProcessDataRequestModel : BaseProcessDataRequestModel { }
public class CostcoClientProcessDataResponseModel : BaseProcessDataResponseModel { }
public class CostcoClientExportDataRequestModel : BaseExportDataRequestModel { }
public class CostcoClientExportDataResponseModel : BaseExportDataResponseModel { }
public interface IDataReader<TIn, TOut>
{
public TOut ReadData(TIn model);
}
public interface IDataProcessor<TIn, TOut>
{
public TOut ProcessData(TIn model);
}
public interface IExportDataHandler<TIn, TOut>
{
public TOut Handle(TIn model);
}
public class CostcoClientDataReader : IDataReader<CostcoClientGetDataRequestModel, CostcoClientGetDataResponseModel>
{
public CostcoClientGetDataResponseModel ReadData(CostcoClientGetDataRequestModel model)
{
throw new NotImplementedException();
}
}
//and so on
You have to implement IDataReader, IDataProcessor, IExportDataHandler, make your logic and call it from GetData, ProcessData, ExportData methods, as an example, and get instances via dependency injection.
Then, we can change your factory to this:
public interface IClientFactory
{
BaseClient GetClientService(ClientServicesEnum value);
}
public class BaseClientFactory : IClientFactory
{
#region Propertied : Protected
protected virtual IEnumerable<BaseClient> Services { get; }
protected string AccountName { get; }
protected string Task { get; set; }
#endregion
#region Constructors
public BaseClientFactory(IEnumerable<BaseClient> services, string accountname, string task)
{
Services = services;
AccountName = accountname;
Task = task;
}
#endregion
public BaseClient GetClientService(ClientServicesEnum value)
=> Services.First(x => x.GetType().Equals(GetClientServiceByCode()[value]));
private Dictionary<ClientServicesEnum, Type> GetClientServiceByCode()
=> new Dictionary<ClientServicesEnum, Type>()
{
{ ClientServicesEnum.CostcoClient, typeof(CostcoClient) }
};
}
public enum ClientServicesEnum
{
CostcoClient = 1,
Another2 = 2,
Another3 = 3
}
Where
protected virtual IEnumerable<BaseClient> Services { get; }
you can get via DI too, and then get correct ServiceHandler by enum.
And your main function to call all this:
switch (clientCode)
{
case 1:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.CostcoClient);
break;
case 2:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.Another2);
break;
default:
break;
}
bool status = baseClient.ProcessData(null); //your model
The main thing is - you can use more than one pattern, for example one from Creational patterns, and one from Structural.
If i need some help in code architecture i use this:
https://refactoring.guru/
I think, using this example you can remove properties AccountName and Task, because of request models in methods.

using localization service GetAllLanguages from a component composer, incorrect DI?

I have an interface as below, which I use to add a specific language if it does not exist:
public interface IGetLanguagesService
{
void GetLanguages(ILocalizationService localization);
}
public class LanguageService : IGetLanguagesService
{
ILocalizationService _localizationService;
public void GetLanguages(ILocalizationService localization)
{
_localizationService = localization;
var currentLanguages = _localizationService.GetAllLanguages();
bool exists = false;
foreach (var currentLan in currentLanguages)
{
if (currentLan.IsoCode == "es-ES")
{
exists = true;
}
}
if (!exists)
{
AddLanguage(_localizationService);
}
}
public void AddLanguage(ILocalizationService localization)
{
var languageSE = new Language("es-ES") { CultureName = "es-ES", IsMandatory = true };
localization.Save(languageSE);
}
}
I want to use this at start-up so have created a component composer, which on Initialize() I want to call CallGetLanguages() but Im not entirely sure what should be in Initialize(), I think my DI may be wrong?
public class LanguagesComposer : ComponentComposer<LanguagesComponent>
{
public void Compose(Composition composition)
{
composition.Register<IGetLanguagesService>(Lifetime.Singleton);
composition.Register<ILocalizationService>(Lifetime.Singleton);
composition.Components().Append<LanguagesComponent>();
}
}
public class LanguagesComponent : IComponent
{
public void Initialize()
{
???????
}
public void Terminate()
{
throw new NotImplementedException();
}
IGetLanguagesService _getLanguagesService;
ILocalizationService _localization;
public void CallGetLanguages(IGetLanguagesService getLanguages, ILocalizationService localization)
{
_getLanguagesService = getLanguages;
_localization = localization;
_getLanguagesService.GetLanguages(localization);
}
}
You've passed ILocalizationService localization instance to LanguageService twice, pass it to constructor instead and use a constructor injection. The same issue with LanguagesComponent, pass all its dependencies to constructor instead of methods

Autofac - Delegate Factories + Type Interceptors together

I am trying to get AutoFac Delegate Factories & Type Interceptors to play nicely with each other, but I cannot seem to get the behaviour I want.
(http://docs.autofac.org/en/latest/advanced/delegate-factories.html)
(http://docs.autofac.org/en/latest/advanced/interceptors.html)
In the example below, I want calls to the IQuoteService.GetQuote(...) to be intercepted by the CallLogger interceptor.
I've tried both of the Enable___(); extension methods for enabling interception, but none of them seem to correctly intercept the call.
I suspect the problem is the way that Autofac is registering the proxy and the signature of the delegate, but to be honest I am a little stuck... I don't know Autofac as well as I know Castle Windsor, but this project is using Autofac.
ANSWERED BELOW
Code updated to working example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Autofac;
using Autofac.Extras.DynamicProxy2;
using Castle.DynamicProxy;
namespace AutofacTest
{
public class Shareholding
{
public delegate Shareholding Factory(string symbol, uint holding);
private readonly IQuoteService _quoteService;
public Shareholding(string symbol, uint holding, IQuoteService quoteService)
{
_quoteService = quoteService;
Symbol = symbol;
Holding = holding;
}
public string Symbol { get; private set; }
public uint Holding { get; set; }
public decimal Value
{
get { return _quoteService.GetQuote(Symbol) * Holding; }
}
}
public class Portfolio
{
private readonly IList<Shareholding> _holdings = new List<Shareholding>();
private readonly Shareholding.Factory _shareholdingFactory;
public Portfolio(Shareholding.Factory shareholdingFactory)
{
_shareholdingFactory = shareholdingFactory;
}
public decimal Value
{
get { return _holdings.Sum(h => h.Value); }
}
public void Add(string symbol, uint holding)
{
_holdings.Add(_shareholdingFactory(symbol, holding));
}
}
public interface IQuoteService
{
decimal GetQuote(string symbol);
}
public class QuoteService : IQuoteService
{
public decimal GetQuote(string symbol)
{
return 10m;
}
}
public class CallLogger : IInterceptor
{
private readonly TextWriter _output;
public CallLogger(TextWriter output)
{
_output = output;
}
public void Intercept(IInvocation invocation)
{
_output.Write("Calling method {0} with parameters {1}... ",
invocation.Method.Name,
string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));
invocation.Proceed();
_output.WriteLine("Done: result was {0}.", invocation.ReturnValue);
}
}
internal class Program
{
private static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Shareholding>();
builder.RegisterType<Portfolio>();
builder.Register(c => new CallLogger(Console.Out));
builder.RegisterType<QuoteService>()
.As<IQuoteService>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(CallLogger));
var container = builder.Build();
var portfolio = container.Resolve<Portfolio>();
portfolio.Add("ABC", 1234);
portfolio.Add("DEF", 4567);
Console.WriteLine(portfolio.Value);
Console.ReadKey();
}
}
}
// Magic?
builder.RegisterType<Portfolio>()
.As<IPortfolio>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(CallLogger));;
builder.Register(c => new CallLogger(Console.Out));
var container = builder.Build();
var isResolved = container.Resolve<IPortfolio>();
It looks to me like you are missing an association between the DynamicProxy for IPortfolio and the IInterceptor type.
This can be remedied via registration:
builder.RegisterType<Portfolio>()
.As<IPortfolio>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(CallLogger));
or via the InterceptAttribute
[Intercept(typeof(CallLogger))]
public interface IPortfolio
{
decimal Value { get; }
void Add(string symbol, uint holding);
}

Ninject Factory Pattern and Bindings

I am trying to implement the Ninject.Extensions.Factory pattern and my program is telling me my bindings aren't right, but I can't figure out why. I keep getting an "Error activating IHashable. No matching bindings are available, and the type is not self-bindable" exception thrown. The relevant areas of my code are below:
public interface IHashable
{
FileInfo File { get; }
string ComputeHash();
}
public interface IHashableFactory
{
IHashable GetNew(FileInfo file);
}
public class MD5ChecksumProvider : IHashable
{
private FileInfo _file;
public FileInfo File
{
get { return _file; }
}
public MD5ChecksumProvider(FileInfo file)
{
if (file == null)
throw new ArgumentNullException("file");
_file = file;
}
public string ComputeHash()
{
// implementation
}
}
public class AppFileProvider : IAppFileProvider
{
private IHashableFactory _hashFactory;
public IHashableFactory HashProvider
{
get { return _hashFactory; }
}
public AppFileProvider(IHashableFactory hashProviderFactory)
{
_hashFactory = hashProviderFactory;
}
public string GetChecksum(FileInfo fileInfo)
{
var hasher = _hashFactory.GetNew(fileInfo);
return hasher.ComputeHash();
}
}
public class BindingProviders : NinjectModule
{
public override void Load()
{
Bind<IHashable>()
.To<MD5ChecksumProvider>();
}
}
public class BindingFactories : NinjectModule
{
public override void Load()
{
Bind<IHashableFactory>()
.ToFactory();
}
}
// my DI container
public sealed class Container : IDisposable
{
private bool _isDisposed;
private IKernel _kernel;
private BindingFactories _bindingFactories;
private BindingObjects _bindingObjects;
private BindingProviders _bindingProviders;
public Container()
{
_isDisposed = false;
_bindingFactories = new BindingFactories();
_bindingObjects = new BindingObjects();
_bindingProviders = new BindingProviders();
_kernel = new StandardKernel(_bindingObjects, _bindingProviders, _bindingFactories);
}
public T Get<T>()
{
return _kernel.Get<T>();
}
public void Dispose()
{
// nothing worth seeing
}
private void Dispose(bool disposing)
{
// nothing worth seeing
}
}
// the program (composition root)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
using (var container = new Container())
{
var fileProvider = container.Get<IAppFileProvider>();
foreach (var file in files)
{
string hash = fileProvider.GetChecksum(storePath, file); // this line throws "Error activating IHashable. No matching bindings are available, and the type is not self-bindable.""
}
}
}
}
I feel like my bindings are setup correctly but I must be missing something obvious. Any ideas why I'm getting the exception from the above code?
This is caused by a feature of Ninject.Extensions.Factory.
It treats methods which start with Get differently from those which don't.
If you rename IHashableFactory.GetNew to Create or Make everything works fine.
The "Get" feature is described here:
The default instace provider of the extension has the convention that it tries to return an instance using a named binding whenever a method starts with “Get”. E.g. IFoo GetMySpecialFoo() is equal to
resolutionRoot.Get<IFoo>("MySpecialFoo");
Since i think this is not obvious to the user and the exception isn't helpful at all in this regard, i have filed an issue report here

Can the WindsorContainer pass a object through the resolve tree when using a factory

I have a problem like this:
public interface IBaseVMFactory
{
public BaseVm Create(TransientDependency otherVM);
}
public class BaseVM
{
BaseVM(ChildVM1 child1, ChildVM2 child2)
}
public class ChildVM1
{
ChildVM1(TransientDependency otherVM)
}
All my viewModels (..VM) needs to be transient. And I need for the childVM1 to get the same instance of otherVM as given to the factory.
I tried to register the BaseVm as ScopedLifestyle, and manually implementing the factory and passing the instance when resolving inside the scope.
But still I get a new instance of the otherVM when resolving.
Am I missing something obvious here?
Kjetil.
I tried reproducing your problem with Windsor 3.2 with the code below:
using System.Diagnostics;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace ConsoleApplication2
{
public class SomeViewModel
{
public SomeViewModel(ISomeFactory factory)
{
var dependency1 = factory.CreateSomeDependency();
var dependency2 = factory.CreateSomeDependency();
Debug.Assert(dependency1 != dependency2);
Debug.Assert(dependency1.Dep == dependency2.Dep);
}
}
public class SomeDependency
{
private readonly DepDep _dep;
public SomeDependency(DepDep dep)
{
_dep = dep;
}
public DepDep Dep
{
get { return _dep; }
}
}
public class DepDep
{
}
public interface ISomeFactory
{
SomeDependency CreateSomeDependency();
}
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<SomeViewModel>().LifestyleTransient(),
Component.For<SomeDependency>().LifestyleTransient(),
Component.For<DepDep>().LifestyleBoundTo<SomeViewModel>(),
Component.For<ISomeFactory>().AsFactory().LifestyleTransient()
);
container.Resolve<SomeViewModel>();
}
}
}
To my suprise this just works. So it seems that the factory is now taking over the scope of the context in which it is created. I hope this will help you.
Kind regards,
Marwijn.

Categories