Extending Umbraco uCommerce with custom Service

First of all. Umbraco is great .NET open source CMS. uCommerce is an e-commerce package for Umbraco (even though they have scary foreign-language banner on the main page right now, they are pretty much English-speakers. Honest!)

Of course there are plenty of articles on how to add own functionality to uCommerce Services, but before I have done it myself, I never thought it would be so easy.

Problem: items with   in it's title have unicode character for nonbreaking space in link address.

What I want: I want every "special" character to be replaced with default "-" dash.

How can I achieve that? First of all I was thinking about default Umbraco settings:

<urlReplacing removeDoubleDashes="true">
    <char org=" ">-</char>
    <char org=" ">-</char>
    <char org="&quot;"></char>
    <char org="'"></char>
    <char org="%"></char>
    <char org="."></char>
    <char org=","></char>
    <char org=";"></char>
    <char org="/"></char>
    <char org="\"></char>
    <char org=":"></char>
    <char org="#"></char>
    <char org="+">plus</char>
    <char org="*">star</char>
    <char org="&amp;"></char>
    <char org="?"></char>
    <char org="æ">ae</char>
    <char org="ø">oe</char>
    <char org="å">aa</char>
    <char org="ä">ae</char>
    <char org="ö">oe</char>
    <char org="ü">ue</char>
    <char org="ß">ss</char>
    <char org="Ä">ae</char>
    <char org="Ö">oe</char>
    <char org="|">-</char>
    <char org="&lt;"></char>
    <char org="&gt;"></char>

It just was not working. I even dig deep into Umbraco sources, only to find out few hours later, that this method is not even being called for uCommerce items. Is there a good reason for uCommerce to not use default Umbraco functionality? Not sure.

Once I realized it's done in uCommerce UrlService, it was a matter of minutes to fix. Having ReSharper with on-the-fly decompilation really helped too. Here is what I see in default UrlService sources:

protected virtual IDictionary<string, string> GetReplacements()
    IDictionary<string, string> dictionary =
(IDictionary<string, string>) new Dictionary<string, string>(); dictionary.Add("ø", "oe"); dictionary.Add("æ", "ae"); dictionary.Add("å", "aa"); dictionary.Add("ö", "oe"); dictionary.Add("ä", "ae"); dictionary.Add("ü", "ue"); dictionary.Add("ß", "ss"); dictionary.Add(" ", "-"); dictionary.Add("\"", ""); dictionary.Add("&", ""); dictionary.Add("?", ""); dictionary.Add("%", ""); dictionary.Add(":", ""); dictionary.Add("<", ""); dictionary.Add(">", ""); dictionary.Add("/", ""); dictionary.Add("+", ""); dictionary.Add("*", ""); dictionary.Add("{", ""); dictionary.Add("}", ""); dictionary.Add("#", ""); dictionary.Add("\\", ""); dictionary.Add("¢", ""); dictionary.Add("£", ""); dictionary.Add("¥", ""); dictionary.Add("€", ""); dictionary.Add("§", ""); dictionary.Add("©", ""); dictionary.Add("®", ""); dictionary.Add("™", ""); return dictionary; }

Now I just override it in my own inherited class:

public class BetterUrlService : UrlService
    public BetterUrlService(ILocalizationContext localizationContext)
        : base(localizationContext)

    protected override IDictionary<string, string> GetReplacements()
        var dictionary = base.GetReplacements();
        dictionary.Add(",", "");
        dictionary.Add(" ", "-");
        dictionary.Add("«", "");
        dictionary.Add("»", "");
        dictionary.Add("—", "-");

        return dictionary;

And then I should tell uCommerce about my Service:

	Custom configuration for uCommerce components.

	Find the ID of component you want to override
	and use the same ID here. Your component will
	override the default.

	You can configure new components here as well
	and have them injected into existing ones.
<component id="UrlService"
service="UCommerce.Catalog.IUrlService, UCommerce"
type="UCommerce.RazorStore.Code.Services.BetterUrlService, UCommerce.RazorStore"/> </components> </configuration>

That's it! Just override and drop a line into xml file! Now characters in address bar are filtered according to my rules. You can watch it work here, for example (warning: Russian language).