My ASP.Net MVC application has to connect to multiple databases at run time. I can overload my class to accept the connection string at run time as shown below
class MyClassDBContext:DbContext
{
public MyClassDBContext(string str) : base(str)
{
this.Database.Connection.ConnectionString = str;
}
}
Currently, I am retrieving this connection string from a database table. My workflow is as follows
Website connects to default database using credentials stored in
web.config
Website queries default database to get connection strings for
other databases.
Websites connects to other databases by supplying the connection
string at run time
The problem I facing right now is in keeping my code clean. Every time I need the connection string for database number 2, I have to look it up in the default database. Is there any cleaner way of doing this? I considered storing the connection string in the profile data but I am not sure if this is a good idea. Every user of my website will need to connect to at most 2-3 different databases depending on their credentials.
I would personally put all connection strings in your App.Config file and use a simple IOC implementation.
Actually the ninject package off Nuget might be perfect for your needs.
Here's what I mean though. Hopefully this makes your code clean. I used this exact same pattern for a previous project and it worked out well.
You could take it a step further and make a Service Locator and register services in your global.asax. Let me know if that interests you. Also check out ninject.
public interface IService()
{
string GetConnectionString();
void DoStuff();
}
public class DBServiceOne : DbContext, IService
{
protected string GetConnectionString()
{
return ConfigurationManager.AppSettings["DBServiceOneConnectionString"]
}
public DBServiceOne(string str) : base(str)
{
this.Database.Connection.ConnectionString = GetConnectionString()
}
public void DoStuff() { //logic goes here }
}
public class DBServiceTwo : DbContext, IService
{
public DBServiceTwo(string str) : base(str)
{
this.Database.Connection.ConnectionString = GetConnectionString();
}
protected string GetConnectionString()
{
return ConfigurationManager.AppSettings["DBServiceTwoConnectionString"]
}
public void DoStuff() { //logic goes here }
}
public class DBServiceThree : DbContext, IService
{
public DBServiceThree(string str) : base(str)
{
this.Database.Connection.ConnectionString = GetConnectionString();
}
protected string GetConnectionString()
{
return ConfigurationManager.AppSettings["DBServiceThreeConnectionString"]
}
public void DoStuff() { //logic goes here }
}
Now for the implementation -- Use Constructor Injection on your controllers
//This could be in your home controller
public class HomeController : AsyncController
{
private IService DBOneService;
private IService DBTwoService;
private IService DBThreeService;
public HomeController(IService one, IService two, IService three)
{
DBOneService= one;
DBTwoService = two;
DBThreeService = three;
}
public HomeController() : this(new DBServiceOne(), new DBServiceTwo(), new DBServiceThree()) {}
public ActionResult Index() {
DBOneService.DoStuff(); //here you'd want to return a list of data and serialize down with json or populate your razor template with it. Hope this helps!
}
I had a slightly different problem. The DB I connect to depends on the state of a product import. During the import databases get attached and detached. The currently available db is stored in a "default database".
The main problem I had was that I had to switch off connection pooling, otherwise invalid connection states existed after detaching databases and attaching them again.
This is might not be a problem for you.
Apart from that I store the current Connectionstring in the application state. Only after each 60 seconds I query the "default database" again. You have to watch out for multithreading issues by using locking.
Related
I have simple classes to saves and get data (not like repository pattern). But while saving data to multiple tables I want to maintain a transaction. So I just went through Unit of work pattern, but that will require me to do a lot of changes. So I'm thinking if my approach will do the same as UOF.
Here's my code:
CalalogueRepository:
public interface ICalalogueRepository
{
void Create(string guid, string fileName);
}
public class CalalogueRepository : ICalalogueRepository
{
private CatalogueContext _catalogueContext;
public CalalogueRepository(CatalogueContext catalogueContext)
{
_catalogueContext = catalogueContext;
}
public void Create(string guid, string fileName)
{
_catalogueContext.Catalogues.Add(new Catalogue
{
CatalogueId = guid,
FileName = fileName
});
}
}
StuffRepo:
public interface IStuffRepo
{
void Create(string guid, List<StuffModel> myStuff);
}
public class StuffRepo : IStuffRepo
{
private CatalogueContext _catalogueContext;
public StuffRepo(CatalogueContext catalogueContext)
{
_catalogueContext = catalogueContext;
}
public void Create(string guid, List<StuffModel> myStuff)
{
//add stuff to _catalogueContext.StuffTable.Add
}
}
Finally a class that does the SaveChanges and Commit:
public class UOW : IUOW
{
private CatalogueContext _catalogueContext;
private ICalalogueRepository _calalogueRepo;
private IStuffRepo _stuffRepo;
public UOW(CatalogueContext catalogueContext,
ICalalogueRepository calalogueRepo,
IStuffRepo stuffRepo)
{
_catalogueContext = catalogueContext;
_calalogueRepo = calalogueRepo;
_stuffRepo = stuffRepo;
}
public void Save (string guid, string fileName, List<StuffModel> myStuff)
{
using (IDbContextTransaction transection = _catalogueContext.Database.BeginTransaction())
{
_calalogueRepo.Create(guid, fileName);
_stuffRepo.Create (guid, myStuff);
_catalogueContext.SaveChanges();
transection.Commit();
}
}
}
I think there is only 1 CatalogueContext throughout the call.
Ok, so as you can see here, AddDbContext is the right way to register it as you wrote in the comment on the question.
Here it says that AddDbContext will register the context as scoped.
And here you can find what scoped means.
Overall I think you are right that your code will use the same context throughout the Save method.
Couple thoughts:
Probably you want to have a try-catch in case an exception is thrown and you want to rollback
If you are not sure if it's working why not try it? You should test your code/application anyways.
Probably this could be done in a better way, but I don't have the context about the rest of your code/application, so I cannot tell. (Not sure what you mean by "...Unit of work pattern, but that will require me to do a lot of changes." for example.)
Now the Create methods not self-contained, meaning if you just want to add a new item to the table it is not enough to call Create, but separately call SaveChanges(). This is not an explicit problem, but has to be kept in mind and might be a little bit confusing for new developers on the project.
I have some problem with understanding how to create injectable classes…
Here is my example:
public interface IService
{
string FindSomeData()
}
Now we create a class which implements the interface:
public class FolderService : IService
{
private string _path;
public FolderService(string path)
{
_path = path;
}
public string FindSomeData()
{
//Open a folder using _path and find some data
}
}
And maybe other class:
public class DbService : IService
{
private MyConnectionClass _connection;
public DbService(MyConnectionClass connection)
{
_connection = connection;
}
public string FindSomeData()
{
//Connect to database using _connection object and find some data
}
}
Now I would like to add one of the classes to IoC Container e.x.:
if (InDebug)
SimpleIoc.Default.Register<IService, FolderService>();
else
SimpleIoc.Default.Register<IService, DbService>();
And know I have a problems.
When I want to pass this object to the constructor of some other classes:
public MyViewModel(IService service)
{
_service = service;
}
// Read folder name from TextBox on View and then call _service.FindSomeData
Then I would like to pass user selected path to the IService object (FolderService) in this case.
How should I do this in a correct way (according to SOLID and other good practiciess patterns…)?
Once I should pass string (folder path), once a MyConnectionClass (if connection to database).
What is the best way to do that kind of things?
Best regards,
Michal
You can encapsulate folder path provide/change logic into a separate provider like IFolderPathProvider and inject it into FolderService
public interface IFolderPathProvider {
string GetFolderPath();
void SetFolderPath(string);
}
public class FolderPathProvider : IFolderPathProvider {
...
}
public class FolderService : IService
{
private IFolderPathProvider _folderPathProvider;
public FolderService(IFolderPathProvider folderPathProvider)
{
_folderPathProvider = folderPathProvider;
}
public string FindSomeData()
{
string path = _folderPathProvider.GetFolderPath();
//Open a folder using path and find some data
}
}
When user changes the path, inject IFolderPathProvider to the handler and call SetFolderPath. Similarly, you can create IDbConnectionProvider. Depending on the situation, they can be combined into one DataConfigProvider but I 'm not sure what exactly do you need there; the main idea is to separate folderpath/dbconnection changing logic from the services and keep using dependency injection.
Consider the following code segment:
public class DatabaseContext : DbContext
{
public DatabaseContext(String connectionString) : base(connectionString)
{
}
}
public class ContextNameDatabaseContext : DatabaseContext
{
public ContextNameDatabaseContext(String connectionString) : base(connectionString)
{
}
}
Would one say it is best practice when building the back-end for a multi-tenant solution where each client has its own database and maintain the data state until a user logs out / off?
Developer using these classes in this instance will need to be aware and careful as to when and how the classes are being used where the 'DatabaseContext' class acts as a base to the 'ContextNameDatabaseContext' class.
Please advise on any thoughts or suggestions.
One approach is to keep all the database connection strings as parameters in the database. However you have to assure that its encrypted.
Then at your DB layer you can pass the connection as parameter in plain text after decrypting and constructing your connection string accordingly:
public class MyDatabase: DbContext
{
public MyDatabase(string connString)
{
this.Database.Connection.ConnectionString = connString;
}
public DbSet<Order> Orders{ get; set; }
}
You can also use IOptions if you are using .NET Core to inject the connection string as a dependency.
I would like to improve my .NET project by adding another layer when accessing the database. This is my code:
namespace Company.Models
{
public static class AgencyBean
{
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static String createGUID(string name)
{
DataAccess dataAccess = new DataAccess();
bool exists = dataAccess.checkIfExists(Id);
if(exist)
{
dataAccess.delete(Id);
}
retur "ok";
}
}
}
I placed DataAccess class in a separate folder called "Helpers" and it contains most of my queries:
public class DataAccess
{
public bool checkIfExists(String Id)
{
try
{
SqlConnection cnn = new SqlConnection(dataConnection);
cnn.Open();
SqlCommand check_Id = new SqlCommand("SELECT COUNT(*) FROM TABLE_GUID WHERE ([USER_ID] = #Id)", cnn);
check_Id.Parameters.AddWithValue("#Id", Id);
int UserExist = (int)check_Id.ExecuteScalar();
if (UserExist > 0)
{
return true;
}
else
{
return false;
}
}
catch (SqlException ex)
{
Debug.WriteLine("SQL Exception " + ex);
DisplaySqlErrors(ex);
throw ex;
}
}
}
public class AgentBeanController : Controller
{
// GET: AgentBean
public ActionResult Index(string name)
{
return View();
}
[AllowAnonymous]
[WebMethod]
public string AgentURL() //here we create Agent URL and return it to the view
{
string var = Models.AgentBean.createGUID("TODO");
return var;
}
}
I'm accessing the database pretty much in very direct way. How would it be with a better technique, so this access can be more secure, like accessing thru a service layer?
I'm connecting to a existing sql database in some server and working with MVC architecture in my project.
So here is what I have done in the past.
First, that is your "models" namespace... models should never have database connectivity. Instead you have a seperate class, such as a controller, that hydrates some model.
Second, I've had a "service" class, which hooks up to a "repository" class. The repository class implements an interface to identify the exact "type" of database you're using.. but if that's not a part of your requirements you probably don't need to go that far.
Third, look up dependency injection (aka, DI). There are several frameworks out there. Personally I've used Autofac, but others exist as well to get the job done easier.
Fourth, on your your "controllers", "services" and "respository" classes, implement dependency injection, as well as any interfaces as needed to form a contract.
Fifth, I would use an actual controller namespace and not be working out of your models namespace to be pushing http calls band and forth.... Instead, create an action in your controller class, and instantiate an instance of your "agencyBean", hydrate it with data, and return that model out to your view.
Basically, in a scenario like this you're trying to keep each component doing what it is designated to do... breaking down responsibilities into smaller pieces and focusing on that. Your controller should just "fetch" your model and maybe do some transformations on it as needed or any other business-type logic.
Your service should handle the communication between your controller and your database layer.
Your data access layer (ie, in this case, some "repository" class...) would do all of those new data connections and/or setting up calls to stored procedures or queries.
Doing things this way has a lot of benefit. Some of the big ones are maintainability, readability, code re-use. Sure it makes your project a bit more complicated in terms of files sitting wherever... but that can be a good thing. It's so much better than slamming everything into one single class and have it do everything :)
But, just FYI, this is from an implementation I've done in the past... I'm sure there are better ways but this setup worked quite well for my team and I.
Here is a small example using some of your code you posted. I DID NOT check this for typos and it wouldn't compile, but should help give a general idea of what I'm talking about....
namespace Company.Models
{
public class AgencyBean
{
public AgencyName{get;set;}
public AgencyId{get;set;}
// other properties...
}
}
namespace Company.Controllers
{
public class MyController : Controller
{
private readonly IMyService myService;
public MyController(IMyService myService) // <-- this is your dependency injection here...
{
this.myService = myService;
}
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static String createGUID(string name)
{
var model = new AgencyBean();
model.AgencyId = 1;
model = myService.getAgency(agencyBean);
return model;
}
}
}
namespace Company.Services
{
public class MyService
{
private readonly IMyRepository myRepository;
public MyService(IMyRepository myRepository) // <-- this is your dependency injection here...
{
this.myRepository = myRepository;
}
public AgencyBean getAgency(AgencyBean model){
var dataTable = myRepository.getAgencyData(model.AgencyId);
// fill other properties of your model you have...
// ...
// ...
return model;
}
}
}
namespace Company.Repositories
{
public class MyRepository : IDatabaseCommon // <-- some interface you would use to ensure that all repo type objects get connection strings or run other necessary database-like setup methods...
{
private readonly String connectionString{get;set;}
public MyRepository()
{
this.connectionString = //get your connection string from web.config or somewhere else...;
}
public DataTable getAgencyData(int id){
var dataTable = new DataTable();
// perform data access and fill up a data table
return dataTable;
}
}
}
Currently, my DbContext class has this code:
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
What I'd like to do, is inspect the subdomain and use that for the database name, so something like http://abc.mysite.com/ would use a connection string with database name abc.
But how do I manipulate the value of "DefaultConnection" in the constructor?
DBContext will take a name or a connection string in its constructor. That constructor is not usually exposed if you have a generated model.
You can use a partial class to expose that constructor:
public partial class DataEntities
{
public DataEntities(string connectionString) : base(connectionString)
{
}
}
I have done that before. My project was set up for DI with Castle Windsor and one of my IWindsorInstallers was DataAccessInstaller responsible for registering, among other classes like repositories, my database context and here is the relevant code:
container.Register(Component
.For<MyDatabaseContext>().Forward<DbContext>()
.ImplementedBy<MyDatabaseContext>()
.LifestylePerWebRequest()
.UsingFactoryMethod(context =>
{
return MyDatabaseContextFactory.Create(HttpContext.Current.Request.Url);
}));
You can have several connection strings set up in your web.config matching your domain.
My context factory implementation:
public static class MyDatabaseContextFactory
{
public static MyDatabaseContext Create(Uri uri)
{
return new MyDatabaseContext(uri.GetTopDomain());
}
}
If you just have a simple project and don't even have DI, you can still make use of a factory that finds out what the website use and instantiates a database context with the appropriate connection string.
Needless to say, your current database context constructor doesn't have to change.