On IIS 6, is it possible to have multiple domain names pointing to the same web application, and conditionally serve CSS from within the web application based on the domain name?
I need to host hundreds of different "skins" on the same web application, with the skin being dependent upon the domain name, and I really don't want to launch tons of web applications.
+1 to rhinof for adding multiple identities, but creating a HttpModule is a bit over kill. You can simply switch the URL of the tag in a Master Page by examining the contents of Request.Headers["HOST"]
1) add the desired domain names as website identifiers in the advanced property page of the Web Site Tab.
2) map the .css extension to the aspnet_isapi.dll
3) write an httpmodule that will re write the url for .css requests based on the domain name
4) enable your module via the web.config
If you use themes, you can change the theme, thereby changing the css, etc. in the Page.PreInit depending on the value of the domain in Request.ServerVariables["Url"] (note, there might be a better server variable to get the domain name, look it up).
If you aren't using themes, you can programatically swap out the css file by checking the same server variable.
MasterPages are going to be your friend here.
Hope that shoves you in the right direction. It is possible and common.
If you are going to have different core content on the sites then I suggest putting in a global identifier to track which site a user is on and put your data in a DB somewhere for reference against that identifier. This is by far the easiest way to extend the app if each instance is unique.
You can put this into a class and have one common pattern for figuring out where stuff should map to. I suggest that once you know the mapping to cache that and then you will be able to do what you want without the latency of a thousand apps or db calls.
You will also need to add this parameter on any general DB calls so that you only get results for the domain that is being hosted. I’ve got a bit of experience with this so just leave some comments if you want to see some specific coding examples.
You can apply this technique to any file, CSS stylesheet or object for referencing purposes.
Yes, this should be simple to do. I'd go with the approach of mapping the domain names to your app using host headers in IIS. Then, as Martin said, interrogate Request.Headers["HOST"] in your app to switch the stylesheet.
Related
I have been given a job to re-develop a news portal. The website already has couple of thousands of unique visits a day. I am going to develop it using ASP.NET webforms. I am currently in the planning phase and I am thinking to offer the main admin a page where he can change site specific configuration information. Some of these are;
Web site title "<title>"
site URL
footer text
default image directory
whether to accept comments without authorisation or not
I listed above some settings so that you can understand my scenario better.
What I can't decide is, where to store all this information. Do I store them in a DB (costly?), a custom XML file? or a .config file. e.g. ConfigurationManager.AppSettings
Any pros or cons would make my day!
Thank you!
My opinion is to store them on web.config on WebConfigurationManager.OpenWebConfiguration().GetSection() because this variables are critical and change only ones - in the initialize of the site.
For example the default image directory is stay the same for the rest of the site life, the same and the site URL the same and the other.
Also when you change this settings probably you need also a restart of the web application because for sure you need to re-read them on some static variables.
And because this variables are stay as is, and need them for start the web (then you read the database and the rest) you need to have it in first hand, from the web.config.
In my research, I found 2 ways to do them.
Both required modifications to the Application_BeginRequest procedure in the Global.Asax, where you would run your code to do the actual URL mapping (mine was with a database view that contained all the friendly URLs and their mapped 'real' URLs). Now the trick is to get your requests run through the .NET engine without an aspx extension. The 2 ways I found are:
Run everything through the .NET engine with a wildcard application extension mapping.
Create a custom aspx error page and tell IIS to send 404's to it.
Now here's my question:
Is there any reason one of these are better to do than the other?
When playing around on my dev server, the first thing I noticed about #1 was it botched frontpage extensions, not a huge deal but that's how I'm used to connecting to my sites. Another issue I have with #1 is that even though my hosting company is lenient with me (as I'm their biggest client) and will consider doing things such as this, they are wary of any security risks it might present.
`#2 works great, but I just have this feeling it's not as efficient as #1. Am I just being delusional?
Thanks
I've used #2 in the past too.
It's more efficient because unlike the wildcard mapping, the ASP.NET engine doesn't need to 'process' requests for all the additional resources like image files, static HTML, CSS, Javascript etc.
Alternatively if you don't mind .aspx extension in your URL's you could use: http://myweb/app/idx.aspx/products/1 - that works fine.
Having said that, the real solution is using IIS 7, where the ASP.NET runtime is a fully fledged part of the IIS HTTP module stack.
If you have the latest version of IIS there is rewrite module for it - see here. If not there are free third party binaries you can use with older IIS (i.e. version 6) - I have used one that reads the rewrite rules from an .ini file and supports regular expression but I cant remember its name sorry (its possibly this). I'd recommend this over cheaping it out with the 404 page.
You have to map all requests through the ASP.NET engine. The way IIS processes requests is by the file extension. By default it only processes the .aspx, .ashx, etc extensions that are meant to only be processed by ASP.NET. The reason is it adds overhead to the processing of the request.
I wrote how to do it with IIS 6 a while back, http://professionalaspnet.com/archive/2007/07/27/Configure-IIS-for-Wildcard-Extensions-in-ASP.NET.aspx.
You are right in doing your mapping from the database. RegEx rewriting, like is used out of the box in MVC. This is because it more or less forces you to put the primary key in the URL and does not have a good way to map characters that are not allowed in URLs, like '.
Did you checked the ASP .Net MVC Framework? Using that framework all your URLs are automatically mapped to Controllers which could perform any desired action (including redirecting to other URLs or controllers). You could also set custom routes with custom parameters. If you don't have seen it yet, maybe it will worth the look.
Is it possible or feasible to run a bunch off web sites off of only 1 code base?
For example I have 1 site that bases it's connection string off of the domain name or subdomain name. So, depending on what domain/subdomain is hitting the site the site returns content that is stored in a database specifically for that site.
What types of issues might occur from doing this? Specifically if doing this with asp.net.
It's quite acceptable.
Just note that anyone can change the domain name that you may pick up (as long as you've configured a host header for it), so just make sure you don't go around making something like 'admin.foo' but relying only on that for security (you'd be mad though, obviously).
I see no problem with it.
It works and is proven. Se DotNetNuke for just 1 example of this.
Request come in. Regex/character matchthe domain name. Load settings for that domain (base path to images, css, config, pages etc etc) and off you go.
The gotcha to look out for is if your application is both a) storing data in memory and b) using the same application space. So if, for example, you want to dish up two different blogs and you want the data to be resident in memory (if, say, your back-end store was XML and you didn't want to parse XML with every request) then you'll have to make sure that Asp.Net sees each call as a separate application (which can both point to the same file-system folder and thus uses the same files).
I ran into this exact situation when coding a multi-blog data provider for BlogEngine.Net. It uses a single code base to serve up different blogs based on the requested URL. However, since BlogEngine.Net carries its data in memory, the data provider won't work unless IIS is configured so that each blog is its own application.
I'm writing a pretty straight forward ASP.NET MVC web app: only a couple of CRUD pages, some folders where clients can browse documents and just 3 or 4 roles. The website will be used in a B2B scenario, where every client will have their "own" website.
At this point, the only thing that will change in the website, from client to client is the content (ie. the documents, and the rows of data they'll see). If this is the case, what's the best way to manage roles across all of my clients? I'm looking for the simplest possible solution because this is a proof of concept and I don't want to invest a lot of time right now.
What if it's not just the content that changes? Maybe some clients will want a few custom static pages. At this point, is my only option replicating the entire website? I'm leery of this because it'll become hard to maintain if I get a lot of clients.
I'd appreciate any help... I just don't want to shoot myself in the foot; I'm sure someone has done this before.
I create Virtual Directories in IIS for each client, all pointed back to the same folder where my ASP.NET code resides.
This allows me to support several dozen nearly-identical "web sites," each with their own database that is basically identical in form, only differs in data.
So, my site URLs look like:
http://mysite.com/clientacme/
http://mysite.com/clientbill/
http://mysite.com/clientcharlie/
There are two key implementation details I worked out for this:
I use the Virtual Directory folder name to determine which DSN my code reads from. This is accomplished by creating a simple static method that injects the folder name into a DSN string template. If you want to use the same database to store everyone's data, you can use the folder name as a default filter in your queries.
I store the settings for each web site (headers and footers, options, links to custom reports, etc.) in a simple "settings" table in each database (key, value) rather than in the web.config (which is shared). This allows me to extend the code base over time to customize the experience for each client without forking the code.
For user authentication, I use Basic authentication, and I keep usernames, passwords, and roles in a table in each database.
The important thing is that if you use different SQL Server databases for each client's content, you need to script any changes to your database tables, indexes, etc. and apply them across all databases at the same time (after testing of course). One simple way to do this is to maintain an Excel sheet with a table of database names and a big "SQL" cell at the top. Beside each database name, create a formula to "USE databasename;" and then concat the SQL code at the top.
I'm not sure if this answers your question completely, but as far as maintaining custom "static" pages I found myself implementing a system on a client's MVC website where the client can create "Pages" from their admin control panel and each Page has a collection of "PageContent" entities which consist of a Title and and HTML content field (populated using a WYISWYG editor). Upon creating a page the MVC application maps http://yoursite.com/Page/Page-Url-Specified-By-The-User to that page and renders its content there. Obviously, the pages are dynamic, but as far as the client can tell they have created a brand new custom page with little or no effort.
Back in the days before Visual Studio Web Server we would host our local dev inside IIS. If you have a workstation version of IIS that means only 1 website. What if you are working on several websites. Easy: create them in VDIRs, e.g. http://localhost/ProjectA, http://localhost/ProjectB.
Living in a VDIR doesn't sound so hard. Make sure all your images/CSS/links are relative paths, use the "~" a lot. Sounds like a good practise. Hardcoding images etc so they only work when the application is served from "/" sounds like a bad practise.
There are some nuances anywhere you have to build a link (mostly not common scenarios):
eg; PROD: http://prodserver.com/images/up.jpg -> DEV: http://localhost/ProjectA/images/up.jpg
links / images in emails
flash/javascript/silverlight requests data from the server which contains links to images
The full link to the a PayPal IPN (the page paypal POSTs their response too)
So.. Are you doing this? Advantages / disadvantages? Any other gotchas I've missed?
I always avoid hardcoded paths, URLs, etc. unless there's a specific reason to do otherwise. Things inevitably change, and there's always the jump from your dev site to production.
The part that is usually the biggest nuisance would be in reusable client behaviors that need to reference other paths, and themselves can be reused in pages across the application's directory structure.
I like the idea handler that responds to "globalvars.ashx" (or something like that; there are many ways to handle this) which dynamically emits (and allows caching) properties regarding the global application properties.
Say the handler responsible for globalvars.ashx writes the result of something like this:
String.Format("var ApplicationProperties = {{ RootPath:{0} }};", Request.ApplicationPath);
Your JS behaviors could theoretically reference that property object at any point via ApplicationProperties.RootPath.
In short, yes. The disadvantages of not doing so outweigh the benefits. I actually think your first two points can also be mostly mitigated from using app-relative paths ("~"), but nevertheless, some scenarios such as "integration-level" ones (like PayPal) may indeed prove tricky.
But at the end of the day, if you need to host your app in a virtual directory you are virtually guaranteed problems if you haven't coded your app to be vdir-friendly from the get go. I know I have.
Some background/context: My current production environment at work is almost always a virtual directory anyway, so I do this by necessity. And I've never had a problem when an application was created as a root-level website. This certainly wouldn't be the case if it was the other way around.