I have the following db context which was auto-genned through the wizard in VS:
MyEntities : DbContext
When I go to the auto-genned definition, I see the following constructor defintion:
public MyEntities() : base("name=SecurityApiEntities")
{
}
I need to be able to set the connection string dynamically. How can I go about doing this? I don't see a way to do this off hand described in this url:
https://msdn.microsoft.com/en-us/library/jj592674(v=vs.113).aspx
If for some reason you can not keep the connection string in the config file you can do something like this:
var entityBuilder = new EntityConnectionStringBuilder();
// use your ADO.NET connection string
entityBuilder.ProviderConnectionString = conString;
// Set the Metadata location.
entityBuilder.Metadata = #"res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl";
var dbContext = new DbContext(entityBuilder.ConnectionString);
To avoid having to do this every single time you want a DbContext you can create a Factory class and method that will return you the DbContext based off of the connection string passed in. Or create a Partial Class that extends your DbContext with a Create function.
Related
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.
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 a repository class that has a constructor with string parameter argument. It is a connection string. I created an interface for it and I'm using Unity in my UI project.
My question is, how do I set this up the 'right' way so that Unity will know how to properly construct my class in order to inject it when instantiating my controller?
I currently 'worked around' this by using a parameterless constructor for my repository but feel like this is a cop out.
Here is my repository constructor I want to use...
public CobraLettersRepository(string dbConnectionString)
{
_connString = dbConnectionString ?? throw new ArgumentNullException(dbConnectionString);
dbConnection = new SqlConnection(_connString);
dbConnection.Open();
}
I created ICobraLettersRepository and want to inject it into my controller constructor.
public CobraLetterController(ICobraLetterRepository cobraLetterRepository)
{
if (cobraLetterRepository == null)
throw new ArgumentNullException(cobraLetterRepository);
_cobraLetterRepo = cobraLetterRepository;
}
When I try this, the code compiles but I get runtime errors whenever I attempt to navigate to a part of my app where those controller methods are called.
I would say to encapsulate the Connection String inside a configuration object and put the get of the connection string inside the constructor of that configuration object.
Then just register your configuration object as other class.
public class ProjectConfiguration
{
public string ConnectionString { get; set; }
public ProjectConfiguration()
{
ConnectionString = //Get the configuration from , i.e: ConfigurationManager
}
}
And then, inject it :
public CobraLettersRepository(ProjectConfiguration configuration)
{
if(configuration == null){
throw new ArgumentNullException(configuration);
}
_connString = configuration.ConnectionString;
dbConnection = new SqlConnection(_connString);
dbConnection.Open();
}
With that you can always isolate the config from the DI container and leave the injection as simple as you can. Also, you can get the config from your config files (one per environment).
EDIT: Also check your repository constructor logic, maybe you don't want to Open the connection on the constructor. Is better to make a using statement on your class methods like :
using(SqlConnection connection = new SqlConnection(_injectedConfiguration.ConnectionString)){
connection.Open();
//Make your stuff here
}
With the using you ensure that the connection will be correctly disposed.
Note that with the configuration object approach you can just store the configuration object in a private readonly variable and use it whatever you need.
During registration use an InjectionConstructor to pass the connection string name. You need to remove all constructors except one that expects a string argument.
container.RegisterType<ICobraLetterRepository,CobraLettersRepository>(new InjectionConstructor("connectionstringname"));
Please note that it will lead to problems somewhere/sometime. You need to change the logic to create the database connection (you may refer to Breaking SOLID Principles in multiple implementation of an Interface or Resolve named registration dependency in Unity with runtime parameter).
I need to pass a WSID in the connectionstring of an Entity Framework context.
I dont want to update all the instanciations that i have, to pass a new connectionstring so i was wondering if there is a method to override that can be of help?
For information, i have this actually:
using(var context = new SampleEntities())
and i dont want to rewrite it like that:
using(var context = new SampleEntities(NewConnectionString))
I tried to override the CreateContext method without success...
With EntityFramework 6, it's not more possible to pass natively a connection string to the constructor of the context (there's no more constructor for that) so i had overload my context class to add the constructor
public partial class MyObjectEntities : DbContext
{
public MyObjectEntities(string connectionString)
: base(connectionString)
{
}
}
In addition, because it's not possible to update the connection string inside the context after instanciation, i had to make the desired connection string before instanciating of my context.
So to do that, i created a dll project (sharable between mutiples projects) able to configure my environnement and containing my desired WSID.
Here is the construtor of a connection string gave by Microsoft http://msdn.microsoft.com/en-US/en-en/library/bb738533%28v=vs.110%29.aspx
I am looking a way to set CommandTimeout for DbContext. After searching I found the way by casting DbContext into ObjectContext and setting value for CommandTimeout property of objectContext.
var objectContext = (this.DbContext as IObjectContextAdapter).ObjectContext;
But I have to work with DbContext.
It will work with your method.
Or subclass it (from msdn forum)
public class YourContext : DbContext
{
public YourContext()
: base("YourConnectionString")
{
// Get the ObjectContext related to this DbContext
var objectContext = (this as IObjectContextAdapter).ObjectContext;
// Sets the command timeout for all the commands
objectContext.CommandTimeout = 120;
}
}
var ctx = new DbContext();
ctx.Database.CommandTimeout = 120;
This may help you.
public class MyContext : DbContext
{
public MyContext () : base(ContextHelper.CreateConnection("my connection string"), true)
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
}
}
I find that changing the .tt file works for me as I don't lose the change later on:
Add this line:
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
Right after the DbContext creator and before the !loader.IsLazy construct:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
public <#=code.Escape(container)#>()
: base("name=<#=container.Name#>")
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
<#
if (!loader.IsLazyLoadingEnabled(container))
It should then appear in your generated Context.cs:
public MyEntities()
: base("name=MyEntities")
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
}
Here's how I solved this problem when using an EDMX file. This solution changes the default T4 template to make the generated class inherit from a custom DbContext class, which specifies a default command timeout, and a property to change it.
I'm using Visual Studio 2012 and EF 5.0. Your experience may differ with other versions.
Create a custom DbContext class
public class CustomDbContext : DbContext
{
ObjectContext _objectContext;
public CustomDbContext( string nameOrConnectionString )
: base( nameOrConnectionString )
{
var adapter = (( IObjectContextAdapter) this);
_objectContext = adapter.ObjectContext;
if ( _objectContext == null )
{
throw new Exception( "ObjectContext is null." );
}
_objectContext.CommandTimeout = Settings.Default.DefaultCommandTimeoutSeconds;
}
public int? CommandTimeout
{
get
{
return _objectContext.CommandTimeout;
}
set
{
_objectContext.CommandTimeout = value;
}
}
}
This has an optional feature: I'm not hard-coding the default command timeout. Instead, I'm loading it from the project settings so that I can change the value in a config file. How to setup and use project settings is not in the scope of this answer.
I'm also not hard-coding the connection string or connection string name. It's already passed into the constructor by the generated context class, so it makes no sense to hard-code it here. This is nothing new; the EDMX file already generates the following constructor for you, so we are just passing along the value.
public MyEntities()
: base("name=MyEntities")
{
}
(This instructs EF to load the connection string named "MyEntities" from the config file.)
I'm throwing a custom exception if the ObjectContext is ever null. I don't think it ever will be, but it's more meaningful than getting a NullReferenceException.
I store the ObjectContext in a field so that I can make a property to access it to override the default.
Modifying the entity context T4 template
In the Solution Explorer, expand the EDMX file so that you see the T4 templates. They have a .tt extension.
Double click the "MyModel.Context.tt" file to open it. Around line 57 you should see this:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
This template line generates the class definition of your "MyEntities" class, which inherits DbContext.
Change the line so that the generated class inherits CustomDbContext, instead:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : CustomDbContext
As soon as you save this file it should regenerate the class. If not, you can right-click the EDMX file and select "Run Custom Tool". If you expand the "MyModel.Context.tt" file under your EDMX file, you will see "MyModel.Context.cs". That's the generated file. Open it, and you should see that it now inherits CustomDbContext.
public partial class MyEntities : CustomDbContext
That's all there is to it.
Issues
Once you change the context class from DbContext to CustomDbContext, Visual Studio will give you an error if you try to add a new MVC controller class using the "Controller with read/write actions and views, using Entity Framework" template. It will say "Unsupported context type.". To get around this, open the generated "MyModel.Context.cs" class, and temporarily change the type it inherits back to DbContext. After adding your new controller, you can change it back to CustomDbContext.
I like the extension approach:
public static class DbContextExtensions
{
public static void SetCommandTimeout(this ObjectContext dbContext,
int TimeOut)
{
dbContext.CommandTimeout = TimeOut;
}
}
and then simply
((IObjectContextAdapter)cx).ObjectContext.SetCommandTimeout(300);
If it can help, this is the VB.Net solution:
Dim objectContext As Objects.ObjectContext = CType(Me,IObjectContextAdapter).ObjectContext
objectContext.commandTimeout = connectionTimeout
This is similar to the approach used by #Glazed above but my approach is also to use a custom DbContext class, but I am doing the reverse. Instead of modifying the T4 template (.tt file under your .edmx), I actually inherit from the resulting MyEntities Class instead like so:
MyEntities class generated by the T4 Template:
public partial class MyEntities : DbContext
{
public MyEntities()
: base("name=MyConnectionStringName")
{
}
...
}
Then create a new custom class as a wrapper around MyEntities like the following:
public class MyEntitiesContainer : MyEntities
{
private static readonly int _DEFAULT_TIMEOUT = 100;
public MyEntitiesContainer()
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = _DEFAULT_TIMEOUT;
}
//Use this method to temporarily override the default timeout
public void SetCommandTimeout(int commandTimeout)
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = commandTimeout;
}
//Use this method to reset the timeout back to default
public void ResetCommandTimeout()
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = _COMMAND_TIMEOUT;
}
}
In your code, instantiate the Container class and if you need to use a custom timeout for a specific command, set it manually using the provided methods.
using (var db = new MyEntitiesContainer()) {
db.SetCommandTimeout(300);
db.DoSomeLongCommand();
db.ResetCommandTimeout();
db.DoShorterCommand1();
db.DoShorterCommand2();
...
}
The benefit to this approach is that you can also create an interface for your Container class and use instances of the interface with dependency injection, then you can mock up your database in your unit tests in addition to having easier control over the command timeout and other properties of the object context that you can create methods for (such as lazy loading, etc).
I came here looking for an example of setting the timeout for a single command rather than such a global setting.
I figure that it will probably help someone to have an example of how I achieved this:
var sqlCmd = new SqlCommand(sql, context.Database.Connection as SqlConnection);
sqlCmd.Parameters.Add(idParam);
sqlCmd.CommandTimeout = 90;
if (sqlCmd.Connection.State == System.Data.ConnectionState.Closed)
{
sqlCmd.Connection.Open();
}
sqlCmd.ExecuteNonQuery();
sqlCmd.Connection.Close();
#PerryTribolet's answer looks good for EF6 but it does work for EF5. For EF, here is one way to do it: create an ObjectContext, set the CommandTimeout on that and then create a DBContext from the ObjectContext. I set the flag to have both objects disposed of together. Here is an example in VB.NET:
Dim context As New ObjectContext("name=Our_Entities")
Dim dbcontext As New System.Data.Entity.DbContext(context, True)
With context
.CommandTimeout = 300 'DBCommandTimeout
End With
You don't have to use "With" of course.