Reputation: 5835
I have an entry in my Web.Config file that indicates which environment I am in for connection strings and junk:
<add key="AppEnv" value ="2" /> <!--(0 = Dev, 1 = test, 2 = prod)-->
I am looking for a way to alert the developer, at the time of publishing, to make sure they have checked this key/value so that they don't publish the 'test' to the 'prod' server and vice versa.
Thanks
Upvotes: 0
Views: 631
Reputation:
Set your Web.Config to "Read only", therefore it won't be overwritten when publishing to these servers.
The trade off is that you'll have to manually maintain your web.configs on each server, and your publish will claim to fail as it couldn't overwrite the web.config on the remote server; but IMHO this is preferable to modifying the config each time you do an upload
Upvotes: 0
Reputation: 475
I have come up with my own (probably unconventional) solution to this issue. We develop many different web projects for many different clients and have migrated all of them to this method due to all of the issues we have had with multiple web.config files, or required edits before publishing.
Basically, we let our app tell us which environment its running under based on the incoming URL. We initialize this on the first request and store it in memory for the life of the app. This way we can store each of our environment specific config values in the same config file and just qualify them with Development, Staging, Production, etc. And any settings that dont differ between environments dont need to be qualified.
First a sample web.config:
<appSettings>
<add key="DevelopmentHost" value="dev.trackmyhours.com" />
<add key="StagingHost" value="staging.trackmyhours.com" />
<add key="ProductionHost" value="www.trackmyhours.com" />
</appSettings>
<connectionStrings>
<clear />
<add name="DevelopmentConnectionString" connectionString="your dev conn string" providerName="System.Data.SqlClient" />
<add name="StagingConnectionString" connectionString="your staging conn string (mine is typically same as staging)" providerName="System.Data.SqlClient" />
<add name="ProductionConnectionString" connectionString="your production conn string" providerName="System.Data.SqlClient" />
</connectionStrings>
Next we have an "App" class that gives us access to our "Site" class, but you could architect your classes however you see fit.
Public Class App
Private Shared _Site As New Site
Public Shared ReadOnly Property Site() As Site
Get
Return _Site
End Get
End Property
End Class
Imports System.Configuration
Imports System.Web
Public Class Site
Public Enum EnvironmentType
Development
Staging
Production
End Enum
Friend Sub New()
If HttpContext.Current IsNot Nothing Then
Dim URL = HttpContext.Current.Request.Url.DnsSafeHost
Select Case URL
Case ConfigurationManager.AppSettings("DevelopmentHost"), "localhost"
_Environment = EnvironmentType.Development
Case ConfigurationManager.AppSettings("StagingHost")
_Environment = EnvironmentType.Staging
Case ConfigurationManager.AppSettings("ProductionHost")
_Environment = EnvironmentType.Production
End Select
Else
'probably getting called from a winforms/console app, or unit tests
_Environment = EnvironmentType.Staging
End If
_ConnectionString = ConfigurationManager.ConnectionStrings(_Environment.ToString & "ConnectionString").ConnectionString
End Sub
Private _Environment As EnvironmentType
Public Property Environment() As EnvironmentType
Get
Return _Environment
End Get
Set(ByVal value As EnvironmentType)
_Environment = value
_ConnectionString = ConfigurationManager.ConnectionStrings(_Environment.ToString & "ConnectionString").ConnectionString
End Set
End Property
Private _ConnectionString As String
Public ReadOnly Property ConnectionString() As String
Get
Return _ConnectionString
End Get
End Property
End Class
We put our classes in our Biz Object class library. We just decided that it is not necessary to determine the environment on every single request, since it really cant change during the app's lifetime. Also, this allows us to reference App.Site.Environment from ANYWHERE in code in the library or code behind. This is also helpful if you need to sprinkle some conditional logic in your code - like not sending emails to real people when running in dev/staging.
One last thing - for our Linq2SQL or EF Data/ObjectContexts, we do not store the connection string in the file, and instead overload the constructor so we can supply our correct environment connection string like this:
Partial Class SampleDataContext
Sub New()
MyBase.New(App.Site.ConnectionString)
End Sub
End Class
Upvotes: 1
Reputation:
I think its bad practice to store connection strings in web.config, I instead creates a separate config file outside my websites in a common known location like
C:\xxxx\config.xml
Then I store all machine dependent settings there. So that on my live server I have my live settings, on the test server connectionstrings to the test DB and on my Dev machine I got my local setttings. These settings can then also be resued along all websites and .net apps on that server. Only a single place to update when the DB changes.
Perfect!
Upvotes: 0
Reputation: 5041
I take any keys that will be different in test and production and put them in an entirely new .config file. I put the test settings on test and the production settings on production and never copy this file from test to production. Then, in your regular web.config, you can specify this new .config file like this:
<appSettings file="ExternalWeb.config>
.... common keys go here
</appSettings>
on Test server, "external.config" will contain the values specific to that server and in production, it will have the prod values. This allows you to copy your entire web.config between the 2 servers without ever manually changing the file.
Upvotes: 0
Reputation: 754598
An eternal question that keeps popping up! I guess just about any serious ASP.NET developer has banged his head against this in some ways.
For ASP.NET 4.0, there's some help on its way - the improved web deployment options will offer a feature called "web.config transformations".
Check out this Channel 9 video on the topic - haven't found any decent written reference just yet...
Marc
Upvotes: 0
Reputation: 12077
Whenever there is a process that always requires more than one step, I know I'm going to screw it up at least half the time. For this reason, I love MSBuild.
There are quite a number of useful tasks that come in the box with MSBuild, such as the AspNetCompiler task, which appears to be a one-step compile/publish action.
There are also several projects which aggregate a large number of "custom" MSBuild tasks for various purposes. The MSBuild Community Tasks Project has a XmlMassUpdate task that is useful for making several changes to an xml-formatted file. In other words, perfect for updating web.config files.
I found an example of using the XmlMassUpdate task in concert with a Web Deployment project here.
Upvotes: 0
Reputation: 18215
I have in bold red letters on the top of the page what mode the site is in if it is not in Production mode.
I also have a diagnostics page which lists what server is is running on and what database it is connected to.
You could also put a lookup table in each database, to make sure you ahve the right flag connected to it. (in the Test DB mark it as 1 and check on Application_Start that the values match)
Upvotes: 0
Reputation: 562398
Here's a solution: store that file as "Web.Config.in
" under source-control.
On each server (dev, test, staging, production), copy Web.Config.in
to Web.Config
, and edit the AppEnv
value carefully.
On each subsequent push from one environment to the next, exclude Web.Config
files. That is, don't overwrite that particular file. Write deployment scripts that run rsync --exclude WebConfig
for example.
Upvotes: 0