Runtime dynamic SQL Server database access by different connection strings - sql-server

I've searched the stackoverflow for a long time and didn't find a solution fit my situation, so I asked here.
I have a single asp.net website, and need the web app to access different SQL Server database by the subdomain name.
According to the url request subdomian to determine the access the different database.
prj1.test.com prj1--->use the prj1_DB
prj2.test.com prj2 use the prj2_DB
I couldn't find a better practice to solve the issue.
My intuition solution:
when the url request coming, get the url subdomain, get the subdomain's db connection string stored in the main db, passing the connection string to the DAL to get the data.
Index.aspx.cs
DataTable dt = ProjectObject.GetProjectIndexNotice(new object[] { 0, CurrentProject.DbConnectionString });
ProjectObject.cs
public static DataTable GetProjectIndexNotice(object[] param)
{
ProjectDLC obj = new ProjectDLC();
return obj.GetProjectIndexNotice(param);
}
ProjectDAL.cs
public DataTable GetProjectIndexNotice(object[] param)
{
return base.GetDataTableFromDatabase(param, "NEMP_GetProjectIndexNotice");
}
DALBase.cs
DataBase db = new Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase(CurrentProject.DbConnectionString);
I want to find a better way to solve this problem.
The solution I using above is:
get the dbConnectionString from main DB,
passing it over the Index.page ->BusinessObject Layer -->DAL Layer
It's so bad that passing the DB connection string from UI page to the DAL layer.
Any ideas?
Update 1:
What I really want is: don't pass the db connection string from UI to DAL layer.
I want to find a solution that don't do pass the db connstr from UI to DAL linearly.
Is there some pattern in asp.net to share some variable for UI layer and DAL Layer?
Update 2:
if I stored the project db info in a xml file or in the main db, it looks like this
it's a key-value part for the project. here is the question, I get the values all in the main DB or a xml file. How I get the key when I need to access the DB in DAL layer?
in the DAL layer, how to get the correct key for the currnet url request?
it's back to the above, pass the key from UI to DAL. that's I want to avoid.
the real problem is, I can get the key from url request in the UI layer, and I can get the value for that key in the DAL layer. but there is a gap between the two layers, How to conquer this gap?

If you can compute your connection string from a base connection string, then you could do something like this:
store the base connection string in your web.config
<connectionStrings>
<add name="BaseConnString"
connectionString="server=MyServer;database=master;Integrated Security=SSPI;" />
</connectionStrings>
load the base connection string into a SqlConnectionStringBuilder in your code:
string baseConnStr = WebConfigurationManager.ConnectionString["BaseConnString"].ConnectionString;
SqlConnectionStringBuilder scsBuilder =
new SqlConnectionStringBuilder(baseConnStr);
now, just define the database you want to connect to, e.g. based on something in your URL
scsBuilder.InitialCatalog = "ProjectDatabase" + ........ ;
use the resulting complete connection string for your SqlConnection:
using(SqlConnection _con = new SqlConnection(scsBuilder.ConnectionString))
{
// do something
}
Check out the MSDN docs on SqlConnectionStringBuilder.
With this approach, you'd store a single "base" connection string in your web.config and this wouldn't be changing, and using SqlConnectionStringBuilder, you can safely and efficiently define and "compute" your real, "dynamic" connection strings at runtime.

How about adding add the connection strings in web.config as:
Subdomain_connectionString
Now read the subdomain from Request:
Reading connection string from web.config in your DL:
ConfigurationManager.ConnectionStrings[Subdomain_connectionString].ConnectionString
Update:
You can also use xml files to store connection string values:
<ROOT>
<Project_1>
<IPAddress></IPAddress>
<DBName></DBName>
...
</Project_1>
<Project_2>
....
</ROOT>
Anytime a new project is added/removed this xml file would be updated. Use XPath expressions to parse the xml file.
#Passing Connection string from UI to DAL: Just try to add the System.web namespace to DAL layer. This would give access to Request object in DAL. Now you can get the subdomain and build the connectionstring in DAL itself. Not sure whether this is a right approach, but might work in your case.

Related

How would I configure Effort Testing Tool to mock Entity Framework's DbContext withOut the actual SQL Server Database up and running?

Our team's application development involves using Effort Testing Tool to mock our Entity Framework's DbContext. However, it seems that Effort Testing Tool needs to be see the actual SQL Server Database that the application uses in order to mock our Entity Framework's DbContext which seems to going against proper Unit Testing principles.
The reason being that in order to unit test our application code by mocking anything related to Database connectivity ( for example Entity Framework's DbContext), we should Never need a Database to be up and running.
How would I configure Effort Testing Tool to mock Entity Framework's DbContext withOut the actual SQL Server Database up and running?
*
Update:
#gert-arnold We are using Entity Framework Model First approach to implement the back-end model and database.
The following excerpt is from the test code:
connection = Effort.EntityConnectionFactory.CreateTransient("name=NorthwindModel");
jsAudtMppngPrvdr = new BlahBlahAuditMappingProvider();
fctry = new BlahBlahDataContext(jsAudtMppngPrvdr, connection, false);
qryCtxt = new BlahBlahDataContext(connection, false);
audtCtxt = new BlahBlahAuditContext(connection, false);
mockedReptryCtxt = new BlahBlahDataContext(connection, false);
_repository = fctry.CreateRepository<Account>(mockedReptryCtxt, null);
_repositoryAccountRoleMaps = fctry.CreateRepository<AccountRoleMap>(null, _repository);
The "name=NorthwindModel" pertains to our edmx file which contains information about our Database tables
and their corresponding relationships.
If I remove the "name=NorthwindModel" by making the connection like the following line of code, I get an error stating that it expects an argument:
connection = Effort.EntityConnectionFactory.CreateTransient(); // throws error
Could you please explain how the aforementioned code should be rewritten?
You only need that connection string because Effort needs to know where the EDMX file is.
The EDMX file contains all information required for creating an inmemory store with an identical schema you have in your database. You have to specify a connection string only because I thought it would be convenient if the user didn't have to mess with EDMX paths.
If you check the implementation of the CreateTransient method you will see that it merely uses the connection string to get the metadata part of it.
public static EntityConnection CreateTransient(string entityConnectionString, IDataLoader dataLoader)
{
var metadata = GetEffortCompatibleMetadataWorkspace(ref entityConnectionString);
var connection = DbConnectionFactory.CreateTransient(dataLoader);
return CreateEntityConnection(metadata, connection);
}
private static MetadataWorkspace GetEffortCompatibleMetadataWorkspace(ref string entityConnectionString)
{
entityConnectionString = GetFullEntityConnectionString(entityConnectionString);
var connectionStringBuilder = new EntityConnectionStringBuilder(entityConnectionString);
return MetadataWorkspaceStore.GetMetadataWorkspace(
connectionStringBuilder.Metadata,
metadata => MetadataWorkspaceHelper.Rewrite(
metadata,
EffortProviderConfiguration.ProviderInvariantName,
EffortProviderManifestTokens.Version1));
}

Database connection from Java handler BIRT

I'm creating a rptlibrary to share with all the reports in my company.
The library has an oda datasource created and shared to all reports. We want to do some querys from ReportEventAdapter.initialize() to the database to get information from the database. I can acces the datasource in the library in this way:
ReportDesignHandle rdh = (ReportDesignHandle)reportContext.getReportRunnable().getDesignHandle();
DesignSessionImpl ds = rdh.getModule().getSession();
String rsf = ds.getResourceFolder( );
LibraryHandle libhan = ds.openLibrary(rsf + "/my.rptlibrary" ).handle( );
DataSourceHandle datasource = libhan.findDataSource("myDS");
But once I have the datasource, there's no way to get a connection to the database from the datasource. The only way to do this, is creating a classic JDBC connection to the database using the data from the datasource? Is there any way to use a more elegant method to connect to the database from the java handler? Like using pooling, reusing the connection, etc..
Thanks.
We can iterate over dataset values in a report script event, thus if a dataset is defined with a JNDI URL, queries can take advantage of a connection pool.
However it is quite complicated. There is a full example in this topic: the script defined in "getDefaultValueList" event of the report parameter can be moved anywhere in the report and then initialize a global variable. In particular we could move it to "initialize" event, or to "beforeFactory" event (in your case "beforeFactory" is probably what you want).

dyanamically change the database name in SqlMapConfig.xml file

I want to change the database name in SqlMapConfig.xml file from the application, does any one help me?
You can override the database when you instantiate the Ibatis mapper instance; I do this for switching between debug and release builds of the application and hence accessing a different target database.
If your xml file is in an assembly called DatalayerAssembly for example, you might have a method for returning your new Ibatis instance based on a database name like this:
public IBatisNet.DataMapper.ISqlMapper CreateNewIbatis(
String serverName,
String databaseName)
{
// Load the config file (embedded resource in assembly).
System.Xml.XmlDocument xmlDoc = IBatisNet.Common.Utilities.Resources.GetEmbeddedResourceAsXmlDocument("SqlMapConfig.xml, DatalayerAssembly");
// Overwrite the connectionString in the XmlDocument, hence changing database.
// NB if your connection string needs extra parameters,
// such as `Integrated Security=SSPI;` for user authentication,
// then append that to InnerText too.
xmlDoc["sqlMapConfig"]["database"]["dataSource"]
.Attributes["connectionString"]
.InnerText = "Server=" + serverName + ";Database=" + databaseName;
// Instantiate Ibatis mapper using the XmlDocument via a Builder,
// instead of Ibatis using the config file.
IBatisNet.DataMapper.Configuration.DomSqlMapBuilder builder = new IBatisNet.DataMapper.Configuration.DomSqlMapBuilder();
IBatisNet.DataMapper.ISqlMapper ibatisInstance = builder.Configure(xmlDoc);
// Now use the ISqlMapper instance ("ibatisInstance") as normal.
return ibatisInstance;
}
I'm using this approach in Ibatis 1.6.2.0 on .Net but the exact SqlMap config file might vary depending by version. Either way the approach is the same; you just might need a different Xml path (i.e. the bit that reads ["sqlMapConfig"]["database"] etc may need changing for your config file)
Hope that helps.

Database connection

I have a WinForms project, which consists of 10 forms. Forms are called to each other, each shape is drawn to the database
(I'm using LINQ to SQL) how best to create a database connection, I set up the connection when loading the main form
string path = "Data Source = | DataDirectory | \ \ Database.sdf";
Database db = new Database (path);
and then loading each window is transmitted through an object constructor db, then work with the database,
Window1 win1 = new Window1(db)
there may be a better way?
Try to use static class for your db operations.
Well for one, you should abstract your database logic / connections into their own class or assembly. The connection string shouldn't be hard coded, but come from the app.config file.
I don't think you should be passing around the connection object.
As I stated above, abstract our your database code and wrap your the context in a Using statement.

DB connection strings in MVC applications using Entity Framework

I am working on an MVC application using Entity Framework.
After creating an EDMX, I noticed the DB connection string is located in TWO places - an app.config file in my Data class library, and a web.config file in my web application.
We want to:
remove these two plain text connection strings
encrypt a single connection string
and use our pre-existing class library to decrypt the connection string when needed
I tried removing one or the other connection string from the config files, and DB access fails. Why are TWO required? And is there any way to do what we want in an MVC - EF project, and how would I tell EF that is what we are doing?
Thanks!
You can ignore the connection string in your EF project, I think, and just set the connection programmatically from your controller.
public class SomeController : Controller
{
public SomeController()
{
/* Substitute whatever method you want to fetch your data source string here */
/* example assumes plain text from web.config */
string dataSource = ConfigurationManager
.ConnectionStrings["ApplicationServices"]
.ConnectionString;
this.Entities = new SomeEntities(dataSource);
}
private SomeEntities Entities { get; set; }
}

Resources