I want to have a "connectionList" where every element a diffrent connection type (TCP,R232) is stored. I made an abstract interface to "Connect" and "Disconnect" but because "Config" needs diffrent parameters in each class, its not possible to implement it into the interface (or is it?).
I made a little visualitation:
One of my solutions would be to cast before the call like ((TCP)connectionList[0]).Config() but that means that i have to try every possible class type (TCP, RS232, ...) if i want for example to config the "Connection 3".
Im sure there are better solutions then this one.
Code example:
List<IConnection> connectionList = new List<IConnection>();
connectionList.Add(new TCP());
connectionList.Add(new RS232());
connectionList[0].Connect();
connectionList[1].Connect(); // Works
connectionList[0].Config(); //Does not work because not in Interface
public abstract class IConnection
{
public abstract void Connect();
}
public class RS232 : IConnection
{
private int _baudRate;
public void Config(int baudRate) //Diffrent parameters then in TCP
{
_baudRate = baudRate;
}
public override void Connect()
{
Console.WriteLine("RS232 connect()");
}
}
public class TCP : IConnection
{
private int _ipAdress;
public void Config(int ipAdress) //Diffrent parameters then in RS232
{
_ipAdress = ipAdress;
}
public override void Connect()
{
Console.WriteLine("TCP Connect()");
}
}
I think you need some interfaces and maybe an abstract base-connection:
public interface ICanConnect
{
public void Connect();
public void Disconnect();
}
public interface IHaveConfig
{
public IConnectionConfig GetConfig();
}
public interface IConnectionConfig
{
}
public interface ITcpConfiguration: IConnectionConfig
{
public string IpAdress { get; set; }
}
// TODO add class
public interface IRS232Configuration : IConnectionConfig
{
public int BaudRate { get; set; }
}
// TODO add class
The configuration should be done before you use the connections:
public abstract class BaseConnection : ICanConnect, IHaveConfig
{
private IConnectionConfig _config;
public BaseConnection(IConnectionConfig config)
{
_config = config;
}
public IConnectionConfig GetConfig() => _config;
public abstract void Connect();
public abstract void Disconnect();
}
So you can add implementations for the TCP- and RS232-connections:
public class TcpConnection: BaseConnection
{
public TcpConnection(ITcpConfiguration tcpConfig) : base(tcpConfig) { }
public override void Connect()
{
ITcpConfiguration config = (ITcpConfiguration) base.GetConfig();
// here you have the IP-Adress
}
public override void Disconnect()
{
throw new NotImplementedException();
}
}
public class IRS232Connection : BaseConnection
{
public IRS232Connection(IRS232Configuration rs232Config) : base(rs232Config) { }
public override void Connect()
{
IRS232Configuration config = (IRS232Configuration) base.GetConfig();
// here you have the Baud-Rate
}
public override void Disconnect()
{
throw new NotImplementedException();
}
}
With a List<BaseConnection> you can use the connect/disconnect methods(polymorphism):
// initialization
List<BaseConnection> connections = new List<BaseConnection>()
{
new TcpConnection(new TcpConfiguration("192.158.1.38")),
new RS232Connection(new RS232Configuration(2400)),
};
// use them
foreach(BaseConnection con in connections)
{
con.Connect();
con.Disconnect();
}
If you want to change the configuration later, for example the IP-Adress of the TcpConnections:
foreach (TcpConnection con in connections.OfType<TcpConnection>())
{
ITcpConfiguration config = con.GetConfig() as ITcpConfiguration;
config.IpAdress = "192.158.1.39";
}
If you are using Dependency Injection you could configure each connection in your startup, or from a factory, if the configuration is dynamic.
interface IConnection
{
void Connect();
void Disconnect();
}
class RS232Conifguration
{
public int BaudRate { get; set; }
}
class RS232 : IConnection
{
private readonly RS232Conifguration _conifguration;
public RS232(RS232Conifguration conifguration)
{
_conifguration = conifguration;
}
public void Connect()
{
throw new System.NotImplementedException();
}
public void Disconnect()
{
throw new System.NotImplementedException();
}
}
public class TCPConfiguration
{
public int IpAddress { get; set; }
}
public class TCP :IConnection
{
private readonly TCPConfiguration _configuration;
public TCP(TCPConfiguration configuration)
{
_configuration = configuration;
}
public void Connect()
{
throw new System.NotImplementedException();
}
public void Disconnect()
{
throw new System.NotImplementedException();
}
}
var services = new ServiceCollection();
services.AddSingleton(new TCPConfiguration() { IpAddress = 423 });
services.AddScoped<IConnection, TCP>();
services.AddSingleton(new RS232Conifguration() { BaudRate = 4 });
services.AddScoped<IConnection, RS232>();
var provider = services.BuildServiceProvider();
var connections = provider.GetServices<IConnection>();
Related
Running into a circular reference from DI into my business services. Not sure what the best way to go about this is. I unfortunately can't remove from either service as I need them in both.
Below is an example of of my problem (not my actual services).
CarService
public class CarService
{
private readonly CarRepository _carRepository;
private readonly RecallService _recallService;
public CarService(CarRepository carRepository, RecallService recallService)
{
_carRepository = carRepository;
_recallService = recallService
}
public void RemoveRecallForCar(Recall recall)
{
//code
}
public void SendRecall(Guid carGuid)
{
Car car = _carRepository.Get(carGuid);
if (car.Model == "Ford")
{
_recallService.SendRecall(carGuid);
}
}
}
}
RecallService
public class RecallService
{
private readonly RecallRepository _recallRepository;
private readonly CarService _carService;
public RecallService(RecallRepository recallRepository,CarService carService)
{
_recallRepository = recallRepository;
_carService = carService
}
public void SendRecall(Guid carGuid)
{
// recall code
}
public GetRecalls()
{
List<Recall> recalls = _recallRepository.Fetch(x => x.IsActive).ToList();
foreach(var recall in recalls)
{
_carService.RemoveRecallForCar(recall);
}
}
}
}
I expect to be able to inject services into services without circular references
You can change your code like below, it will help you fix the circular references issue.
ICustomService.cs
public interface ICustomService
{
void SendRecall(Guid carGuid);
void RemoveRecallForCar(Recall recall);
}
RecallService.cs
public class RecallService : ICustomService
{
private readonly RecallRepository _recallRepository;
private readonly CarService _carService;
public RecallService(RecallRepository recallRepository, CarService carService)
{
_recallRepository = recallRepository;
_carService = carService;
}
public void SendRecall(Guid carGuid)
{
}
public GetRecalls()
{
List<Recall> recalls = _recallRepository.Fetch(x => x.IsActive).ToList();
foreach(var recall in recalls)
{
_carService.RemoveRecallForCar(recall);
}
}
public void RemoveRecallForCar(Recall recall)
{
}
}
CarService.cs
public class CarService
{
private readonly CarRepository _carRepository;
private readonly ICustomService _customService;
public CarService(CarRepository carRepository, ICustomService customService)
{
_carRepository = carRepository;
_customService = customService;
}
public void RemoveRecallForCar(Recall recall)
{
}
public void SendRecall(Guid carGuid)
{
Car car = _carRepository.Get(carGuid);
if (car.Model == "Ford")
{
_customService .SendRecall(carGuid);
}
}
}
Own way is, use Autofac or another DI library.
The other way ,that not a good solution, is you can divided your services to multiple services.
CarService1 :
public class CarService1
{
private readonly CarRepository _carRepository;
public CarrContactService(CarRepository carRepository)
{
_carRepository = carRepository;
}
public void RemoveRecallForCar(Recall recall)
{
//code
}
}
CarService2:
public class CarService2
{
private readonly CarRepository _carRepository;
private readonly RecallService _recallService;
public CarrContactService(CarRepository carRepository, RecallService recallService)
{
_carRepository = carRepository;
_recallService = recallService
}
public void SendRecall(Guid carGuid)
{
Car car = _carRepository.Get(carGuid);
if (car.Model == "Ford")
{
_recallService.SendRecall(carGuid);
}
}
}
RecallService :
public class RecallService
{
private readonly RecallRepository _recallRepository;
private readonly CarService1 _carService;
public RecallService(RecallRepository recallRepository,CarService1 carService)
{
_recallRepository = recallRepository;
_carService = carService
}
public void SendRecall(Guid carGuid)
{
// recall code
}
public GetRecalls()
{
List<Recall> recalls = _recallRepository.Fetch(x => x.IsActive).ToList();
foreach(var recall in recalls)
{
_carService.RemoveRecallForCar(recall);
}
}
}
Following i have a worker class and there is a foreach.
Inside the forach there is service call which can be GetX(), GetY() ...
as implementation, I have to re-initialize the Api client based on the parameter, is there pattern to avoid _aService.SetApiClient(p) Line?
public class Worker
{
private readonly IAService _aService;
public Worker(IAService entryPointService)
{
_aService = entryPointService;
}
protected void ExecuteAsync()
{
while (true)
{
new List<string>() { "x", "y", "z" }.ForEach(p =>
{
_aService.SetApiClient(p);
_aService.GetX();
// OR _aService.GetY(),_aService.GetYZ();//
});
}
}
}
public class AService : IAService
{
private GoogleApiClient _googleApiClient;
public AService(GoogleApiClient apiClient)
{
_googleApiClient = apiClient;
}
public void SetApiClient(string param)
{
_googleApiClient = new GoogleApiClient(new AuthProvider (param));
}
public string GetX()
{
return _googleApiClient.CallX();
}
}
public interface IAService
{
void SetApiClient(string param);
string GetX();
}
public interface IGoogleApiClient
{
string CallX();
string CallY();
string CallZ();
}
public class GoogleApiClient : IGoogleApiClient
{
private AuthProvider _param;
public GoogleApiClient(AuthProvider param)
{
_param = param;
}
public string CallX()
{
return DoSomeCal("X", _param);
}
public string CallY()
{
return DoSomeCal("Y", _param);
}
public string CallZ()
{
return DoSomeCal("Z", _param)
}
}
please note that string list values can be any thing
Your api client really doesn't need to hold state.(private field}) It is a service / gateway class. Rather just pass param into the methods e.g.GetX(string param}.
I have this object structure
public interface IHandler<in TMessage>
{
void HandleMessage(TMessage messageType);
}
public class MessageType1
{
}
public class MessageType2
{
}
public class HandlerMessageType1 : IHandler<MessageType1>
{
public void HandleMessage(T messageType)
{
}
}
public class HandlerMessageType2 : IHandler<MessageType2>
{
public void HandleMessage(T messageType)
{
}
}
and the registration
container.Collection.Register(typeof(IHandler<>), new[]
{
typeof(HandlerMessageType1),
typeof(HandlerMessageType2)
});
how the constructor of the class where this is injected should look like?
public class ClientClass
{
public ClientClass(IEnumerable<IHandler<>> handlers)
{
}
}
like this doesn't work... how the signature of the client class constructor should look like?
this was edited to improve the example.
tkx in advance
Paulo Aboim Pinto
I Know if I understood, but with unity you can have:
public class Handler1 : IHandler
{
public void HandlerType()
{
Console.WriteLine("Handler1");
}
}
public class Handler2 : IHandler
{
public void HandlerType()
{
Console.WriteLine("Handler2");
}
}
public interface IHandler
{
void HandlerType();
}
Unity configuration
public static class DependencyConfiguration
{
public static UnityContainer Config()
{
var unity = new UnityContainer();
unity.RegisterType<IHandler, Handler1>("Handler1");
unity.RegisterType<IHandler, Handler2>("Handler2");
unity.RegisterType<IEnumerable<IHandler>>();
return unity;
}
}
A class to resolve:
public class ListOfTypes
{
private List<IHandler> handlers;
public ListOfTypes(IEnumerable<IHandler> handlers)
{
this.handlers = handlers.ToList();
}
public void PrintHandlers()
{
handlers.ForEach(_ => _.HandlerType());
}
}
The program:
static void Main(string[] args)
{
Console.WriteLine("Resolve sample");
var unity = DependencyConfiguration.Config();
var lstOfTypes = unity.Resolve<ListOfTypes>();
lstOfTypes.PrintHandlers();
Console.ReadLine();
}
Result:
Let's assume that I have this scenario: I have got 2 repositories of information, and I want to access both, but it would be nice to leave the task of deciding which repo to use to common class.
The goal is to accomplish this with something similar to the code I've wrote below, but this sounds pretty bad:
where TOnline : class
where TOffline : class
where TContract : class
Sure I can ommit that, but bassically what I'm asking is what to do in order to stop using reflection and go typed. Maybe any design-pattern recomendation?
Code (if you copy/paste this on a console app replacing the Program class you should be able to run the example)
using CustomerDispatcher = DispatcherProxy<CustomerOnline, CustomerOffline, ICustomer>;
public interface ICustomer
{
string Get(int id);
}
public class CustomerOnline : ICustomer
{
public string Get(int id)
{
// Get From intranet DB
return "From DB";
}
}
public class CustomerOffline : ICustomer
{
public string Get(int id)
{
// Get From local storage
return "From local storage";
}
}
public class DispatcherProxy<TOnline, TOffline, TContract>
where TOnline : class
where TOffline : class
where TContract : class
{
public TContract Instance { get; set; }
public bool IsConnected { get; set; }
public DispatcherProxy()
{
// Asume that I check if it's connected or not
if (this.IsConnected)
this.Instance = (TContract)Activator.CreateInstance(typeof(TOnline));
else
this.Instance = (TContract)Activator.CreateInstance(typeof(TOffline));
}
}
class Program
{
static void Main(string[] args)
{
var customerDispatcher = new CustomerDispatcher();
Console.WriteLine("Result: " + customerDispatcher.Instance.Get(1));
Console.Read();
}
}
Thanks in advance!
You can add the new() constraint:
public class DispatcherProxy<TOnline, TOffline, TContract>
where TOnline : class, new()
where TOffline : class, new()
where TContract : class //isn't TContract an interface?
{
public TContract Instance { get; set; }
public bool IsConnected { get; set; }
public DispatcherProxy()
{
// Asume that I check if it's connected or not
if (this.IsConnected)
this.Instance = new TOnline() as TContract;
else
this.Instance = new TOffline() as TContract;
}
}
In case any of you are interested, I had to change the way I did this because it was checking connection at Constructor Level, and I needed that check at Operation Level.
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace ConsoleApplication1
{
public enum ConnectionStatus
{
Online,
Offline,
System // System checks connectivity
}
public static class Connectivity
{
private static ConnectionStatus ConnectionStatus = ConnectionStatus.Offline;
public static void ForceConnectionStatus(ConnectionStatus connectionStatus)
{
ConnectionStatus = connectionStatus;
}
public static bool IsConnected()
{
switch (ConnectionStatus)
{
case ConnectionStatus.Online:
return true;
case ConnectionStatus.Offline:
return false;
case ConnectionStatus.System:
return CheckConnection();
}
return false;
}
private static bool CheckConnection()
{
return true;
}
}
public class Unity
{
public static IUnityContainer Container;
public static void Initialize()
{
Container = new UnityContainer();
Container.AddNewExtension<Interception>();
Container.RegisterType<ILogger, OnlineLogger>();
Container.Configure<Interception>().SetInterceptorFor<ILogger>(new InterfaceInterceptor());
}
}
class Program
{
static void Main(string[] args)
{
Unity.Initialize();
var r = new Router<ILogger, OnlineLogger, OnlineLogger>();
Connectivity.ForceConnectionStatus(ConnectionStatus.Offline);
Console.WriteLine("Calling Online, will attend offline: ");
r.Logger.Write("Used offline.");
Connectivity.ForceConnectionStatus(ConnectionStatus.Online);
Console.WriteLine("Calling Online, will attend online: ");
r.Logger.Write("Used Online. Clap Clap Clap.");
Console.ReadKey();
}
}
public class Router<TContract, TOnline, TOffline>
where TOnline : TContract
where TOffline : TContract
{
public TContract Logger;
public Router()
{
Logger = Unity.Container.Resolve<TContract>();
}
}
public interface IOnline
{
IOffline Offline { get; set; }
}
public interface IOffline
{
}
public interface ILogger
{
[Test()]
void Write(string message);
}
public class OnlineLogger : ILogger, IOnline
{
public IOffline Offline { get; set; }
public OnlineLogger()
{
this.Offline = new OfflineLogger();
}
public void Write(string message)
{
Console.WriteLine("Online Logger: " + message);
}
}
public class OfflineLogger : ILogger, IOffline
{
public IOnline Online { get; set; }
public void Write(string message)
{
Console.WriteLine("Offline Logger: " + message);
}
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public class TestAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new TestHandler();
}
}
public class TestHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("It's been intercepted.");
if (!Connectivity.IsConnected() && input.Target is IOnline)
{
Console.WriteLine("It's been canceled.");
var offline = ((input.Target as IOnline).Offline);
if (offline == null)
throw new Exception("Online class did not initialized Offline Dispatcher.");
var offlineResult = input.MethodBase.Invoke(offline, this.GetObjects(input.Inputs));
return input.CreateMethodReturn(offlineResult, this.GetObjects(input.Inputs));
}
return getNext()(input, getNext);
}
private object[] GetObjects(IParameterCollection parameterCollection)
{
var parameters = new object[parameterCollection.Count];
int i = 0;
foreach (var parameter in parameterCollection)
{
parameters[i] = parameter;
i++;
}
return parameters;
}
}
}
On AppEngine "Franch" and "English" as a dependency injection what do I do?
class Program
{
static void Main(string[] args)
{
IContainer container = ConfigureDependencies();
IAppEngine appEngine = container.GetInstance<IAppEngine>();
IGeeter g1 = container.GetInstance<IGeeter>("Franch");
IGeeter g2 = container.GetInstance<IGeeter>("English");
appEngine.Run();
}
private static IContainer ConfigureDependencies()
{
return new Container(x =>
{
x.For<IGeeter>().Add<FrenchGreeter>().Named("Franch");
x.For<IGeeter>().Add<EnglishGreeter>().Named("English");
x.For<IAppEngine>().Use<AppEngine>();
x.For<IGeeter>().Use<EnglishGreeter>();
x.For<IOutputDisplay>().Use<ConsoleOutputDisplay>();
});
}
}
public interface IAppEngine
{
void Run();
}
public interface IGeeter
{
string GetGreeting();
}
public interface IOutputDisplay
{
void Show(string message);
}
public class AppEngine : IAppEngine
{
private readonly IGeeter english;
private readonly IGeeter franch;
private readonly IOutputDisplay outputDisplay;
public AppEngine(IGeeter english,IGeeter franch, IOutputDisplay outputDisplay)
{
this.english = english;
this.franch = franch;
this.outputDisplay = outputDisplay;
}
public void Run()
{
outputDisplay.Show(greeter.GetGreeting());
}
}
public class EnglishGreeter : IGeeter
{
public string GetGreeting()
{
return "Hello";
}
}
public class FrenchGreeter : IGeeter
{
public string GetGreeting()
{
return "Bonjour";
}
}
As the contract for FrenchGreeter and EnglishGreeter is the same, StructureMap will not know which to use. For each wireing it uses only one instance per contract. Try something like this:
For<IGreeter>().Use<FrenchGreeter>().Named("French");
For<IGreeter>().Use<EnglishGreeter>().Named("English");
For<IAppEngine>().Use<AppEngine>()
.Ctor<IGreeter>("French").Is(x => x.TheInstanceNamed("French"))
.Ctor<IGreeter>("English").Is(x => x.TheInstanceNamed("English"));