One-click publish in vs 2012: how to remove _ConnectionStringsToInsert? - msdeploy

I usually put my connection string to a separate file, adding something like this in web.config:
<connectionStrings configSource="WebConnection.config" />
I've just installed VS 2012 and it automatically picked up my existing publish settings.
However, when I do a webpublish it now adds two connections strings by itself, so my web.config on the deployment target now looks like that:
<connectionStrings configSource="WebConnection.config">
<add name="EF.Model.DbContext" connectionString="EF.Model.DbContext_ConnectionString" providerName="System.Data.SqlClient" />
<add name="Migrations.Db.MigrationDb" connectionString="Migrations.Db.MigrationDb_ConnectionString" providerName="System.Data.SqlClient" />
</connectionStrings>
certainly, that produces an error (node contents must be empty when using configSource).
I noticed, that in newly generated .pubxml files (where publish settings are now stored) there are following lines:
<ItemGroup>
<_ConnectionStringsToInsert Include="EF.Model.DbContext" />
<_ConnectionStringsToInsert Include="Migrations.Db.MigrationDb" />
</ItemGroup>
How can I remove them? :) If I delete them from file, Web-publish dialog adds them anytime I edit the publish settings.

I suddenly resolved that by going to project properties, "Package/Publish Web" and checking the mark "Include all databases configured in P/P SQL tab" (and I don't have any DB configured there :)).
After doing this and deleting the mentioned lines from .pubxml everything went fine.
Seems like a hack, but it was a way to go for me :)
#Sayed, thanks for confirming it's a bug, hope it'll be resolved!

I came up with a (possibly) less hacky solution for bypassing the bug in publish that forces discovered Entity Framework code first db contexts to have a connection string. This is still an issue that I'm having in VS 2013.
In your web.config, add a dummy version of the connection string:
<add name="DbContextName" connectionString="This is a dummy connection string to bi-pass publish bug." providerName="System.Data.SqlClient" />
Now, setup a transform for the configuration you want to create a publish package for. Read more about it here.
In your web.config.{configuration} file, use the following transform to remove the connection string:
<connectionStrings>
<add name="DbContextName" xdt:Transform="Remove" xdt:Locator="Match(name)"/>
</connectionStrings>
This transform runs AFTER the publish transform in your pubxml runs, so it clears out the unwanted connection string.

On the Settings tab of the publish profile, clear the Use this connection string at runtime check box and the Apply Code First migrations check box. Make sure that migrations is enabled, or the Use this connection string box won't stay cleared, and even then you may have to clear it again each time you open the profile.

Related

How to get web.config transformation to include external secrets file?

Is there a way to get a web.config transformation in Visual Studio 2015+ to include the contents of an externally-referenced secrets file as described here?
This works well when developing locally, and doesn't include the file in source control, but when I go to deploy the web app to the server, I want it to include the username and password for another web service which it connects to. If I enter the settings manually in IIS on the server, they are lost each time I publish the app.
If I omit the keys in the appSettings block in my web.config (so that they are only referred to in the secrets file), the manually-entered settings in IIS on the server are removed completely whenever I publish the app.
Being able to refer to certain things in an external file for the sake of better security and not checking in passwords to source control isn't turning out to be a very good idea IMHO because my deployment is now a nightmare. I don't want to manually enter the passwords in the web.config file on the server after every deployment.
I'd rather not look into encryption, either, because I would have to do that for each server I deploy to so that the relevant machine key is used for each web.config file.
I've only recently thought about removing this password from source control, in response to a recent push to improve security practises at work - which I well understand and agree with - but I can also see why security is so poorly considered because the life of the ordinary developer becomes extremely unpleasant if there the tools available don't make it easy.
Surely there's a way without resorting to encryption?
Thanks.
Without a CI system I think your best option is probably a pre/post build action that executes a script?
I'd suggest you replace the actual values with tokens for your sensitive web.config values (something unique/easy to find like MY_PRODUCT_DATABASE_PASSWORD etc). Your web.config can then be checked into source control safely.
In VS you can add a build action to run a custom powershell or exe to basically perform a find-and-replace on the tokens with actual values before you zip & deploy as normal.
Exactly how/where you store the real values and how the script works is up to you. you could easily find a file on your deployment machine or a row in some database based on data passed to the script/exe from vs or from data within web.config itself (or embedded as a comment in web.config even).
Here's details of the variables available from vs you could pass to your exe or script in a build action: https://msdn.microsoft.com/en-us/library/42x5kfw4.aspx
It you wanted to use PowerShell you could read/replace/write values to a web.config(or any text file) like this answer: How can I replace every occurrence of a String in a file with PowerShell?
Following the Microsoft Docs example you've linked to, putting this XDT transformation inside Web.Release.config should do the trick:
<appSettings file="..\..\AppSettingsSecrets.config" xdt:Transform="SetAttributes">
<add key="mailAccount" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="mailPassword" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="TwilioSid" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="TwilioToken" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="TwilioFromPhone" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="GoogClientID" xdt:Locator="Match(key)" xdt:Transform="Remove" />
<add key="GoogClientSecret" xdt:Locator="Match(key)" xdt:Transform="Remove" />
</appSettings>
You dont need xdt:Locator attribute on <appSettings> element itself, because there is only one appSettings.
Edit: I've misunderstood the original question. The goal is to include contents of referenced file, which is not possible using XDT. There has to be another way.

Change Web.config session value in Global.ascx?

We are storing session data in the database, ideally each developer wants a session database on their own pcs, or possibly 1 developer might use inproc, another a mssql connection, another Oracle (if we get it working)
Is this possible? Can you access the session key in code and change it in the application startup? Or is there a file which could be merged with the web.config file that wouldn't get checked in?
Or option C which is easier but which I haven't thought of :-)
thanks
(Edit) Just found this which goes into this in some detail
developer specific app.config/web.config files in Visual Studio
(Answer). This came from a mix of Andrew Barber in the comments and the above
(1) In the web.config have this
<sessionState configSource="SystemWeb.config" />
(2) Make a file called SystemWebDefault.config which holds something like this:
<sessionState mode="SQLServer" allowCustomSqlDatabase="true" etc
(3) Each developer has to copy the default into a file called SystemWeb.config, changing it to suit themselves. This file should be explicitly ignored in subversion or whatever source control system you use.
(4) The build box needs a copy step
Something that might do what you want is NConfig (NuGet link). I've used it on projects to let multiple developers in our team have different connection strings for their local DB copies. It lets you define a machine specific config file to replace your default config values. For example you can define a {MachineName}.Custom.config that might look like this:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="main" connectionString="data source=(local)\SQLExpress;uid=username;pwd=password;initial catalog=mydb" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
I've never tried it with the session settings, but I can't find anything that says it won't work.

Make the connectionstring's AttachDbFilename relative in config file

I am working on a project using an mdf file generated locally using Entity Framework Code First. The path to this mdf is set in several config files in my solution using <connectionStrings> sections like so :
<add name="DataContext" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename="E:\path\to\project\app_data\local.mdf";Integrated Security=True" providerName="System.Data.SqlClient" />
I use git versionning on this project both from work and at home, thus at work the mdf filepath has to be E:\path\to\project\app_data\local.mdf\ and at home D:\otherpath\to\project\app_data\local.mdf.
This is painful to change everytime I comute (first world problem, I know).
I have seen how to set a substitution string but this seems to be using code outside the config file and I don't want that. Maybe there is a way to set a relative |DataDirectory| value inside the config file ?
Can I make this path relative to a unique place next to my .sln file, using only those config files ?
This would ideally be something like that :
<add name="DataContext" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename="|RelativeToWorkplaceDynamicPath|\local.mdf";Integrated Security=True" providerName="System.Data.SqlClient" />
Thanks.
I think I figured out how to make this work.
I explain in detail at: How to embed a database in a visual studio solution?
In short, you start your connection string with the substitution string "|DataDirectory|". And then you set your current AppDomain's "DataDirectory" setting to where you want it to be, before you access the database.
It's not perfectly clean, but it's workable.

Connection Strings

Could you help me understand what this piece of code does in simple English? This is a beginner. Thank you in advance.
<connectionStrings>
<add name="BalloonShopConnection" connectionString="Server=(local)\Sql➥
Express; Database=BalloonShop; User=balloonshop; Password=ecommerce" ➥
providerName="System.Data.SqlClient" />
<remove name="LocalSqlServer"/>
<add name="LocalSqlServer" connectionString="Server=(local)\SqlExpress;➥
Database=BalloonShop; User=balloonshop; Password=ecommerce" providerName=➥
"System.Data.SqlClient" />
</connectionStrings>
This is from a tutorial. I covered everything up to first half of the book but this seems strange.
The web.config for your app is only part of the configuration settings your app gets. The total configuration is a combination of your web.config as well as the machine.config file, and settings defined in IIS. This line:
<remove name="LocalSqlServer"/>
implies that the there is a connection string named LocalSqlServer defined elsewhere that you may be getting from somewhere other than your web.config. So in your web.config they are explicitly removing that other LocalSqlServer connection string you would otherwise get, and replacing it with the one defined below that line. That change only affects your application. This is explained here: http://weblogs.asp.net/jgalloway/archive/2012/01/17/10-things-asp-net-developers-should-know-about-web-config-inheritance-and-overrides.aspx
If the remove tag wasn't there, and that connection string was also defined higher up the chain, your app would use the one defined higher up, and ignore the one defined in your web.config (which can be quite confusing!). That's why the remove tag is needed.
See also:
Avoid web.config inheritance in child web application using inheritInChildApplications
You add connection string which names BalloonShopConnection. Your sql server names (local)\SqlExpress; Your databese is BalloonShop user is balloonshop so you add second one which is very similar :)

Conditional ConnectionString based on which folder the app is published to

I'm entering a parallel test and dev stage where I need to use one db for test and a different one for dev. How can I have the app choose which connection string to implement based on which physical folder it (the app) sits in?
I know there are SVN strategies to consider but this is small-scale enough to avoid 2 sperate code-bases. Would like to be able to publish the same VS project to either of my 2 directories without having to remind myself to change the connection string.
I'm running under IIS7 so perhaps it offers better control than conditionals in (and overrides) web.config. (or not)
thankx!
A word of advice:
I wouldn't base your connection string on your published folder. Down the road, the folder might change, and folks may not be aware that that determines which connection string you're using.
Instead, control it with a setting in your web.config file. Just add a setting that allows you to switch between production and dev databases. In fact, you could simply test for the presence of a debug mode setting. If that setting is there, you're targeting the development database; otherwise, you're targeting production.
The nice thing about that solution is that it doesn't depend on where you deploy the site, and you can document the setting in the Web.config file.
Hope this helps.
Edit for Clarity: By "a debug mode setting" I mean a setting that determines which database you're targeting, dev/production. Not whether your application is running in Debug mode, since the Framework already provides a function that does that. Also, you wouldn't necessarily remove the setting, since you'd want to keep it for documentation purposes. Rather, you'd comment it out.
You could e.g. create a <connectionStrings> container that contains a connection string for each folder your app could be in:
<connectionStrings>
<add name="Folder1" connectionString=".....(conn str. #1)...:" />
<add name="Folder2" connectionString=".....(conn str. #2)...:" />
....
<add name="Folder-n" connectionString=".....(conn str. #n)...:" />
</connectionStrings>
and then just pick the right one, depending on where your app starts up from.
Marc
Get a unique string for the application, perhaps something like:
string folder = Regex.Match(Server.MapPath("~"), #"\(.+?)\$").Groups[0].Value;
Then use the string to get a value from the web.config:
ConnectionStringSetting connectionString = ConfigurationManager.ConnectionStrings["ConnectionString." + folder] ?? ConfigurationManager.ConnectionStrings["ConnectionString"];
In the web.config you can add several connection strings with the folder names appended for each dev site, and a default connection string with just the name and no folder.
I usually put the connection strings into a separate config file and reference them from the main web.config using configSource:
In web.config:
<?xml version="1.0"?>
<configuration>
<!-- connection strings are located in an external config
file to facilitate deployment in various environments -->
<connectionStrings configSource="connections.config"></connectionStrings>
</configuration>
In connections.config:
<?xml version="1.0"?>
<connectionStrings>
<add name="ConnectionName" connectionString="[your connection string]"/>
</connectionStrings>
Once deployed, I usually exclude connections.config from future deployments (unless it should be changed, that is).

Resources