I am busy developing a class library project in C# to be reused and attached to different projects in future. It will mainly be used for Table Valued Parameters. My question is, how do I pass a SQL connection to it? The connection will be instantiated in another (main project) that the .dll gets attached to.
I currently have a Class Library Project, and have a Console Application Project created in the same solution for testing purposed.
One last requirement is that I don't want to use ConfigurationManager as the connection string will not be stored in app.config or web.config and by default the queries must be passed back to the calling application.
I've come accross a couple of links like the one below, but nothing I can really use:
Sharing a connection string
Please excuse the noobness, I am 7 weeks into professional programming.
In your dll, simply require an IDbConnection or IDbCommand. All the method is then properly abstracted against the interfaces for the data access.
For example:
In your shared dll
public static int LookUpIntForSomething(IDbConnection connection)
{
using (var command = connection.CreateCommand())
{
// use command.
}
}
In your calling app
using (var connection = new SqlConnection("ConnectionString"))
{
var int = DbQueries.LookupIntForSomething(connection);
}
This is excellent example for dependency injection. I would recommend using enterprise library unity for this kind of stuff. In your data access layer library I would define interface:
public interface IConnectionProvider {
string ConnectionString { get; }
}
public interface IAccountProvider {
Account GetAccountById(int accountID);
}
internal class AccountProvider : IAccountProvider {
private IConnectionProvider _connectionProvider;
public AccountProvider(IConnectionProvider connectionProvider) {
if (connectionProvider == null) {
throw new ArgumentNullException("connectionProvider");
}
_connectionProvider = connectionProvider;
}
public Account GetAccountById(int accountID) {
Account result;
using(var conn = new SqlConnection(connectionProvider)) {
// retrieve result here
}
return result;
}
}
public static class Bootstrapper {
public static void Init() {
ServiceLocator.AddSingleton<IAccountProvider, AccountProvider>();
}
}
Then in any assembly using your data access library you can define implementation for IConnectionProvider, like this:
internal class WebConnectionProvider : IConnectionProvider {
public string ConnectionString { get { return "Server=..."; } }
}
internal static class WebBootstrapper {
public static void Init() {
Bootstrapper.Init();
ServiceLocator.AddSingleton<IConnectionProvider, WebConnectionProvider>();
}
}
And anywhere after you call WebBootstrapper.Init() in your assembly you can use:
var accountProvider = ServiceLocator.Resolve<IAccountProvider>();
accountProvider.GetAccountById(1);
Service locator:
using System;
using Microsoft.Practices.Unity;
public class ServiceLocator {
private IUnityContainer m_Container = new UnityContainer();
public void Add<TFrom, TTo>() where TTo : TFrom {
m_Container.RegisterType<TFrom, TTo>();
}
public void BuildUp<T>(T instance) {
m_Container.BuildUp<T>(instance);
}
public void BuildUp(Type type, object instance) {
m_Container.BuildUp(type, instance);
}
public void AddSingleton<TFrom, TTo>() where TTo : TFrom {
m_Container.RegisterType<TFrom, TTo>(new ContainerControlledLifetimeManager());
}
public void AddInstance<T>(T instance) {
m_Container.RegisterInstance<T>(instance);
}
public T Resolve<T>() {
return m_Container.Resolve<T>();
}
private static ServiceLocator m_Instance;
public static ServiceLocator Instance {
get { return m_Instance; }
}
static ServiceLocator() {
m_Instance = new ServiceLocator();
}
}
if i understand your requirements correctly,I'm not sure that i do, i would setup a static struct as such
public static struct ConnectionString
{
public int ID;
public string Connection;
public override string ToString()
{
return Connection;
}
public static ConnectionString DataBase1 = new ConnectionString{ ID = 1 , Connection = "YourConnectionStringhere"};
public static ConnectionString DataBase2 = new ConnectionString{ ID = 2 , Connection = "YourConnectionString2here"};
}
and then use it as such
public void SomeMethod()
{
var I = ReferencedDll.DoSomething(ConnectionString.DataBase1.ToString());
}
or
public void SomeMethod()
{
var ClassFromDll = new ReferencedDll.SomeClass(ConnectionString.DataBase1.ToString());
ClassFromDll.DoSomething();
}
of course this leaves your connection strings hard coded which is not ideal
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 need help from you guys. Currently I am working on Dependency Injection in my Console Application. In single class i have define three layers just to understand dependency injection.
Actually I am trying to inject object of data acess layer which can be either Oracle or Sql based on the requirement.But injection is happening based on which layer is registerd last.Could any guys tell me how can I do proper injection?
UI LAYER:
class Program
{
static void Main(string[] args)
{
IUnityContainer objconatiner = new UnityContainer();
objconatiner.RegisterType<Customer>();
objconatiner.RegisterType<IDal, SqlserverDal>();
objconatiner.RegisterType<IDal, OracleServerDal>();
Customer ocust = objconatiner.Resolve<Customer>();
ocust.CustName = "Taylor Swift";
ocust.Add();
}
}
MIDDLE LAYER:
public class Customer
{
private IDal oidal;
public string CustName { get; set; }
public Customer(IDal idal)
{
oidal = idal;
}
public void Add()
{
oidal.Add();
}
}
DAL LAYER:
public interface IDal
{
void Add();
}
public class SqlserverDal : IDal
{
public void Add()
{
Console.Write("Now using Sql server");
}
}
public class OracleServerDal : IDal
{
public void Add()
{
Console.Write("Now using Orcale server");
}
}
This exact situation is where named registrations come in to play.
static void Main(string[] args)
{
IUnityContainer objconatiner = new UnityContainer();
objconatiner.RegisterType<Customer>();
objconatiner.RegisterType<IDal, SqlserverDal>("SqlServer");
objconatiner.RegisterType<IDal, OracleServerDal>("Oracle");
Customer ocust = objconatiner.Resolve<Customer>();
ocust.CustName = "Taylor Swift";
ocust.Add();
}
public class Customer
{
private IDal oidal;
public string CustName { get; set; }
public Customer([Dependency("SqlServer")]IDal idal)
{
oidal = idal;
}
public void Add()
{
oidal.Add();
}
}
Now both registrations can be used but you must specify which registration you want via name when you do your resolving, this can be done via attributes as I have shown above or via the Resolve call that takes in a string.
I want to change the connection to a database at runtime in a REST Api. I want to put a variable of the request and let the Api decide which connectionstring to use.
For example:
I put the variable "dbid" with the value "develop" in the request header and send it to the Api.
The Api sees the header and gets the correct connectionstring from the web.config.
I have three layers (data, business, api). The data contains EntityFramework to get and set data. Like this:
public class WebsiteContext : IocDbContext, IWebsites
{
public DbSet<Website> Websites { get; set; }
public IEnumerable<Website> GetAll()
{
return Websites.ToList();
}
}
(IoCDbContext.cs)
public class IocDbContext : DbContext, IDbContext
{
public IocDbContext() : base("develop")
{
}
public void ChangeDatabase(string connectionString)
{
Database.Connection.ConnectionString= connectionString;
}
}
In the business I have a class to retrieve data from the datalayer and do some logical stuff (not needed here, but still good for the story).
public class Websites : IWebsites
{
private readonly Data.Interfaces.IWebsites _websiteContext;
#region Constructor
public Websites(Data.Interfaces.IWebsites websiteContext)
{
_websiteContext = websiteContext;
}
#endregion
#region IWebsites implementation
public IEnumerable<Website> GetWebsites()
{
List<Data.Objects.Website> websiteDtos = _websiteContext.GetAll().ToList();
return websiteDtos.Select(web => web.ToModel()).ToList();
}
#endregion
}
public static class WebsiteMapper
{
public static Website ToModel(this Data.Objects.Website value)
{
if (value == null)
return null;
return new Website
{
Id = value.Id,
Name = value.Name
};
}
}
And, last but not least, the controller:
public class WebsiteController : ApiController
{
private readonly IWebsites _websites;
public WebsiteController(IWebsites websites)
{
_websites = websites;
}
public IEnumerable<Website> GetAll()
{
return _websites.GetWebsites().ToList();
}
}
My Unity configuration:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<Business.Interfaces.IWebsites, Websites>();
container.RegisterType<IDbContext, IocDbContext>();
container.RegisterType<IWebsites, WebsiteContext>();
// e.g. container.RegisterType<ITestService, TestService>();
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
So as you can see the connection string with the name "develop" is used by default. This will return a website with the name "website". Now I would change the header variable "dbid" to "live". The api should see this and should get the connectionstring that corresponds with the name "live". This last part is something I am trying, but nothing works.
This I tried:
Adding session to webapi. This means I break the stateless idea of REST api: not done
Statics cannot work either, because everyone could get the same connectionstring, but its user specific
Google, but most of the examples don't work for me
Searching StackOverflow... See previous point.
This is driving me crazy! There should be a way to change the connectionstring given by a value in a request header, right?
I have the same scenario in a multi-tenant application I created where I use a different connection string for each tenant.
It doesn't matter the implementation you choose, but you have to determine how you are going to differentiate each request per connection string. In my application, I created a custom route value, and used it in the url to differentiate each request. The important thing is to create whatever this mechanism is, and it needs to be the 1st thing you register in your DI framework, on a per request basis.
For example (using Ninject):
private static void RegisterServicdes(IKernel kernel)
{
kernel.Bind<ISiteContext>().To<SiteContext>().InRequestScope();
kernel.Bind<IDbContextFactory>().To<DbContextFactory>().InRequestScope();
// register other services...
}
Rather than your implementation of your DbContext, I would change to be this, then always create your DbContext instance via a DbContextFactory.
public class IocDbContext : DbContext, IDbContext
{
public IocDbContext(string connectionStringType) : base(connectionStringType) { }
}
Then you need to create a DbContextFactory that you use when you create your DbContext, and take the above class as a dependency. Or you can take the dependency into your services, and pass it into the DbContextFactory instead.
public interface IDbContextFactory
{
TestModel CreateContext();
}
public class DbContextFactory : IDbContextFactory
{
private string _siteType;
public DbContextFactory(ISiteContext siteContext)
{
_siteType = siteContext.Tenant;
}
public TestModel CreateContext()
{
return new TestModel(FormatConnectionStringBySiteType(_siteType));
}
// or you can use this if you pass the IMultiTenantHelper dependency into your service
public static TestModel CreateContext(string siteName)
{
return new TestModel(FormatConnectionStringBySiteType(siteName));
}
private static string FormatConnectionStringBySiteType(string siteType)
{
// format from web.config
string newConnectionString = #"data source={0};initial catalog={1};integrated security=True;MultipleActiveResultSets=True;App=EntityFramework";
if (siteType.Equals("a"))
{
return String.Format(newConnectionString, #"(LocalDb)\MSSQLLocalDB", "DbOne");
}
else
{
return String.Format(newConnectionString, #"(LocalDb)\MSSQLLocalDB", "DbTwo");
}
}
}
Then you can use it like so when accessing your DbContext:
public class DbAccess
{
private IDbContextFactory _dbContextFactory;
public DbAccess(IDbContextFactory dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public void DoWork()
{
using (IocDbContext db = _dbContextFactory.CreateContext())
{
// use EF here...
}
}
}
ISiteContext interface implementation (for using route).
public interface ISiteContext
{
string Tenant { get; }
}
public class SiteContext : ISiteContext
{
private const string _routeId = "tenantId";
private string _tenant;
public string Tenant { get { return _tenant; } }
public SiteContext()
{
_tenant = GetTenantViaRoute();
}
private string GetTenantViaRoute()
{
var routedata = HttpContext.Current.Request.RequestContext.RouteData;
// Default Routing
if (routedata.Values[_routeId] != null)
{
return routedata.Values[_routeId].ToString().ToLower();
}
// Attribute Routing
if (routedata.Values.ContainsKey("MS_SubRoutes"))
{
var msSubRoutes = routedata.Values["MS_SubRoutes"] as IEnumerable<IHttpRouteData>;
if (msSubRoutes != null && msSubRoutes.Any())
{
var subRoute = msSubRoutes.FirstOrDefault();
if (subRoute != null && subRoute.Values.ContainsKey(_routeId))
{
return (string)subRoute.Values
.Where(x => x.Key.Equals(_routeId))
.Select(x => x.Value)
.Single();
}
}
}
return string.Empty;
}
}
API action:
[Route("api/{tenantId}/Values/Get")]
[HttpGet]
public IEnumerable<string> Get()
{
_testService.DoDatabaseWork();
return new string[] { "value1", "value2" };
}
you need to create a factory class for Dynamic picking of connection string.
It is the responsibility of that class to give correct connectionString based on the certain Parameter.
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.
First of all I read this on an article - which basically tells me I should not be using a singleton at all -
Most commonly, singletons don't allow any parameters to be specified when creating the instance - as otherwise a second request for an instance but with a different parameter could be problematic! (If the same instance should be accessed for all requests with the same parameter, the factory pattern is more appropriate.)
Since I need parameters, and same instances with same parameters - I concluded I need a factory pattern.
But I was unable to find a good factory pattern implementation anywhere.
Kindly direct me if you find any good c# singleton factory pattern implementation with parameters
Ok I am going to try and be very specific here... hope this explains my situation.
Alternate methods are most welcome. I just combined a lot of implementations - my understanding may be off.
So I have a class 'A'. It is a class used to connect to a database - Database connection.
The connection needs 4 parameters & the constraints are:
I need to have multiple connections possible - with different databases (parameters differ)
I need only 1 instance of a specific connection - a singleton with parameters which are same (in my understanding)
I will need a factory model as per the article mentioned above and also to limit the number of connections, close the connection after a timeout etc.
On this basis I need a singleton factory with paramenters/arguements... I assume
So the class A is going to look something like this
<which access modifier ?> Class A {
private Class A(string hostname, string port, string username, string pw_hash) {
//create a new instance with the specified parameters
}
//other methods on the connection
protected void close() {
//close the connection
}
}
public class AFactory//should it inherit class A?? {
private IList<A> connections = new List<A>();
private AFactory()
{
//do something
}
private static readonly Lazy<AFactory> lazy
= new Lazy<AFactory>(() => new AFactory());
public static AFactory Instance { get { return lazy.Value; } }
public A getA(string hostname, string service, string username, string pw_hash)
{
foreach (A a in A)
{
if (a.hostname == hostname && a.service == service && a.username == username)
return a;
}
A d = new A(hostname, service, username, pw_hash);
connections.Add(d);
return d;
}
Now this works well and good as long as the class A constructor is public - but It kind of defeats the purpose of a singleton.
What do I need to do to get this code to work.
I need only 1 instance of class A for the specified parameters.
Thanks
Indrajit
Factory is used to generate object rather than manage object. I think a DB connection manager is more suitable in your situation. You can declare the manager as singleton. For individual connection you can use internal class/struct.
See below example:
class DBConnectionManager
{
struct Connection
{
public string Hostname;
public string ServerName;
public string UserName;
public string Password;
public void Connect()
{
}
public void Close()
{
}
}
private static s_instance;
public static DBConnectionManager Instance
{
get {return s_instance; }
}
private List<Connection> m_connections;
public Connection GetConnection(string hostname, string serverName, string userName, string password)
{
// if already exist in m_connections
// return the connection
// otherwise create new connection and add to m_connections
}
public void CloseConnection(string hostname, string serverName, string userName, string password)
{
// if find it in m_connections
// then call Close()
}
public void CloseAll()
{
//
}
}
So I have done this and it works... can you tell me if it is correct. And also is it Thread-Safe?
public Class A
{
private A(string hostname, string port, string username, string pw_hash) {
//create a new instance with the specified parameters
}
//other methods on the connection
protected void close() {
//close the connection
}
public class AFactory
{
private IList<A> connections = new List<A>();
private AFactory()
{
//do something
}
private static readonly Lazy<AFactory> lazy
= new Lazy<AFactory>(() => new AFactory());
public static AFactory Instance { get { return lazy.Value; } }
public A getA(string hostname, string service, string username, string pw_hash)
{
foreach (A a in connections)
{
if (a.hostname == hostname && a.service == service && a.username == username)
return a;
}
A d = new A(hostname, service, username, pw_hash);
connections.Add(d);
return d;
}
}
}
I am using it like this:
A.AFactory fact = A.AFactory.Instance;
A conn = fact.getA(a, b, c, d);
A conn2 = fact.getA(e, f, g, h);
Is there something glaringly wrong with this implementation?
you could try this:
public static class Singlett<Param,T>
where T : class
{
static volatile Lazy<Func<Param, T>> _instance;
static object _lock = new object();
static Singlett()
{
}
public static Func<Param, T> Instance
{
get
{
if (_instance == null)
{
_instance = new Lazy<Func<Param, T>>(() =>
{
lock (Singlett<Param,T>._lock)
{
try
{
ConstructorInfo constructor = null;
Type[] methodArgs = { typeof(Param) };
constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, methodArgs, null);// Binding flags excludes public constructors.
if (constructor == null)
{
constructor = typeof(T).GetConstructor(BindingFlags.Public, null, methodArgs, null);
if (constructor == null)
return delegate(Param o) { return (T)Activator.CreateInstance(typeof(T), new object[] { o }); };
}
return delegate(Param o) { return (T)constructor.Invoke(new object[] { o }); };
}
catch (Exception exception)
{
throw exception;
}
}
});
}
return _instance.Value;
}
}
}
then to use it:
instead of
int i = 10;
MyClass class = new MyClass(i);
you can write:
int i = 10;
MyClass class = Singlett<int,MyClass>.Instance(i);
Try this:
This interface is exposed from the factory initializer and contains the exposed methods and properties.
public interface IDatabase
{
string ConnectionString { get; set; }
IDataReader ExecuteSql(string sql);
}
Factory base abstract class where you can perform common features to different types of database factories.
public abstract class FactoryBase
{
public FactoryBase() { }
public abstract IDatabase GetDataLayer();
}
Concrete sql class that contains your calls. Have a look at the ExecuteSql method. The connection is self contained in the command so you don't have to worry about opening and closing and disposing of it.
public class SQL : IDatabase
{
private string m_ConnectionString = string.Empty;
public string ConnectionString
{
get { return m_ConnectionString; }
set { m_ConnectionString = value; }
}
public IDataReader ExecuteSql(string sql)
{
using (var command = new SqlCommand(sql, new SqlConnection(ConnectionString)) { CommandType = CommandType.Text, CommandText = sql, CommandTimeout = 0 })
{
if (command.Connection.State != ConnectionState.Open) command.Connection.Open();
return command.ExecuteReader();
}
}
}
Sql factory class that creates an instance of the Sql concrete class.
class SQLFactory : FactoryBase
{
public override IDatabase GetDataLayer()
{
return new SQL();
}
}
The factory initializer class that a developer will use to pass in a type of factory and it will return the IDatabase.
public static class FactoryInitializer
{
public static IDatabase LoadFactory<T>(string connectionstring) where T : FactoryBase, new()
{
var factory = new T();
var data = factory.GetDataLayer();
data.ConnectionString = connectionstring;
return data;
}
}
Then use it as:
var factory = FactoryInitializer.LoadFactory<SQLFactory>(connectionString);
factory.ExecuteSql("SELECT ...");
You can then create may be an OracleFactory and an Oracle concrete class and use it the same way.