Want to follow this site? Here's the RSS feed.

Fundamentals of Themelia - Processor Factories

Tuesday, August 26, 2008

This documentation has been updated for Themelia Framework 2.0 Beta 5.

One of the most basics concepts in Themelia is the handler factory.  If you recall, this allows simplified access to any HTTP handler.  In stead of registering a handler as "Sample.Web.AuthenticateHandler, Sample.Web", you could simply use "Authenticate" or "Auth" depending on how your handler factory was setup.  This factory also created the HTTP handler thereby giving a small boost in performance over dynamically creating an instance of "Sample.Web.AuthenticateHandler, Sample.Web".

Analogous to this is a processor factory, it's identical every every way to an handler factory, except that it generated any and all types of processors.  You can alias pre processors, mid processors, fall through processors, error processors, post processors, and post state processors.  Thus, instead of registering the long name of "Themelia.Web.Routing.ForbiddenFallThroughProcessor, Themelia.Web" you may simply register "ForbiddenFallThroughProcessor" and instead of "ABCCorp.Web.Routing.SalesPreProcessor, ABCCorp.Web", you just register "SalesPreProcessor" or "Sales" or whatever you want (however it's a good idea to leave the processor type suffix).

In fact, for our example, let's look at Themelia's internal processor factory:

internal class CommonProcessorFactory : Themelia.Web.Routing.ProcessorFactoryBase
{
    //- @CreateProcessor -//
    public override IProcessor CreateProcessor(String text)
    {
        switch (text)
        {
            case "passthrough":
                return new PassThroughPreProcessor();
            case "emailsendingerrorprocessor":
                return new EmailSendingErrorProcessor();
            case "forbiddenfallthroughprocessor":
                return new ForbiddenFallThroughProcessor();
            case "passthroughfallthroughprocessor":
                return new PassThroughFallThroughProcessor();
            case "pagealiasfallthroughprocessor":
                return new PageAliasFallThroughProcessor();
            case "redirectfallthroughprocessor":
                return new RedirectFallThroughProcessor();
        }
        //+
        return null;
    }
}

As you can see, every common reusable processor type is registered so that you don't need to write out the entire type each time.  Also, once again, we have a small performance boost since dynamic creation is now out of the question.

As a side note to this, where as handlers are created on each request (lest they share stale state), Themelia pools processors so they are only created once.  Actually, pools processors regardless if you are using a processor factory or not.  So, the performance boost in a processor factory isn't nearly that much as the boost in a handler factory.  However, it sure does help you remember the name of the types.

It's important to remember that you can use a processor factory for any type of processor.  You do not need to have a separate processor factory for each type of processor.  A single processor factory may create anything form error processors to mid processors to post state processors and everything in between.

A processor factory is made by creating a class that inherits from Themelia.Web.Routing.ProcessorFactoryBase. This is an abstract class that requires you to implement the following signature:

IProcessor CreateProcessor(String text)

Processor factories like all Themelia factories are registered in web.config in the <factories> collection.  Below is an example:

<themelia.web>
  <webDomains>
    <add>
      <factories>
        <add type="Sample.Web.Routing.ProcessorFactory, Sample.Web" />
      </factories>
    </add>
  </webDomains>
</themelia.web>

Lastly, processor factories are also installed using web components, thus showing once again that web components are the end all for the Themelia pipeline.  You register one Themelia web component and all your Themelia functionality is registered and running.

Links

Fundamentals of Themelia - Web Domains

Friday, August 15, 2008

This documentation has been updated for Themelia Framework 2.0 Beta 5.

A web domain is a Themelia 2.0 concept which is somewhat similar to an AppDomain.  MSDN describes an AppDomain as follows: "Represents an application domain, which is an isolated environment where applications execute."  The keyword here is "isolated" and anyone who has worked intimately work AppDomains you can appreciate their power of isolation.

You often create AppDomains when you want the ability to control what aspect of your application has what functionality (i.e. you cannot unload assemblies from an AppDomain, but you can unload AppDomains). The majority of your application may only have base level functionality, but maybe you want certain financial functionality, perhaps using a plug-in model, in a particular isolated area.  AppDomains are exactly what you need.  Well, Themelia 2.0 web domain analogously brings that functionality to the web (except you don't "unload" web domains; that makes no sense in a web model.)

With any .NET application there will always be at least one AppDomain.  In Themelia, there will always be one web domain, called the "root" web domain.  When you install any part of Themelia, you are installing it into a particular web domain.  HTTP handlers, error processors, pre processors, processor factories, aliased handler factories, injection processors, mid processors, fall through processors, post processors, and post state processors are all installed into web domains, not to your entire web site.  However, if you only have one web domain, then functionally these features actually are installed into your entire web site.

When you are using only one web domain, you barely even know you are using one.  For example, in the following simple Themelia configuration, you aren't using a web domain directly, so you forget about its existence:

<themelia.web>
  <webDomains>
    <add>
      <components>
        <add key="Security" type="Sample.Web.SecurityComponent, Sample.Web" />
      </components>
    </add>
  </webDomains>
</themelia.web>

However, take a look at following configuration based on the Minima 3.1 sample web site, you can see the web domains very clearly:

<themelia.web>
  <webDomains>
    <add>
      <components>
        <add key="Minima" type="Minima.Web.Routing.Component.MinimaComponent, Minima.Web">
          <parameters>
            <add name="page" value="/Page_/Information/Blog.aspx" />
            <add name="blogGuid" value="19277C41-7E4D-4AE0-A196-25F45AC48762" />
          </parameters>
        </add>
      </components>
      <handlers>
        <add matchType="contains" name="PassThrough" text="example.abc" />
      </handlers>
    </add>
    <add name="second" path="/second/" basedOn="root">
      <components>
        <add key="Minima">
          <parameters>
            <add name="page" value="/Page_/Information/Second.aspx" />
            <add name="blogGuid" value="B23115B1-42E8-46A2-88DE-A56CE505E7D0" />
          </parameters>
        </add>
      </components>
    </add>
  </webDomains>
</themelia.web>

In this example, you can see that there are two web domains.  Minima's core component is installed into the "root" (blank) web domain with one specific configuration and an extra HTTP handler.  Minima's core component is then installed into the "second" web domain with a different specific configuration and with no other features installed.

There are many things to notice about this.  First, notice that web domains require a name and a path.  If there is only one web domain, "root" is assumed, but you may feel free to explicitly set name to "root".  If you are using root, the path is ignored. Second, notice the "basedOn" attribute.  If you are familiar with WPF, then this should feel natural to you.  If not, prepare to learn two things at once.

In WPF, you can create a style for use by various visual entities or by a specific entity type (i.e. TextBox).  This style can have various properties set.  Your style might, for example, have a property setter for FontSize with a value of 14 and another property setter for BorderThickness with a value of 0.  You then create other styles which are based on this style by by setting the "BasedOn" XML attribute, giving the new style all the information from the old.  You may then add your own styles to the new one.  It's very similar to class-based inheritance in object-oriented programming (OOP).

In the same way, when you base one web domain on another, you essentially copy all of it's contents.  In this case, the "second" web domain copies the component information as well as the HTTP handler.  You may object by say "No, you completely declared the component again".  If you were thinking that, you lose some points.  If you look closer, I didn't have to set the component type in the web domain that is based on another web section with a component with the same key.

Also, it's important to note that all the parameters from the component in the "root" web domain copies to the component in the "second" web domain.  In the "second" web domain, I'm not setting the values so much as I am resetting them.  If I didn't override a parameter, the "root" parameter value would be used.  In other words, all inherited parameters are marked as "virtual".

Resetting

Sometimes you may not want to copy all of a web domain's content.  Perhaps you want all of it except for one part.  Fortunately, with Themelia you have that level of flexibility.  On a web domain element, you have an attribute titled "resetSeries", which may contains a comma separated list of codes used to specify what parts of a web domain you want to reset to an empty set.  Below is a list of codes you may use with a reset series.  These are not case sensitive and may be placed in any order.

  • handler
  • alias
  • redirect
  • pre
  • mid
  • post
  • postState
  • fallThrough
  • error
  • handlerFactory
  • processorFactory
  • objectFactory
  • component
  • denial

You may also use special group reset codes which will reset multiple segments of these.  There are two of these:

  • processor
  • factory

Here's an example of using these:

<add name="second" path="/second/" basedOn="root" resetSeries="handler,processor" />

With this mechanism you can have HTTP handlers active for one part of your system and completely nonexistent for another.  You could even have one handler handle one type of request in one web domain and have a completely different handler work in a different web domain.  Just reset that feature before adding your own.

Web Domain Inheritance Chain Example

You are allowed to have web domains based on web domains as long own an inheritance chain as you would like.  Perhaps you want folder /x/ to have one web domain and /x/y/ with a different web domain.  One web domain, for example, may handle the ".svc" extension using a custom service handler while a different web domain may handle the same extension using WCF (which, by the way, is done by setting .svc to use the PassThroughHttpHandler).

As I've mentioned before, all Themelia content is copied from one web domain to another.  That ability combined with resetting gives you a tremendous amount of flexibility to control what happens in your entire web site.  You can see an example of this in the following configuration snippet:

<themelia.web>
  <webDomains>
    <add name="finance" path="/finance/">
      <handlerFactories>
        <add type="ABCCorp.Web.Routing.CorporateHandlerFactory, ABCCorp" />
      </handlerFactories>
      <accessDenials>
        <add type="address" text="69.147.112.160" message="Go away" target="" enabled="true" />
      </accessDenials>
      <handlers>
        <add matchType="endsWith" name="ReportWriter" text=".xls" />
      </handlers>
    </add>
    <add name="sales" path="/finance/sales/" basedOn="finance">
      <accessDenials reset="true" />
    </add>
    <add name="marketing" path="/marketing/" basedOn="sales">
      <handlers reset="true">
        <add matchType="endsWith" name="ConverstionTracking" text="/tracking/" />
      </handlers>
    </add>
  </webDomains>
</themelia.web>

In this example we have four web domains: "root", "finance", "sales", and "marketing".  Under the /finance/ branch we are watching for any ".xls" access, sending requests to the ReportWriter handler.  We are also blocking any access from a specific IP address.  Under the /finance/sales" branch, like under the /finance/ branch, we are monitoring for ".xls".  However, we aren't blocking any access.  Finally, under the /marketing/ branch we aren't watching for ".xls" access nor are we blocking any addresses, however, we are looking for any access under "/marketing/tracking/", sending it to the ConverstionTracking handler. Finally, these are all sharing the same aliased handler factory to allow http handlers aliasing in a centralized location.

Default Pages

One of the core features of Themelia is that is disconnects the logical and physical representations of your web site,  For example, the logical paths /, /login/, and /logout/ may be point to the same physical /Sequence_/Security.aspx file and /contact/ and /suggestion/ may both share /Sequence_/Contact.aspx.  There's no relation between the two.  This is also true of the default document.

In Themelia, the /default.aspx is non-existent.  Themelia doesn't follow the paradigm of "web site root".  Instead, it uses this concept of a web domain.  Therefore, since you don't have a "web site root", but a "web domain root", the entire idea of /default.aspx is meaningless.

In Themelia, here's how you state to what page the "/" of your web site points:

<themelia.web>
  <webDomains>
    <add defaultPage="/Page_/Security/Login.aspx">
    </add>
  </webDomains>
</themelia.web>

The above code shows that we are in the default web domain (called "root") and that when the root of this web domain is accessed, internally load /Page_/Security/Login.aspx.

Now given that you may have numerous web domains in Themelia, you may, therefore, have multiple roots.  Each could even point to the same physical file.  For example:

<themelia.web>
  <webDomains>
    <add defaultPage="/Sequence_/Security.aspx">
    </add>
    <add name="sales" path="sales" defaultPage="/Sequence_/Security.aspx" />
    <add name="finance" path="finance" basedOn="sales" />
    <!---->
    <add name="public" path="public" defaultPage="/Page_/Information/Welcome.aspx" />
  </webDomains>
</themelia.web>

Activating the Root Web Domain Default Page

It's critical to note that the root web domain is treated as special by your web server.  This isn't because of anything in Themelia, but because the default document of the Themelia web domain, is the same as the default document for the web site that web server recognizes.  Therefore, to wake up the web server, all Themelia web sites require a blank file called default.htm in the root of the web site.

Links

Fundamentals of Themelia - Access Denial

Thursday, August 7, 2008

This documentation has been updated for Themelia Framework 2.0 Beta 5.

In addition to what you may think of as "positive" routing where routing goes to a living place, Themelia also provides "negative" routing with its access denial feature.  By using this simple feature you can block certain IP addresses, user agents, or HTTP referrers.  You may send them to a page with a simple message or forward them to another location.

Access denials are in the accessDenial collection and require a denial type, text, and either a message or target.  Here's an example of a very simple IP address denial:

<themelia.web>
  <webDomains>
    <add>
      <accessDenials>
        <add name="localBlock" type="address" text="127.0.0.1" message="Your IP address has been blocked" target="" enabled="true" />
      </accessDenials>
    </add>
  </webDomains>
</themelia.web>

This denial does nothing more than blocks your local host from seeing the web site at all.  If you were to look at any part of the web site from your local host IP address, you would see a simple message saying "Your IP address has been blocked".  If you have a target set, you will simply be redirected to that link.  If both a target and a message is set, the target takes precedence.

The following access denial demonstrates shows how you can use the target attribute to send people away:

<themelia.web>
  <webDomains>
    <add>
      <accessDenials>
        <add name="ie6Denial" type="useragent" text="MSIE 6.0" message="You're fired." target="http://www.getfirefox.com/" enabled="true" />
      </accessDenials>
    </add>
  </webDomains>
</themelia.web>

For example, if a particular forum post is constantly sending you people who wish to do nothing but write YouTube (a.k.a. bathroom wall) style comments on your blog, you can tell them to go away.  Or, better yet, send them away.  When the immature people stop expressing their extreme personal insecurities, you can either delete the entry or disable that entry by setting the enabled attribute to false.

You may also use the priority attribute (1, highest to 10, lowest) on an access denial to change the order in which the denials match the URL.  Logically, you should make sure that you're more specific or more important ones are at the topic.

Lastly, It's also important to note that access denials run before anything else in your Themelia pipeline.  Preprocessors won't even run.  So keep that in mind when using these denials.

Links

Creative Commons License
This work is licensed under a Creative Commons Attribution 2.5 License.

Powered by the Minima 3.1 and Squid Micro-Blogging Library.

Built on Themelia Framework 2.0

Developed using NetFXHarmonics DevServer 1.1.

(all of which are NetFXHarmonics products created by David Betz)

Mini-icons are part of the Silk Icons set of icons at famfamfam.com