Subscribe
Twitter
Search

Zetetic.Chain - .NET / C# "Chain of Responsibility" Library

Zetetic.Chain is a .NET / C# library implementing the "chain of responsibility" concept, very much like Apache Commons Chain. Zetetic.Chain is released under a BSD-style license.

Zetetc.Chain on Github

What is it?

Zetetic.Chain makes it easy to build flexible, loosely-coupled systems, where you can simply run commands by name rather than by embedding a lot of logic and dependencies in your code. Later, you can change and review the behavior of these commands via configuration. This results in cleaner, testable, maintainable code in your application.

Why should I use Zetetic.Chain?

Because Zetetic.Chain offers a robust feature set, including:

  • Serialization.

    Serialization of properties into real data types.

  • Factories

    Factories for creating chains help you to reduce code.

  • .NET Remoting

    Utilize .NET remoting to execute commands on remote hosts.

How It Works

Zetetic.Chain is a .NET / C# library implementing the “chain of responsibility” concept, very much like Apache Commons Chain . Zetetic.Chain is released under a BSD-style license.

Zetetic.Chain makes it easy to build flexible, loosely-coupled systems, where you can simply run commands by name rather than by embedding a lot of logic and dependencies in your code. Later, you can change and review the behavior of these commands via configuration. This results in cleaner, testable, maintainable code in your application.

For example, if you’re building an application to do something complicated, like ordering the ingredients online to make lemonade, you might not yet know all the steps required to make that happen in real life. And, your ingredient list or online store may change someday, and you might switch payment methods, so you don’t want to build these dependencies in unnecessarily. Using Zetetic.Chain, your code might look like this:

context["GlassesOfLemonade"] = 10;
context["CustomerId"] = "Me";
catalog["OrderLemonadeIngredients"].Execute(context);

All we’ve done here is store some contextual information – how many glasses worth of ingredients we need to order, and for whom – and passed it on to the “OrderLemonadeIngredients” command.

Zetetic.Chain locates the command by name and manages the execution of everything involved in the process. The registry for these commands is the Catalog. Zetetic.Chain includes facilities to read and write the Catalog in XML, and automatically ensures that the commands you include are configured before use.

Sticking with our lemonade example, the Catalog to support ordering ingredients might look like this:

<catalog>
  <chain name="OrderLemonadeIngredients">
    <command name="VerifyQuantity" .... />
    <command name="GetNumberOfLemons" .... />
    <command name="GetTablespoonsOfSugar" .... />
    <command name="GetShippingAddress" .... />
    <command name="GetPaymentInfo" .... />
    <command name="SubmitVendorOrder" .... />
    <command name="RecordReceiptDetails" .... />
  </chain>
</catalog>

In this case, the command named “OrderLemonadeIngredients” is actually a Chain – a series of steps – but the part of your application that just wants to “get it done” doesn’t need to know that.

You can add, modify, and remove steps – like validation to make sure we don’t try to order more than 50 glasses’ worth of ingredients at once – without changing the bulk of your code. Just add another simple command to take a look at the context, and throw an exception if you don’t like what you see. Zetetic.Chain will stop executing the order, and will give each of the commands that already fired an opportunity to handle the exception.

Sample Catalog

Let’s consider a web application that needs to add some data to the user’s session from an LDAP datastore and, separately, log an event to a file or database. This catalog demonstrates a catalog with two commands you can invoke – “userchain” and “audit.”

<?xml version="1.0" encoding="utf-8" ?>
<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns="http://zetetic.net/schemas/chain/catalog.xsd">
  <chain name="userchain">
    <command name="userinfo" typeName="Demo.GetUpnCommand, Demo">
    </command>
    <command name="Surname" typeName="Demo.LdapSearchCommand, Demo">
      <add key="LdapItem" value="sn" />
      <add key="SessionItem" value="LASTNM" />
      <add key="Attributes" value="sn" />
      <add key="Filter" value="(|(uid={0})(sAMAccountName={0}))" />
      <add key="LdapConfig" value="ldap1" />
    </command>
    <command name="Groups" typeName="Demo.LdapSearchCommand, Demo">
      <add key="LdapItem" value="distinguishedName" />
      <add key="SessionItem" value="GROUPDNS" />
      <add key="Attributes" value="1.1" />
      <add key="Filter" value="(|(member={0})(uniqueMember={0}))" />
      <add key="LdapConfig" value="ldap2" />
    </command>
  </chain>
  <command name="audit" typeName="Demo.SqlAuditor, Demo">
      <add key="Connection" value="MyConnectionString" />  
  </command>
</catalog>

As shown, you can reuse the same ICommand implementation class in multiple places with different configuration properties. The "key"s correspond to public properties of each command type/class. (See the general-purpose commands in Zetetic.Chain.Generic for a few quick examples.)

Usage of the catalog and its commands is straightforward:

ICatalog catalog = CatalogFactory.GetFactory().GetCatalog("mycatalog.xml");
IContext context = new ContextBase();
context["just testing"] = true;

catalog["userchain"].Execute(context);
catalog["audit"].Execute(context);

That’s all there is to it. With well-designed commands and chains, you won’t have to change your application code to pull in more values from the hypothetical LDAP source. The automatic configuration/property mapper in Zetetic.Chain means it’s often easier and more natural-feeling to make this stuff more flexible than less!