Navigatie

Contact

Send mail to the author(s) E-mail

View Richard Soeteman's profile on LinkedIn

RSS 2.0 | Atom 1.0 | CDF

Archief

Categorieën

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Sign In

Zoeken

# Wednesday, 01 April 2009
Wednesday, 01 April 2009 21:24:15 (GMT Daylight Time, UTC+01:00) ( Umbraco )

This Blog is not active anymore, further posts will be available on my company website. Read new posts here

Last week I had a meeting with Nico Lubbers and we discussed the possibility of adding Dictionary Items on the fly. You can read in this post from Tim that it's been done before, but we want to make sure that it works in every situation (Template, Usercontrol and Xslt) and we don't want a baseclass for just adding items to the dictionary . Also we want logical keys (like savebuttonText, companynameLabel etc.) instead of generated keys. Basically we want the pain of adding  the dictionary items in the templates, usercontrols and xslt's  but we don't want the pain of adding  the dictionary items in Umbraco manually. Now before your read on I must warn you that the solution is not based on an architecture ;-)

What happens if Umbraco can't find a dictionary item?

When you add a dictionary item on a template, usercontrol or XSLT and Umbraco can't find it an exception is thrown. Umbraco will catch that exception and write it to the tracelog. For this blogpost I've used a standard Umbraco 4.0.1 instance with Runway and the modules contact form and standard navigation installed. In the example below I'be added a few non existing Dictionary items to my code.

Template

<umbraco:Item field="#Template_DetailHeader" runat="server"></umbraco:Item>

XSLT

<xsl:value-of select="umbraco.library:GetDictionaryItem('XSLT_FromDictionary')"/>

Usercontrol Markup

<%=umbraco.library.GetDictionaryItem("UserControl_Details") %>

Usercontrol Codebehind

lb_name.Text = umbraco.library.GetDictionaryItem("UserControl_LabelCaption"); 

Now when you view the page you will see empty places instead of the dictionary values. What's more interesting is to view the page with the queryparameter ?umbdebugshowtrace=true what shows you the trace info of the page like the image below.

traceinfo 

How can we get that data?

While it's nice that we can view the data, it would be great if we can parse the trace info and automatically add the missing dictionary items. This can be done using a Trace Listener, when an item is added to the trace you can configure 1 or more trace listeners that recieve the message then we can parse. In the  Class below I derive from the TraceListener class. The TraceListener methods calls the AddItemUnknown method which check the message with a regular expression. If the message can be parsed the unknow dictionary key is retrieved from the message and will be added to Umbraco. To ensure we will see the value when we refresh the page the key will also be added as the value for every language.

   1:  using System;
   2:  using System.Diagnostics;
   3:  using System.Text.RegularExpressions;
   4:  using umbraco.BusinessLogic;
   5:  using umbraco.cms.businesslogic.language;
   6:   
   7:  namespace SoetemanSoftware.Tools
   8:  {
   9:      public class AddUnknownDictionaryItemsListener : TraceListener
  10:      {
  11:          public override void Fail(string message)
  12:          {
  13:              AddItemWhenUnknown(message);
  14:          }
  15:   
  16:          public override void Fail(string message, string detailMessage)
  17:          {
  18:              AddItemWhenUnknown(message);
  19:          }
  20:   
  21:          public override void Write(string message)
  22:          {
  23:              AddItemWhenUnknown(message);
  24:          }
  25:   
  26:          public override void WriteLine(string message)
  27:          {
  28:              AddItemWhenUnknown(message);
  29:          }
  30:          public override void WriteLine(string message, string category)
  31:          {
  32:              AddItemWhenUnknown(message);
  33:          }
  34:   
  35:          /// <summary>
  36:          /// Parse at the message 
  37:          /// </summary>
  38:          /// <param name="message"></param>
  39:          private void AddItemWhenUnknown(string message)
  40:          {
  41:              try
  42:              {
  43:                  Match match = Regex.Match(message, "(Error returning dictionary item ')(.*)(' --)", RegexOptions.Multiline);
  44:                  if (match.Groups.Count > 1)
  45:                  {
  46:                      //Get key from the mach collection
  47:                      string key = match.Groups[2].Value;
  48:                      //Check if key is allready in Umbraco
  49:                      if (!umbraco.cms.businesslogic.Dictionary.DictionaryItem.hasKey(key))
  50:                      {
  51:                          //Add new key with default value to Umbraco
  52:                          int dictionaryID = umbraco.cms.businesslogic.Dictionary.DictionaryItem.addKey(key, string.Format("[{0}]", key));
  53:   
  54:                          var dictionaryItem = new umbraco.cms.businesslogic.Dictionary.DictionaryItem(dictionaryID);
  55:                          foreach (Language l in Language.getAll)
  56:                          {
  57:                              dictionaryItem.setValue(l.id, string.Format("[{0}]", key));
  58:                          }
  59:                          dictionaryItem.Save();
  60:                      }
  61:                  }
  62:              }
  63:              catch (Exception ex)
  64:              {
  65:                  //Logic may never break on this Listener
  66:                  Log.Add(LogTypes.Error, -1, string.Format("Error in Dictionary listener when adding item to dictionary {0} ", ex.Message));
  67:              }
  68:          }
  69:      }
  70:  }

Configure the TraceListener

When you want to use the TraceListener you have to configure it in the web.config. Add the following section to your web.config file.

    <system.diagnostics>
        <trace autoflush="true" indentsize="4">
            <listeners>
                <remove name="Default"/>
                <add name="AddDictionaryListener" type="SoetemanSoftware.Tools.AddUnknownDictionaryItemsListener,AddUnknownDictionaryItemsListener" />
            </listeners>
        </trace>
    </system.diagnostics>

Also modify the existing Trace element by adding the writeToDiagnosticsTrace="true". This will forward the ASP.NET trace messages to our AddUnknownDictionaryItemsListener. Simply set this attribute to false if you don't want the items to be added automatically.

<trace enabled="true" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" writeToDiagnosticsTrace="true" /> 

View the output

When you configured the trace listener and hit the page again the missing dictionary items are added to Umbraco.

dictionary items

Refresh the page again and you will see the following output

output

Sometimes you will encounter caching issues. When you want to avoid that use the umbdebugshowtrace=true querystring parameter which will prevent caching.

Download

You can download the DLL here. You can also dowload the source here.

Thursday, 02 April 2009 08:20:45 (GMT Daylight Time, UTC+01:00)
Superb trick!
Petr Snobelt
Wednesday, 15 April 2009 09:23:39 (GMT Daylight Time, UTC+01:00)
This is a really useful post, many thanks for this.
Ismail Mayat
Comments are closed.