Dynamically Set Web.Config at Application Start for MVC - c#

I have a web application built in ASP.NET MVC that will be used by several clients. Each client has its own database to store information, but each instance will have the same functionality. I am using tips from this question/answer How can I host multiple websites in IIS 7 and use the same MVC application for all them? to consolidate to a single app folder for easier maintenance.
Right now, I setup each client in its own folder and each with its own Web.Config file. There are a couple of appConfig settings as well as the connectionStrings that are unique to that client.
What I would like to do is have a single app folder that contains the MVC project, but the application then dynamically pulls the correct web.config folder (stored in another folder.) I will select the web.config probably based on the host settings (i.e. www.domain.com loads the domain.web.config file.)
I would like for this to update the behavior of the ConfigurationManagement object. I have seen several posts on how to load a configuration file (and most are regarding app.config for desktop apps) but not how to make it a semi-global change or unique characteristics of ASP.NET MVC and web.config.
How can I accomplish this?

What you are looking to do is called multi-tenancy. And this is quite complex task.
You can't really play about with web.config substitution and for one request give one file and for another request give another config. What if 2 requests from different tenants will come exactly at the same time?
At the moment we are converting our application to multi-tenancy and this is very complex task, so can't really be described in one answer on SO.
You can have a look on this write-up http://www.scribd.com/doc/140181293/setting-up-an-mvc4-multi-tenant-site-v1-1
Also if you google for "multi-tenancy MVC" you'll get many articles on that.
Basic principles for our multi-tenancy look like this: DI container is aware of different tenants and knows that request for tenant1.site.com should use configuration set 1 and for request tenant2.site.com configuration set 2 should be used.
Apart from DI container, no other component knows about tenants. And DI container orchestrates the configurations. Connection strings are sitting in configuration objects and these objects are given to EF contexts before they are created... somewhat complex.
If your case is simple and you don't use caches, to substitute the connection strings, I'd save them outwith web.config and provide them based on tenant request. Probably you can get away without complex DI setups.

The overhead of maintaining multiple config files is small if you use external config files to isolate the connection strings that are unique to the customer leaving the bulk of the config file unchanged.
<?xml version='1.0' encoding='utf-8'?>
<configuration>
<connectionStrings configSource="connections.config"/>
</configuration>
For more options about resolving config information at runtime look at
http://msdn.microsoft.com/en-us/library/ms254494(v=vs.110).aspx
For app settings in an internal file see Moving Settings to another config file

Related

Multiple azure websites on same application?

I have a web app that I need to deploy on different websites.
Conditions:
The application code is identical across all websites;
The application is database driven;
Different websites have to connect to different databases;
Connection strings for databases are defined in web.config.
How can I make different websites use the same deployment of the application with different web.config to pull data from different databases?
Here is what my control panel looks like now:
These websites are all applications that I publish separately out of Visual Studio.
The end goal is this:
I found this article: http://www.wadewegner.com/2011/02/running-multiple-websites-in-a-windows-azure-web-role/
It talks briefly about this in “Run the Same Project in Two Sites in the Web Role”
But it seems like this is supposed to be for a local setup and does not discuss how I can get this on the remote Azure instance.
This seems pretty straight forward. Not sure what exactly your issue is.
You can easily map (Deploy from source control) multiple Azure Web Sites to same source code repository. Then, if you are using VSO (Visual Studio Online), the linking will create a new CI build definition for each site. Then you only have to edit the Build Configuration to include the appropriate configuration settings for each environment.
If you are using other source control, you can still customize how the continuous deployment works. All the settings are configurable via a special .dpeloyment file. You can read more about these configurable settings here. Most important part:
SCM_BUILD_ARGS=-p:Configuration=Debug;PublishProfile=MyChainedTransform
You can change build configuration to match that of the target site.
Now, how to make this independently of the source control. Nice Kudu Gurus have thought about that, too. You can tweak these settings via Application Setting for the web site itself (check section Using App Settings instead of .deployment file:
Instead, you can use App Settings to set the same values that are supported
in the .deployment file. The steps are:
Go to the Configure tab for you site in the Azure portal
Add an App Setting called Project, and set its value to something like
WebProject/WebProject.csproj
Then in your other web site you can set Project to point to a different .csproj file.
So you add a new entry with key SCM_BUILD_ARGS and value -p:Configuration=<your_desired_configuration> in the Site Application Settings and you should be ready to go.
Disclaimer: have not check the solutions, but there is no reason why either should not work.

How do I use log4net within a dll that does not depend on a client's app or web.config?

I want to be able to dynamically control the level of logging my Azure cloud-based applications perform. To do this I'm creating a shared log4net-based DLL.
There are lots of questions about log4net logging but almost all of them involve entering and manipulating settings in a config file or other text file. In the Azure cloud, changing the web.config means redeploying. I want to change the logging by making web service calls into the applications from an admin portal.
I also have several applications and I want each to use my new log4net-based DLL without having to store identical settings such as Appender details in each config file. The applications log the same, consistent data.
I do not want to use the Azure diagnostics because this will reduce performance of this large user base application. In addition, I want to reduce logging and diagnostics to a minimum (or disable completely) and only enable them at various levels to debug production problems or take snapshots of their performance. I don't want to redeploy my apps.
What's the best approach?
I would recommend not storing log4net configuration in web/app.config files but rather in a different file that can be updated externally (ie: in blob storage) and location of which can be dynamically changed from the Service Config or contents of which can be changed w/o redeploying.
Look into the log4net.Config.XmlConfigurator.Configure method. You can pass it many different parameters instead of just calling it with no parameters (no parameters default method reads from app.config files).
One way to do what you want is to pass that Configure method a public URL of a config file stored in your Azure storage. Location of the config file can be controlled from the Service Config.
Alternatively if you do not want to make the config file public, you can implement your own reader of the XML config from some private location in storage and pass the XML document to the Configure() method instead.
Check for more information here:
http://logging.apache.org/log4net/release/manual/configuration.html
I can think of 2 ways:
Use Web Deploy which just updates the files on the server without having to do the full blown deployment process.
Enable RDP on your Azure instances and just log in and alter the config file in situ, just like any other server

Load variables to AppSettings on web service start-up

I have the following situation (.NET, C#):
My web service needs authentication data, which is stored in a database. The authentication is used for large volume POSTs done to the web service with transactional data. However, it is too heavy for to query the database every time there is a POST, because we are talking many transactions per second. I therefore want to keep the variables for authentication in Cache - which I can do via AppSettings. How do I load these variables into AppSettings when the web services is first started, without some manual process I need to remember to do?
Thanks,
Anders
It's not so easy to save information to web.config or app.config into AppSettings. Truly speaking, for me it's look dangerous when service tries to modify web.config, because a tiny error could cause all service to go down.
Anyway, when you need it, here is link for MSDN article, use ConfigurationManager class. And this article has a full example how to do it:
http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.aspx
But I suggest you another approach. Use caching either simple System.Runtime.Caching.MemoryCache (or System.Web.Caching.Cache as in one of comments said) or more advanced and scalable scenario using AppFabric caching (for exampe have found link on stackoverflow for you)

Multiple web sites, one common code base and different configuration files

I have two web sites in IIS like
http://domainA.com
http://domainB.com
I would like to use the same code for these web sites but a different web.config files. Is this possible? I store database connectionstrings etc in the web.config files, all the other code in the applications are the same.
I have tried some different approches with creating a folder structure like
-Root
- Domain A
- web.config for domain A
- Code
- Virtual Directory to Source Code
- Domain B
- web.config for domain B
- Code
- Virtual Directory to Source Code
- Source Code
I will then point the website for domain A to "Root/Domain A" and domain B to "Root/Domain B" but the problem is then that the code must be accessed one level down, like
http://domainA.com/Code/
http://domainB.com/Code/
Any ideas?
I will base my answer on the assumption that you are writing custom code rather than using an out of the box solution such as DNN or SharePoint.
One solution that comes to mind to keep a common code base is to maintain your website specific configuration settings in your database instead of the web.config. You can keep your database structure fairly dynamic by using a set of name/value pairs. You would of course need to take this into account in the design of your application and plan for it in your database. This gives you the advantage of only having a single code base as well as a single web.config. If you need to maintain content in separate databases for each site, the connection string info to those content databases can be one of the name/value pairs in your configuration database.
You can even take this one step further by having a single website in IIS for all domains as well (unless you will be using SSL, in which case separate IIS sites would be better). You would need to add host headers to the website and then look for the host header in your code to determine what settings to use and what content to serve. You would lose the ability to create separate app pools so you should check your requirements if this is a feasible option for your situation.
This is actually a similar model to how both DNN and SharePoint work but can certainly be done in a custom application as well.

Assemblies, Web.config and App.Config -- Building failover logic

How do I engineer failover logic properly if an Assembly (.dll) cannot find a web.config file?
Background: I've got our website code nicely modularized into two different .dlls. For simplicity's sake, let's call them:
website.dll
commonengine.dll
The website code and .aspx / .ascx files calls upon the commonengine library for all data layer stuff. For connection strings, the commonengine in turn looks not to the app.config but to the website's web.config file (that's my own preference -- I prefer to have our production constants all in one place). The website code occasionally (very rarely) needs to access stuff in that web.config file. All good so far (even though not entirely pure).
Here's the trouble. I've written a third module. It's a Windows Service (specifically, it's a POP3 checker/processor -- processing mailbox requests and using the commonengine.dll for some data layer stuff).
The problem is the Windows Service calls upon the commonengine.dll, and the commonengine.dll cannot find web.config anywhere because, after all, it's a Windows service (.exe) and doesn't live in a website directory.
What's the proper test/logic here to use app.config when a web.config file cannot be found? Can any ASP.NET configuration gurus give me some guidance here? Thanks much if so.
I never read Web.config explicitly, I use the System.Configuration class to read it (e.g. System.Configuration.ConfigurationStrings["conn name"]). It will automatically go to Web.config in an ASP.NET app and app.config in an EXE.
Of course, you still have to take into account the fact that the config section might be missing.

Categories

Resources