How to server-side cache ASP.NET custom HttpHandler response - asp.net

I've got a custom HttpHandler in my ASP.NET application, that basically builds and returns a javascript object. I have no experience with server-side caching, and my (possibly incompetent) google searches aren't returning anything basic enough to get me started.
Could anyone provide a very simple example to give me an idea of how to access and use the server-side cache from a custom HttpHandler, or, leave some links to get me started? Thanks a lot.
Additional info: I'm on IIS 6, and my code-behind is in C# (although a VB example would work as well).

Very simple example to get you started, without locking or error handling:
public void ProcessRequest(HttpContext context) {
MyObject thing = context.Cache["object_name"];
if (thing == null) {
thing = new MyObject();
context.Cache["object_name"] = thing;
}
// use thing here to process request
}

Related

Is it possible to access HttpContext.Current.Session from Web API

Is it possible to access HttpContext.Current.Session through a WebAPI ? can we make it inheriting IRequiresSession?
I have a generic handler doing a Session set after an API call which I want to remove.
public void AccountController : ApiController, IRequiresSessionState
{
public void Login()
{
setsession(){}
}
}
Technically, yes, although I'd really advise against this practice - a REST API should be completely stateless (cookies and other client-side state is OK).
If you absolutely must do this, you can grab the HTTP context like so:
var context = Request.Properties["MS_HttpContext"] as HttpContext;
At which point you just use its Session property to get the session.
Note that this breaks certain contracts assumed by System.Net.Http - specifically it means your API controllers can never be self-hosted because they're coupled to ASP.NET. If you're OK with this, and with the fact that your API controllers may not work properly from a web farm unless you re-architect everything to use distributed sessions - well then, go for it.
P.S. It is also possible to use IRequiresSessionState, but you can't use it on the controller itself, you need to use it on an HttpControllerHandler and set it as the RouteHandler. The approach is discussed in this MSDN thread. Again, I can't recommend strongly enough against this idea, it violates the basic principle of a Web API - but, if you've got a really good reason for it, then it's another option which is a bit more reusable.
Casting it as HttpContext did not work for me using Web Api 2.1. However I could use HttpContextWrapper.
var context = Request.Properties["MS_HttpContext"] as HttpContextWrapper;
Yes - although not recommended. Here's a working answer based on the answers above (for WebAPI version 2.x)
var context =(HttpContextWrapper)Request.Properties["MS_HttpContext"];
var sessionId = context.Request.Params["ASP.NET_SessionId"];

Replacement for ASP.NET Virtual Directory for Multi-tenancy

I am working on an ASP.NET WebForms Application, using ASP.NET 4.5
The Application has multi-tenancy support. Each tenant has an own URL like:
http://myApplication.net/DemoTenant1/
Very simplified in the Login.aspx the application calls this method and translates this URL to an internal ID.
public static string getTenant(HttpRequest request)
{
return = request.Url.ToString();
}
The problem is now, we have more than 200 tenants, for each we need to define an WebApplication which is
a bunch of work :-)
probably very inefficient as an own worker process for each tenant is opend
I am looking for a smart replacement where I stay compatible to the old URLs.
I am looking for an idea how to solve this via URL Routing or maybe to mix WebForms with MVC and add a Login Controller?
Also open to other ideas...
I agree with what Alexander said, the proper way to do this would be with URL Routing.
But... If you are trying to save time...
First, remove all of your web applications;
So get rid of...
http://myApplication.net/DemoTenant1/
http://myApplication.net/DemoTenant2/
http://myApplication.net/DemoTenant3/
And then you need to make sure that typing in the following:
http://myApplication.net/
... takes you to the actual WebApplication you want to use.
Then, in the global.asax file... you need to capture 404 exceptions.
So when someone types in:
http://myApplication.net/DemoTenant1/
... it will throw a 404 exception which you could catch in your global.asax file like this:
void Application_Error(object sender, EventArgs e)
{
string urlData = Request.ServerVariables["SCRIPT_NAME"];
// do some string splitting to get the DemoTenant1 value
// Response.Redirect("~Login.aspx?tenant=DemoTenant1");
}
Its a bit messy but I have done this in the past when I was in exactly the same situation as you. Although, you do now have the routing module built by Microsoft (which I did not have at the time). I am quite sure that you can use the Routing modules within Webforms, without having to use MVC.

ASP.NET Routing - GetRouteData does not work if path exists

I have a HttpModule which intercepts all requests and loads data from the database based on routing rules. However, I run into one problem all the time; GetRouteData only works if the path does not exist:
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
Assuming a request comes in for the url http://localhost/contact, I get the correct routing data relating to that url if that path does not exist in the file system. The problem appears when I want to customize the page at that url which I do by creating an aspx page in the path ~/contact/default.aspx. Once I do that, GetRouteData return null.
I have even tried creating a new HttpContext object, but I still can not retrieve route data if the page exists.
Has anyone ever run into this problem? Is there a solution/workaround?
All help will be greatly appreciated.
Set RouteCollection.RouteExistingFiles to true.
public static void RegisterRoutes(RouteCollection routes)
{
// Cause paths to be routed even if they exists physically
routes.RouteExistingFiles = true;
// Map routes
routes.MapPageRoute("...", "...", "...");
}
Beware though. IIS7 behaves a little differently than the server used when debugging within Visual Studio. I got bit by this when I deployed my application to the web. Check out this feedback I submitted to Microsoft Connection.

How to defer to the "default" HttpHandler for ASP.NET MVC after handling a potential override?

I need to implement a custom handler for MVC that gives me the first look at URLs requests to determine if it should rewrite the urls before submitting the URL to the routing engine. Any pattern is a candidate for the redirect, so I need to intercept the URL request before the standard MVC routing engine takes a look at it.
After looking at a whole bunch of examples, blogs, articles, etc. of implementing custom routing for ASP.NET MVC, I still haven't found a use-case that fits my scenario. We have an existing implementation for ASP.NET that works fine, but we're returning the "standard" handler when no overrides are matched. The technique we're currently using is very similar to that described in this MSDN article: http://msdn.microsoft.com/en-us/library/ms972974.aspx#urlrewriting_topic5 which says "the HTTP handler factory can return the HTTP handler returned by the System.Web.UI.PageParser class's GetCompiledPageInstance() method. (This is the same technique by which the built-in ASP.NET Web page HTTP handler factory, PageHandlerFactory, works.)".
What I'm trying to figure out is: how can I get the first look at the incoming request, then pass it to the MVC routing if the current request doesn't match any of the dynamically configured (via a data table) values?
You would need to:
Not use the standard MapRoute extension method in global.asax (this is what sets up the route handler).
Instead, write your own route subtype, like this.
Although I explained to Craig I may not need to override scenario any more (favoring the future rather than the past), I realized there is an easy and reasonably clean place this override could be implemented - in the Default.aspx code behind file. Here's the standard Page_Load method:
public void Page_Load(object sender, System.EventArgs e)
{
// Change the current path so that the Routing handler can correctly interpret
// the request, then restore the original path so that the OutputCache module
// can correctly process the response (if caching is enabled).
string originalPath = Request.Path;
HttpContext.Current.RewritePath(Request.ApplicationPath, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(HttpContext.Current);
HttpContext.Current.RewritePath(originalPath, false);
}
As you can see, it would be very easy to stick a url processing interceptor in front of the MVC handler. This changes the standard default page behavior and would need to be reflected in any other MVC app you'd want to create with this same method, but it sure looks like it would work.

Bypass Forms Authentication auto redirect to login, How to?

I'm writing an app using asp.net-mvc deploying to iis6. I'm using forms authentication. Usually when a user tries to access a resource without proper authorization I want them to be redirected to a login page. FormsAuth does this for me easy enough.
Problem: Now I have an action being accessed by a console app. Whats the quickest way to have this action respond w/ status 401 instead of redirecting the request to the login page?
I want the console app to be able to react to this 401 StatusCode instead of it being transparent. I'd also like to keep the default, redirect unauthorized requests to login page behavior.
Note: As a test I added this to my global.asax and it didn't bypass forms auth:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpContext.Current.SkipAuthorization = true;
}
#Dale and Andy
I'm using the AuthorizeAttributeFilter provided in MVC preview 4. This is returning an HttpUnauthorizedResult. This result is correctly setting the statusCode to 401. The problem, as i understand it, is that asp.net is intercepting the response (since its taged as a 401) and redirecting to the login page instead of just letting it go through. I want to bypass this interception for certain urls.
Ok, I worked around this. I made a custom ActionResult (HttpForbiddenResult) and custom ActionFilter (NoFallBackAuthorize).
To avoid redirection, HttpForbiddenResult marks responses with status code 403. FormsAuthentication doesn't catch responses with this code so the login redirection is effectively skipped. The NoFallBackAuthorize filter checks to see if the user is authorized much like the, included, Authorize filter. It differs in that it returns HttpForbiddenResult when access is denied.
The HttpForbiddenResult is pretty trivial:
public class HttpForbiddenResult : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.HttpContext.Response.StatusCode = 0x193; // 403
}
}
It doesn't appear to be possible to skip the login page redirection in the FormsAuthenticationModule.
Might be a kludge (and may not even work) but on your Login page see if Request.QueryString["ReturnUrl"] != null and if so set Response.StatusCode = 401.
Bear in mind that you'll still need to get your console app to authenticate somehow. You don't get HTTP basic auth for free: you have to roll your own, but there are plenty of implementations about.
Did you write your own FormsAuth attribute for the action? If so, in the OnActionExecuting method, you get passed the FilterExecutingContext. You can use this to pass back the 401 code.
public class FormsAuth : ActionFilterAttribute
{
public override void OnActionExecuting(FilterExecutingContext filterContext)
{
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.Cancel = true;
}
}
This should work. I am not sure if you wrote the FormsAuth attribute or if you got it from somewhere else.
I haven't used the AuthorizeAttribute that comes in Preview 4 yet. I rolled my own, because I have been using the MVC framework since the first CTP. I took a quick look at the attribute in reflector and it is doing what I mentioned above internally, except they use the hex equivalent of 401. I will need to look further up the call, to see where the exception is caught, because more than likely that is where they are doing the redirect. This is the functionality you will need to override. I am not sure if you can do it yet, but I will post back when I find it and give you a work around, unless Haacked sees this and posts it himself.
I did some googling and this is what I came up with:
HttpContext.Current.Response.StatusCode = 401;
Not sure if it works or not, I haven't tested it. Either way, it's worth a try, right? :)

Resources