Handling development time web.config conflicts - asp.net

I am looking for a way to handle this challenge: we are a geographically dispersed dev team using ASP.NET Web API and Angular to build a web app.
The thing that causes the grief is the fact that not all team members use the same database setup for their dev work. Yes, I know - I can use web.config transforms to set the proper connection strings for test, staging and production (and I'm already doing this) - but this is not what I'm talking about.
Due to reasons beyond our control at this time, we have
some developers working on a local SQL Server instance using server=(local);database=OurDB as their connection string
other developers using a central developer SQL Server in their location, using something like server=someserver.mycorp.com;database=OurDB
and a few exotic cases with yet other settings
Now every time someone commits a change to the Git repo, and happens to also change something in the web.config, his connection string is committed to the repo. So when I then go pull that latest commit, my settings to my local DB server are overwritten by this other guy's settings.
I am looking for a way to handle this - I was hoping I might be able to
hook into the Git pull process and automagically update the web.config connection string to my local needs whenever I pull something
somehow reference a connection string (or external config file) based on e.g. my currently logged in user's name or something like that
But I can't seem to find any way of doing this. I was wondering if I need to build a VS extension to handle this - any starters for that? Has anyone done something like this before and could share his code? (or has it up on Github)

The web.config configuration system used in ASP.NET is not flexible enough to support the more advanced scenario you have described. So, why use it? You could store the configuration in files within the repository, one per developer. Or they could be stored outside the repository or otherwise ignored.
The real trick is that most older applications don't have a single root that retrieve the configuration, so you have to refactor your application to utilize a flexible configuration system. For your staging/production environments you probably still want to use the config in web.config. The following code can give you a basic idea of one way to structure it:
public class MyApplicationConfiguration
{
public string MainConnectionString { get; set; }
}
public class ConfigurationRetriever
{
public MyApplicationConfiguration GetConfiguration()
{
// You might look for the absence or presence of an environment variable to determine this
bool isLocalDevelopment = IsApplicationLocalDevelopment();
var config = new MyApplicationConfiguration();
if(isLocalDevelopment)
{
config.MainConnectionString = Environment.GetEnvironmentVariable("MyApplication_MainConnectionString");
//or get it from a JSON file or XML file or config database
}
else
{
config.MainConnectionString = ConfigurationManager.ConnectionStrings["MainConnectionString"].ConnectionString;
}
}
}
Rather than rolling your own config building logic, you might refactor your application to leverage Microsoft.Extensions.Configuration. It's not just for .NET Core. It's for .NET Standard. So you can use it even in your legacy ASP.NET applications. For reading the web.config, you could probably use Microsoft.Extensions.Configuration.Xml. Or you can write your own adapter that pulls values out of ConfigurationManager. I did a basic test, and this worked as expected.

Related

Setting project url in VS2015 ASP.NET 5 Web API application

I'm trying to create a Web API project and a client-side web project, where the web project can access the API via ajax. Currently my project looks like this:
I saw this answer on here: Setting app a separate Web API project and ASP.NET app, which explains how the project url can be set to localhost:[port]/api.
But for ASP.NET 5 projects, the properties only have 3 tabs (as opposed to the several found in ASP.NET 4 projects):
What I'm wondering is:
Do I have to set this option somewhere else? (i.e project.json)
How would this work when I publish? Ideally I'd want [websiteURL]/api to serve up my API, whereas that link explicitly put localhost:8080.
Is having these as two projects a good idea? I could easily put API and web in the same project, but I like the separation of client-side and server-side logic.
Any help would be appreciated!
First Point:
Generally speaking in ASP.NET 5, the routing defaults are very good and should work out of the box without much in the way of configuration. You can use configuration and/or attribute based routing in your application (with a detailed overview of both here), although my personal preference is for the attributed approach. Provided you have the following line in your Startup.cs file (which you should have in a new project):
app.UseMvc();
you should be able to route requests to your api controllers in the fashion required (i.e. "/api/...") simply by using [Route] attributes as below (example taken from a standard generated ASP.NET 5 Web API application)
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
The above example will route any GET request made to "/api/values".
While this approach can be used to handle requests made to your api, in order to deliver the files needed for your front end javascript application/single page app, you will need to enable static file serving. If you add the following to the Configure method in your Startup.cs class:
app.UseStaticFiles();
this will allow your application to serve those static files - by default, these are served from the ‘wwwroot’ folder, although this can be changed in the project.json file if required. The files needed for your front end app should then be added to this folder. A tutorial on serving static files can be found here.
Second Point:
In my experience this will not be an issue when you publish your website - provided your server is set up correctly, you will not need to include the port when making a request - navigating to [yourwebsitename]/api/... will suffice.
Third point:
In my opinion this entirely depends on how large the project is likely to grow, although preference and opinion will vary from developer to developer. Generally speaking, if the project will remain small in scope then keeping both in a single project is perfectly ok, as unnecessary complexity is reduced. However it is also very useful as you have pointed out, to maintain a separation of concerns between projects. So aside from the organisational advantage of your approach, the respective dependencies of the two projects are/will be kept separate also.

Where should connection strings be stored in a n-tier asp.net application

Folks,
I have an ASP.NET project which is pretty n-tier, by namespace, but I need to separate into three projects: Data Layer, Middle Tier and Front End.
I am doing this because...
A) It seems the right thing to do, and
B) I am having all sorts of problems running unit tests for ASP.NET hosted assemblies.
Anyway, my question is, where do you keep your config info?
Right now, for example, my middle tier classes (which uses Linq to SQL) automatically pull their connection string information from the web.config when instantiating a new data context.
If my data layer is in another project can/should it be using the web.config for configuration info?
If so, how will a unit test, (typically in a separate assembly) provide soch configuration info?
Thank you for your time!
We keep them in a global "Settings" file which happens to be XML. This file contains all the GLOBAL settings, one of which is a connection string pointing to the appropriate server as well as username and password. Then, when my applications consume it, they put the specific catalog (database) they need in the connection string.
We have a version of the file for each operating environment (prod, dev, staging, etc). Then, with two settings -- file path (with a token representing the environment) and the environment -- I can pick up the correct settings files.
This also has the nice benefit of a 30 second failover. Simple change the server name in the settings file and restart the applications (web) and you have failed over (of course you have to restore your data if necessary).
Then when the application starts, we write the correct connection string to the web.config file (if it is different). With this, we can change a website from DEV to PROD by changing one appSettings value.
As long as there isn't too much, it's convenient to have it in the web.config. Of course, your DAL should have absolutely no clue that it comes from there.
A good option is for your data layer to be given its config information when it is called upon to do something, and it will be called upon to do something when a web call comes in. Go ahead and put the information in your web.config. In my current project, I have a static dictionary of connection strings in my data layer, which I fill out like so in a routine called from my global.asax:
CAPPData.ConnectionStrings(DatabaseName.Foo) =
ConfigurationManager.ConnectionStrings("FooConnStr").ConnectionString()
CAPPData.ConnectionStrings(DatabaseName.Bar) =
ConfigurationManager.ConnectionStrings("BarConnStr").ConnectionString()
etc.
"Injecting" it like this can be good for automated testing purposes, depending on how/if you test your DAL. For me, it's just because I didn't want to make a separate configuration file.
For testing purposes don't instantiate DataContext with default ctor. Pass connection string info to constructor.
I prefer to use IoC frameworks to inject connection to data context then inject context to other classes.

Using web services in different environments

We have a series of web services that live in different environments (dev/qa/staging/production) that are accessed from a web application, a web site, and other services. There are a few different service areas as well. So for production, we have services on four different boxes.
We conquered the db connection string issue by checking the hostname in global.asax and setting some application wide settings based on that hostname. There is a config.xml that is in source control that list the various hostnames and what settings they should get.
However, we haven't found an elegant solution for web services. What we have done so far is add references to all the environments to the projects and add several using statements to the files that use the services. When we checkout the project, we uncomment the appropriate using statement for the environment we're in.
It looks something like this:
// Development
// using com.tracking-services.dev
// using com.upload-services.dev
// QA
// using com.tracking-services.qa
// using com.upload-services.qa
// Production
// using com.tracking-services.www
// using com.upload-services.www
Obviously as we use web services more and more this technique will get more and more burdensome.
I have considered putting the namespaces into web.config.dev, web.config.qa, etc and swapping them out on application start in global.asax. I don't think that will work because by the time global.asax is run the compilation is already done and the web.config changes won't have much effect.
Since the "best practices" include using web services for data access, I'm hoping this is not a unique problem and someone has already come up with a solution.
Or are we going about this whole thing wrong?
Edit:
These are asmx web services. There is no url referenced in the web.config that I can find.
Make one reference and use configuration to switch the target urls as appropriate. No reason to have separate proxies at all.

Problems with Web.config and App.config

Intro:
Normally we store ConnectionStrings and some other settings (<appSettings> <add key...) in the Web.config or App.config.
My scenery:
Web application using factory pattern
with direct injection to read data
providers.
In the web.config I have the key
that tells me which DLL (provider)
will I use to retrieve my data.
I can have more than one provider
(each DLL will be a provider for MS
SQL, MySQL, or get the data from
some SOA service).
Each DLL has his own name (ID and namespaces) and will need to have is own
configurations (dataconnections,
service urls, etc...) , the first
idea is to write then in the
app.config.
Problems:
#1 - The website is running (runtime) I need to change the Data Provider, how can I do this? Somehow the default value written in the Web.config will be changed.
My objective is to be able to have multiple providers (and during runtime: add/delete providers and change configurations) - this leads me to my second problem:
.
#2 - Each Data Provider has custom configurations and App.Config files do not work with dll assemblies, only executables. This means that I need to write then on my Web.Config (I do not like this option, because once again I am updating my web.config in runtime). how can I solve this?
I am trying to avoid to write a custom settings XML file. My ideal solution is to deploy somehow the DLL and DLL.config per each provider. And once again during runtime I may need to change this configuration values.
.
Ok guys, while I was waiting for some help I put my hands to work and I was able to find a good solution (in my opinion of course :P).
Let me share it with you:
So, I have one web application, or one console application, or some other kind of application, and lots of class library, and I need to store informations (different per Visual Studio project) that will change during runtime.
Storing this information inside the Web.config or App.config is not a good idea for the many problems it takes.
The other way I see it is to have one XML config file per project.
Each application will read his own XML and add it to the Cache with CacheDependency (will expire when the XML config file is updated). This way we will not need to read the configuration all the times, and we also know when the configuration is changed.
IMO THIS IS THE FASTEST AND EASIEST WAY TO SOLVE THE PROBLEM, no need to use 3rd party frameworks (neither the time it takes to learn/program it).
.
Example code:
protected void Page_Load(object sender, EventArgs e)
{
DBConfiguration cachConf;
cachConf = Cache["cachConf"] as DBConfiguration;
if (cachConf == null)
{
cachConf = new DBConfiguration();
XmlDocument doc = new XmlDocument();
doc.Load(HttpContext.Current.Request.PhysicalApplicationPath + "bin/MyConf.xml");
XmlNodeList xnl = doc.GetElementsByTagName("username");
XmlElement xe = (XmlElement)xnl[0];
cachConf.Username = xe.InnerText.ToString();
xnl = doc.GetElementsByTagName("password");
xe = (XmlElement)xnl[0];
cachConf.Password = xe.InnerText.ToString();
Cache.Insert("cachConf", cachConf,
new System.Web.Caching.CacheDependency(
HttpContext.Current.Request.PhysicalApplicationPath + "MyConf.xml"),
DateTime.Now.AddMinutes(60), TimeSpan.Zero,
System.Web.Caching.CacheItemPriority.Default,
new System.Web.Caching.CacheItemRemovedCallback(
CacheItemRemovedCallBack));
}
LabelUsername.Text = cachConf.Username;
LabelPassword.Text = cachConf.Password;
}
private void CacheItemRemovedCallBack(string key, object value, CacheItemRemovedReason reason)
{
//Response.Write("Hello world");
}
You could store the credentials in a secondary config file referenced from web.config as follows:
<appSettings file="AppSettings.config"/>
You would still need to be careful to avoid editing conflicts on the external file.
Problem 1 - Runtime changes:
The solution that Microsoft hopes you apply to this type of problem is to simply keep the web server stateless. When an ASP.NET application recycles, it lets existing requests complete new requests start on a new process. For background, read about IIS Process Recycling. A change to web.config recycle the worker process, but users will not notice this (unless you keep state in the web server process). That's the MS design.
If you want to monitor for changes without recycling a process, you'll want something other than default web.config behavior. An example that comes to mind are cruise controls project files. They have a component that maps objects to and from xml, using that, you can use the FileSystemWatcher class to monitor for changes.
Problem 2 - Custom configurations:
It sounds like you have components from different libraries that have different dependencies. Your main assembly needs a means to instantiate a service, with a given set of dependencies. The MS data provider model is cool, but not this cool.
To be this cool, use an inversion of control container, because this is exactly what they do. I like autofac (because I like the Philip K Dick reference), but castle windsor is great.
Now, if you are talking about changes databases or data providers on the fly, it may be that configuration is not the right place. If your are reporting against x databases of y types, you need a central repository of that database information, and a configuration file is not the right place, nor is an IOC container the right solution.
As Precipitous suggested, try Castle Windsor:
http://www.castleproject.org/container/
You're doing Inversion of Control manually. Windsor will take the burden off of you.

Easy way to handle developemnt/production URLs in flex air app

Easy way to handle developemnt/production URLs in flex air app? I want to point to my local box for testing, but when I launch I want it to automatically point to the production URL.
You can use namespaces and configure the current namespace (DEV/RELEASE) in your compiler options.
CONFIG::release
public function connect()
{
//connect to release url
}
CONFIG::dev
public function connect()
{
//connect to dev url
}
then define these options for the compiler:
-define=CONFIG::release,false
-define=CONFIG::dev,true
I suggest either using a configuration file or changing your hosts file to point domains to localhost or dev servers on your development machine. With the latter option you always use your production URLs in code, but your dev machine will resolve those domains to your local machine because it checks the hosts file first.
The best approach here is to externalize this information into a config file - perhaps an XML file - that is loaded via a relative url. The config file might like look this:
<config>
<serviceEndpoint>http://www.mydomain.com/services</serviceEndpoint>
</config>
Be sure to name your XML elements with valid ActionScript variable names or you may encounter some difficulty working with the file (for instance, E4X expressions may become difficult.
You can then use HTTPService to load "config.xml" which is placed alongside your application's SWF when deployed. This will allow you to repoint a SWF hosted on any domain to backend hosted anywhere else. This is especially useful if you are developing locally and are connecting to a shared development server.
Compiling this information into your SWF is very inflexible and a poor practice.
I typically will look at the url in the contentLoaderInfo object in either the Application (Flex -- http://livedocs.adobe.com/flex/201/langref/mx/core/Application.html#url) or root display object (Flash -- http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/LoaderInfo.html#url). If the url begins with "file", you know you are in your development/IDE, if it's "http", it's being run in a browser. If you're just working in the browser, you might also pass a parameter to the object that has something like
{
url: $_SERVER['SERVER_NAME'];
}
and perform some init/startup method to switch based on the path the app is running under.
I had this very issue in an AIR app I am writing that hits a Rails app via WebORB.
I just need to switch between http://localhost and http://fakeproductionurl.com depending on whether I was running in Flex Builder (via adl).
This is what I ended up using:
if (NativeApplication.nativeApplication.publisherID != "") {
return "http://fakeproductionurl.com";
}
else {
return "http://localhost";
}
It doesn't give you the ability to switch between 3+ different environments, but it's a very easy way to toggle between development / production environments.

Resources