Is it possible to have one .NET MVC application, and have it accessible from different domains, in such a way that the content will be domain-dependant?
For example, both www(dot)site1(dot)com and www(dot)site2(dot)com will point to my server's IP, and to the same website in IIS. In that website my .NET MVC application will reside. Now, I want the ability to know which site (domain name) triggered the ControllerAction, and act accordingly (for example, display different content for the homepage in the Index action, or allow/prevent access to specific content assigned to a specific site).
I would appreciate any help on this. I can accept an extra parameter passed to all controller actions (probably using Routing), but if there's a more elegant solution that would be ideal.
Well, you can always get the domain from the Request.RawUrl property.
As Mercer mentioned, deploying these as two separate web apps would be a better solution though. If that isn't possible, I would try to design something relatively generic that would check the domain and return different Views for each domain.
I have written a blog post about how to do this with an example web application for download.
It uses an abstract base Controller that is aware of the site it is being called for - by creating controllers that inherit from this base class you have automatic access to the current "site" for the current request.
It also allows you to load all your sites from a single database - can save you a bit on hosting fees if you're on a shared host, or if you run your own server you don't have to set up a new database for each site you create.
You can easily access the domain name used in the request with something along the lines of the following:
switch(Request.ServerVariables("SERVER_NAME"))
{
case "www.site1.com":
//do something
case "www.site2.com":
//do something else
default:
//????
}
You can do this in anywhere you have access to the Request object.
An elegant solution would be to have 2 deployments for 2 domains, and to separate content.
You could still have common content, but separating the content without hardcoding this inside the application is a win situation.
If you use different databases to keep the data separate, then in the Session Start configure the application to use one of the databases based on the Server Name variable. Then place the working connection string in the session for the user.
protected void Session_Start(Object sender, EventArgs e)
{
NameValueCollection NVCSrvElements = Request.ServerVariables;
switch (NVCSrvElements.Get("SERVER_NAME"))
{
case "www.whatever1.com":
Session["ConnStr"]="db1 connection string";
break;
case "www.whatever2.com":
Session["ConnStr"] = "db2 connection string";
break;
}
}
Then use this connection string in the rest of the application.
Related
Problem trying to solve: Move the URLS from the config and use class type to dynamically substitute the URL. I have one Website configured in IIS with multiple Host Names.
I am working on Art Academy website using .NET Framework WEB API + React (SPA).
Students have two option of ClassType - it can be either 1) Dance Or 2) Art
> if Dance is choosen i want them to see URL - myDomain.classesForDance.com
> else if Art is choosen i want them to see URL - myDomain.classesforArt.com
Both URL points to same website except change in LOGO and some other minor details
which are handled in code based on classType selected by the students
I am trying to resolve how do i go about IIS binding with multiple host names so that i don't have to manage two websites. IIS will have one website where it points to two Host Names as below:
myDomain.classesForDance.com
myDomain.classesforArt.com
In the appSettings.config (web.config) I have URL for various environments like QA, Stage, Prod etc
For example, on QA
SignInUrl="http://login.qa.classesForDance.net/auth?siteCode=DANCE"
AuthenticationDomain=".qa.classesForDance.net"
What i want to do is, i want to dynamically send back URL like
Either LogInUrl=http://login.qa.classesForDance.net/auth?siteCode=DANCE
OR LogInUrl=http://login.qa.classesforArt.net/auth?siteCode=ART
based on student's class selected as per their profile. Move the URLS from the config and use selected class type to dynamically substitute the URL.
How do i go about solving this problem
Note** System.Web.Hosting.HostingEnvironment won't solve as I can only access properties like SiteName etc.
What i need is correct URL based on ClassType students have opted for.
One solution i have thought so far is to come up with a service which first reads the DB and replaces the appSettings.config - config URL based on ClassType. I don't want to add more Keys to AppSettings for another hostname, for example what if i add another classType - singing in future - the design should be able to accommodate easily without much changes in code and simply by adding one more classType in DB - return myDomain.classesforSinging.com
Is there any better or alternative approach someone can suggest? Anything i need to consider while handling this problem?
I have a single ASMX web service that has a host of methods that can be called. However, I'm wanting to restrict certain methods so that the caller either needs to be authenticated in order to be able to call them, or even better can only be called from the local server in which the service is running from.
Basically those methods needing to be protected will be called by the Microsoft Windows Scheduler on the local server.
Is either option possible, and what is the best and preferred way of achieving this.
At the top of the web services you want to protect, you can do something like:
if (!Request.IsLocal)
{
Response.StatusCode = 401;
Response.StatusDescription = "Unauthorized";
return null;
}
You could also check if they are authenticated with the IsAuthenticated property.
Of the two methods you mention, by far the easiest is to restrict access to just the local server. You can do this through code (as another comment has noted), or by administration of IIS itself.
If you load up the IIS Manager and select the folder that your asmx file is in, you'll see on the right-hand side a section 'IP Address and Domain Restrictions'. Open this up, add a default deny rule, and then an allow rule for 127.0.0.1.
Be aware that using this method will restrict all services in this folder, so you may need to move this into its own folder if this isn't required or desirable.
I've a personal project, and the logic layer and database is equal, but I've two domains that the only thing that changes is the URL, and the master page.
What I need is a simple system to recognize the URL and show the correct site master, because I what use the same database with the configuration of ASP.NET tables, stored procedure and so one.
The most similar thing I've saw, it's the DNN portal system, but I don't need all the features, like separate login system.
Thanks in advance.
I think something along these lines will get you what you need:
In IIS, point both URLs to the same virtual directory, so they are both being served from the same place -
Add a PreInit event to read the URL then load a MasterPage accordingly:
void Page_PreInit(Object sender, EventArgs e)
{
if(Request.Url.AbsoluteUri.Contains("mysite.com"))
{
this.MasterPageFile = "master page file goes here";
}
}
Hope that gets you in the right direction!
You could make the master page dynamic. The host name can be found in:
HttpContext.Current.Request.ServerVariables["SERVER_NAME"]
You can use this inside the master page to change its output.
I would take it one step further and abstracting everything away that differ and then use dependency injection to resolve what you need.
I am building a web application in which there will be a core library and database that is shared by many instances. To give a more concrete example lets say I have a blogging engine and users can sign up to their own blog which will act independently of the others on the system.
Each instance must have their own subdomain eg: http://john.extremeblogging.tld/ and also have the option to have their own domain mapped to it eg: http://jonnyblogger.tld/
The problem I have is not knowing how to notify IIS 7.5 what to do when requests come in from either of those domains. Is it as simple as setting this web application to the default site within IIS and the application can use the request headers to take the appropriate action?
It strikes me that this should be a pretty common task so I don't anticipate this to be too difficult to solve but at the moment I am not sure how to approach it.
Any guidance is appreciated.
Thanks
id
Its been very long this question was asked, but still answering it so it might be helpful to others in need.
I happened to work on a big SaaS based multi-tenant project which involved unique subdomains for each of the users site. User could design and manage the content on his own site.
On the registration of a tenant/user we can add domain binding with the IIS using C# following this link-
http://amitpatelit.com/2013/03/12/enter-iis-binding-entry-by-c-code/
Alongside we need to check the host name from the request headers and get the subdomain name to fetch the subdomain specific data and interface etc.
protected override void OnAuthorization(AuthorizationContext filter_context)
{
var url = Request.Headers["HOST"];
var index = url.IndexOf(".");
if(index > 0)
{
var sub = url.Split('.')[0];
FrontSiteData = CommonService.GetSiteData(sub);
}
}
Please let me know if you require more information.
Regards,
Manik
Similar but not the same:
How to securely store database connection details
Securely connecting to database within a application
Hi all, I have a C# WinForms application connecting to a database server. The database connection string, including a generic user/pass, is placed in a NHibernate configuration file, which lies in the same directory as the exe file.
Now I have this issue: The user that runs the application should not get to know the username/password of the general database user because I don't want him to rummage around in the database directly.
Alternatively I could hardcode the connection string, which is bad because the administrator must be able to change it if the database is moved or if he wants to switch between dev/test/prod environments.
So long I've found three possibilities:
The first referenced question was generally answered by making the file only readable for the user that runs the application.
But that's not not enough in my case (the user running the application is a person. The database user/pass are general and shouldn't even be accessible by the person.)
The first answer additionally proposed to encrypt the connection data before writing it to the file.
With this approach, the administrator is not able anymore to configure the connection string because he cannot encrypt it by hand.
The second referenced question provides an approach for this very scenario but it seems very complicated.
My questions to you:
This is a very general issue, so isn't there any general "how-to-do-it" way, somehow a "design pattern"?
Is there some support in .NET's config infrastructure?
(optional, maybe out of scope) Can I combine that easily with the NHibernate configuration mechanism?
Update:
In response to the first answers: There are several reasons why I would want to connect to the database directly and not use a web service:
(N)Hibernate can only be used with a database, not webservices (am I right?)
We plan to provide offline capability, i.e. if the database or network should be down, the user can continue his work. To manage this, I'm thinking of having a local, in-proc database, e.g. SQL Server Compact, and using MS Sync framework to synchronize it with the server database as soon as it is up again.
Do you have any further ideas taking this into account?
First of all, letting untrusted users connect to a database is generally not a good idea. So many things can go wrong. Put a web service inbetween.
If you absolutely have to do it, make it so that it doesn't matter even if they get the username and password. Limit their privileges in the database so that they can only execute a few stored procedures that have built-in security checks.
Whatever you do, you can't give the username/password of a privileged user to an untrusted person. It's just asking for trouble. No matter how well you try to hide your credentials within an encrypted string inside a binary file or whatnot, there's always a way to find them out. Of course whether anyone'll actually do it depends on how interesting your data is, but silently hoping that mean people with debuggers will just leave you alone is not a very good security measure.
Actually the WebService approach (mentioned in some other answer) means that you move NHibernate and its logic to the web-service. The WebService then, exposes the db functionality available to the application using the WebService's methods.
There is practically only one user for the database, the one the WebService uses and if you want the application user to have different db privileges you abstract it from the WebService layer
In the end, the WinForms application is only aware of the location of the WebService where it requests data through the WebService's methods and you can apply any required security measure between these two endpoints.
For off-line capability it all boils down to making a secure way to persist your data to local storage and providing a synchronization method via the WebService
I have actually done this using a webservice that communicated with the DB and a WinForm application (.NET Compact Framework) that only talked to the webservice and in case of no cellular network coverage it would serialize the changes to the memory card (the data was not important so for my case obscure/obscene security measures where not taken)
UPDATE with a small example as requested (i do find it strange though to ask for an example on this)
you have set up your domain classes and nhibernate configuration and (for example) your repository stuff in a project of type ASP.NET WebService Application. For the sake of simplicity i'm only going to have a single web-service class Foo (in Foo.asmx.cs) and well as a single Bar domain class
so you get this (actual implementation varies):
namespace FWS
{
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class FooService : WebService
{
private readonly ILog errorLogger = LogManager.GetLogger("ErrorRollingLogFileAppender");
private readonly IDaoFactory daoFactory = new DaoFactory();
private readonly ISession nhSession = HibernateSessionManager.Instance.GetSession();
}
[WebMethod]
public Bar[] GetFavoriteBars(string someParam, int? onceMore){
return daoFactory.GetBarDao().GetFavoriteBars(someParam, onceMore); //returns a Bar[]
}
}
and we abstract the daobehaviour, or just use the nhsession directly, exposed as a webmethod.
Now from the WinForm application all you need to do is Add a WebReference which makes all necessary changes to configuration but also generates all necessary classes (in this example, it will create a Bar class as the web-service exposes it).
namespace WinFormK
{
public class KForm(): System.Windows.Forms.Form
{
public void Do()
{
var service = new FWS.FooService();
string filePath = "C:\\temp\FooData.xml";
Bar[] fetched = service.GetFavoriteBars("yes!", null);
//lets write this to local storage
var frosties = new XmlSerializer(typeof(Bar));
TextReader reader = new StreamReader(filePath);
try
{
var persisted = (T)frosties.Deserialize(reader);
}
catch(InvalidOperationException)
{
//spock, do something
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
}
there are certain things you have to take note to:
You essentially lose lazy stuff, or at least you lose it in your winform application. The XML serializer cannot serialize proxies and as such you either turn of lazy fetching on those collections/properties or you use the [XmlIgnore] attribute which in turn do what it implies on serialization.
You cannot return interfaces on the WebMethod signatures. They have to be concrete classes. So, returning IList<Bar> will have to be transformed to List<Bar> or something of the like
The webservice is executed by IIS and is visible from a web browser. By default, only local browser requests will be served (but that can be changed) so you can test your data access layer separately of what your winform does.
The receiving end (winform app) has no knowledge of NHibernate whatsoever.
In the example above i've kept the same name for the dao-methods for the web-methods; As long as you didn't keep nhibernate--specific methods in your dao's (lets say like a NHibernate.Criterions.Order parameter) you will probably find no problem. In fact you can have as many .asmx classes in your webservice as you want, probably even 'map' them to the corresponding dao's (like public class FooService : WebService, public class BarService : WebService, public class CheService : WebService where each corresponds to a DAO).
You will probably have to write some kind of polling method between your endpoints to keep your presented data fresh.
WebService data is verbose; extremely so. It is advisable to zip them or something before sending them over the wire (and maybe encrypt them as well)
the win application only knows a configuration entry: http://server/FWS/FooService.asmx
Webservices have Session disabled by default. remember that before starting using the session for user data.
You will probably have to write some kind of authentication for the webservice
In the example above i am returning a Bar[] with Bar being mapped with nhibernate. More often than not this may not be the case and you may be required to write an auxiliary class WSBar where it adapts the original Bar class to what the webservice and the winform application can consume. This class is actually just a data carrier. Again this depends on how much integration exists with your domain classes and nhibernate as well as how muxh complicated your classes are: Certain data structures cannot be serialized by default.
This model may not suit what you have already done with your application
I think it's hard to do : it's like you don't want a user of stackoverflow to know his password.
A user can always trace his network traffic and see the user/password (you can had an encoding, but it still won't be 100% sure I think).
I think that you should add a webservice between your user and your database with a unique id for each user.
This is why database desktop apps suck. There is no good way to slice it. Best bet would be to use stored procedures or web services. Basically, another layer that can be locked down and control access to the database.