asp.net production / development environments - asp.net

Most of my previous web applications have built using the pyramid (python) framework. With pyramid, it is possible to run the application in either development or production mode. This is achieved by providing the location of a production.ini or a development.ini settings file as one of the start up arguments to the application.
This file contains settings relating to logging levels, error reporting and database connections. The equivalent of these files in the .net world would appear to be web.config files. I assume i can create different execution environments, by simply creating a new web.config, renaming it to something appropriate, and restarting the application.
My question is, how can i get my app to target the correct *.config file (hypothetically call them production.config and development.config)?

You may want to look at MSDeploy. I use this for similar situations and it's helped me establish a single parameters file (of what is to be replaced, regardless of if it's XML, a filepath, text file, etc.) and multiple set parameter files [you can read about declareParam and setParam here.
Without knowing too much of your structure you are basically going to do something to the effect of this.
msdeploy -verb:sync -source:contentPath=c:\pathtosite\root -dest:package=c:\package.zip -declareParamFile=c:\packageparameters.xml"
Create an associated parameters file for each environment such as
development.xml
staging.xml
production.xml
(Here is a good explanation of parameter file setup)
then for your deploy you would have something (depending on the providers you want to use)
msdeploy -verb:sync -source:package=c:\package.zip -dest:contentPath=c:\inetpub\production -setParamFile=c:\<environment>.xml
The # of providers is pretty extensive. Content Path is just an easy example, but you can pull directly from IIS, to IIS, etc. Pretty robust.

There's no way that I know of to specify a different web.config file. Since .NET 4.0, however, you can use something called web.config transforms, which modify your base web.config on build. You can have a Web.Debug.Config and Web.Release.Config, which get applied depending on which build configuration you're using. Keep in mind these aren't normal web.config files, but rather transform files that modify the base web.config.
For more info and a walkthrough of the basic idea involved, see here on MSDN. The basic example given of a web.config transform file is this, which modifies a connection string to use a different connection string for the release build:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="MyDB" connectionString="ReleaseSQLServer"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
</configuration>

Related

Web Deploy Package - setParameter for web.config with complex XML

I've been making some headway using Web Deploy packages that transform web.config files on deploy rather than build. The goal in this is "build once, deploy everywhere". The problem I'm having is when I need to add or change complex XML in a web.config.
For example, if my base web.config contains this:
<customSection>
</customSection>
I might want to the deployed web.config to look like this:
<customSection>
<someSettingKey>QA Setting</someSettingKey>
</customSection>
It seems to work to have my SetParameters.xml look something like:
<setParameter name="customSection" value="<someSettingKey>QA Setting</someSettingKey>" />
But that seems a bit cumbersome, especially when the XML gets more nested / complex.
Are there better ways of doing this?
I was able to break up the configuration a bit so that the base web.config (for local testing) has the simple XML, and have one transform for the Release configuration (i.e. what runs on the servers). This transform adds the complex XML, and only a few keys within it need to change via the SetParameters.xml for QA, Production, etc.
The complexity in the XML came from encrypting a web.config section. The encryption (and thus, complexity) is only needed on the server.
I suppose another way to do it might be breaking up the config files using the configSource attribute for certain sections... however I didn't really flesh that out.

Web.Configs across different development environments (and SVN)

So we have a build process that handles different development web.configs across different environments. We use the ConfigSource attribute and have Team City pick the appropriate file.
That's great, but what do I do when the developers have slightly different environments?
CI, can't help, because everyones getting it straight out of SVN (i.e. CI obviously doesn't build to each developers local machine).
I'll use the ConnectionStrings config section as an example:
<connectionStrings configSource=".\Config\ConnectionStrings.config">
</connectionStrings>
And we have:
configs\ConnectionStrings.config (the generic one)
But I might need to use:
configs\ConnectionStrings.dev1.config
configs\ConnectionStrings.dev2.config
configs\ConnectionStrings.dev3.config
depending on which developer is using the code at the moment.
Any ideas?
Have you tried looking into web.config transformations? They might be able to provide the functionality that you seek while still keeping everything in version control or needing any code changes. Plus it will work for more things than just connection strings, but also directories, etc.
One technique we've used in the past (I recall Ayende mentioning it on a web cast) is that each connection string is named with the developers machine name e.g.
<connectionStrings>
<add name="BobsPC" connectionString=""/>
<add name="JonsPC" connectionString=""/>
</connectionStrings>
When in debug we then look for a connection string name of the "current" machine name.
This saves having multiple connection string files. Instead we have one file with multiple connection strings.
We have a separate connection file just like you mentioned with the current machine name in it.
In the build event for the projects that need a connection string we've added a pre built event that deletes the connection.config file from the current project and in the post build event we copy connections.machine.config to connections.config in the current project folder.
In our web.config we have a so .NET will look in a separate file for the connection string information.
Web.config transformations can only be used when you actually deploy a project. The 'default' web.config will always be used on your local development machine so this is not an option for development environments.
You can extend this mechanism also to app settings and other config files by placing the machine specif ones in the solution folder and just copying them on build.

How to Reference ConnectionString in ASP.NET?

I have a web project and a separate project for a class which contains a constant and I am thinking of adding a connection string. What is the best way for storing this?
Thanks
Add a section to your web.config file called ConnectionStrings, as a child of the <configuration> element. An example might look like:
<connectionStrings>
<add name="MyConnectionString"
connectionString="Server=myserver;Database=mydatabase;Uid=username;Pwd=password;"/>
</connectionStrings>
In your code, use the ConfigurationManager to access your connection strings. For example,
string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString();
Add it to settings file. In Visual Studio, go to My Project -> Settings and add it there as (Connection String). You can access it this way: C# - properties.settings.default...; VB - My.Settings...
I would advise against storing your connection string in a hard-coded constant. There are many problems with that, not the least of which you aren't actually able to "configure" your connection string for different environments. Having it hard coded makes it very difficult to test your code in one environment against a different database than your production environment, without having to recompile your code. There are also security concerns in regards to hard-coding configuration, particularly connection strings.
I recommend reading the following article...it should give you a good base about storing connection strings in the standard .NET way:
Connection Strings and Configuration Files (ADO.NET)
Put it in the settings file for the project. The settings file is merged into the .config file - and you get a class automatically built for you with accessors for the stuff in the settings file.

How can you change the name of the web.config file and have IIS read from the newly-named file?

Is it possible to configure an IIS site to read ASP.Net settings from a site OTHER than web.config?
We'd like to have three config files in our codebase -- web-dev.config, web-test.config, and web-prod.config. Each IIS instance would be configured to read from their specific file. This way we have version control them all next to each other (and one-click deploy the entire site) but know that each IIS instance will read the settings specific to itself.
I've found in IIS where it shows where the web.config is, but I can't see how to change the location.
I use the configSource property to specify an external config file for sections that need different values for dev and production.
<connectionStrings configSource="Config\ConnDev.config"/>
Then you only have to change one setting (manually or with a tool) to switch from Dev to Production configs.
The best solution right now is to use different configs for development and production. This however will change with .net 4 and VS 2010 which they have added Web.Debug.config, Web.Release.config, Web.Staging.config and Web.Testing.config which will then publish the config you need in relation to the environment.
At my company we just have our deployment tool set to copy the appropriate file to web.config depending on what kind of deployment we're doing.
I believe it has to be named web.config.
You are facing a common problem.
One solution that I have used that worked really well in a large organization was to set environment variables on the web servers. Such as DEV, QA, UAT, PROD. Then, in code, you can query the environment variable to see which machine you are on, and then choose the values of appSettings accordingly. For example, you could have a database connection string named DEVconnection, and another named UATconnection. If your code determines from the environment variable that you are on UAT, then it would use UATconnection.
This does assume that you have the ability to set environment variables on the web server. In this instance, the admins running the servers were the ones who suggested this solution.
What was sweet about this was that there was ever only one version of web.config.
I do not think we can make web.config declaratively so that we can specify different config file. One thing you can do you can split your configuration file and set for different environments.
Please go through this article
http://jetmathew.wordpress.com/2011/02/07/split-web-config-for-different-environment/
cheers

Alternatives to using web.config to store settings (for complex solutions)

In our web applications, we seperate our Data Access Layers out into their own projects.
This creates some problems related to settings.
Because the DAL will eventually need to be consumed from perhaps more than one application, web.config does not seem like a good place to keep the connection strings and some of the other DAL-related settings.
To solve this, on some of our recent projects we introduced a third project just for settings. We put the setting in a system of .Setting files... With a simple wrapper, the ability to have different settings for various enviroments (Dev, QA, Staging, Production, etc) was easy to achieve.
The only problem there is that the settings project (including the .Settings class) compiles into an assembly, so you can't change it without doing a build/deployment, and some of our customers want to be able to configure their projects without Visual Studio.
So, is there a best practice for this? I have that sense that I'm reinventing the wheel.
Some solutions such as storing settings in a fixed directory on the server in, say, our own XML format occurred to us. But again, I would rather avoid having to re-create encryption for sensitive values and so on. And I would rather keep the solution self-contained if possible.
EDIT: The original question did not contain the really penetrating reason that we can't (I think) use web.config ... That puts a few (very good) answers out of context, my bad.
System.Configuration.ConfigurationManager.ConnectionStrings and System.Configuration.ConfigurationManager.AppSettings
Contain settings from the executing application so in your DAL you can get the settings stored in your web.config file.
For your system you can create a custom configuration section that will sit in your web.config file or your DAL's consumer*.config file In these config files you can specify that they load from a separate config file of your design and location.
Referencing external config files from Web.Config
How to: Create Custom Configuration Sections Using ConfigurationSection
Alternativly you can manualy load your DAL configuration data from any file using ConfigurationManager.OpenExeConfiguration
You can add the equivalent to a web.config file called app.config that compiles into a file named for the dll or exe project of your code behind. This is completely changeable without having to recompile. You can use the standard settings for connection strings and various app settings that can be defined in a key/value pair - or with a little more work you can define your own custom config settings class and section. You can even reference settings in your app config - so you could have 3 settings stored in your app (DEV, QA, PROD) and then only reference the one you want at runtime in your app.config file. Here is an example of one that was created for a webs service setting.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="{Project}.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
<section name="microsoft.web.services3" type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<applicationSettings>
<{Project}.Properties.Settings>
<setting name="{SettingName}" serializeAs="String">
<value>{SettingValue}</value>
</setting>
</{Project}.Properties.Settings>
</applicationSettings>
<microsoft.web.services3>
<security>
<securityTokenManager>
<add type="Microsoft.Web.Services3.Security.Tokens.UsernameTokenManager, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" localName="UsernameToken" />
</securityTokenManager>
</security>
</microsoft.web.services3>
</configuration>
It sounds like you do not understand how web.config/app.config work, if I'm reading you correctly. Let's say you have a structure like the following:
DAL Project
References:
Some core libraries
Miscellaneous references
Classes:
DatabaseHelper
ObjectClass1
ObjectClass2
etc...
Web Project
References:
Some core libraries
DAL Project
Miscellaneous references
Pages:
Default.aspx
SomePage1.aspx
etc...
Web.config
In your DatabaseHelper class, you might reference the connection string like so:
string connString = ConfigurationManager
.ConnectionStrings["myConnString"]
.ConnectionString;
When this happens at runtime, your DatabaseHelper class will be running under the same app domain as your web page, and thus, any calls to ConfigurationManager will load the request from the web.config file provided by the web project.
Therefore, you only need the one config file in your web/console/winforms/etc... project, and do not need to worry about having one at design time in each of your class library projects.
If you actually run your DAL as a service or a separate console application or something, then and only then would you need to give the DAL project it's own app.config / web.config file.
Split it up. Use the fixed-XML storage file solution for the database connection, encrypted with .NET's built-in encryptor functions (do not roll your own). Then, using the resultant database connection, look up your 'settings table' in the database. This way you can modify your settings without a redeploy. If your customers need to be able to change the database connection string without visual studio, just write a small Windows Forms app that is capable of generating the encrypted connection string and saving the fixed-XML storage file, and, if necessary, also can connect to DB (via that same file) and modify the Settings table as the user needs.
A completely different approach would be to use SQLite and store all your application settings in there. You can password protect the database in question, if that is of importance to the application, and you can create some simple property/value tables to store the data.
Using the SQLite ADO adapter would only require 1 additional DLL into the projects to access the settings and the SQLite DB itself would be accessible to those folks that don't want to use Visual Studio. There is even a plugin for Firefox to interact with SQLite databases.
You could store the settings in any old Xml file and use the XmlSerializer to take your class and convert it to < - > from Xml. In another answer I wrote some code that did just that. The linked answer serializes a list of simple objects, but it also works to serialize one large configuration object.
Because the XmlSerializer serializes to/from public properties, if you don't want to allow values to change, you might need make the class itself immutable (popsicle style) or have a read-only facade that sits in front of the deserialized one.
It's a handy trick. You can set it up via ConfigurationManager.AppSettings[] with it's own config section and external file references, or you can alternatively just hardcode a specifc xml filename per configuration class.
Take a look of Config.Net - the easiest configuration framework for .NET developers.
A comprehensive easy to use and powerful .NET configuration library, fully covered with unit tests and tested in the wild on thousands of servers and applications.
You could have a Interface that mapped you settings that is used on your DAL. Then on the App you could just use IoC to feed the settings to the DAL.
If you're using a DI framework (like Unity) you can specify constructor arguments. So, hypothetically, your DAL provider could have a constructor that takes its connection string.
I know you can't enforce constructors in interfaces, but that's something we have to deal with. I know the framework has a few places where there are unspoken dependencies on constructor signatures...
Have a look at DslConfig. It seems this solves what you are looking for.

Resources