I want to inject a custom connection string into my EF context instead of using the connection string in my web.config. The idea is to move all database related logic off of my MVC project into a separate layer. I also want this layer to be responsible for the proper connection strings instead of my web applications.
The services currently using the context are calling the default constructor:
using (var context = new MyDbContext()) {
//...
}
The default constructor is internally calling DbContext
with the name of the connection string from the web.config
:
public partial class MyDbContext : DbContext
{
public MyDbContext()
: base("name=MyDbContext")
{
}
//...
}
In order to inject my custom connection string I would need an overloaded constructor which takes the connection string as an argument. Unfortunately there is not such a constructor provided.
It is obvious that adding the constructor overload manually right inside the MyDbContext
class would be a very bad idea, since this class is auto-generated and will be overwritten any time soon. Let's not talk about this any more, it's forbidden. Period.
Since MyDbContext
is a partial class, one could add the additional constructor in a separate class file partial class MyDbContext
, but this seems smelly either. I don't know why, but my brain says bad idea.
After some investigation I found out, that one can tell EF to include this additional constructor by editing the T4 template Model.Context.tt
which is a mix of C# and some template markup. Here is the original constructor:
public <#=Code.Escape(container)#>()
: base("name=<#=container.Name#>")
{
<#
WriteLazyLoadingEnabled(container);
#>
}
It is obviously easy to add similar logic to generate an overloaded constructor containing the connection string:
public <#=Code.Escape(container)#>(string nameOrConnectionString)
: base(nameOrConnectionString)
{
<#
WriteLazyLoadingEnabled(container);
#>
}
I tried this and noticed, that both re-generating the model classes and updating the model from DB will not affect the T4 template, thus the additional constructor will always be there. Good! At first glance this looks like a suitable solution, but...
And here is my question: Is that really a good solution?
Let's compare the three options again:
From these three options the third seems to me to be the most convenient and clean solution. What is your opinion? Has someone a good reason, why this would be a bad idea? Are there more options to inject connection strings, maybe using a custom connectionFactory
? If so, how would I do that?
Like @shaft proposed, I replaced my T4 template approach to using a partial class. As it turned out, this is indeed a lot simpler and intuitive, than any other solution I currently know of.
The auto-generated class looks like:
public partial class MyDbContext : DbContext
{
public MyDbContext() : base("name=MyDbContext")
{
}
//...
}
I just added another partial class of the same name. Issue solved.
public partial class MyDbContext
{
public MyDbContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With