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

Gems of Themelia - Map and Template

Thursday, July 31, 2008

Themelia isn't a monolith.  It couldn't be.  Whatever major features it may have, those features have to be built from smaller pieces and those smaller pieces are reusable.  You might call these caller pieces, the Gems of Themelia.  They are the components that make the Themelia world go round, not just the Themelia web world either.  These gems aren't even the Themelia.Web assembly, but are rather in the Themelia assembly ready for use in WPF, WCF, and console applications alike.  There are many of them and I'll discuss a piece here and there in various documentation entries.  In this entry: the Map and the Template.

At first glance, a Map looks like a regular .NET generic dictionary and in a sense, it is.  In fact, the idea behind a map is that some data is mapped to other data, which is basically what a dictionary is.  The thing that makes a Map a Map, however, is how the data is input and accessed.

A map comes in many varieties: the generic Map<T1, T2>, the Map, the StringObjectMap, among a few others.  The generic Map contains GetKeyList and GetValueList methods, both of returns a .NET List object.  The generic map also includes a PeekSafely method, which allows you to access data from the Map without having to check if it contains the key.  If the key doesn't exist, the default of the type is returned. In addition to this method, there's also the Pull method, which returns the value of a mapped pair and completely removes it from the Map.

The non-generic Map types inherit from the generic Map.  The most feature rich of these types is the type simply called Map.  This type adds a series of helpful methods to aide in more efficient development and code reading.  Besides having a AddMapEntrySeries, which allows quick addition of many MapEntry types, Map has a number of methods that accept what's called a Map pair, which is a string with the pattern "key=value".  Using the AddPair and AddPairSeries methods, you can add multiple values like this: map.AddPairSeries("FirstName=John", "LastName="Doe"), which, by the way, is the same signature as the constructor.  Here are some Map examples:

Map map = new Map("FirstName=John", "LastName=Doe");

//+ add single pair, pair series, and query string
map.AddPair("UserName=JohnDoe");
map.AddPairSeries("Email=johndoe@tempuri.org", "WebSite=www.tempuri.org");
map.AddQueryString("SpouseName=Jane Doe&Birthdate=04/14/1974");

The Map is used all over Themelia and Themelia-based web sites.  For example, a PayPal callback sends a query string-like, not in the URL, but in the content stream.  Using a map (as well as the Themelia.Web.HttpData class), we can do this:

String data = Themelia.Web.HttpData.InputContentString;
Map map = new Map(data.Split('&'));
String paypalId = map.Pull("payer_id"); 

In addition to this, you can could also create a Map with whatever data you wanted, then databind that data to a WPF ListView, a ASP.NET DropDownList, or whatever by the GetMapEntryList( ) method, which provides a List of MapEntry elements, allowing for binding to a Key and Value property.

Another Themelia type that's used regularly is called the Template.  This type makes code a lot easier to read.  You can setup a template to accept a number of parameters, you can call a template's Interopolate method to create a string based upon that template using the information from a map.  Given the previously shown example of a Map accepting a pair, a pair series, and query string, the following shows how the template can quickly quick very readable strings:

//+ template with pattern
String pattern = "My name is {FirstName} {LastName}; {Email}; {WebSite}; {UserName}; {SpouseName}; {Birthdate}";
Template person = new Template(pattern);

//+ Interpolate with data with string
Console.WriteLine(person.Interpolate(map));

This example uses replaces the appropriate sections in the template with the actually data in the map.  Compare that to the following:

Console.WriteLine(String.Format("My name is {0} {1}; {2}; {3}; {4}; {5}; {6}", firstName, LastName, email, webSite, UserName, spouseName, birthdate));

The template code is obviously more readable and manageable.  Furthermore, by using this, you can set up a base set of templates and just pass Maps around to create strings in a centralized manner.  Obviously, template patterns could easily be put into resources files too.

This isn't the end of the story with the Map as it will show up time and time again as it saves the day in many circumstances.  For more information, please see the intellisense documentation provided in Themelia.

Links

Dynamically Configuring HTTP Handlers in Themelia

Monday, July 28, 2008

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

One of the things that expert ASP.NET developers often find themselves doing is carefully inserting processes at just the right place in the ASP.NET pipeline and page life cycle. It's incredibly important for developers to have a strong familiarity with the ASP.NET order of operations. If you do something too early, a control may not exist or session may not be initialized. If you do it too late, any data you set will be overwritten.

Fortunately, if you aren't familiar with these concepts, there are many resources available to us. For example, Rick Strahl has written "A low-level Look at the ASP.NET Architecture" to help developers understand the order of these operations. Furthermore, MSDN contains an overview of the page life cycle eggheadcafe.com has a very detailed reference image.  Then there's a PowerPoint presentation by the queen of all architecture everywhere, Michele Leroux Bustamante, entitled "Inside the ASP.NET Runtime - Intercepting HTTP Requests".  For those of us who are already well versed in the ASP.NET pipeline and page life cycle, these are great reference to which we can turn when we (by we I mean me) forget a thing or two after not doing any pipeline hacking for a while.

Themelia Order of Operations

Within the ASP.NET pipeline and the page life cycle, Themelia runs after all HTTP modules have run, but, because Themelia is the creator of the HTTP handler, before an HTTP handler has been created. This means that you are able to modify HTTP handler properties or even call HTTP handler method before the handler themselves ever run. Granted, the former situation makes more sense than the latter, but the option for method call does exist.

To understand how this is possible, you must first understand the various parts of Themelia as explained in previous posts.  You must also know the Themelia order of operations. Here is a quick run down of the order of operations within Themelia:

  • ConfigurationPreProcessor (loads configuration information)
  • DebugPreProcessor runs
  • WebDomainPreProcessor runs
  • DefaultPagePreProcessor runs
  • Web Components Load
  • PreProcessors run
  • Exit if PassThroughHttpHandler.ForceUse was set
  • Handler Factory Load
  • Injection Processor Load
  • MidProcessors run
  • If no handler was set yet, HTTP Handler Matching Happens; otherwise skip to post processing
  • If no handler is found, the fall through processor runs
  • If no handler is found, pass the request through to IIS
  • PostProcessors run
  • SessionPostPostProcessor runs
  • PostStateProcessors run
  • Continue ASP.NET Pipeline

Dynamically Configuring HTTP Handlers

As this information demonstrates, an HTTP handler will always be set by the time the post processors run. Therefore, if you create an HTTP handler containing properties, you may use a postprocessor to configure that handler.  By doing this, when the HTTP handler itself runs, it will have the information required for its own logic.

For instance, if you want to create an efficient Windows Workflow Foundation ("WF") sales reporting workflow activator, you could create a lightweight HTTP handler that did nothing but run that specific workflow. Using Themelia, you may then create a postprocessor designed to configure that specific HTTP handler. This configuration might be nothing more than setting a the workflow activity type.  The following snippet shows what we're talking about:

public class SalesStatisticsWorkflowPostProcessor : Themelia.Web.Routing.PostProcessorBase
{
    public override IHttpHandler OnPostProcessorExecute(HttpContext context, IHttpHandler activeHttpHandler, params Object[] parameterArray)
    {
        ReportingWorkflowHttpHandler handler = activeHttpHandler as ReportingWorkflowHttpHandler;
        if (handler != null)
        {
            handler.ReportWorkFlowActivity = "Sales.Workflow.StatisticsActivity, Sales.Workflow";
        }
        //+
        return handler;
    }
}

In this particular example, the HTTP handler is abstracted away from any workflow activity.  It's the post processor that provides this information.  Developers could extend this further by utilizing Themelia web components, creating prepacked processors per department for specific workflow activity sets. Or, if the developers really thought ahead, they could use some of Themelia's supporting helping features to determine what workflow HTTP handler to run based upon a REST-style URL. For example, take a look at the following Themelia postprocessor with its associated registration:

public class SalesWorkflowPostProcessor : Themelia.Web.Routing.PostProcessorBase
{
    public override IHttpHandler OnPostProcessorExecute(HttpContext context, IHttpHandler activeHttpHandler, params Object[] parameterArray)
    {
        ReportingWorkflowHttpHandler handler = activeHttpHandler as ReportingWorkflowHttpHandler;
        if (handler != null)
        {
            String pattern = "Sales.Workflow.{0}Activity, Sales.Workflow";
            if (Http.GetHttpPart(Http.Position.Antepenultima) == "report")
            {
                String reportName = Themelia.Case.GetPascalCase(Http.GetHttpPart(Http.Position.Ultima));
                handler.ReportWorkFlowActivity = String.Format(pattern, reportName);
                handler.Region = Http.GetHttpPart(Http.Position.Penultima);
            }
        }
        //+
        return handler;
    }
}

Here is the associated HTTP handler registration for ReportWorkflowHttpHandler (obviously, there would be a aliased handler factory used here, but that's not important for out discussion):

<add matchType="contains" name="ReportingWorkFlow" text="/report/" />

In this example, the postprocessor checks to see if the HTTP handler that is going to run is ReportingWorkFlowHttpHandler.  If so, the postprocessor checks to see if the third to the last part of the URL is "report". If this is the case, then the last part of the URL is set as the workflow activity name and the second to the last part of the URL is set as the workflow sales region. For example, "http://www.netfxharmonics.com/workflow/report/signapore/demographic/" would run the "Sales.Workflow.DemographicActivity, Sales.Workflow" while "http://www.netfxharmonics.com/workflow/report/kansascity/annual/" would run the "Sales.Workflow.AnnualActivity, Sales.Workflow". The custom workflow HTTP handler would also have the region information ready to send to WF.

There's one final concluding thought that I would like to mention in passing. Since Themelia provides the SessionPostStateProcessor which allow adding to session before session state is initialized, adding to ASP.NET session is essentially available at every point in Themelia. Therefore, you may feel free to utilize session in your processors as you see fit. In this example, perhaps you would like to create a preprocessor that pulls the penultimate (second to the last) position of the URL and inserts a custom object into session based on that information so all future processors will have it available.

Links

Fundamentals of Themelia - HTTP Route Debugging

Thursday, July 24, 2008

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

One of the most important aspects of development is unfortunately debugging.  We shouldn't have to do it.  Stuff should just work.  However, as it stands, we all type stupid stuff.  Computers are deterministic and if there's a problem somewhere in an application, you don't blame the computer, you blame the programmer, network administrator, or, preferably, the project manager.  So, we need to be able to debug our work and Themelia HTTP routing is no exception.

When working with Themelia, we will register many processors and various handlers.  However, what happens when we have a typo?  As it stands, in Themelia, nothing happens. The last thing anyone needs is your web site to shutdown just because someone forgot that a particular HTTP handler was moved from the Commerce to the Commerce.Web assembly.  Therefore, you never have to worry about your web site shutting down because of a faulty component. If Themelia did throw exceptions on faulty exceptions the situation would be analogous to a process leaking its fault resources (i.e. memory) into another process.  No thanks.

Now, while it's great that your web site won't explode, without errors, there can be no true debugging. In other words, how in the world can we figure out what's wrong with our routing? To make matters worst, if you are building a complex Themelia web component, the error could be a single letter missing in any of a dozen of places. So goes all development.

Because of this, we may use Themelia's information reporting capabilities to aide in HTTP routing debugging.  Now, while complete coverage of Themelia's reporting capabilities is far beyond the scope of this entry, we will make use of it for routing debugging.  Thus, for now, we do need to have a very tiny introduction to what's entailed in Themelia reporting.

Themelia's reporting model is not in the Themelia.Web assembly, but rather in the Themelia assembly thus making it non-web specific and ready for use in WPF, WCF, console, and web applications alike.  As such, there's also a different configuration section for it: themelia.system, which is registered in your app.config or web.config as such:

<configSections>
  <section name="themelia.system" type="Themelia.Configuration.SystemSection, Themelia" />
</configSections>

The actual configuration area looks like this:

<themelia.system>
  <appInfo name="My Web Site" />
  <reporting>
  </reporting>
</themelia.system>

Themelia reporting, though a large topic, can be boiled down the one simple concept: the reporter.  A reporter is simply a combination of a report creator, a formatter, and a sender.  Report creators create, formatters format, and senders send. Thus ends the mini-explanation of Themelia reporting!

To enable HTTP route debugging, you simply need to register a reporter with the name WebRouteDebug.  For the time being, use the following settings:

<themelia.system>
  <appInfo name="My Web Site" />
  <reporting>
    <reporters>
      <add name="WebRouteDebug" creator="Map" sender="EventLog" formatter="Wiki" />
    </reporters>
  </reporting>
</themelia.system>

These settings mean to use the map report creator and save the report in Wiki format in the Event Log.  You could easily replace EventLog with a another sender and Wiki with another formatter, but the regardless of what you set as the report creator, Themelia web routing will force the map report creator.  But, this isn't a lesson on reporting, so that's a discussion for a different time.

Once this is simple reporter is activated, Themelia's HTTP routing engine will automatically start logging all exceptions thrown within it's boundaries.  The errors will be cataloged together, passed through the map report creator, formatted to the Wiki (yes, as in Wikipedia formatting; it's cooler than plain text) and saved to the Themelia event log.  That's seriously all there is to it.  To disable that particular report, just comment out the XML line or set enable to "false"; it's true by default.

One final thing one reporting that should be said is that reporting is not strictly a debugging mechanism.  There is no excessive cost for running it (and you could use the individual parts of reporting as well; I use Themelia report creators and formatters all over the place outside of reporting). So, you could theoretically leave it on at all times, but since it deals mostly with setup, you really only need to have HTTP route debugging enabled while you are debugging the configuration.  It kind of seems meaningless to leave it in this context.

Links

Fundamentals of Themelia - Web Components

Monday, July 14, 2008

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

In a previous Themelia post, I discussed some of the advanced HTTP routing features in Themelia. In this post, I would like to introduce a Themelia concept that ties each of the advanced features together into a single unit: a Themelia Web Component

In essence, a Themelia web component is a package that automatically registers pre processors, processor factories, handler factories, mid processors, post processors, post state processors, error processors and a fall through processor. The idea is that by creating a web component, a developer may centralize all Themelia routing registration and configuration. Therefore, using a web component, you may now think of web development and HTTP routing in terms of componentization.

One major example of a web component is in Minima 3.1, which is completely packaged into a web component. As you can see from the below configuration snippet, installation of Minima is nothing more than the registration of a Themelia web component:

<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>
    </add>
  </webDomains>
</themelia.web>

The registration of a Themelia web component should look fairly straight forward. In the components collection in web.config, just add in your component. Themelia will load the web component and automatically install any Themelia pipeline features that are in the web component.

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

public  void Register(FactoryDataList factoryDataList, ProcessorDataList processorDataList, HandlerDataList handlerDataList, AliasDataList aliasDataList, RedirectDataList redirectDataList);

Inside of the Register method, you then add the various Themelia parts to the appropriate list using a static method on the Data class for a particular entity.  Here's an example of how you add a factory to the factoryDataList:

factoryDataList.Add(FactoryData.Create("Sample.Web.Routing.ProcessorFactory, Sample.Web"));

If the factory, processor, handler, alias, or redirect accepts initialization parameters, you may also set them by just adding them as arguments:

processorDataList.Add(ProcessorData.Create<ProcessorData>("ForbiddenFallThroughProcessor", new Object[] { "This page is not publicly accessible" }));

Notice how the ProcessorData accepts a generic value.  For all processors other than and error processor, you may use the ProcessorData type.  However, for error processors you must use ErrorProcessorData.  Here's an example:

processorDataList.Add(ProcessorData.Create<ErrorProcessorData>("SavingError"));

Handlers, aliases, and redirects are created the same way as processors and factories.  Here's an example of a handler registration:

handlerDataList.Add(HandlerData.Create("Authentication", "webDomainPathStartsWith", "/authenticate/"));

At this point you should understand how to programmatically register your elements fairly well.  Here's a complete component example which ties together the past few examples:

public class SecurityComponent : Themelia.Web.Routing.ComponentBase
{
    //- @Register -//
    public override void Register(FactoryDataList factoryDataList, ProcessorDataList processorDataList, HandlerDataList handlerDataList, AliasDataList aliasDataList, RedirectDataList redirectDataList)
    {
        factoryDataList.Add(FactoryData.Create("Sample.Web.Routing.ProcessorFactory, Sample.Web"));
        factoryDataList.Add(FactoryData.Create("Sample.Web.Routing.HandlerFactory, Sample.Web"));
        processorDataList.Add(ProcessorData.Create<ProcessorData>("ForbiddenFallThroughProcessor", new Object[] { "This page is not publicly accessible" }));
        processorDataList.Add(ProcessorData.Create<ProcessorData>("HandlerRegistration"));
        processorDataList.Add(ProcessorData.Create<ErrorProcessorData>("SavingError"));
        handlerDataList.Add(HandlerData.Create("Authentication", "webDomainPathStartsWith", "/authenticate/"));
    }
}

That's all there is to it.  You can either register your elements in configuration or register them in a reusable or deployable component.  The option is yours.

Component in Web Domain Inheritance

When working with web domain inheritance, components are also copies along side processors, factories, and other elements.  Because of this, you do not need to declare the component type in more than one location.  This will be copies along with the component's contents.

Furthermore, the parameters of a component are also copied.  Because of this, you are also allowed to override individual parameters to change the value.  In the following example, there are two web domains.  The second copies all of the contents of the first, including parameters, but it changes the value of one of them.

<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>
    </add>
    <add name="second" path="second" basedOn="root">
      <components>
        <add key="Minima">
          <parameters>
            <add name="blogGuid" value="A47C9A9F-5F5B-4b24-A032-992CEDE640C6" />
          </parameters>
        </add>
      </components>
    </add>
  </webDomains>
</themelia.web>

You also have the option to reset all parameters in a component when doing web domain inheritance.  Due to the completely different nature of component parameters from web domain elements, resetting them works differently.  While you use the resetSeries attribute on a web domain to erase entire handlers or processors, when working with component parameters, all you need to do is set the reset attribute on the parameters element to true.  Here's an example:

<themelia.web>
  <webDomains>
    <add>
      <components>
        <add key="Sample" type="Sample.Component, Minima.Web">
          <parameters>
            <add name="personId" value="2" />
          </parameters>
        </add>
      </components>
    </add>
    <add name="second" path="second" basedOn="root">
      <components>
        <add key="Sample">
          <parameters reset="true">
            <add name="firstName" value="john" />
            <add name="lastName" value="doe" />
          </parameters>
        </add>
      </components>
    </add>
  </webDomains>
</themelia.web>

Links

Fundamentals of Themelia - Default Index Redirection

Thursday, July 3, 2008

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

Today I would like to introduce an HTTP routing concept of Themelia called default index redirection (or just index redirection). This feature helps me manage my web sites a little better than usual, though it probably won't be that big of a deal to most people. As it stands, though, I personally can't standing having similar files being disorganized all over a folder structure. For example, I have no idea how anyone can put up with having active web forms (web forms being used as web forms) in different folders all over a web site.

Therefore, to help me manage a web site, I like to put my basic web forms in a logical organization structure un the /Page_/ branch and let Themelia do all the URL rewriting. Even then, there's still that pesky default document in the root. Not only does that break my pattern of active web forms, but I still have a page that requires management in the root of my web site. No thanks.

Therefore, Themelia gives the ability to move your default document to another location so all active web forms may live together in peace. This is possible through Themelia's index redirection feature.

To use this feature, set the defaultTarget attribute on the Themelia rewrite element to your true default document. Then, to trick IIS into loading the web site, create a blank file in your root called Default.htm; this also means you will need to add Default.htm as a default document in IIS. The following Themelia configuration snippet demonstrate the setup:

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

To stop the flow of about a million questions, yes, this feature is functionally the same as putting a Service.Transfer("/Pages_/Security/Login.aspx") in your default document. However, this couples configuration directly with your web application. Furthermore, the point of using this default.htm file is to signal to the world that it's not to be used. Otherwise, some intern will come along and add more code to your /default.aspx file. Therefore, in my web sites, the default.htm stands as a big "Go Away" sign containing only the test "This page intentionally left blank."

Internals

The index redirection feature is a prime example of a preprocessor and midprocessor working together. Internally, Themelia runs IndexRedirectPreProcessor::OnPreHttpHandlerExecute to check to see if the request is for the default document and if index redirection is active. This is actually the internal Themelia preprocessor that uses the parameter array as the following snippet shows:

new IndexRedirectPreProcessor().OnPreProcessorExecute(context, midProcessorList);

IndexRedirectPreProcessor will then do a few checks to see if index redirection should occur. If so, IndexRedirectPreProcessor adds IndexRedirectMidProcessor to the midProcessorList parameter so that Themelia will load IndexRedirectMidProcessor when it runs though midprocessors. IndexRedirectPreProcessor also sets two HTTP context items so as to communicate with IndexRedirectMidProcessor and the URLRewriteHttpHandler, one item stating that URL rewriting must occur and the other stating the true index redirection path.

Later when Themelia runs through the various midprocessors, it will run the previously registered IndexRedirectMidProcessor. IndexRedirectMidProcessor then checks to see if IndexRedirectPreProcessor has requested it to start URLRewriting. If so, it returns an instance of UrlRewriteHttpHandler. If you recall, midprocessors have the power to basically skip over the HTTP selection process. In this case, by returning an instance of UrlRewriteHttpHandler to Themelia, IndexRedirectMidProcessor is effectively telling Themelia to run URL rewriting regardless of the HTTP handler selection algorithm or any fallthrough processor (a postprocessor can, however, alter this.)

When the UrlRewriteHttpHandler runs, it checks the other context item set by IndexRedirectPreProcessor to see if an index redirect path was found. If so, the root default document (default.htm) is rewritten to true real default document.

This information should help you to further understand how you may further exploit Themelia's advanced HTTP routing features.

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