Development and Production databases - c#

I and my team are currently doing a project, where we are using Entity Framework 4.1 (Code First). We want to write some tests, but we don't want them to run on our primary database, as we have a team in Singapore writing a client for what we do, and they are hitting that database constantly.
So to avoid disturbance when running our tests, we would like to have a different database for testing. How do we handle a second database when using Entity Framework? We want a solution that is semi-automatic (at least), so we don't have to fiddle around with Web.config each time we need to run tests.

Fiddling around with the web.config can a process that is prone to error... unless you are using web.config Transformations that is.
I would create a new configuration, "Test" for your project in Visual Studio... it can be a copy of your existing development configuration (or Debug / Release, whatever). Then, right click your Web.config file in Solution Explorer and click Add Config Transforms. Follow the instructions here on how to write a transform file. If you only need to change the EF connection string for the test environment it would look something like this in web.Test.config:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="AdventureWorksEntities"
connectionString="metadata=.\AdventureWorks.csdl|.\AdventureWorks.ssdl|.\AdventureWorks.msl;
provider=System.Data.SqlClient;provider connection string='Data Source=TestDB;
Initial Catalog=AdventureWorks;Integrated Security=True;Connection Timeout=60;
multipleactiveresultsets=true'" providerName="System.Data.EntityClient"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
Just be sure to build under the correct configuration when you want to run your tests.
There is also a Visual Studio Add-in SlowCheetah Which makes this whole process very seamless from within the IDE.

Solution apprehended from this post:
//Get the connection string from app.config and assign it to sqlconnection string builder
SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder(((EntityConnection)context.Connection).StoreConnection.ConnectionString);
sb.IntegratedSecurity = false;
sb.UserID ="User1";
sb.Password = "Password1";
//set the object context connection string back from string builder. This will assign modified connection string.
((EntityConnection)context.Connection).StoreConnection.ConnectionString = sb.ConnectionString;
This allows you to change connection string at runtime. There are couple of other possible solutions:
Create a wrapper property around connection string. From tests, set it to a different value.
Use #IF TEST pragmas to specify correct connection string at compile-time

Related

Support multiple database using Entity Framework 6.0 with connection string transforms

I've a Web API project which uses EF 6.0 for database operations. I have 3 different Azure SQL databases (Dev, Test, Prod).
I have been able to create an Entity Data Model with data first approach.
I've used configuration manager of VS2017 to create a web.test config file, but transformation of connection strings isn't working.
Currently my web.config file has the connection string that points to Dev environment as follows:
<connectionStrings>
<add name="ProjectDbEntity"
connectionString="metadata=res://*/Data.ProjectEntityModel.csdl|res://*/Data.ProjectEntityModel.ssdl|res://*/Data.ProjectEntityModel.msl;provider=System.Data.SqlClient;provider connection string="data source=company-ai-Projectserver.database.windows.net;initial catalog=company.DB_Dev;persist security info=True;user id=Project;password=Password1234$$;MultipleActiveResultSets=True;App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
And, web.test.config is as follows:
<connectionStrings>
<add name="ProjectDbEntity"
connectionString="metadata=res://*/Data.ProjectEntityModel.csdl|res://*/Data.ProjectEntityModel.ssdl|res://*/Data.ProjectEntityModel.msl;provider=System.Data.SqlClient;provider connection string="data source=company-ai-Projectserver.database.windows.net;initial catalog=company.DB_Test;persist security info=True;user id=Project;password=Project1234$$;MultipleActiveResultSets=True;App=EntityFramework""
providerName="System.Data.EntityClient"
xdt:Transform="SetAttributes"
xdt:Locator="Match(name)"/>
</connectionStrings>
I'm not able to figure out how do I make EF change connection string, when I'm using it to build a EF model using one instance of database, but during deployment I want to use other database instances with the same schema.
I've been reading up on the following post, but somehow not able to make it work.
EDIT: I found the solution. All I had to do is select Publish option, then Settings and again select Settings on the popup, and finally select the configuration from the drop down option to the desired configuration. It seems selecting the configuration on the main menu does not publishes the same environment unless explicitly selected.
I found the solution. All I had to do is select Publish option, then Settings and again select Settings on the popup, and finally select the configuration from the drop down option to the desired configuration. It seems selecting the configuration on the main menu does not publishes the same environment unless explicitly selected

Not publishing a SQL connection string on deployment when it already exists using Transforms

TFS 2015, vNext build process (not xaml)
I'm trying to automate the deployment process for an MVC web app. The servers that it would be deploying to have different SQL connection strings. So my current deployment is to copy the web.config file to web.config.save manually, deploy the new version using WebDeploy then go to the old web.config.save file and copy over the connection string. I'm to the size now where this is not going to be sustainable much longer. So I need to automate this process further. I've got TFS automatically building and deploying to my test server (which also has a different connection string so it's a great test). In the "publish" properties, I tried deselecting the "Use This connection string at runtime (update destination web.config)" checkbox in the publish-settings-database section then checked in the project again to TFS. But when deployed, the web.config took the default setting. I don't want to remove this setting because I want a default connection string there for new installs.
I could write an xml transfer program to save off the current connection string then overwrite when complete again. But I figured there must be a way to do this with the current tool set and why try reinventing the wheel?
I started down the path to use transforms. So I created a web.config.release in VS2015 then added in this into the web.config.release file:
<connectionStrings>
<add xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" name="AppEntities" connectionString="metadata=res://*/Models.DBName.csdl|res://*/Models.DBName.ssdl|res://*/Models.DBName.msl;provider=System.Data.SqlClient;provider connection string="data source=.\SQLExpress;initial catalog=DBName;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
So, does anyone know how I can make the SQL connection string update only if it doesn't exist in the current web.config for deployment?
I got this experience with TFS 2015 vNext build,
in the 2Q of 2016 we assigned a Dev Ops person, who was really good with PowerShell, and he took ownership of the build and deploy process. Some of the things he came up with was a post build script.
Now to answer your question: For us, the Post-Build script would do the deployment part, and as part of the deployment you would update the connection string in the web.config. Now this would require someone in your team to become really good with PowerShell.
Now what I would do is write a special word in the original file like "{ConStringHere}", and the replace it with the Powershell script, that way you'll only replace it once.
See this how to verify if a file contains a word and replace it using PowerShell:
Powershell, using contains to check if files contain a certain word
I'll highlight some of the benefits we have encountered with this approach:
You don't need a solution, project and classes to modify some files. Most post-build files modifications can be done in powershell with line or 2.
You can keep the powershell scripts in TFS keeping a history and comments of the changes.
You can have the special values (Connection Strings, users, passwords) defined as build variables that are easier to change and with higher security than hardcoded values in a project.
You can have multiple scripts per environment. Ideally all scripts should be almost the same per environment, but maybe in production you are publishing to 2 different servers, so you'll need to call a line twice.
You'll save developers time, since the person maintaining the powershell doesn't have to be a full stack developer.

Code-First Migrations for multiple databases?

I have the following connection string:
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings>
<add name="MyContext" connectionString="metadata=res://*;provider=System.Data.SqlClient;provider connection string='data source=SQLSERVERDB;initial catalog=TestDB_CodeFirst;user id=***;password=***;MultipleActiveResultSets=True;App=EntityFramework'" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
When I try to enable migrations I first get a warning:
Cannot determine a valid start-up project. Using project 'MyApp.Model' instead.
Your configuration file and working directory may not be set as expected.
Use the -StartUpProjectName parameter to set one explicitly.
Then I get this exception:
Argument 'xmlReader' is not valid. A minimum of one .ssdl artifact must be supplied.
Is the connection string wrong and why should I need ssdl if I'm using Code First?
NOTE
My context is in MyApp.Model project where my Migrations folder should be located.
I don't have connection strings in my main startup project because connection strings are retrieved from a second database and the user can select one of them when logging in to the application.
I have just one connection string shown above in my MyApp.Model project which points to my development database.
Also, my second question is:
If I use CF migrations, will all databases be migrated each time a user selects a different database for the first time?
EDIT
I changed the connection as mentioned below, and I get the following exception:
The item with identity 'table1' already exists in the metadata collection.
Parameter name: item
It must be noted that I reverse-engineered an existing database. So I don't know what possibly went wrong!
I've also deleted the Migrations folder and checked the database but there is no migration_history table created.
You are trying to use a connectionString designed to work with Database First / Model First. You can tell because your providerName is System.Data.EntityClient instead of System.Data.SqlClient.
Your connection string should look like this:
<connectionStrings>
<add name="MyContext"
connectionString="Data Source=SQLSERVERDB; Initial Catalog=TestDB_CodeFirst;user id=***;password=***;"
providerName="System.Data.SqlClient" />
</connectionStrings
Although I would suggest using Integrated Security instead of a user/password. Just personal preference, though.

ProviderName for Sql Server .SDF file to use in app.config

I've created a DB file in a project Add -> New Item -> Local Database and created a table for it.
Now I would like to create a connection string for it in app.config.
The problem is that all example code that I find uses code only to create a connection, and not app.config. Hence I can't figure out which providerName I should use.
So what is it?
<add name="DemoDb" providerName="XXXXXX" connectionString="Data Source=ExampleDb.sdf;Persist Security Info=False;"/>
System.Data.SqlServerCE.4.0 or System.Data.SqlServerCe.3.5 depending framework version

WebService doesn't read web.config

I've got 3 connectionstrings in web.config, and I used theirs like this:
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SomeName"].ConnectionString))
Every metgod is called by winforms application.
One of webmethods doesn't work properly because it reads only one connectionString:
data source=.\\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true
It's not a connectionString from my web.config .
I invoke every method in the same way.
How it's impossible ??
EDITED:
I use facade: This is structure:
WinForms calls WebMethod SaveItem
SaveItem calls method on Facade: SaveItemAndDoDatabaseStuff
SaveItemAndDoDatabaseStuff does database stuff.
We can't see your web structure, but is it possible that your app isn't configured as an application in IIS, therefore is picking up the master web.config? Which would look exactly like that...
Go into IIS and ensure it is an application (it may have a cog icon).
If your WinForms application talks directly to database X (not via the web service), then the connection string for database X should be in app.config (in the WinForms project).
If your Web Service (as I understand, this includes your facade and your database layer), talks to databases X, Y and Z, then the connection strings for X, Y, and Z need to be in web.config (in the Web Services Project).
It's using the default connection string asp.net has (in the machine.config in the .net installation folders).
Do a clear:
<configuration>
<connectionStrings>
<clear/>
... your connection strings here
</connectionStrings>
</configuration>
Btw, when you say you are using "SomeName" in the connection string. It isn't surely any random connection string you used, its the default: "LocalSqlServer".
You should store the connection-strings in the web.config or app.config in whatever project that you are executing.
In your case, you should have the connection-strings in your app.config for your winforms application.
Why not just add a Trace line to print out the configuration file being used just before you ask for the connection string. Simply add the following line:
System.Diagnostics.Trace.WriteLine(
System.AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
"APP_CONFIG");
Set a breakpoint after this and look at the Output window for a line that starts with "APP_CONFIG:". This will give the full path to the configuration file and allow you to determine where it's being loaded. If you still see a discrepancy between the runtime values and the configuration file then likely something is changing those values at runtime within your application.
This is a late answer, but perhaps worthwhile.
I have a web-service project, and I want to run it in two modes.
One is "local as app" (for testing), and for that, at least in my current system setup, the file where it reads from is
Web.config (which it apparently reads in deug mode INSTEAD of Web.Debug.config, at least for database configuration)
So, one replace the attribute section with and copy in the ones you would use in the "Calling project for hte web service).
So replace
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
with
<appSettings>
<!-- Database Connection -->
<add key="AppDatabase" value="RedactedDatabase"/>
<add key="AppLoginID" value="RedactedLoginID"/>
<add key="AppLoginPwd" value="RedactedPwd"/>
</appSettings>
The above are found in app.config in the "calling project".... To me, this is more elegant anyway.
Now it will work in both modes.
One could use a conditional compile in the C#, but now you just read it in:
C# code:
String whichDatabase = System.Configuration.ConfigurationManager.AppSettings["AppDatabase"];
String appUsedID = System.Configuration.ConfigurationManager.AppSettings["AppLoginID"];
String appUsedPwd = System.Configuration.ConfigurationManager.AppSettings["AppLoginPwd"];
The above works in either mode, without conditional compile directives.

Categories

Resources