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

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

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

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