Fundamentals of Themelia - Pipeline Processors (Pre, Mid, Post, and PostState)
Wednesday, June 18, 2008
This documentation has been updated for Themelia Framework 2.0 Beta 5.
Themelia has various processors which handle allow for custom logic at various points in the Themelia pipeline. These processors include pre processors, mid processors, post processors, and post state processors and since they work directly on the pipeline they are referred to as the pipeline processors. I'll just run through them, explaining what they are, how to build and use them and also give a few examples.
Pre Processors
PreProcessors allow the developer to do any custom logic that is required to run after HTTP modules, but before any other part of the system. These also run before any HTTP handlers as well as before any other feature of Themelia. You can use preprocessors for many things, but they were originally designed to setup the environment for the HTTP handlers.
For instance, perhaps you want to parse the query string, set a context item, detect for a certain browser or even want to pull something directly from the HTTP POST or modify viewstate. This is a good place to do those things. All your settings will be in place before your HTTP handlers are called and, therefore, before web forms even think about loading. So, this is your chance, if you are using webforms, to do processing to control data even before Init, PreInit, and even the web form constructor!
One example of a preprocessor is in Minima called MinimaPreProcessor. Minima uses this feature to read the BlogGuid from configuration so that the other HTTP handlers will have it available. Themelia itself also uses preprocessors, but these are used to support features that will be discussed in a future post. For now, however, feel free to look at the Themelia source code to see these examples of preprocessors.
Another example of a PreProcessor is in Themelia itself. Something has to read the Themelia configuration, right? Internally, Themelia uses the ConfigurationPreProcessor to do all configuration processing so that the rest of the system will have all the information it needs. There are
A preprocessor is made by creating a class that inherits from Themelia.Web.Routing.PreProcessorBase. This is an abstract class that requires you to implement the following signature. However, the params array in this signature is used for Themelia internal use, for Themelia web components as well as for processor initialization, the latter being topics for future discussions.
void OnPreProcessorExecute(System.Web.HttpContext context, params Object[] parameterArray)
Though this isn't the place for a full discussion of it, pre-processing may be the last thing that runs in certain cases. This possibility comes from a Themelia feature called PassThrough. For now, be aware, that there's more going on than the execution of the various processors written about here.
Mid Processors
Mid processors are a bit similar to preprocessors in that their sole purpose is to do any form of processing that you need. However, these are done after preprocessors have run, handler factories have loaded, and after injection processors (discussed elsewhere) have injected their handlers, but just prior to HTTP handler selection. This gives you an opportunity to use the information already provided to you by the other Themelia features to possibly alter the routing process in some way.
Probably the most obvious use of a mid processor is in detecting to see if the information already provided gives enough information to skip the entire HTTP handler selection process, which would otherwise happen just after all mid processors run. For example, based on certain security information provided to you in a custom preprocessor, you may already know you need to use a specific injected HTTP handler.
A mid processor is made by creating a class that inherits from Themelia.Web.Routing.MidProcessorBase. This is an abstract class that requires you to implement the following signature:
IHttpHandler OnMidProcessorExecute(HttpContext context, params Object[] parameterArray)
By returning an HTTP handler, the HTTP selection process is skipped. By returning null, routing continues as usual.
Fall Through Processors (not a Pipeline Processor)
Though, there's more to it than this, after mid processors have executed, Themelia runs a HTTP handler selection algorithm to find the best match for the specific request. If there is no handler match, a fall through processor, if set, catches the route and handles it itself. If no fall through processor, which isn't actually a pipeline processor) is provided or if all registered fall through processors return null, Themelia defaults to passing the request back to IIS to let if figure out the route.
However, due to the fact that they are so different than these other types of processors, they are discusses in a separate place. For the time being though, just know that they run after mid-processors, but before post-processors. After you see a few examples of this and read some more docs, this should all make more sense.
Post Processors
Post processors are a bit similar to pre processors and mid processors. However, these are the very last processors to run in the route activator. This means that run after fall through processors (discussed elsewhere), giving you one last chance to override something a previous processor or even the fall through processor may have done. In fact, this is where you could set a handler if the fall through processor didn't. If you want to switch to a different HTTP handler based on some custom logic, this is your time to do it.
A post processor is made by creating a class that inherits from Themelia.Web.Routing.PostProcessorBase. This is an abstract class that requires you to implement the following signature:
IHttpHandler OnPostProcessorExecute(HttpContext context, IHttpHandler activeHttpHandler, params Object[] parameterArray)
As you can see from this signature, the currently active HTTP handler comes in as a parameter. This means you may use the HTTP handler at this point for some reason. Perhaps you would like to set a few properties on the handler or even call a handler method.
By returning an HTTP handler, you are effectively override all previous processors. By returning null, the existing HTTP handler remains and routing continues as usual.
One final note that shouldn't be overlooked is that at any point in the Themelia pipeline, you can send a signal to skip post-processing. This should obviously be used with extreme caution, but if you do want to skips this processors, you may call the FlowControl.SkipPostProcessing() method and post processing won't execute.
PostStateProcessors
Post state processors are similar to preprocessors in that they exist simply to work with information. A preprocessor may load some information to prepare the pipeline whereas a post state processor may do some last-chance processing on information from the pipeline. A post state processor, as its name suggests, runs after ASP.NET state has been initialized and therefore has full access to session information. So, if you need to configure some information in session, this is your place to do it. However, remember that by the time a post state processor runs, your HTTP handler has already been set and you are not allowed to change it.
This type of processor is actually the only processor that has direct access to session information. However, that doesn't mean that you can't set session in other processors. How's that possible if you don't have direct access to session? Themelia internally has a post state processor called SessionPostStateProcessor which runs before any custom post state processors. This post state processor has a single object in it called Data of StringObjectMap. Any information set in this single, will be copied to session before custom post state processors runs.
As an example, the following preprocessor, while it doesn't have access to session, registers a string to session via the SessionPostStateProcessor:
public class AuthenticationPreProcessor : PreProcessorBase { public override void OnPreHttpHandlerExecute(HttpContext context, params Object[] parameterArray) { SessionPostStateProcessor.Data["UserName"] = "John Doe"; } }
When using this or the even items context, session data, or cache data, it's generally a good idea to scope your information using the scope operator. The above example is rather poorly written because the session item name "UserName" is rather general and may be overwritten by someone else. Therefore, something like the following is recommend:
public class AuthenticationPreProcessor : PreProcessorBase { //- @Info -// public class Info { public const string Scope = "Authentication"; } //- @OnPreHttpHandlerExecute -// public override void OnPreHttpHandlerExecute(HttpContext context, params Object[] parameterArray) { SessionPostStateProcessor.Data[Info.Scope + "::UserName"] = "John Doe"; } }
Themelia inherently understands item scope and uses it at many places internally. To access the above information after it's in session, you may use the following:
Themelia.Web.HttpData.GetScopedSessionItem<String>(AuthenticationPreProcessor.Info.Scope, "UserName");
A post state processor is made by creating a class that inherits from Themelia.Web.Routing.PostStateProcessorBase. This is an abstract class that requires you to implement the following signature:
void OnPostStateProcessorExecute(HttpContext context, params Object[] parameterArray)
This signature should look familiar as it's basically the same signature as a preprocessors.
These four types of processors give you a wide variety of control over the flow of your routing. Each of these concepts give you a measure of control over the entire HTTP pipeline. However, these are intended to be understood by themselves. Without, for example, a full understanding of fall through processors, the flow of the Themelia pipeline is incomplete.
Registration
Registering any type of processor in Themelia is as simple as providing the site's web.config file with the processor type:
<themelia.web> <webDomains> <add> <processors> <add type="Sample.Web.Routing.PreProcessor, Sample.Web" /> <add type="Sample.Web.Routing.MidProcessor, Sample.Web" /> <add type="Sample.Web.Routing.PostProcessor, Sample.Web" /> <add type="Sample.Web.Routing.PostStateProcessor, Sample.Web" /> </processors> </add> </webDomains> </themelia.web>
Processor Factories
No one likes to type long fully qualified types. Therefore, Themelia provides various categories of factories to help register various pieces. For factories, we have processor factories. By using a processor factory we can turn the above configuration into the following:
<themelia.web> <webDomains> <add> <processors> <add type="PreProcessor" /> <add type="MidProcessor" /> <add type="PostProcessor" /> <add type="PostStateProcessor" /> </processors> </add> </webDomains> </themelia.web>
For more information on processor factories, see the processor factory documentation.




