I have a connection string and I can do it without a problem
<connectionStrings>
<add name="DbName"
connectionString="server=serverName;database=DbTest;user=x;pwd=xxx;"
providerName="System.Data.SqlClient" />
</connectionStrings>
and I have the connection of Entity Framework:
public DbContext1() : base("DbName")
{
}
But I need to make a query to DbContext1 to get a new string connection from a table to connect to an other database, but I do not know how use the string connection that I receive from the query.
How can I use the string connection from the table to make a new DbContext?
Do something like this:
public DbContext1(string connString) : base(connString)
{
}
The constructor your derived class needs call is this one. The string argument is treated as either a valid connection string itself, or name of a connection string.
This sounds like a multi-tenant scenario where users authenticate against a central database then get directed to a specific database instance containing their own data. As a simple example during authentication:
using (var context = new AuthDbContext())
{ // Where AuthDbContext is the central DB containing authentication and the connection string to that user's home database..
// ... On successful authentication...
var connectionString = context.Tenants
.Where(x => x.TenantId == authenticatedUser.TenantId)
.Select(x => x.ConnectionString)
.Single();
}
Ideally if you are persisting user details (User ID, name, etc.) to session state then you could load the associated connection string and persist it as part of that data structure as well.
Then create a AppDbContextFactory class or UnitOfWork pattern class to inject into your services/controllers to provide a DbContext based on the current user's connection string.
As a very basic example:
public interface IUserStateFacade
{
string CurrentUserConnectionString { get; }
}
public class UserSessionState : IUserStateFacade
{
public const string UserStateSessionName = "UserState";
public string CurrentUserConnectionString
{
get
{
var userState = (UserSessionState)Session[UserStateSessionName] ?? throw new ApplicationException("Session state missing/expired.");
return userState.ConnectionString;
}
}
}
public interface IAppContextFactory
{
AppContext Create();
}
public class AppContextFactory
{
private readonly IUserStateFacade _userState = null;
public AppContextFactory(IUserStateFacade userState)
{
_userState = userState ?? throw new ArgumentNullException("userState");
}
/// <summary>
/// Create a DbContext. Calling code is responsible for disposing.
/// </summary>
public AppContext Create()
{
return new AppContext(_userState.ConnectionString);
}
}
Then in your controllers etc. that would normally want to create or inject a DbContext with a default constructor would instead use something like:
using (var context = AppContextFactory.Create())
{ }
or inject a value initialized via the AppContextFactory.
For ASP.Net apps using Session, you may need to wrap Session so that an dependency injection library can resolve the connection string/user structure out of the current session state.
Again, this is only a very rudimentary example to outline an option to facilitate dynamic connection strings assuming something like an ASP.Net web application. Additional security measures should be considered but it should hopefully provide some ideas on how it can be structured.
Related
I'm writing an MVC C# application. I use dapper as a lightweight ORM. My connection strings are defined with server and initial catalog, and currently if I need to access a different database I define another connection string, and use Ninject bindings to use a particular connection string based on the manager i'm injecting it into, like so:
public class NinjectBindings : NinjectModule
{
public override void Load()
{
Bind<IDbConnection>().To<SqlConnection>()
.WhenInjectedInto<DashboardManager>()
.InRequestScope()
.Named("myDashboard")
.WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["dbDashboard"].ConnectionString);
Bind<IDbConnection>().To<SqlConnection>()
.WhenInjectedInto<ScoreboardManager>()
.InRequestScope()
.Named("myScoreboard")
.WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["dbScoreboard"].ConnectionString);
}
}
Unfortunately this doesn't work if I have code in the same Manager that needs to call stored procedures that are on different databases than the initially specified catalog.
Question is: Can I just define one connection string, lose all the ninject binding stuff above, and simply change the Initial Catalog to a point to a different database on the fly?
Do you need both Named and WhenInjectedInto constraints for your bindings?
I believe you have a class that requires both connectionstrings, this could be achieved using Named binding:
Bind<IDbConnection>().To<SqlConnection>()
.InRequestScope()
.Named("myDashboard")
.WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["dbDashboard"].ConnectionString);
Bind<IDbConnection>().To<SqlConnection>()
.InRequestScope()
.Named("myScoreboard")
.WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["dbScoreboard"].ConnectionString);
And your class can get both connections:
public class ClassWith2DbDependency // <-- I would question this class for SRP violation
{
private readonly IDbConnection _dashboardConnection;
private readonly IDbConnection _scoreboardConnection;
public ClassWith2DBDependency(
[Named("myDashboard")] IDbConnection dashboardConnection
[Named("myScoreboard")] IDbConnection scoreboardConnection)
{
_dashboardConnection = dashboardConnection;
_scoreboardConnection = scoreboardConnection;
}
public void WriteTo2Dbs()
{
// execute dashboard DB procedure
// execute scoreboard DB procedure
}
}
Can I just define one connection string, lose all the ninject binding
stuff above, and simply change the Initial Catalog to a point to a
different database on the fly?
Changing Initial Catalog doesn't affect an existing SqlConnection. It is possible to manage the dependencies yourself, but you still need 2 connectionstrings:
public class ClassWith2DbDependency
{
public void WriteTo2Dbs()
{
var dashboardCon = ConfigurationManager.ConnectionStrings["dbDashboard"].ConnectionString;
using (SqlConnection connection = new SqlConnection(dashboardCon))
{
// execute dashboard DB procedure
}
var scoreboardCon = ConfigurationManager.ConnectionStrings["dbScoreboard"].ConnectionString;
using (SqlConnection connection = new SqlConnection(scoreboardCon))
{
// execute scoreboard DB procedure
}
}
}
However, I do NOT recommend this approach, the above class violates DI principle, by having Opaque Dependencies.
I haven't seen your code, but it doesn't sound like you are using Repository Pattern? This could be a good option...
I have an application that uses Structuremap for DI for both my business and DAL layer. Up to this point, I have had a single DAL per environment that I have been working on. So I would grab it from the config and use that value for all my connections. An example of this is.
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["Database"].ToString()))
{
//Do a call to db here.
}
I am calling this method using structure map as follows.
ObjectFactory.GetInstance<IDALManager>().MethodName();
Now I have a new feature where I want to allow the users to make change in a dev environment and then push a button to elevate it to test or prod environment. Therefore my connectionstring for the DAL manager will need to be able to change. I also would like to keep all the connection string access in the DAL and not in the other layers. I am looking for advice on how to do this or what design patterns to look into for this.
UPDATED INFORMATION
The user will determine which connection string needs to be used. For example, they will be moving data from dev to test, they will select a source and a destination.
string source = \\user selection from combobox.
if (source == "DEV")
{
//Instantiate dev instance of manager
}
if (source == "TEST")
{
//Instantiate Test Instance of manager.
}
You need an abstract factory. Take a look at the answer in this question for some examples.
In your particular case, your abstract factory interface should look like this:
public interface IDALManagerFactory
{
IDALManager Create(string environment);
}
You need to create an implementation of this interface that creates a "DAL Manager" with the appropriate connection string.
To be able to do this, you need the connection string to be injected into the constructor of your class like this:
public class MyDalManager: IDALManager
{
private readonly string connectionString;
public MyDalManager(string connectionString)
{
this.connectionString = connectionString;
}
public MyMethod()
{
//..
using (SqlConnection con = new SqlConnection(connectionString))
{
//Do a call to db here.
}
}
}
Now the implementation of the factory would look something like this:
public class DALManagerFactory : IDALManagerFactory
{
public IDALManager Create(string environment)
{
if(environment == "DEV")
return new MyDalManager(
ConfigurationManager.ConnectionStrings["Database"].ToString());
//...
}
}
This factory class should live in the Composition Root. You can also access the container inside this factory class to create the "DAL Manager".
Now, the class that needs access to the appropriate "DAL Manager" should have a IDALManagerFactory injected into its constructor, and it would use such factory to create a IDALManager by invoking the Create method passing the environment name.
Please note that in your code, you are accessing the connection string in the DAL layer. You really should access such information in the composition root only.
I am building an MVC application that connect to diferent databases depending on the user that has log in.
For this i have 3 projects DAL using entity framework(DataBaseFirst) where i have extended the dbcontext so that i can pass the connectionstring like this:
public partial class ARACultivoEntities
{
public ARACultivoEntities(string nameOfConnectionString)
: base(nameOfConnectionString)
{
}
}
Note: I have the connections strings defined in the web.config of the mvc project.
There is also another project, Services where i have a genericService from where other service can inherit this like this:
public class GenericService<T> : IGenericService<T>
where T : class
{
protected ARACultivoEntities Db;
protected DbSet<T> Table;
public GenericService(string nameConnectionString)
{
if (string.IsNullOrEmpty(nameConnectionString))
{
throw new ArgumentNullException("nameConnectionString");
}
Db = new ARACultivoEntities(nameConnectionString);
Table = Db.Set<T>();
}
Now i save the name of the connection string in the user claims when he logs in and in the controllers i have something like this:
public class DeduccionController : Controller
{
private IGenericService<Deducciones> service;
public DeduccionController()
{
service = ServiceFactoryGeneric<Deducciones>.InitGenericService(GetClaimsUser.Cadena);
//GetClaimsUser.Cadena has the name of the connectionString
//ServiceFactoryGeneric<Deducciones>.InitGenericService do this:
// return new GenericService<T>(connectionString);
}
now i want to instead of having my own factories i want to use an Ioc Container and i have chosen unity for this, i am new to this, i've read some articles and i think i undsertand the basics but i dont know how to pass the connection string after the user has log in because my RegisterTypes hapen at the application start
public static void RegisterTypes(IUnityContainer container)
{
// this happen at application start
// string nameOfConnectionString = *user is still not loged in*
container.RegisterType<IGenericService<T>, GenericService<T>>(
new InjectionConstructor(nameOfConnectionString));
}
i been thinkin to try to tweet the code to register my types after the user has loged in but i dont think this a good idea..
i also have been thinking about adding a public method to my IGenericService so that i can set my connectionString after the service is constructed and implemented something like this:
public void SetConnectionString(string nameOfConnectionString)
{
Db.Database.Connection.ConnectionString = nameOfConnectionString;
//not sure if this actually works
}
then my controller will be something like this:
public class DeduccionController : Controller
{
private IGenericService<Deducciones> _service;
public DeduccionController(IGenericService<Deducciones> service)
{
_service = service;
_service.SetConnectionString(GetUserClaims.Cadena);
}
and let my RegisterTypes just with the:
container.RegisterType<IGenericService<T>, GenericService<T>>()
but since i new to this world of IoCs i am not sure if this is the best way
What would be the correct way to do this using Unity?
Thank you for reading.
I am sorry for my english not my first languague.
I recently had to do something similar by swapping connection strings based on a route parameter specifying a geo-location.
I would recommend building your own Unity LifetimeManager that acts in a instance per session scope. Register an object that acts as a configuration container for the connection string property.
[See Unity Lifetime Manager: http://msdn.microsoft.com/en-us/library/microsoft.practices.unity.lifetimemanager(v=pandp.30).aspx]
Then you could inject that singleton instance of this configuration object into your controller and set the connection string property once a user has logged in. You could then inject that same singleton instance into a DbContext factory that instantiates your DbContext using the connection string specified in your configuration object.
Like I said, it may not be the most elegant solution, but I liked it better than having to pass a connection string through the many tiers of your application stack. Hope this helps.
I want to have ASP.NET MVC website that would have some frontend for looking into, adding and other things with data. And then I want to have Web Api for getting data for mobile devices and so. I want to use code first from EF (and I am using Ninject). I create classes for hotel and others. I created HotelManagerContext and database is created and looks good. I am adding data by HomeController and by Repository for this. When I looked at database in Visual Studio data are there. But when I tried to use my HotelsController for Api datacontext is empty. What's wrong? What I forget to set? Something with connection string or what?
This is my ApiController:
public class HotelsController : ApiController
{
private IHotelRepository _hotelRepo { get; set; }
public HotelsController(IHotelRepository repo)
{
_hotelRepo = repo;
}
// GET api/Hotels
public IEnumerable<Hotel> GetHotels()
{
return _hotelRepo.GetAll();
}
// GET api/Hotels/5
public Hotel Gethotel(int id)
{
return _hotelRepo.Get(id);
}
}
This is part of my controller for frontend:
public class HomeController : Controller
{
private IHotelRepository _hotelRepo { get; set; }
public HomeController(IHotelRepository repo)
{
_hotelRepo = repo;
}
public ActionResult Index()
{
return View();
}
// next methods, for adding data and so
}
This is my repository:
public class HotelRepository : IHotelRepository
{
private HotelManagerContext db { get; set; }
public HotelRepository()
:this (new HotelManagerContext())
{
}
public HotelRepository(HotelManagerContext hotelManagerContext)
{
// TODO: Complete member initialization
this.db = hotelManagerContext;
}
public Models.Hotel Get(int id)
{
return db.hotels.SingleOrDefault(h => h.hotId == id);
}
public IQueryable<Models.Hotel> GetAll()
{
return db.hotels;
}
public Hotel Add(Hotel hotel)
{
db.hotels.Add(hotel);
db.SaveChanges();
return hotel;
}
}
This is my HotelManagerContext:
public class HotelManagerContext : DbContext
{
public HotelManagerContext() : base("name=HotelManagerContext")
{
}
public DbSet<Hotel> hotels { get; set; }
}
Edit:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHotelRepository>().To<HotelRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
}
Edit2:
Here is my connection string:
<add name="HotelManagerContext" connectionString="Data Source=(localdb)\v11.0; Initial Catalog=HotelManagerContext-20121219191411; Integrated Security=True; MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|HotelManagerContext-20121219191411.mdf" providerName="System.Data.SqlClient" />
And I just found that even in HomeController I have empty datacontext. So when I check content of database in Server Explorer there are data which I added (in HomeController). But everytime when I have request page (web api or frontend) datacontext is empty and I can add items there are counting from zero but in database there are already next but can't get it. It's really weird.
What does your connection string look like? "name=HotelManagerContext" seems incomplete. I think you would want to also explicitly specify providerName="System.Data.EntityClient" at the very least (see here). In any case, it is common practice to put the connection string in the Web.Config file and assign the name there (i.e. name="HotelMamangerContext") then, under normal circumstances, EF will just discover the connection string by convention as long as the name of your DbContext class matches the name of the connection string in Web.Config (otherwise you can still specify it explicitly in the constructor).
On a different note (I don't think this should be related to you current problem), you could consider injecting you DbContext as well. Then you could drop the parameter-less constructor on your repository class unless you need to keep it around for another reason such as unit testing. Also, if you are using Ninject.Web.Common, you may want to consider scoping the instances to the request level (see InRequestScope).
...
kernel.Bind<HotelMamangerContext>().ToSelf().InRequestScope();
kernel.Bind<IHotelRepository>().To<HotelRepository>().InRequestScope();
...
I can't find solution for this so I create new project and I did everything like in the question. I have same classes, copy and paste code frome question. I can't find any important difference but second time it's working.
I know this isn't exactly solution but in this case I could start my project from begging so I tried it and it really helps. Just don't know where is problem.
I have a occasionally connected application where there is a server that stores information about products. I am using a database cache to store this information locally so when a connection is unavailable the application will still work when trying to read the database.
Since the database is configured and I do not have access to modify the tables, I did not implement 2 way updating and it only downloads a snapshot. A side question is if it is possible to create a database cache and have 2-way sync with only tracking columns on the client machine? I cannot add any columns or tables to the server. I know this might be a question for a separate post, but if this is true then it would change my direction for this problem completely, to a separate module detecting and syncing the database and handling any sync errors that are thrown and always connecting to the cache.
I am using a generic repository and I am wondering what the best practice to go about handling if a connection is available or not and using either a local or remote database depending on this status.
Should I add an interface to the generic repository that handles returning the correct string, and lets the repository know if it is live or not? I need to enable/disable certain features depending on the connection state so I also will need a property somewhere so that when this repository is used there can be a way to bind various controls enabled state to this status.
Instead should I have a wrapper that contains for example an IRepository and IConnectionStringManager and then handles feeding and initializing the repository connection string based on availability? This wrapper would expose the repository and any status properties required.
I guess I am not sure if I should be setting up my program to use IRepository with all the automatic connection sensing behind the scenes, or if I should have IRepositoryManager that has a IRepository and IConnectionStringManager in it.
Maybe both of those options are wrong?
I like the way Entity Framework allows you to provide a connection string as a constructor argument to its contexts. That way you can leverage a dependency injection framework to apply special logic when creating the context, and you only have to change the code in one place (assuming you're using DI principles). You could do something similar with your repository implementation.
Update
Since you're using Entity Framework, here's an idea of what it might look like in code:
// DI Bindings, Ninject style
Bind<Func<MyContext>>().ToMethod(
c => new MyContext(
c.Kernel.Get<IConnectionManager>().IsOnline()
? OnlineConnectionString
: OfflineConnectionString));
// Usage
public class ThingRepository : IThingRepository
{
private Func<MyContext> _getContext;
public ThingRepository(Func<MyContext> getContext)
{
_getContext = getContext;
}
public IEnumerable<Thing> GetAllThings()
{
using(var context = _getContext())
{
return context.Things.ToList();
}
}
}
Or, if you prefer to use a more explicit factory implementation:
public interface IMyContextFactory
{
MyContextFactory Get();
}
public class MyContextFactory : IMyContextFactory
{
private const string OnlineConnectionString = "...";
private const string OfflineConnectionString = "...";
private IConnectionManager _connectionManager;
public MyContextFactory(IConnectionManager connectionManager)
{
_connectionManager = connectionManager;
}
public MyContextFactory Get()
{
var connectionString = _connectionManager.IsOnline()
? OnlineConnectionString
: OfflineConnectionString
return new MyContext(connectionString);
}
}
// DI Bindings, Ninject style
Bind<IMyContextFactory>().To<MyContextFactory>();
// Usage
public class ThingRepository : IThingRepository
{
private IMyContextFactory _myContextFactory;
public ThingRepository(IMyContextFactory myContextFactory)
{
_myContextFactory = myContextFactory;
}
public IEnumerable<Thing> GetAllThings()
{
using(var context = _myContextFactory.Get())
{
return context.Things.ToList();
}
}
}