Tag Archives: broker

DD4T.Web: Publication Resolving

The next DD4T release (1.30) which will be out shortly, features a new .NET library: DD4T.Web. This library contains functionality which can be used within a .NET web application, regardless of whether you are using MVC or not. In a short series I will introduce the most important functionality in this library. This episode: Publication Resolving.

 

DD4T is all about URLs. When the request comes in, the framework looks in the Tridion broker database for pages with a matching URL. Or rather: a matching path. For example: if the URL is http://www.acme.com/products/foobar.html, the path is /products/foobar.html.

But what if there are more matches? This is entirely possible because of Tridion’s BluePrinting model. Imagine the Acme corporation decides to launch a German web site, with the base URL http://www.acme.de. They manage this site in a Tridion publication which is a child of their ‘dotcom publication’ (which manages the www.acme.com site). Given the nature of BluePrinting, the German page about their ‘Foobar’ product, will have the url http://www.acme.de/products/foobar.html, and the path of this page is /products/foobar.html.

As you see, the path is identical to the path in the English publication. So how can DD4T tell which page to serve? This is done by the PublicationResolver. This is a very simple class, whose job it is to find out which publication the current request belongs to. In the example above, the PublicationResolver could look at the host name and return the correct publication id: if the host name is ‘www.acme.de’, it should return the id of the German publication, if it’s ‘www.acme.com’ it returns the id of the DotCom publication.

Resolving the publication based on the host name is an obvious choice in many cases, but there are alternative scenarios. For example: you could look at the preferred browser language and base the publication id on that. So: if my browser language is German, I will see the German site, regardless of the host name. Technically, I wouldn’t need the www.acme.de domain at all (although I don’t think Google will like it if the same URL can return a page in different languages!)

And then there is the simplest form of all: you can simply decide that all the requests in your web application should use the same publication id. This is actually the default behavior. DD4T comes with one implementation of the PublicationResolver interface, the DefaultPublicationResolver, and it simply looks in the Web.config for an appSetting called ‘DD4T.PublicationId’. This id is then used to look up all the pages, components and binaries. The downside is of course that you need to set up a separate web application for each language that you’re supporting. Not very efficient and tough to manage!

 

Implement your own resolver

It’s very easy to write your own publication resolver.

  • First, create a class library project in Visual Studio.
  • Add a class which implements the DD4T.ContentModel.Contracts.Resolvers.IPublicationResolver.  
  • Right-click the word IPublicationResolver and select ‘implement interface’.

Your code now looks like this:

using System;
using System.Web;
using DD4T.ContentModel.Contracts.Resolvers;

namespace Trivident.DD4T.Examples.PublicationResolvers
{
   public class HostNamePublicationResolver : IPublicationResolver
   {
      public int ResolvePublicationId()
      {
      }
   }
}

As you see, this interface defines only one method: ResolvePublicationId(). In that method, we will check the host name in the URL and use it to determine the publication id. In a very simple (not to say a moronic) form, the code might look like this:

using System;
using System.Web;
using DD4T.ContentModel.Contracts.Resolvers;

namespace Trivident.DD4T.Examples.PublicationResolvers
{
   public class HostNamePublicationResolver : IPublicationResolver
   {
      public int ResolvePublicationId()
      {
         switch (HttpContext.Current.Request.Url.Host)
         {
            case "www.acme.de":
               return 17;
            case "www.acme.com":
               return 16;
         }
         throw new InvalidOperationException(string.Format("unknown hostname '{0}", HttpContext.Current.Request.Url.Host));
      }
   }
}

In a real life implementation you would probably want to get rid of the hardcoded IDs, but the point is clear, I hope.

Using  it in your application

The PublicationResolver is a property of the factories (PageFactory, ComponentFactory, BinaryFactory, LinkFactory). If you’re using a dependency injection framework (like MEF or Unity) you can simply configure it as a dependency of those factories. Otherwise, you can set it manually (in code). In your PageController for example:

 

private IPageFactory _pageFactory = null;
public override ContentModel.Factories.IPageFactory PageFactory
{
   get
   {
      if (_pageFactory == null)
      {
         _pageFactory = base.PageFactory;
         _pageFactory.PublicationResolver = new HostNamePublicationResolver();
      }
      return _pageFactory;
   }
}

 

Using DD4T without publication resolving

It’s possible to use DD4T without doing any publication resolving. In that case the publication is not used when looking up the page in the broker database. This works if all the paths in your system are unique. So in our Acme example, the URLs of the English and German ‘foobar’ pages should be:

  • http://www.acme.com/products/foobar.html (English)
  • http://www.acme.com/de/products/foobar.html (German)

In this case, DD4T can and will always find the correct page.

If ‘the business’ can live with this style of URL, then go for it. It saves you the trouble of resolving anything!

To use this approach, just use the default publication resolver (this requires no action) and remove the key ‘DD4T.PublicationId’ from the Web.config.

 

 

 

 

Tridion and JMS: removing another SPOF

When you use Tridion’s content delivery API to retrieve dynamic content, resolve links, etcetera, you are well advised to use the built-in caching mechanism. Without it, every page request would result in dozens of queries on your broker database (or dozens of data files being opened, which is just as bad for performance). With caching, most requests can be handled completely from memory, which makes your site a lot faster.

There is one catch to caching: Tridion being a content management system, it is highly likely that the content and links will change from time to time. That is why Tridion offers a notification system, so that your web application will always show content which is up to date and links that lead to the correct destination.

Actually, Tridion offers not one such notification system, but two. Most implementations use the so-called Cache Channel Service. This is a proprietary service which runs as a windows service or a stand-alone java process. Its job is to notify the broker instances when a new version of an item has been published to the broker repository. The Cache Channel Service uses the RMI protocol to communicate between the different virtual machines (which contain the broker instances).

Although this is certainly the most popular notification mechanism, it has some drawbacks:

  • RMI is not a messaging protocol, so things might go wrong when the Cache Channel Service is temporarily down. Fortunately, Tridion has solved this by some clever programming in the broker, but it is still a work-around which makes the CCS slightly unstable at times.
  • RMI uses unpredictable ports, which means that all ports > 1024 must be open between all your machines running a Tridion broker and the one running the CCS.
  • There is no easy way to handle multiple channels (like a staging site, a live site, a mobile site, development environments, etc). You can only achieve this by running more than one CCS instance, which means running multiple processes, each on a different port, or even running the CCS on multiple machines.
  • The CCS is a single point of failure (SPOF), since it cannot be scaled up.

As a solution architect, I find these disadvantages quite unsettling. Especially the last one: removing single points of failure from a solution is what we architects drool over.

Fortunately, SDL has come up with an alternative notification system. Instead of installing the CCS, you can also install a JMS instance. JMS – Java Message Service – is Java’s messaging system. There are many implementations available, including free ones like Apache’s ActiveMQ.

JMS is designed to pass messages from one application to another. These messages are organized in containers called ‘topics’. Applications can subscribe to a topic. Whenever a message becomes available in this topic, it will be passed on to all subscribing applications.

JMS addresses each of the problems of the Cache Channel Service mentioned above:

  • JMS can work over http on a fixed port (typically 61616, but it can be configured to run on any port including 80)
  • Multiple channels can be accommodated on a single JMS instance by simply configuring extra topics
  • Since JMS works on http, it can easily be accessed through a load balancer. This removes the single point of failure from the architecture.
There is a common idea about JMS, and that is that it would be unsuited for a .NET presentation stack. This idea is incorrect. I can guarantee that the solution will work just as fine if your web site is on IIS. After all, the content broker core is always Java, and it is this core that does the communication through JMS.

Where’s the catch then? Well, there isn’t any, other than the lack of awareness of this solution in the Tridion community, and the lack of configuration examples in Tridion’s product documentation. But with some perseverance, the help of this excellent post by Julian Wraith and – if necessary – the assistance of Tridion customer support, it can certainly be done. The end result is a more stable and more robust solution.