How can I replace config file database links in one place in source code? (asp.net/razor) - asp.net-mvc-3

I have an ASP.NET/Razor 3 web application which uses a SQL Server database via MS EntityFramework.
If/when I want to change the database connection string, for example to change the password or point to a different database (e.g. test vs. live), the string needs to replaced in about seven places in three different XML config files in the project (app.config, web.config, and app.release.config), which is an error-prone pain.
Worse, the default web server behavior on unhandled exceptions can include displaying sections of the config files to web users, which has in fact resulted in the web server displaying the lines that show the database path and password over the web. Not good.
For both reasons, and because this is not a product for which anyone would ever just edit the config file on the server (any change is pretty much, and may as well be, a build operation), I would much prefer to have the database connection information compiled into the web application and loaded from code rather than a config file, and to be able to do this such that when I want to change the database information, I can do it in one place instead of seven.
How would I achieve this?

The database connection string(s) can be set up centrally in 1 place, in the Global.asax.cs file, as part of the Application State, and then referenced from anywhere else in the project.
Step-1: Define the connection string(s) as static variables in Global.asax.cs:
namespace TestProject
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
public static string ConnectionString1;
public static string ConnectionString2;
protected void Application_Start()
{
#region Build application state for the app-specific items needed by us
ConnectionString1 = "Server=yourserver;Database=yourdb;etc etc";
ConnectionString2 = "Server=yourserver;Database=yourdb;etc etc";
#endregion
#region Code auto-generated and needed by system - do not change
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
#endregion
}
}
}
Step-2: Use the strings from anywhere else in the project:
string cnxStr1 = TestProject.MvcApplication.ConnectionString1;
string cnxStr2 = TestProject.MvcApplication.ConnectionString2;
(Please note that by default, the strings would be accessible only from within the same project. You will need to add references to the project if you need to use the strings from any other project within the same solution.)

The answer above by Krishna is pretty good. For me I would personally prefer to have them as static string in a static class and use it where ever is needed.

If you don't want to put the connection strings in the global file, you can:
Create a separate .config file for connection strings. e.g.
connectionStrings.config.
Create a hard-link to this file or the
folder containing this file that's in the same directory as your
other application.config and web.config files.
Set the configSource property on the connectionStrings element in each app.config or
web.config.
From then on, you only have one place to manage your connection strings that are common between apps.
The reason for the hard link is that configSource must reference a file in the same folder or sub-folder of the folder containing the application config.
Note that changing the connection strings will recycle all your web application pools that use them. For console, desktop, and service apps, you will have to restart for changes to take effect.
For the second problem you describe, you could have a separate connectionStrings.config file for each environment: development, test, production. Using config transforms or some other process, you only have to update the configSource property in each connectionString element to switch environments.

Related

NUnit 3 using Visual Studio 2015 How do I supply my tests with some parameters?

For example, I might write lots of Selenium tests for my staging website, now instead of writing the exact same code again but with the URL on my live website I'd like to reuse the code.
(I might need more than just the URL, I might need a different login/password etc.)
I thought it might be possible by using a .testsettings file and in my tests I could read what the current URL is that I should test against etc.
There has to be a way, how do you do it?
I would suggest storing your test configuration in a simple text based file. It could be as simple as URI on the first line, username on the second and password on the third, etc. Or, if you already have NewtonSoft.JSON in your project, create a simple JSON config file.
Then in your Test Assembly Setup, you could read in that file and parse it into a global static test settings object that you can access from all of your tests.
I would check the default TestSettings.json into source control so it is always available, then you can check if a TestSettings.local.json is present. If so, load it, otherwise load the default.
You could also set the defaults in code and override them if TestSettings.json is present.
To load the file before all of your tests run, use the SetupFixture attribute which allows you to run code when your test assembly loads, before all of your tests run.
namespace NUnit.Tests
{
using System;
using NUnit.Framework;
[SetUpFixture]
public class MySetUpClass
{
public static TestSettings Settings { get; set; }
[OneTimeSetUp]
RunBeforeAnyTests()
{
// Load your settings file here into the static
// Settings property
}
}
}

Proper project organization and architecture for sharing code in Visual Studio/.NET projects

I'm looking for recommendations on how to best share code between multiple Visual Studio projects. I'm struggling with a fundamental topic and trying to get some ideas to get over it.
My solution has:
Several web app projects
Several standalone process projects, eg Windows Services and/or console apps and/or Azure WebJobs
An example of functionality which is common to all projects is the need to call some common web service, or the need to read and write from Amazon S3, for example.
Where I struggle is this: Obviously the code that implements the common functionality should be broken out on its own, for example in a separate class library project. To talk to S3 for example, the code needs to know my Amazon credentials, S3 endpoints, etc. - all these things would normally be stored in app configuration files. But I don't like the idea of putting config files in class library projects because it binds a particular implementation to them. But in order to not do that, I have to pass in this information from the calling project. So for example the web app's web.config and the console app's app.config files contain this connection information. When calling the S3 code, I would assumingly pass this config info into the shared code.
However, this seems yucky* to me and I'm not sure why. It still feels to me like I'm "binding" the S3 code (for example) to a particular config method, if that makes sense. I'm not sure if my feeling is a mis-formed bias.
*For example, I may have an arbitrary amount of configuration data that would have to be passed in:
Connection strings
Credentials for web services
API endpoints
Arbitrary data from my app's config settings (which some of the callers will need, but others won't, so lots of times the data will just be useless yet I have to do the work of passing something in)
So every time I added a config variable in my main app, I'd have to modify the constructor of the common code. Things would be in constant motion.
Can you give me suggestions on this?
I like to use Configuration objects as parameters, that way the signature never changes, even if you add/remove properties. For instance....
public class AmazonConfigSettings {
public string AWSkey { get; set; }
public string ApiEndpoint { get; set; }
......
}
Your signature could then always look like:
public MySharedClass(AmazonConfigSettings config) { .... }
Even if (when) Amazon overhauls their webservice settings completely.

attaching unit test data to unit tests in visual studio

I heavily make use of unit tests for my developer needs (POCs, unit tests, etc). For one particular test method there was a line that went...
var file = #"D:\data\file.eml";
So I am referencing some file on my file system.
Now in a team when other people are trying to run my "personal" tests (POCs or whatever) they don't have a reference to that file in that path...hence the tests fails. How we'd have to normally make this work is to provide the test data, and allow the user to modify the test code so that it runs on his computer.
Any visual studio way to manage this particular problem?
Whats the benefit in this? Well, people can review the test data (email in my case) as well as the method I wrote for testing, and can raise defects in TFS (the source control system) relating to it if need be.
One way I often handle data files for unit test projects are to set the data files as Resources. (* Note that this link is for vs2010 but I have used this approach through vs2015RC).
In the project with the data file: Project -> Properties -> Resources and choose to add a resource file if you the project doesn't already have one. Select Files in the resource pane and click Add Resource or just drag and drop your data files onto the resource manager. By default resources are marked internal, so to access the resources from another project you have several ways:
In the assembly with the data files, add the following to your AssemblyInfo.cs file and this will allow only specified assemblies to access the internal resources
[assembly: InternalsVisibleTo("NameSpace.Of.Other.Assembly.To.Access.Resources")]
Create a simple provider class to abstract away the entire Resource mechanism, such as:
public static class DataProvider
{
public static string GetDataFile(int dataScenarioId)
{
return Properties.Resources.ResourceManager.GetString(
string.Format("resource_file_name_{0}", id));
}
}
Change the resource management to public (not an approach I have used)You can then access the data file (now a resource) from a unit test such as:
[TestCase(1)]
public void X_Does_Y(int id)
{
//Arrange
var dataAsAString = Assembly_With_DataFile.DataProvider.GetScenario(id);
//Act
var result = classUnderTest.X(dataAsAString);
//Assert
Assert.NotNull(result);
}
Note that using data files as resources, the ResourceManager handles the file I/O and returns strings of the file contents.
Update: The test method in the example above is from an NUnit project and is not meant to imply process, but a mechanism by which a data file can be accessed from another project.
What you'd normally do is add the file to your project and check it into TFS. Then make sure the item's settings are:
Build action: Content
Copy to output: If newer
Then put an attribute on your Test method or Test class:
[DeploymentItem("file.eml")]
You can optionally specify an output dircetory:
[DeploymentItem("file.eml", "Directory to place the item")]
If you put the files in subdirectories of your test project, then adjust the attribute accordingly:
[DeploymentItem(#"testdata\file.eml")]
The file will be copied to the working directory of your test project and that makes it easy to access from your test code. Either load the file directly, or pass the path to any method that needs it.
If you tests expect the files in a specific location you can use a simple System.IO.File.Copy() or System.IO.File.Move() to put the item in the place you need it to be.
The process is explained here on MSDN.
I suppose the most straight forward way is to simply add whatever to the project, and set the correct value for Copy To Output Directory. In other words, say your data is in a text file.
Add text file to your test project
Right-click to access properties window
Set copy to output directory field as Always or Copy if newer.
Now if you build the test project, the file gets copied to your output directly. This enables to write unit test code of the fashion:
var dataFile = File.OpenRead("data.txt");

Visual studio 2010 - difference between Settings.settings and Resources.resx

simple question here. What is the difference between putting a string in Settings.settings and putting a string in Resources.resx ?
Regards
In Settings.setting the string will be placed in a config file, bassicaly a xml document which stores all kind of information your application needs to run. It's best practice to store configurable information in here. Also you can set the scope of the config value (application and user).
Application scoped config values will be shared among all users, while the user ones are limited to the current executing user of the application.
The .resx file is the place for storing all kinds of stuff your application needs to run, like images and so on. Files in here should be normally not editable by the user, its as the name states, a resource pool for your application. Also resources are also always global.

Change the connection string in app.config with InstallShield 2011 setup

I'm creating an InstallShield 2011 basic MSI installer project.
I'm trying to change the connection string in my app.config according to the user selections from the database login dialog made in the setup. How can I apply these connection string settings to the connection string entry in the app.config of my windows application I'm trying to install?
XML File Change is the right place to start from. Since changing the connection string is a common task my hope was that there is a best practice to do exactly this task.
-- edit --
There are two main difficulties:
How do I reference a file in InstallShield which will be created on build? The App.config gets copied to MyAppName.config. I don't want to hardwire the application name into the setup at this place again.
The connection string in the config file is used by Entity framework, thus contains more information than given by the database selection from InstallShield. I have to patch an attribute within an element of the config file, if I just want to change the Server and InitialCatalog properties of the connection string. It looks like XML File Change only supports replacing of an entire element or attribute.
As far as I remember, the XML File Changes is designed for this purpose. You can place the user's choice as a property value when defining your XPath and element/attribute values. For me, it was one of the areas of InstallShield which worked quite good and as described.

Resources