Autofac WCF injection on reflection - c#

I have N validators on my aplication but a client doesn't use all validators, I got by procedure all classes that my current client will need to instantiate.
My Business layer:
public class MyClass
{
public void MyMethod(int idClient)
{
//This array is returned by a procedure passing idClient
string[] validatorsName = { "ValidatorName", "ValidatorName2" };
foreach (string name in validatorsName)
{
IValidator validator = (IValidator)Activator.CreateInstance(Type.GetType(name));
//Error. I need pass the INameDB;
validator.Process();
}
}
}
My Interface:
public interface IValidator
{
void Process();
}
The Validators:
public class ValidatorName : IValidator
{
INameDB nameDB;
public ValidatorName(INameDB nameDB)
{
this.nameDB = nameDB;
}
public void Process()
{
nameDB.AnyThing(pedidoId);
}
}
public class ValidatorName2 : IValidator
{
INameDB2 nameDB;
public ValidatorName(INameDB2 nameDB)
{
this.nameDB = nameDB;
}
public void Process()
{
nameDB.AnyThing2(pedidoId);
}
}
public class ValidatorName3 : IValidator
{
INameDB2 nameDB;
public ValidatorName(INameDB2 nameDB)
{
this.nameDB = nameDB;
}
public void Process()
{
nameDB.AnyThing2(pedidoId);
}
}
On Global, I could register all validators and with the IList<IValidator>, so I would remove from the list the validators that I will not need.
string[] validatorsName = { "ValidatorName", "ValidatorName2" };
validators = validators .Where(p => validatorsName .Contains(p.GetType().Name)).ToList();
but I have a lot of classes, it would register this no need.
My Global:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<NameDB>().As<INameDB>();
builder.RegisterType<NameDB2>().As<INameDB2>();
//builder.RegisterType<ValidatorName1>().As<IValidator>();
//builder.RegisterType<ValidatorName2>().As<IValidator>();
//builder.RegisterType<ValidatorName3>().As<IValidator>();
AutofacHostFactory.Container = builder.Build();
//AutofacHostFactory.Container.Resolve<IList<IValidator>>();
}
}
My question is how can I detect the interface INameDB or INameDB2, get the instance on Autofac and use on Activator.CreateInstance?
Thanks.

After some days, I could code the solution:
My main class, I create a method to injection the validators list:
public class MyClass
{
private IList<IValidator> listValidators;
public void MyMethod(int idClient)
{
ExecuteValidations(idClient);
}
private void ValidatorInjection(int idClient)
{
listValidators = new List<IValidator>();
//This array is returned by a procedure passing idClient
string[] validatorsName = { "ValidatorName", "ValidatorName2" };
foreach (string name in validatorsName)
{
IValidator validador = (IValidator)Activator.CreateInstance(Type.GetType(name));
listValidators.Add(validador);
}
}
private void ExecuteValidations(int idClient)
{
ValidatorInjection(idClient);
RunValidatorsList();
}
private void RunValidatorsList()
{
foreach (var validator in listValidators)
{
validator.Process();
}
}
}
My validators, I needed get the interface database instance on container with INameDB2 db = AutofacHostFactory.Container.Resolve<INameDB2>();:
public class ValidatorName : IValidator
{
public void Process()
{
INameDB db = AutofacHostFactory.Container.Resolve<INameDB>();
db.AnyThing(pedidoId);
}
}
public class ValidatorName2 : IValidator
{
public void Process()
{
INameDB2 db = AutofacHostFactory.Container.Resolve<INameDB2>();
db.AnyThing2(pedidoId);
}
}
public class ValidatorName3 : IValidator
{
public void Process()
{
INameDB2 db = AutofacHostFactory.Container.Resolve<INameDB2>();
db.AnyThing2(pedidoId);
}
}
On Global, I did a way that I don't need add line to register a new class that IValidator implement:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<NameDB>().As<INameDB>();
builder.RegisterType<NameDB2>().As<INameDB2>();
string assembly = "MY_ASSEMBLY";
builder.RegisterAssemblyTypes(Assembly.Load(assembly)).Where(t => t.IsAssignableTo<IValidator>()).AsImplementedInterfaces();
AutofacHostFactory.Container = builder.Build();
}
}

Related

Call same method on multiple objects

I have a number of methods that are called on different 3rd party systems. I now have another 3rd party system that will have the same set of methods actioned against it. If both 3rd party systems are connected I will then call the methods on each object in turn.
Currently I have a class that I pass round that I can call the method once and it checks and then calls it on each system that is enabled, this has an instance of each objects classes, similar to this:
public class AACSCaller
{
3rdPartySystem1 _system1;
3rdPartySystem2 _system2;
public AACSCaller(Settings appSettings)
{
_appSettings = appSettings;
if (appSettings.system1Enabled)
{
_system1 = new 3rdPartySystem1();
}
if (appSettings.system2Enabled)
{
_system2 = new 3rdPartySystem2();
}
}
public void Method1()
{
if (appSettings.system1Enabled)
{
_system1.Method1();
}
if (appSettings.system2Enabled)
{
_system2.Method1();
}
}
public void Method2()
{
if (appSettings.system1Enabled)
{
_system1.Method2();
}
if (appSettings.system2Enabled)
{
_system2.Method2();
}
}
}
Is this sensible, as it does seem there maybe a better way and I may well be connecting additional system at some point.
A possible solution here is to define an interface or base class for 3rdPartySystem1 and 3rdPartySystem2 classes, store instances in a collection and call required methods for every item in collection. If only one system is enabled, you'll have only one item in collection, if both is enabled, you'll call them one by one in loop
public interface IThirdPartySystem
{
void Method1();
void Method2();
}
public class ThirdPartySystem1 : IThirdPartySystem
{
//implementation
}
public class ThirdPartySystem2 : IThirdPartySystem
{
//implementation
}
public class AACSCaller
{
IList<IThirdPartySystem> _systems = new List<IThirdPartySystem>();
public AACSCaller(Settings appSettings)
{
_appSettings = appSettings;
if (appSettings.system1Enabled)
{
_systems.Add(new ThirdPartySystem1());
}
if (appSettings.system2Enabled)
{
_systems.Add(new ThirdPartySystem2());
}
}
public void Method1()
{
foreach (var system in _systems)
system.Method1();
}
public void Method2()
{
foreach (var system in _systems)
system.Method2();
}
}
I suggest you to use interface that have Method1 and Method2 methods and then create to classes System1 and System2 that are implements the interface. Where AACSCaller is create you initialize the correct implementation of the interface and in your methods your just Call to the correct instance method without conditions.
public class AACSCaller
{
IThirdPartySystem ThirdPartySystem;
public AACSCaller(Settings appSettings)
{
_appSettings = appSettings;
ThirdPartySystem = appSettings.system1Enabled ? new ThirdPartySystem1() : new ThirdPartySystem2();
}
public void Method1() => ThirdPartySystem.Method1();
public void Method2() => ThirdPartySystem.Method2();
}
public interface IThirdPartySystem
{
void Method1();
void Method2();
}
public class ThirdPartySystem1 : IThirdPartySystem
{
public void Method1()
{
//code here..
}
public void Method2()
{
//code here..
}
}
public class ThirdPartySystem2 : IThirdPartySystem
{
public void Method1()
{
//code here..
}
public void Method2()
{
//code here..
}
}

How to implement a non-generic interface and call with generic

Probably a bad title, but I am trying to abstract away the type "EventHub" from my generic Handler class.
I would like to inject a function instead into my subscribe method to decouple the two types. Unfortunately, the only way I can see doing this is if I make my IHandler a generic, but this causes other problems.
Is there a design pattern to decouple these two types? Commented out are lines that I would like in some way.
public interface IHandler
{
//void Subscribe(Func<Action<T>, Guid> subscribe);
void Subscribe(EventHub eventHub);
void Unsubscribe(Action<Guid> action);
}
public abstract class Handler<T> : IHandler
{
private Guid _subscriptionToken;
public virtual void Subscribe(EventHub eventHub)
{
var action = new Action<T>(Handle);
_subscriptionToken = eventHub.Subscribe(action);
}
/*public virtual void Subscribe(Func<Action<T>, Guid> subscribe)
{
var action = new Action<T>(Handle);
_subscriptionToken = subscribe(action);
}*/
public virtual void Unsubscribe(Action<Guid> action)
{
action(_subscriptionToken);
}
public abstract void Handle(T eventType);
}
Thanks for the help!
internal interface IHandler
{
void Subscribe(Func<Action<object>, Guid> subscribe);
void Unsubscribe(Action<Guid> action);
}
public abstract class Handler<T> : IHandler
{
private Guid _subscriptionToken;
public virtual void Subscribe(Func<Action<object>, Guid> subscribe)
{
var action = new Action<T>(HandleNonAsync);
_subscriptionToken = subscribe(Convert(action));
}
public virtual void Unsubscribe(Action<Guid> action)
{
action(_subscriptionToken);
}
public abstract Task HandleAsync(T eventType);
private void HandleNonAsync(T eventType)
{
HandleAsync(eventType).GetAwaiter().GetResult();
}
private Action<object> Convert(Action<T> myActionT)
{
if (myActionT == null) return null;
else return new Action<object>(o => myActionT((T)o));
}
}

How to call static method of static generic class with C# Reflection?

I have many classes with these implementations:
internal static class WindowsServiceConfiguration<T, Y> where T : WindowsServiceJobContainer<Y>, new() where Y : IJob, new()
{
internal static void Create()
{
}
}
public class WindowsServiceJobContainer<T> : IWindowsService where T : IJob, new()
{
private T Job { get; } = new T();
private IJobExecutionContext ExecutionContext { get; }
public void Start()
{
}
public void Install()
{
}
public void Pause()
{
}
public void Resume()
{
}
public void Stop()
{
}
public void UnInstall()
{
}
}
public interface IWindowsService
{
void Start();
void Stop();
void Install();
void UnInstall();
void Pause();
void Resume();
}
public class SyncMarketCommisionsJob : IJob
{
public void Execute(IJobExecutionContext context)
{
}
}
public interface IJob
{
void Execute(IJobExecutionContext context);
}
I would like to call Create() method of WindowsServiceConfiguration static class by reflection as below:
WindowsServiceConfiguration<WindowsServiceJobContainer<SyncMarketCommisionsJob>, SyncMarketCommisionsJob>.Create();
and I don't know how to do that by using Activator or something like that in order to call Create method in my C# code?
best regards.
Something like this ought to work:
// Get the type info for the open type
Type openGeneric = typeof(WindowsServiceConfiguration<,>);
// Make a type for a specific value of T
Type closedGeneric = openGeneric.MakeGenericType(typeof(WindowsServiceJobContainer<SyncMarketCommisionsJob>), typeof(SyncMarketCommisionsJob));
// Find the desired method
MethodInfo method = closedGeneric.GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
// Invoke the static method
method.Invoke(null, new object[0]);

MS unity container

I have an interface IInterface and it looks something like below -
public interface IInterface
{
void SomeMethod1();
void SomeMethod2();
void SomeMethod3();
.
.
.
}
One of the implementations is something like -
public class Implementation : IInterface
{
private Object obj;
public Implementation(Object obj)
{
this.obj = obj;
// Do Something
}
public void SomeMethod1()
{
lock(obj)
{
// Do Something
}
}
public void SomeMethod2()
{
// Do Something
}
public void SomeMethod3()
{
lock(obj)
{
// Do Something
}
}
.
.
.
}
How to pass a static readonly instance of type Object while registering Implementation class with type IInterface via unity configuration?
My preferred approach is probably to create a factory for creating IInterfaces
public interface IInterface
{
void SomeMethod1();
}
public interface IInterfaceFactory
{
IInterface CreateInterface();
}
public class StandardInterfaceFactory : IInterfaceFactory
{
// Define your static lock object here. Other customers
// can define their own IInterfaceFactory to use a
// different lock object.
private static readonly object lockObject = new object();
public IInterface CreateInterface()
{
return new StandardInterface(lockObject);
}
}
public class StandardInterface : IInterface
{
private readonly object lockObject;
public StandardInterface(object lockObject)
{
this.lockObject = lockObject;
}
public void SomeMethod1()
{
lock (this.lockObject)
{
Console.WriteLine("I've locked on " + lockObject);
}
}
}
Your unity configuration and client code will then look like this.
void Main()
{
IUnityContainer container = new UnityContainer();
// This mapping can be done trivially in XML configuration.
// Left as an exercise for the reader :)
container.RegisterType<IInterfaceFactory, StandardInterfaceFactory>();
IInterfaceFactory factory = container.Resolve<IInterfaceFactory>();
IInterface myInterface = factory.CreateInterface();
myInterface.SomeMethod1();
}

Passing dependency into Factory

We are using factory to create an instance of Subscribers. Each subscriber can have its own dependency.
Each subscriber will use constructor injection.
Should I pass dependency into subscribers through Subscriber Factory? Every time adding new dependency in any subscriber will change Subscriber factory?
public interface IMessageSubscriber
{
bool Process(string message)
}
public class MessageSubscriber1 : IMessageSubscriber
{
public bool Process(string message)
{
//Some custom logic
}
}
public class MessageSubscriber2 : IMessageSubscriber
{
public bool Process(string message)
{
//Some custom logic
}
}
public class MessageSubscriberFactory
{
//SubscriberType is enum
public IMessageSubscriber Get(SubscriberType type)
{
if(type == 1)
{
return new MessageSubscriber1();
}
else if(type == 2)
{
return new MessageSubscriber2();
}
}
}
//Main class
public class Process
{
public static void Main(string[] args)
{
MessageSubscriberFactory fac = new MessageSubscriberFactory();
foreach SubscriberType
{
string = "Message";
IMessageSubscriber subscriber = fac.Get(type);
subscriber.Process(message)
}
}
}
One approach would be to use named registrations with a DI/IOC container. This would involve using the container in a service locator fashion (which some people oppose), but I think it could make sense in this case. The example below is pretty crude, but it does give you an approach to handle subscribers with different dependencies without passing them into the factory. I used Unity here and you'd want to wrap the container reference rather than referencing directly, but this gets the point across.
public interface ILowerCaseWriter
{
void Write(string message);
}
public class LowerCaseWriter : ILowerCaseWriter
{
public void Write(string message)
{
Console.WriteLine(message.ToLower());
}
}
public interface IUpperCaseWriter
{
void Write(string message, int number);
}
public class UpperCaseWriter : IUpperCaseWriter
{
public void Write(string message, int number)
{
Console.WriteLine("{0}:{1}", number, message.ToUpper());
}
}
public interface ISubscriber
{
void Write();
}
public class Subscriber1 : ISubscriber
{
private ILowerCaseWriter _writer;
public Subscriber1(ILowerCaseWriter writer)
{
_writer = writer;
}
public void Write()
{
_writer.Write("Using subscriber 1");
}
}
public class Subscriber2 : ISubscriber
{
private IUpperCaseWriter _writer;
public Subscriber2(IUpperCaseWriter writer)
{
_writer = writer;
}
public void Write()
{
_writer.Write("Using subscriber 2", 2);
}
}
public class SubscriberFactory
{
private UnityContainer _container;
public SubscriberFactory()
{
_container = new UnityContainer();
_container.RegisterType<ILowerCaseWriter, LowerCaseWriter>();
_container.RegisterType<IUpperCaseWriter, UpperCaseWriter>();
_container.RegisterType<ISubscriber, Subscriber1>("Subscriber1");
_container.RegisterType<ISubscriber, Subscriber2>("Subscriber2");
}
public ISubscriber GetSubscriber(int type)
{
switch (type)
{
case 1:
return _container.Resolve<ISubscriber>("Subscriber1");
case 2:
return _container.Resolve<ISubscriber>("Subscriber2");
default:
throw new Exception();
}
}
}
class Program
{
private static void Main(string[] args)
{
var factory = new SubscriberFactory();
var subscriber = factory.GetSubscriber(1);
subscriber.Write();
Console.ReadLine();
}
}

Categories

Resources