With our current setup there is a requirement to maintain mirrored sessions between two sites, one existing ASP.NET website hosted in IIS 6.0 which is now containing the new website in an iFrame, and hosted seperately in IIS 7.5 (It's MVC3).
Does anyone have any suggestions as how to keep the parent session in line with the child website session?
My initial thought was to create an ActionFilter to fire a HttpWebRequest to an HTTPHandler of sorts on the parent site on the OnActionExecuting method. There has been doubts raised as to how this would keep the specific sessions inline, perhaps missing knowledge about session ID's of sorts?
Something like:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
var request = WebRequest.Create(
ConfigurationManager.AppSettings["HeartbeatURI"]);
using (var webResponse = request.GetResponse())
{
var response = webResponse as HttpWebResponse;
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
Does anyone have any recommendations/ advice here? Thanks!
Update:
After some helpful suggestions I will be investigating whether a solution from the browser, something like:
function setHeartbeat() {
setTimeout("heartbeat()", 300000); // every 5 min
}
function heartbeat() {
$.get(
"http://soemthing:1234/heartbeathandler.ashx",
null,
function(data) {
setHeartbeat();
},
"json"
);
}
Will perform as I require.
There are two fundamental issues your code example is not taking into consideration:
First, sessions are per-client. This solution attempts to 'heartbeat' a single connection from the secondary server. So it won't work.
Second, sessions require client interaction, either via cookies or special, extra URL values. This solution makes no attempt to incorporate those, so no session will be created at all.
EDIT: There's also a third problem: In-process sessions are not guaranteed to stay alive no matter what you do; the application is subject to being recycled at any time, and application recycles will wipe in-process session values. So, you would need to have some external session management system, so that sessions (on both servers) are maintained.
Really, though; it's pretty brittle to try to keep sessions maintained like this. It sounds like it's really important to your application, but there's almost no guarantee it will work all the time. Rearcitecting your application not to require sessions, or to be able to rebuild them on the fly, would be a better option, IMO.
Related
I have a web application which is a mesh of a few different servers and 1 server is the front-end server which handles all request external incoming requests.
So some of these request will have to be passed along to different servers and ideally the only thing I want to change is the host and Uri fields of these request. Is there a way to map an entire incoming request to a new outgoing request and just change a few fields?
I tried something like this:
// some controller
public HttpResponseMessage get()
{
return this.Request.Rewrite("192.168.10.13/api/action");
}
//extension method Rewrite
public static HttpResponseMessage Rewrite(this HttpRequestMessage requestIn, string Uri) {
HttpClient httpClient = new HttpClient(new HttpClientHandler());
HttpRequestMessage requestOut = new HttpRequestMessage(requestIn.Method, Uri);
requestOut.Content = requestIn.Content;
var headerCollection = requestIn.Headers.ToDictionary(x => x.Key, y => y.Value);
foreach (var i in headerCollection)
{
requestOut.Headers.Add(i.Key, i.Value);
}
return httpClient.SendAsync(requestOut).Result;
}
The issue I am having is that this has a whole slew of issues. If the request is a get Content shouldn't be set. THe headers are incorrect since it also copies things like host which shouldn't be touched afterwards etc.
Is there an easier way to do something like this?
I had to do this in C# code for a Silverlight solution once. It was not pretty.
What you're wanting is called reverse proxying and application request routing.
First, reverse proxy solutions... they're relatively simple.
Here's Scott Forsyth and Carlos Aguilar Mares guides for creating a reverse proxy using web.config under IIS.
Here's a module some dude named Paul Johnston wrote if you don't like the normal solution. All of these focus on IIS.
Non-IIS reverse proxies are more common for load balancing. Typically they're Apache based or proprietary hardware. They vary from free to expensive as balls. Forgive the slang.
To maintain consistency for the client's perspective you may need more than just a reverse proxy configuration. So before you go down the pure reverse proxy route... there's some considerations.
The servers likely need to share Machine Keys to synchronize view state and other stuff, and share the Session Store too.
If that's not consistent enough, you may want to implement session stickiness through Application Request Routing (look for Server Affinity), such that a given session cookie (or IP address, or maybe have it generate a token cookie) maps the user to the same server on every request.
I also wrote a simple but powerful reverse proxy for asp.net / web api. It does exactly what you need.
You can find it here:
https://github.com/SharpTools/SharpReverseProxy
Just add to your project via nuget and you're good to go. You can even modify on the fly the request, the response, or deny a forwarding due to authentication failure.
Take a look at the source code, it's really easy to implement :)
I have two ASP.NET applications running on the same server and sharing the same database. One is the front-end, developed with MVC, that caches data to avoid database calls to retrieve the same objects. The other is the back-end, developed with WebForms, that is used to manage CRUD operations.
I'd like to invalidate the front-end cache when a back-end operation occur. I don't need a refined mechanism... back-end will be used only sporadically and could invalidate ALL cached objects.
I've come across some solutions, but they're not very clean solutions... like, putting a flag on a db settings table, using a shared configuration file, calling a front-end web service from the back-end application. Every solution needs to be applied every time a front-end page is called, so I need it to be less resource consuming as possibile.
I don't want to use memcached or AppFabric or similar 'cause I think they're overkill for my basic needs.
Thank you very much!
You can just make an action that will invalidate cache. You can pass it a secret token to check if the request comes from your other web application for security.
So it will look like this:
public ActionResult Invalidate(string key)
{
if (key == ConfigurationManager.AppSettings["ApplicationSecurityKey"])
{
_cacheService.Invalidate();
return Content("ok");
}
return null;
}
In both web.config files of both projects you will have:
<appSettings>
<add key="ApplicationSecurityKey" value="SomeVerySecureValue" />
</appsettings>
And you can call it from your other web application like this:
WebClient client = new WebClient();
client.QueryString.Add("key", ConfigurationManager.AppSettings["ApplicationSecurityKey"]);
string response = client.DownloadString(url)
Got a bit of an odd problem. Here goes:
I have two ASP.NET applications: A web app and a web service app.
Information arriving via the webservice effects data in the database used by the web app.
One particular bit of data controls items in a drop down menu - when the data is altered in the app it can call:
HttpContext.Current.Cache.Remove
but I now need to clear the cache in the web service as i can recieve messages which update that information.
Can anyone recommend a way of doing this?
Cache invalidation can be hard. Off the top of my head I can think of 3 solutions of varying complexity which may or may not work for you.
First, you could write a web service for the web app that the web service app calls to invalidate the cache. This is probably the hardest.
Second, you could have the web service app write a "dirty" flag in the database that the web app could check before it renders the drop down menu. This is the route I would go.
Third, you could simply stop caching that particular data.
You could have a web method whose sole purpose is to clear the cache.
var webRequest = HttpWebRequest.Create(clearCacheURL);
var webResponse = webRequest.GetResponse();
// receive the response and return it as function result
var sr = new System.IO.StreamReader(webResponse.GetResponseStream());
var result = sr.ReadToEnd();
Implement the cache with an expiry time.
Cache.Insert("DSN", connectionString, null,
DateTime.Now.AddMinutes(2), Cache.NoSlidingExpiration);
Cache.Insert Method
You can try SQL Dependency. It will trigger an event when the table you have subscribed has any changes.
https://www.codeproject.com/Articles/12335/Using-SqlDependency-for-data-change-events
I have created a large application and I have now run into a problem.
I have separated customers by virdirs so they have always been in different application pools. I took advantage of this and set static variables for db connection string and other context stuff on session_start and had it available to me throughout my app.
Now I have been overloaded with the amount of virdirs I have had to create (over 500 and quickly growing) and I feel I need to move these to one (or several) application pools. The problem is I don't pass the "session context" I get from the URL, throughout the app. Changing to the app to pass the context down would basically mean I would need to rewrite the app.
Is there a way I could set this context for a session (ie, one call to my API) and not for the entire app domain? Your help is greatly appreciated!
context example
- db con str
- customer log folder
EDIT: I was thinking I could maybe have a table that links the context information to the thread id (System.Threading.Thread.CurrentThread.ManagedThreadId)?
What do you mean by 'context'? Do you mean the request/response/session information? You do not need to pass them manually. For the duration of processing of a http request, the ASP.Net framework exposes all that in a static way:
var ctx = System.Web.HttpContext.Current;
var req = ctx.Request;
var rsp = ctx.Response;
var sess = ctx.Session;
var cache = ctx.Cache;
var myOtherFoos = ctx.Items;
In an ASP.Net application, you can access the static Current-Context from just anywhere, provided you have added the reference to System.Web assembly.
If you do not mean that "context", but if you mean some your own additional information that you need to pass along with the request-processing, then the Items of HttpContext is just for that! It is a fresh collection created at each new request and you can use it as a lightweight scratchpad to keep your things during single-request processing. Unlike Cache or Session, the "Items" evaporate at the moment the request processing ends, so there's no worry about leaks or mixing data with other requests. Just be careful in what keys you pick, try to not collide with the framework thingies that sit there :)
I have a class that implements IHttpModule. This is a support class to help my application defend against DDOS attacks. After implementing the BeginRequest method, I tried to debug my code and for some reason, each time that I debug the class, I have multiple threads in Visual studio. I can't understand why, all of the sudden, while running this application on my local machine, I'm getting several threads, and it happens only in this class.
The HttpModule probably intercepts all requests to your application, including files (js, css, images, etc.)
Take a look at the Request object of each request, and look at the Url property to see what is happening.
Edit:
HttpModules are active very early in the request flow, and they will often get hit by most requests for the server, so keep the code in the HttpModule to a minimum. An example: if you're making permissions on files, make sure the request is actually hitting a file (ie. the requested url starts with /files/). Whenever possible, cache data for use in HttpModules, don't go to the database for each and every request in a HttpModule!
The reason why you probably get less hits in your actual application, is that even requests for images, js files, css files, etc. might make a hit in the HttpModule, but in your application, only requests meant for the application will hit your break points (aspx, asmx, etc. for Web Forms and recognized routes in ASP.NET MVC).
To get a look at what requests you're handling in a HttpModule, look at the value of the url variable:
void context_BeginRequest(object sender, EventArgs e) {
HttpApplication app = (HttpApplication)sender;
String url = app.Request.Url.OriginalString;
}