How to save data between calls to a IHttpHandler? - asp.net

I have a IHttpHandler that acts as a source to a jQuery Autocomplete input field. In the constructor of the handler I generate an index that remains fairly static between request (needs to be rebuilt maybe once a day).
How can I cache the the index between calls? Debugging indicates that the constructor is called for each request. I've set IsReusable to "false".

Your handler is passed an HttpContext which means it has access to the application cache (e.g. context.Cache["Foo"] = myVal) and can save values there. However, you can also save the value in Session (e.g. context.Session["Bar"]) if your handler implements the IRequiresSessionState interface.

HttpHandlers have a special propert IsReusable. You can override that property in your Handler implementation and set it to return True. IsReusable is a value indicating whether another request can use the IHttpHandler instance.
So first time when the handler is accessed the Handler instance is created and upon next request the same instance serves the request back - so your caching trick will work right in this case.
http://msdn.microsoft.com/en-us/library/system.web.ihttphandler.isreusable.aspx

Related

What is the complete lifecycle of an OData controller http request in WebApi 2

I wonder what is the full lifecycle of an odata http request over an ODataController hosted in IIS.
For instance:
What are the IIS pipelining steps ?
How is the request handled when entering the ASP.NET controllers area ?
When routing is applied ?
When the Attributes such HttpPost, ApplyFilter are applied ?
Maybe this thread can help you:
The ASP.NET Web API 2 HTTP Message Lifecycle in 43 Easy Steps
It all starts with IIS:
IIS (or OWIN self-hosting) receives a request.
The request is then passed to an instance of HttpServer.
HttpServer is responsible for dispatching HttpRequestMessage objects.
HttpRequestMessage provides strongly-typed access to the request.
If one or more global instances of DelegatingHandler exist on the pipeline, the request is passed to it. The request arrives at the instances of DelegatingHandler in the order said instances were added to the pipeline.
DelegatingHandler instances can skip the remainder of the pipeline and create their own response. I do exactly this in my Custom Validation with FluentValidation post.
If the HttpRequestMessage passes the DelegatingHandler instances (or no such handler exists), then the request proceeds to the HttpRoutingDispatcher instance.
HttpRoutingDispatcher chooses which routing handler to call based on the matching route. If no such route exists (e.g. Route.Handler is null, as seen in the diagram) then the request proceeds directly to Step 10.
If a Route Handler exists for the given route, the HttpRequestMessage is sent to that handler.
It is possible to have instances of DelegatingHandler attached to individual routes. If such handlers exist, the request goes to them (in the order they were added to the pipeline).
An instance of HttpMessageHandler then handles the request. If you provide a custom HttpMessageHandler, said handler can optionally return the request to the "main" path or to a custom end point.
The request is received by an instance of HttpControllerDispatcher, which will route the request to the appropriate route as determined by the request's URL.
The HttpControllerDispatcher selects the appropriate controller to route the request to.
An instance of IHttpControllerSelector selects the appropriate HttpControllerDescriptor for the given HttpMessage.
The IHttpControllerSelector calls an instance of IHttpControllerTypeResolver, which will finally call...
an instance of IAssembliesResolver, which ultimately selects the appropriate controller and returns it to the HttpControllerDispatcher from Step 11.
NOTE: If you implement Dependency Injection, the IAssembliesResolver will be replaced by whatever container you register.
Once the HttpControllerDispatcher has a reference to the appropriate controller, it calls the Create() method on an IHttpControllerActivator...
which creates the actual controller and returns it to the Dispatcher. The dispatcher then sends the request into the Select Controller Action routine, as shown below.
We now have an instance of ApiController which represents the actual controller class the request is routed to. Said instance calls the SelectAction() method on IHttpActionSelector...
Which returns an instance of HttpActionDescriptor representing the action that needs to be called.
Once the pipeline has determined which action to route the request to, it executes any Authentication Filters which are inserted into the pipeline (either globally or local to the invoked action).
These filters allow you to authenticate requests to either individual actions, entire controllers, or globally throughout the application. Any filters which exist are executed in the order they are added to the pipeline (global filters first, then controller-level filters, then action-level filters).
The request then proceeds to the [Authorization Filters] layer, where any Authorization Filters which exist are applied to the request.
Authorization Filters can optionally create their own response and send that back, rather than allowing the request to proceed through the pipeline. These filters are applied in the same manner as Authentication Filters (globally, controller-level, action-level). Note that Authorization Filters can only be used on the Request, not the Response, as it is assumed that if a Response exists, the user had the authorization to generate it.
The request now enters the Model Binding process, which is shown in the next part of the main poster. Each parameter needed by the action can be bound to its value by one of three separate paths. Which path the binding system uses depends on where the value needed exists within the request.
If data needed for an action parameter value exists in the entity body, Web API reads the body of the request; an instance of FormatterParameterBinding will invoke the appropriate formatter classes...
which bind the values to a media type (using MediaTypeFormatter)...
which results in a new complex type.
If data needed for a parameter value exists in the URL or query string, said URL is passed into an instance of IModelBinder, which uses an IValueProvider to map values to a model (see Phil Haack's post about this topic for more info)....
which results in a simple type.
If a custom HttpParameterBinding exists, the system uses that custom binding to build the value...
which results in any kind (simple or complex) of object being mappable (see Mike Stall's wonderful series on this topic).
Now that the request is bound to a model, it is passed through any Action Filters which may exist in the pipeline (either globally or just for the action being invoked).
Once the action filters are passed, the action itself is invoked, and the system waits for a response from it.
If the action produces an exception AND an exception filter exists, the exception filter receives and processes the exception.
If no exception occurred, the action produces an instance of HttpResponseMessage by running the Result Conversion subroutine, shown in the next screenshot.
If the return type is already an HttpResponseMessage, we don't need to do any conversion, so pass the return on through.
If the return type is void, .NET will return an HttpResponseMessage with the status 204 No Content.
If the return type is an IHttpActionResult, call the method ExecuteAsync to create an HttpResponseMessage.
In any Web API method in which you use return Ok(); or return BadRequest(); or something similar, that return statement follows this process, rather than any of the other processes, since the return type of those actions is IHttpActionResult.
For all other types, .NET will create an HttpResponseMessage and place the serialized value of the return in the body of that message.
Once the HttpResponseMessage has been created, return it to the main pipeline.
Pass the newly-created HttpResponseMessage through any AuthenticationFilters which may exist.
The HttpResponseMessage flows through the HttpControllerDispatcher, which at this point probably won't do anything with it.
The Response also flows through the HttpRoutingDispatcher, which again won't do anything with it.
The Response now proceeds through any DelegatingHandlers that are set up to handle it. At this point, the DelegatingHandler objects can really only change the response being sent (e.g. intercept certain responses and change to the appropriate HTTP status).
The final HttpResponseMessage is given to the HttpServer instance.
which returns an Http response to the invoking client
Looking at the source code ,ODataController is another controller which is inherited from
ApiController with custom routing and formatting. So I guess all the logic applied for ApiController
applies to that as well.It also has Custom Formatting and Custom Routing applies using ODataFormatting and ODataRouting
What are the IIS pipelining steps ?
IIS pipelining steps are same like any other mvc controller .In essense,we have all the httpmodules and handlers which forms the pipeline.More details can be found asp.net application lifecycle. From this pieline,when an mvc request comes URLRoutingModule,MvcRouteHandler and Mvchandler works in tandem to serve an MVC request. Explained detailed for the next question.
How is the request handled when entering the ASP.NET controllers area ? When is routing applied ?
Everything starts with an ODataController .Almost everything in MVC is extensible(13 extensibility points in asp.net mvc) you name it and all those points are extended for OData. e.g Starting with Custom Controllers,we have
custom ODataActionSelector which is from IHttpActionSelector .You can find a sample implementation here
IActionValueBinder ,sample implementation here
IContentNegotiator
etc like this many more.
/// Defines a base class for OData controllers that support writing and reading data using the OData formats
/// </summary>
[ODataFormatting]
[ODataRouting]
[ApiExplorerSettings(IgnoreApi = true)]
public abstract class ODataController : ApiController
Receive first request for the application -> In the Global.asax file, Route objects are added to the RouteTable object.
Perform routing -> The UrlRoutingModule module uses the first matching Route object in the RouteTable collection .From ODataRouting, The routes are added to RouteTable collection.
Create MVC request handler -> The MvcRouteHandler object creates an instance of the MvcHandler class and passes the RequestContext instance to the handler
Create controller -> The MvcHandler object uses the RequestContext instance to identify the IControllerFactory object to create the controller instance with
Execute controller -> The MvcHandler instance calls the controller's Execute method
Invoke action -> For controllers that inherit from the ControllerBase class, the ControllerActionInvoker object that is associated with the controller determines which action method of the controller class to call, and then calls that method
7.Action returns all custom CreatedODataResult,UpdatedODataResult etc
There are Custom ODataMediaTypeFormatter registered for ODATA to format the data.

Call a controller from an interceptor's preHandle method

I have an interceptor that checks the ldap group membership of a user and if it's deemed wrong will redirect to a NoAuthorisation page like so:
public class MyIntercept implements HandlerInterceptor {
public boolean preHandle (HttpServletRequest request, HttpServletReaponse response, Object handler) {
If ( // check access) {
response.redirect(/NoAuthorisation?reason=Blablabla);
return false;
}
return true
}
}
This works but I'd like to send the reason in a more not so obvious fashion (not in url)
I was thinking I call the NoAuthorisation controller directly but don't know how to do that.
Any advise and best practices?
SpringMVC has a concept of Flash. It is a way to simply pass arbitrary attributes to a redirected request with 2 characteristics:
you do not use the URL
you are not limited to strings
It is very simple to use in #RequestMapping annotated controllers, since you simply pass a RedirectAttributes parameter to the controller method, populates it and return a redirect:... string.
It can be used in an interceptor but you must explicitely require the output flash map with static methods from RequestContextUtils.
public boolean preHandle (HttpServletRequest request, HttpServletReaponse response, Object handler) {
If ( // check access) {
Map<String, Object> flash = RequestContextUtils.getOutputFlashMap(request);
// populate the flash map with attributes you want to pass to redirected controller
response.redirect(/NoAuthorisation?reason=Blablabla);
return false;
}
return true
}
}
Extract from Spring reference manual:
Flash attributes provide a way for one request to store attributes intended for use in another. This is most commonly needed when redirecting — for example, the Post/Redirect/Get pattern. Flash attributes are saved temporarily before the redirect (typically in the session) to be made available to the request after the redirect and removed immediately.
...
Flash attribute support is always "on" and does not need to enabled explicitly although if not used, it never causes HTTP session creation. On each request there is an "input" FlashMap with attributes passed from a previous request (if any) and an "output" FlashMap with attributes to save for a subsequent request. Both FlashMap instances are accessible from anywhere in Spring MVC through static methods in RequestContextUtils.
... after the redirect, attributes from the "input" FlashMap are automatically added to the Model of the controller serving the target URL.
You could get the Session from the request and put a reason on the session as session parameter and get it back from the session at your redirect endpoint.
Don't forget to clean your session as soon as possible though.

Why is session not created if page is cached?

Question: Why is there no session created (and session cookie) when an aspx page requested is pulled from cache?
Background Information
I've made quite a few google searches, but I can't find anything that indicates that this is the intended behavior. Our desired behavior is that a new session/cookie are always generated regardless of whether the page requested is pulled from cache.
We are caching pages using the following code. (.NET 3.5, IIS 7.5)
Response.Cache.SetExpires(DateTime.Now.AddMonths(1));
Response.Cache.SetCacheability(HttpCacheability.Server);
Response.Cache.SetVaryByCustom("IsLoggedIn");
Response.Cache.VaryByParams["*"] = true;
Response.Cache.SetValidUntilExpires(true);
Response.AddCacheItemDependency("Pages");
Any relevant information would be greatly appreciated.
In order to understand why an output-cached request will not create a session, you need to understand a little bit about the ASP.NET Application Life Cycle, the events . The basics are that are a defined series of HttpApplication events that may fire during each request. These events are typically subscribed to using event handlers by either HttpModule implementations or a Global.asax file.
Not every application event fires on every request, but the events that do fire will always fire in the defined order. The order of events that fire on IIS 7
1. BeginRequest
2. AuthenticateRequest
PostAuthenticateRequest
3. AuthorizeRequest
PostAuthorizeRequest
4. ResolveRequestCache
PostResolveRequestCache
5. MapRequestHandler (Integrated Mode Only)
PostMapRequestHandler
6. AcquireRequestState
PostAcquireRequestState
7. PreRequestHandlerExecute
<--- the IHttpHandler.ProcessRequest() method is called here
PostRequestHandlerExecute
8. ReleaseRequestState
PostReleaseRequestState
9. UpdateRequestCache
PostUpdateRequestCache
10. LogRequest (Integrated Mode Only)
PostLogRequest (Integrated Mode Only)
11. EndRequest
12. PreSendRequestHeaders
13. PreSendRequestContent
How an IHttpModule Works
The IHttpModule interface looks like:
public interface IHttpModule
{
void Init(HttpApplication context);
void Dispose();
}
The Init() method is used to subscribes event handlers to the application events and the Dispose() method cleans up after the module when the application is done with it.
How ASP.NET Sessions Work
System.Web defines an IHttpModule implementation named System.Web.SessionState.SessionStateModule. If the session is not disabled in the web.config, the following event handlers get wired up:
// app is the current HttpApplication ;
app.AddOnAcquireRequestStateAsync(this.BeginAcquireState, this.EndAcquireState);
app.ReleaseRequestState += this.OnReleaseState;
app.EndRequest += this.OnEndRequest;
Sessions work differently depending on what session mode is running but the key thing to understand is that sessions are retrieved and created in the SessionStateModule.BeginAcquireState method and that method is wired up asynchronously to the AcquireRequestState event.
How Output Caching Works
System.Web defines an internal IHttpModule implementation named System.Web.Caching.OutputCacheModule. The Init() method looks like:
void IHttpModule.Init(HttpApplication app)
{
if (RuntimeConfig.GetAppConfig().OutputCache.EnableOutputCache)
{
app.ResolveRequestCache += new EventHandler(this.OnEnter);
app.UpdateRequestCache += new EventHandler(this.OnLeave);
}
}
The OnEnter method evaluates the cache parameters and looks for a cached response that matches the request. The OnLeave method caches cacheable responses. The one thing you need to know is that if the OnEnter method is successful in retrieving a cached response, it calls the CompleteRequest() method on the HttpApplication instance. The documentation for this method reads: "Causes ASP.NET to bypass all events and filtering in the HTTP pipeline chain of execution and directly execute the EndRequest event". So, any events that occur between the time that CompleteRequest() is called and the EndRequest() event are skipped.
Why is session not created if page is cached?
The SessionStateModule subscribes SessionStateModule.BeginAcquireState to the application's AcquireRequestState event, so that is where sessions are created and retrieved.
The OutputCacheModule subscribes OutputCacheModule.OnEnter to the application's ResolveRequestCache event, so that is where cached responses are retrieved and where CompleteRequest() gets called. That means that the following events will never fire for a cached request: MapRequestHandler/PostMapRequestHandler; AcquireRequestState/PostAcquireRequestState; PreRequestHandlerExecute; IHttpHandler.ProcessRequest; PostRequestHandlerExecute; ReleaseRequestState/PostReleaseRequestState; UpdateRequestCache/PostUpdateRequestCache; and, LogRequest/PostLogRequest.
If a cached response is retrieved, then HttpApplication.CompleteRequest() is called, the AcquireRequestState event never fires, and the session is never created.
What to do about it?
Whether disabling output cache on pages in favor of controls is a viable solution depends on: (1) whether the code that uses the session is in the controls or in the pages; (2) how much load your application instance needs to be able to support; and, (3) what other caching mechanisms exist in either the application or its supporting infrastructure. Depending on your infrastructure, there may be other factors to consider. For example, ASP.NET sessions can perform and behave very differently depending on the session state mode and on whether the environment is load balanced or not. Also, if you happened to be running an HTTP accelerator cache like Varnish (for example), enabling sessions on a previously output-cached ASP.NET paged might change the behavior from omitting a session to attaching a stale session that belongs to a different user. This is just a hypothetical example, but the point is that there may be additional factors to consider when making these kinds of decisions.
Apparently this is default .NET behavior. If you create a new app, enable session, cache an aspx page, and then have a new user pull the cached version of that page, they will be given no session/cookie.
As a workaround...I think we'll just disable page outputcache and use more aggressive control caching.

Regarding the usage of IRequiresSessionState

please tell me why IHttpHandler need to implement IRequiresSessionState. without implementing it we can not read/write anything in session variable?
can't we access directly HttpContext.Current.session like this way.
please explain.......thanks
public class MyHttpHandler : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
var MyValue = context.Session["MyKey"] as String;
MyValue = "Hello World";
context.Session["MyKey"] = MyValue;
}
public bool IsReusable
{
get { return true; }
}
}
The session state is not a native part of the HTTP infrastructure. This means that the request will need to serialize/load the session information (either from memory or database or another server) for requests that need access to session and save it back when done.
HttpHandler is a the process (frequently referred to as the "endpoint") that runs in response to a request made to ASP.NET http runtime. It is used to handle a particular type of object/class/resource as you define it. If processing of that resource does not need access to session, that particular request does not need to go through the loading/saving of session data unnecessarily. So, by default, session is not available for HTTPhandlers, unless it is a predefined handler like Page handler.
To successfully resolve any call to the Session object, the runtime environment must add the session state to the call context of the request being processed, which is IRequireSessionState in this case.
Check out this msdn link for more details.
To answer your question, no, if you dont implement the IRequireSessionState, you will not have access to the session objects in your handler class due to the above mentioned facts.
If you do not implement this interface you should not be able to successfully use the session object. You are supposed to use this interface if you want access to the session, regardless of how you access it.
It shouldn't work without it. If it does, its a fluke and don't rely on it.
The ASP.NET SessionStateModule will not populate the context's session properties unless the handler is marked with the IRequiresSessionState interface.

Asp.Net Ajax - Call non-static method

From client side, I need to call a server method that is not static.
For example, I got the following user control ucData (private instance of code-behind) that is Databind in the load event.
The server method I need should return ucData.IsValid(). So it can't be static
Is there a way I can do that ?
No...because there is no instance on the server to call the method on. Once the page is generated and sent to the client, there is no more context and all instances are destroyed.
Your best option is going to be to:
Create a static method
Pass that method the info needed to create the instance of the object you need
Call the method on the instance you just created
Return the results from your static method.

Resources