So,
I have an MVC 2 site on IIS 6 (wildcard application maps/aspnet_isapi.dll hack) that where we want to direct people to different URLs depending on their preferred location, let's say la.acme.com vs. nyc.acme.com.
I do not want anyone to end up at www.acme.com or acme.com.
To acc开发者_JAVA百科omplish this I am doing the following (I'll admit it may not be the best way, which is why I am asking this question):
In my base controller, I am doing the following:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
ReturnURL = requestContext.HttpContext.Request.Url.PathAndQuery;
BaseUrl = requestContext.HttpContext.Request.Url.Host;
if (!requestContext.HttpContext.Request.Url.IsDefaultPort) {
BaseUrl += ":" + requestContext.HttpContext.Request.Url.Port;
}
ViewData["BaseUrl"] = BaseUrl;
base.Initialize(requestContext);
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
var route = filterContext.RequestContext.RouteData;
var controller = route.GetRequiredString("controller");
var action = route.GetRequiredString("action");
string basePlusHttp = "http://" + BaseUrl;
string basePlusHttps = "https://" + BaseUrl;
string actionsToSkip = "ChooseCity|DisplayPhoto|ChooseLocation|Press|ContactUs|AboutUs|TermsOfService|PrivacyPolicy|Logon|Register|Prospect|";
if (!actionsToSkip.Contains(action + "|")) {
if (BaseUrl.Contains("www.acme.com") || basePlusHttp.StartsWith("http://acme.com") || basePlusHttps.StartsWith("https://acme.com")) {
if (filterContext.HttpContext.Request.Cookies["StoreLocationID"] != null && Convert.ToInt32(filterContext.HttpContext.Request.Cookies["StoreLocationID"].Value) > 0) {
filterContext.HttpContext.Response.Redirect("/Home/ChooseCity/" + Convert.ToInt32(filterContext.HttpContext.Request.Cookies["StoreLocationID"].Value) + "?returnURL=" + ReturnURL);
} else {
aspnet_User user = Repository.GetAspnet_User(filterContext.HttpContext.User.Identity.Name);
if (user != null) {
if (user.StoreLocationID != null) {
int storeLocationID = Convert.ToInt32(user.StoreLocationID);
filterContext.HttpContext.Response.Redirect("/Home/ChooseCity/" + storeLocationID + "?returnURL=" + ReturnURL);
} else {
//get location by IP
string zip = getZipFromIP();
if (!string.IsNullOrEmpty(zip)) {
var zipCode = Repository.GetZipCode(zip);
if (zipCode != null) {
var storeLocation = Repository.GetStoreLocationByZipCodeID(zipCode.ZipCodeID);
if (storeLocation != null) {
filterContext.HttpContext.Response.Redirect("/Home/ChooseCity/" + storeLocation.StoreLocationID + "?returnURL=" + ReturnURL);
} else {
filterContext.HttpContext.Response.Redirect("/Home/ChooseLocation/");
}
} else {
filterContext.HttpContext.Response.Redirect("/Home/ChooseLocation/");
}
} else {
filterContext.HttpContext.Response.Redirect("/Home/ChooseLocation/");
}
}
} else {
//get location by IP
string zip = getZipFromIP();
if (!string.IsNullOrEmpty(zip)) {
var zipCode = Repository.GetZipCode(zip);
if (zipCode != null) {
var storeLocation = Repository.GetStoreLocationByZipCodeID(zipCode.ZipCodeID);
if (storeLocation != null) {
filterContext.HttpContext.Response.Redirect("/Home/ChooseCity/" + storeLocation.StoreLocationID + "?returnURL=" + ReturnURL);
} else {
filterContext.HttpContext.Response.Redirect("/Home/ChooseLocation/");
}
} else {
filterContext.HttpContext.Response.Redirect("/Home/ChooseLocation/");
}
} else {
filterContext.HttpContext.Response.Redirect("/Home/ChooseLocation/");
}
}
}
} else { //make sure the storelocation chookie value is correct based on the URL...we should not have a nyc.acme.com url with an 'la' cookie.
if (BaseUrl.Contains("nyc.")) {
if (filterContext.HttpContext.Request.Cookies["StoreLocationID"] == null) {
filterContext.HttpContext.Response.Redirect("/Home/ChooseCity/3?returnURL=" + ReturnURL);
} else {
if (filterContext.HttpContext.Request.Cookies["StoreLocationID"].Value != "3") {
filterContext.HttpContext.Response.Redirect("/Home/ChooseCity/3?returnURL=" + ReturnURL);
}
}
}
if (BaseUrl.Contains("la.")) {
if (filterContext.HttpContext.Request.Cookies["StoreLocationID"] == null) {
filterContext.HttpContext.Response.Redirect("/Home/ChooseCity/5?returnURL=" + ReturnURL);
} else {
if (filterContext.HttpContext.Request.Cookies["StoreLocationID"].Value != "5") {
filterContext.HttpContext.Response.Redirect("/Home/ChooseCity/5?returnURL=" + ReturnURL);
}
}
}
}
}
base.OnActionExecuted(filterContext);
}
Here's a summary of the lengthy code in OnActionExecuted
above:
if the user is on an "Action" where we will allow www.acme.com or acme.com (like PrivacyPolicy), then don't bother going any further;
if the url contains "www" or it does not contain the city prefix, then let's move on as we need to fix the situation;
if they have a cookie (StoreLocationID) that specifies their preferred city, then redirect to /Home/ChooseCity where we will set other cookies and redirect to the correct URL: nyc.acme.com or la.acme.com.
if they are signed-in, and if their user account lists a preferred city, then use that (redirect to /Home/ChooseCity -- same as 3 above)
they have no cookie and no stored in a user account, so use their IP to get a zip and see if the zip is in or around a city we cover, if so send to /Home/ChooseCity as in 3 & 4 above
finally, if we cannot determine what city they'd prefer, we have them choose manually at /Home/ChooseLocation/
This all works. BUT, we are starting to notice the following at random times...
Sometimes (and with no seeming pattern) a user will click a link and end up at a completely random page (not the destination of the clicked link). It would seem that the location they end up at is usually a location that another user (cities apart) may have been requesting (I know that you're thinking quantum entanglement, but I've ruled that out). It's as if IIS is getting confused as to whom asked for what.
My question (after all that) is can my logic above (in OnActionExecuted
) be causing IIS to trip up? It should be noted that the "random locations" problem arises even for users with nyc or la in the URL...users who have the proper storelocation cookie. This means that the user should never be redirected to "/Home/ChooseCity" or "/Home/ChooseLocation" as they have the proper configuration of URL and cookies.
The final answer to this is that I was using static classes/properties in places where this was not appropriate. I did not understand that such static classes were shared across the entire web application (meaning all users). I assumed they were contained to one user at a time.
The weird behavior was the result of race conditions on shared properties.
精彩评论