Wintellect  

Browse by Tags

All Tags » fluent interfaces   (RSS)

One of the most common examples to help learn a language or framework is an RSS Reader. This is an ideal mini-project because it includes networking, parsing XML, and binding to data elements such as lists. I wanted to provide an example that shows some more interesting solutions that are possible using C# in Silverlight. This is the first part in a series. By the end of this post, we'll have a working reader. What I'll then do is add some more detailed error handling, provide unit tests, tackle skinning and visual states, and hopefully end up with a fairly advanced client.

Today, let's focus on getting a client where we can enter a feed and get some listings. A perfect way to test this will be a Twitter feed. If you would like to read my recent tweets as RSS, for example, you can simply navigate to http://twitter.com/statuses/user_timeline/46210370.rss. By viewing the source, you can see the basic structure of an RSS feed. It is fairly straightforward.

Download the source for this project

Domain Entities

The first step is to define some domain entities. These are the "models" for our application, and represent the actual data we are working with. With an RSS feed, it is fairly simple. We'll work our way backward from the item up to the channel. Our item to start with looks like this:

 
public class Item
{
    public string Title { get; set; }

    public string Description { get; set; }

    public DateTime PublishDate { get; set; }

    public string Guid { get; set; }

    public Uri Link { get; set; }
}

A channel is simply some header information with a collection of items. For starters, we'll make it look like this:

public class Channel
{
    public Channel()
    {
        Items = new ObservableCollection<Item>();
    }

    public string Title { get; set; }

    public Uri Link { get; set; }

    public string Description { get; set; }

    public ObservableCollection<Item> Items { get; set; }
}

Note that I build my entities based on the actual content, not how the content is delivered. In other words, even though the RSS stream may encode a link or a date as text, I want my domain entity to be able to work with the property as it was intended. Therefore, there are no "hacks" to force something into a Uri that doesn't belong: we use that type for the links. Similarly, the date time is handled as a date, and we can worry about how to display it when the time is right. The point is this keeps the data we're dealing with abstracted from the way we receive it, so if down the road we are reading a database or connecting to a different type of service, we only need to change the way we adapt from the service into our domain.

De-serialization

One of the challenges we'll face with RSS feeds is taking the feed data and turning it into our domain objects (de-serializing the data). There are a number of different approaches, but I wanted to present one that I think makes it extremely easy to expand and extend entities that are mapped to XML documents. It involves using Silverlight's powerful LINQ to XML features.

The concept is relatively simple: XML data is mostly strings in elements and attributes. For RSS feeds, the data is entirely in elements. Therefore, it should be relatively straightforward to parse an XML element into an entity. We'll know the target property and the type of that property, so all we need is the element and the conversion.

To tackle the element, I decided to create a custom attribute called RssElement that allows me to tag a property with the name of the element the property's value is contained within. Here is the attribute:

[AttributeUsage(AttributeTargets.Property,AllowMultiple = false)]
public class RssElementAttribute : System.Attribute
{
    public readonly string ElementName; 

    public RssElementAttribute(string elementName)
    {
        ElementName = elementName;
    }
}

Now I can circle back to my entities and tag them with the source elements. First, the item:

public class Item
{
    [RssElement("title")]
    public string Title { get; set; }

    [RssElement("description")]
    public string Description { get; set; }

    [RssElement("pubDate")]
    public DateTime PublishDate { get; set; }

    [RssElement("guid")]
    public string Guid { get; set; }

    [RssElement("link")]
    public Uri Link { get; set; }
}

And then the channel:

public class Channel
{
    public Channel()
    {
        Items = new ObservableCollection();
    }

    [RssElement("title")]
    public string Title { get; set; }

    [RssElement("link")]
    public Uri Link { get; set; }

    [RssElement("description")]
    public string Description { get; set; }

    public ObservableCollection<Item> Items { get; set; }
}

Now that we have a way of tagging the properties, we can create a fluent extension to move from an XElement (what LINQ gives us) to an actual type.

I created a static class called LinqExtensions to extend my LINQ classes. Again, working backward, let's consider what happens to the value of an element in XML when we move it to our entity. We'll need to take that value (which is a string) and convert it based on the target type. It has a consistent method signature: receive a string, return a type. Therefore, I decided to implement a dictionary to map the conversion process to the target types. Working with the types I know I'll need, my dictionary looks like this:

public static class LinqExtensions
{
    private static readonly Dictionary<Type, Func<string, object>> _propertyMap;

    static LinqExtensions()
    {
        _propertyMap = new Dictionary<Type, Func<string, object>>
                           {
                               {typeof (string), s => s},
                               {typeof (Uri), s => new Uri(s)},
                               {typeof (DateTime), s => DateTime.Parse(s)}
                           };
    }

This is very simple when you see where I'm going. Everything is mapped to a function that takes a string and returns an object. A string is a pass-through (s => s). A Uri converts the string to a Uri (s => new Uri(s)) and a date time attempts to parse the date (s => DateTime.Parse(s)). By using the type as the key to the dictionary, I can do this:

...
DateTime date = _propertyMap[typeof(DateTime)]("1/1/2010") as DateTime; 
...

Of course, part of what we can do down the road is add some better error handling and contract checking. Next, let's use this conversion. I am taking in an element, then using the property information that I have to set the value onto an instance of the target class. Given a class instance T, an element, and the information about a property, I can inspect the custom attribute to find the element name, then use the conversion for the type of the property to set the value. My method looks like this:

private static void _ProcessProperty<T>(T instance, PropertyInfo property, XContainer element)
{
    var attribute =
        (RssElementAttribute) (property.GetCustomAttributes(true)
                                  .Where(a => a is RssElementAttribute))
                                  .SingleOrDefault();

    XElement targetElement = element.Element(attribute.ElementName);

    if (targetElement != null && _propertyMap.ContainsKey(property.PropertyType))
    {
        property.SetValue(instance, _propertyMap[property.PropertyType](targetElement.Value), null);
    }
}

As you can see, we grab the element, find the value in the XML fragment we're passed, then use the property's SetValue method to set the value based on the conversion we find in the property map.

How do we get the property info? Take a look at this fluent extension. It takes an element and is typed to a target class. It will create a new instance of the class and iterate the properties to set the values. By using it as a fluent extension, I can write this in code, which I think makes it very readable:

...
var widget = xmlElement.ParseAs<Widget>(); 
...

The "parse as" method looks like this:

public static T ParseAs<T>(this XElement element) where T : new()
{
    var retVal = new T();

    ((from p in typeof (T).GetProperties()
      where (from a in p.GetCustomAttributes(true) where a is RssElementAttribute select a).Count() > 0
      select p).AsEnumerable()).ForEach(p => _ProcessProperty(retVal, p, element));

    return retVal;
}

I basically grab all properties with the custom attribute, then pass the class, element, and property to the method we developed earlier to set the value. Finally, I return the new instance of the class. The ForEach is available with the toolkit, but you can roll your own enumerator extension like this:

public static class IteratorExtensions
{
    public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
    {
        foreach(var item in list)
        {
            action(item);
        }
    }
}

To me, it saves code and makes it easier to read what's going on if you have to perform a simple action and use the ForEach extension to do it.

While we're having fun with our fluent extensions, we're almost ready to take an RSS feed and turn it into a group of objects. We need a way to get the text we receive from the call into an XDocument, so I made this extension:

public static XDocument AsXDocument(this string xml)
{
    return XDocument.Parse(xml);
}

We also need to take the XDocument and iterate the elements to build channels and items. Because we already built our ParseAs method and have tagged the entities for channels and elements, this becomes as simple as:

public static List<Channel> AsRssChannelList(this XDocument rssDoc)
{
    var retVal = new List<Channel>();

    if (rssDoc.Root != null)
    {
        foreach(var c in rssDoc.Root.Elements("channel"))
        {
            var channel = c.ParseAs<Channel>();
            c.Elements("item").ForEach(item => channel.Items.Add(item.ParseAs<Item>()));
            retVal.Add(channel);                    
        }
    }

    return retVal;
}

Again, I believe the fluent extensions are making our life easier because one logical layer builds on the next. We already have our entities tagged and our parsing worked out, so now we simply iterate the channels and parse those as channels, then iterate the items and parse those as items. Could it be an easier? Now, if I have the text of an RSS feed in a variable called rssFeed, the only thing I need to do in order to turn it into a list of channels and items is this:

...
var channelList = rssFeed.AsXDocument().AsRssChannelList(); 
...

We've done most of the heavy lifting, so let's tackle actually going out and fetching the feed. If you've worked with Silverlight and tried to fetch any type of information from another website, you'll be familiar with the strict cross-domain policies that Silverlight has. You can read the Microsoft article on Network Security Access Restrictions in Silverlight to get the full scoop.

In a nutshell, it says most likely we won't be able to reach out from our Silverlight client to touch the RSS feeder and bring back the information. How do you like that twist? Fortunately, there is a workaround.

Using a Handler to Bypass Cross Domain Concerns

Silverlight is allowed to pull information from the same server that it is hosted from. One simple way to bypass the issue with going out directly from the client to the reader is to create a proxy. We don't have the same restrictions on the server with going across domains, so we can have Silverlight "ask" the server to pull the feed for us, and deliver it back.

This, however, has its own issues. I can make a handler that takes a Uri and then returns the data, but this would expose a potential security risk in my web application. It would open the door for malicious attackers to hit other websites and make it look like it is coming from my server! It's sort of like the old "call-forwarding" techniques that old school phreakers would use to hide their illicit telecommunications activities.

I am going to use the handler approach, but make it a little more difficult to abuse. In a production system, I'd implement a full brown encryption scheme. The issue with the Silverlight side is that it gets downloaded to the browser, so a would-be hacker can easily pull apart the code and dissect what's going on. You'll want a fairly strong algorithm to circumvent foul play. For this blog example, I'm going to implement a very light security piece that will thwart any casual foul play by preventing someone from guessing how to pull a feed without knowing the algorithm. OK, so it's not very secret because I'm letting you in on the deal.

For the sake of illustration, I'm simply going to have the Silverlight client generate a guid, then generate a hash on the GUID using SHA1. Again, for a more secured solution, I'd have a SALT and keywords, etc, but this at least shows a way to secure the communication and should get you thinking about security concerns when you start exposing services for Silverlight to consume.

In order for this to work, both the client and the server need to implement the same algorithm. I am a big fan of DRY (Don't Repeat Yourself) so I don't want to duplicate the algorithm in both places. Instead, I'll build this simple piece on the Silverlight side:

public static class SecurityToken
{        
    public static string GenerateToken(string seed)
    {
        Encoder enc = Encoding.Unicode.GetEncoder();

        var unicodeText = new byte[seed.Length * 2];
        enc.GetBytes(seed.ToCharArray(), 0, seed.Length, unicodeText, 0, true);

        System.Security.Cryptography.SHA1 sha = new System.Security.Cryptography.SHA1Managed();

        byte[] result = sha.ComputeHash(unicodeText);

        var sb = new StringBuilder();

        for (int i = 0; i 

It's a simple method that takes a string and returns the hash as digits. On the web server side, I go into my project and use "add existing item."

Then, I navigate to the security class in my Silverlight project, highlight it, then choose "add as link."

This allows me to share the code between the two sides. I can make a change once and ensure both are always in sync. I call this "poor man's WCF RIA." OK, bad joke. Let's move along.

In the ClientBin folder, I add a handler. I do it here because it makes it easy for Silverlight to reference the handler using a relative Uri. Otherwise, I'll have to hack around with the application root and parse strings and do lots of work I just don't care to do. This way, I can reference it as:

...
var handlerUri = new Uri("RssHandler.ashx"); 
...

And be done with it. Silverlight will pass the guid, the key, and the desired Uri. My handler will generate the key from the guid, make sure it matches what was passed, and then proxy the feed. The code looks like this:

[WebService(Namespace = "http://jeremylikness.com/rssReader")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class RssHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/xml";

        if (context.Request.QueryString["key"].Equals(SecurityToken.GenerateToken(context.Request.QueryString["guid"])))
        {
            using (var client = new WebClient())
            {
                context.Response.Write(client.DownloadString(context.Request.QueryString["rssuri"]));
            }
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Now we need to the build the service on Silverlight.

The Reader Service

First, let's start with the interface for the service. What we want is to pass in the URL of the RSS feed, and receive a list of channels with corresponding items that were fetched from the feed. That ends up looking like this:

public interface IRssReader
{
    void GetFeed(Uri feedUri, Action<List<Channel>> result);
}

Notice I'm making life easy for classes that use the service. They won't have to worry about the asynchronous nature of the service calls or how the result comes back, etc. All that is needed is to pass a method that will accept the list of channels when it becomes available.

As I mentioned earlier, we already did most of the heavy lifting with parsing out the feed, so wiring in the service is very straightforward. The implementation looks like this:

public class RssReader : IRssReader 
{
    private const string PROXY = "RssHandler.ashx?guid={0}&key={1}&rssuri={2}";

    public void GetFeed(Uri feedUri, Action<List<Channel>> result)
    {

        var client = new WebClient();

        Guid guid = Guid.NewGuid();
       
        client.DownloadStringCompleted += ClientDownloadStringCompleted;
        client.DownloadStringAsync(new Uri(
                                       string.Format(PROXY,
                                                     guid,                                                         
                                                     SecurityToken.GenerateToken(guid.ToString()),
                                                     feedUri), UriKind.Relative), result);
    }

    static void ClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        var client = sender as WebClient;
        
        if (client != null)
        {
            client.DownloadStringCompleted -= ClientDownloadStringCompleted;
        }

        if (e.Error != null)
        {
            throw e.Error; 
        }

        var result = e.UserState as Action<List<Channel>>; 

        if (result != null)
        {
            result(e.Result.AsXDocument().AsRssChannelList()); 
        }
    }
}

Walking through the steps, we first get the Uri and the method to call when we're done. We wire up a web client and pass it the URL of our handler. This has parameters for the guid and our key, as well as the Uri we want to fetch. We also pass the method to call when we're done. The asynchronous calls all provide a generic object to pass state, so when the call returns we know which version of the call we're dealing with (nice of them, hey?)

When the call is completed, we unhook the event to avoid any dangling references. If there was an error, we throw it. (Yeah, part of our refactoring in future posts will be dealing with all of the errors I'm either throwing or not catching throughout the example). We take the state object and turn it back into an action, then pass the received value as the list of channels using our fluent extensions.

So now we can get it and load it into our models. We need a view model to host all of this!

The View Model

For the first pass on this, I'm going to wire everything myself. No fancy PRISM or MEF extensions, we can refactor those later. Let's get to showing something on the screen.

Our view model should be able to accept the URL of a feed, let the user click "load" and possibly "refresh" on the feed, then show it to us. We want to give them some feedback if the feed isn't a valid Uri, and we probably should keep the load button disabled until there is a valid feed. I ended up creating this for phase one:

public class RssViewModel : INotifyPropertyChanged
{
    private readonly IRssReader _reader; 

    public RssViewModel(IRssReader reader)
    {
        _reader = reader;
        Channels = new ObservableCollection<Channel>();
    }

    private Uri _feedUri;

    private string _uri; 

    public string FeedUri
    {
        get { return _uri; }
        set
        {
            // this will throw an error if invalid, for validation
            _feedUri = new Uri(value);
            _uri = value;
            RaisePropertyChanged("FeedUri");
            RaisePropertyChanged("CanRefresh");
        }
    }

    public bool CanRefresh { get { return _feedUri != null; }}

    public void RefreshCommand()
    {
        if (CanRefresh)
        {
            Channels.Clear();
            _reader.GetFeed(_feedUri, LoadChannels);
        }
    }

    public void LoadChannels(List<Channel> channelList)
    {
        channelList.ForEach(channel=>Channels.Add(channel));
    }

    public ObservableCollection<Channel> Channels { get; set; }

    protected void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

The view model implements INotifyPropertyChanged to support binding. In lieu of using a converter for the Uri, I decided to deal with it as a string, then cast it to a Uri. If the cast fails, it throws an error, so we can use the Silverlight validation engine to display the error. Only if the text was successfully cast to a valid Uri will we enable the refresh button. When it's clicked, we call the service and clear the list of channels, then populate the list on the return call.

A Basic Page

Now we can throw together some XAML to show it. In this first iteration I'm not about getting stylish or fancy, so I tossed together something fast. I'm using grids in lieu of stack panels so they auto-size well, and a custom ItemsControl that allows vertical scroll bars. We simply add the scroll viewer around the items presenter using a style, like this:

<Style 
    TargetType="ItemsControl" 
    BasedOn="{StaticResource ItemsControlStyle}"
    x:Name="ItemsControlOuterStyle">
    <Setter Property="ItemsControl.Template">
        <Setter.Value>
            <ControlTemplate>
                <ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}">
                    <ItemsPresenter />
                </ScrollViewer>
            </ControlTemplate>
        </Setter.Value>
    </Setter>            
</Style>

I know the high priests of MVVM are going to try and burn me for blasphemy with this next move, but we're still in the proof of concept, OK? So far we have no testing, IoC, nor beautiful command extensions. Yes, you are about to see a plain old code-behind event:

<TextBlock
    Grid.Column="0"
    Margin="5"
    Text="RSS Feed URL:"/>
<TextBox 
    Grid.Column="1"
    Width="200"
    Margin="5"
    Text="{Binding Path=FeedUri,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnExceptions=True}"/>
<Button
    Grid.Column="2"
    Margin="5"
    IsEnabled="{Binding Path=CanRefresh}"
    Content="Refresh"
    Click="Button_Click"/>

Here you can enter the feed. When you tab out, it will validate it and show an error if it is invalid. If it passes, the button will be enabled.

This next chunk of XAML shows the items. We'll do more refactoring as well. I will introduce the concept of formatters than will parse things like hyperlinks and Twitter hash terms to provide more interactive functionality, but for now let's just get it out there:

<ItemsControl
    Style="{StaticResource ItemsControlOuterStyle}"
    Grid.Row="1" 
    ItemsSource="{Binding Channels}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid 
                Margin="5"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Top">
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                    <HyperlinkButton 
                        Grid.Row="0"
                        Margin="5"
                        FontWeight="Bold"
                        Content="{Binding Title}"
                        NavigateUri="{Binding Link}"/>
                    <TextBlock 
                        Grid.Row="1"
                        Margin="5"
                        TextWrapping="Wrap"
                        Text="{Binding Description}"/>
                <ItemsControl 
                    Grid.Row="2"
                    Style="{StaticResource ItemsControlStyle}"
                    ItemsSource="{Binding Items}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Grid HorizontalAlignment="Stretch"
                                  VerticalAlignment="Top"
                                  Margin="5">
                                <Grid.RowDefinitions>
                                    <RowDefinition/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock 
                                    Margin="5"
                                    Grid.Row="0"
                                    Grid.Column="0"
                                    Text="{Binding PublishDate}"/>
                                <HyperlinkButton
                                    Margin="5"
                                    Grid.Row="0"
                                    Grid.Column="1" 
                                    Content="{Binding Title}"
                                    NavigateUri="{Binding Link}"/>
                                <TextBlock 
                                    Grid.Row="1"
                                    Grid.Column="0"
                                    Grid.ColumnSpan="2"
                                    TextWrapping="Wrap"
                                    Text="{Binding Description}"/>
                            </Grid>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Grid>                   
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Whew! Now we just need to put in a little bit of code behind. We'll enrage the dependency injection purists by creating hard coded instances and further stoke the ire of MVVM evangelists by wiring in a code behind for the button click:

public partial class MainPage
{
    public MainPage()
    {
        InitializeComponent();
        LayoutRoot.DataContext = new RssViewModel(new RssReader());
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ((RssViewModel)LayoutRoot.DataContext).RefreshCommand();
    }
}

Upon publishing and hitting the service, I was able to pull up my Twitter feed:

That's it. Now we have a proof of concept, and it worked. We have a lot more to do ... making it expandable to handle different types of feeds including HTML, styling it, perhaps looking at using multiple feeds, tests, and the lot (yes, I know, I know, the tests should have come earlier). I hope you enjoyed this first look into my process of creating a basic reader and we'll continue to evolve the project with time!

Download the source for this project

Jeremy Likness

One reason a developer would use a technology like MEF is to, as the name implies, make an application extensible through a process called discovery. Discovery is simply a method for locating classes, types, or other resources in an assembly. MEF uses the Export tag to flag items for discovery, and the composition process then aggregates those items and provides them to the entities requesting them via the Import tag.

Download the source code for this example

It occurred to me when working with PRISM and MEF (see the recap of my short series here) that some of this can be done through traditional means and I might be abusing the overhead of a framework if all I'm doing is something simple like marrying a view to a region.

Challenges with PRISM include both determining how views make it into regions and how to avoid magic strings and have strict type compliance when dealing with regions. This post will address one possible solution using custom attributes and some fluent interfaces.

Fluent Interfaces

Fluent interfaces simply refers to the practice of using the built-in support for an object-oriented language to create more "human-readable" code. It's really a topic in and of itself, but I felt it made sense to simplify some of the steps in this post and introduce some higher level concepts and examples along the way.

There are several ways to provide fluent interfaces. One that is built-in to the C# language is simply using the type initializer feature. Instead of this:


public class MyClass 
{
   public string Foo { get; set; }
   public string Bar { get; set; }

   public MyClass() 
   {
   }

   public MyClass(string foo, string bar) 
   {
       Foo = foo; 
       Bar = bar;
   } 
}

Which results in code like this:


...
MyClass myClass = new MyClass(string1, string2); 
...

Question: which string is foo, and which string is bar, based on the above snippet? Would you consider this to be more readable and "self-documenting"?


...
MyClass myClass = new MyClass { Foo = string1, Bar = string2 };
...

It works for me! So let's do something simple in our PRISM project. If you've worked with PRISM, then you'll know the pattern of creating a Shell and then assinging it to the root visual in a Bootstrapper. The typical code looks like this in your Bootstrapper class:


protected override DependencyObject CreateShell()
{
   Shell shell = new Shell(); 
   Application.Current.RootVisual = shell;
   return shell; 
}

That's nice, but wouldn't it also be nice if you could do something simple and readable, like this? Keep in mind we're not cutting down on generated code (and in fact, sometimes fluent interfaces may increase the amount of generated code, which is a consideration to keep in mind), but we're focused on the maintainability and readability of the source code.


protected override DependencyObject CreateShell()
{
   return Container.Resolve<Shell>().AsRootVisual();             
}

In one line of code I'm asking the container to provide me with the shell (I do this as a common practice as opposed to creating a new instance so that any dependencies I may have in the shell will be resolved), then return it "as root visual." I think that is pretty readable, but how do we get there?

The answer in this case is using extension methods. In my "common" project I created a static class called Fluent which contains my fluent interfaces (this is for the example only and would not scale in production ... you will want to segregate your interfaces into separate classes related to the modules they act upon). In this static class, I create the following extension method:


public static UserControl AsRootVisual(this UserControl control)
{
    Application.Current.RootVisual = control;
    return control;
}

An extension method does a few things. By using the keyword this on the parameter, it tells the compiler this method will extend the type. The semantics in the code look you are calling something on the UserControl, but the compiler is really taking the user control, then calling the method on the static class and passing the instance in. It is common for the extension methods to return the same instance so they can be chained. In this case, we simply assign the control to the root visual, then return it so it can be used elsewhere. We're really doing the same thing we did before, but adding a second method call, in order to make the code that much more readable.

One important concern to have and address with fluent interfaces is the potential for "hidden magic." What I mean by this is the extension methods aren't available on the base class and only appear when you include a reference to the class with the extensions. This may make them less discoverable based on how you manage your code. It also means you will look at methods that aren't part of the known interface. It's not difficult to determine where the method comes from. Intellisense will flag extension methods as extensions, and you can always right click and "go to definition" to see where the method was declared.

Auto-discoverable Views

I have two main goals with this project: the first is to be able to tag views so they are automatically discovered and placed into a region, and the second is to type the region so I'm not using magic strings all over the place. My ideal solution would allow me to add a view to a project, tag it with a region, and run it, and have it magically appear in that region. Possible? Of course!

Typing the Regions

I am going to type the regions to avoid magic strings. Because the main shell defines the regions, I'm fine with the strings there ... that is sort of the "overall definition", but then I want to make sure elsewhere in the code I can't accidentally refer to a region that doesn't exist. My first step is to create a common project that all other modules can reference, and then add an enumeration for the regions. The enumeration for this examle is simple:


namespace ViewDiscovery.Common
{
   public enum Regions
    {
        TopLeft,
        TopRight,
        BottomLeft,
        BottomRight
    }
}

Enumerations are nice because I can call ToString() and turn it into the string value of the enumeration itself. I decided to adopt the convention "Region." when tagging it in the shell, so my shell looks like this:


<UserControl x:Class="ViewDiscovery.Shell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:region="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
    >
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Text="View Discovery"/>       
        <ItemsControl Grid.Row="1" Grid.Column="0" region:RegionManager.RegionName="Region.TopLeft"/>
        <ItemsControl Grid.Row="1" Grid.Column="1" region:RegionManager.RegionName="Region.TopRight"/>
        <ItemsControl Grid.Row="2" Grid.Column="0" region:RegionManager.RegionName="Region.BottomLeft"/>
        <ItemsControl Grid.Row="2" Grid.Column="1" region:RegionManager.RegionName="Region.BottomRight"/>
    </Grid>
</UserControl>

This is just a simple 2x2 grid with a region per cell. I used the ItemsControl so each cell can host multiple views. We're off to a good start! Now let's figure out how to tag our views.

The Custom Attribute

Custom attributes are powerful and easy to implement. I want to be able to tag a view as a region using my enumeration, so I define this custom attribute:


namespace ViewDiscovery.Common
{
    [AttributeUsage(AttributeTargets.Class,AllowMultiple=false)]
    public class RegionAttribute : System.Attribute
    {
        const string REGIONTEMPLATE = "Region.{0}";

        public readonly string Region;

        public RegionAttribute(Regions region)
        {
            Region = region.ToString().FormattedWith(REGIONTEMPLATE);              
        }
    }
}

Notice that I don't allow multiple attributes and that this attribute is only valid when placed on a class. Attributes can take both positional parameters (defined in the constructor) and named parameters (defined as properties). In this case, I only have one value so I chose to make it positional. When the region enumeration is passed in, I cast it to a string and then format it with the prefix, so that Regions.TopLeft becomes the string Region.TopLeft. Notice I snuck in another fluent interface, the FormattedWith. To me, that's a sight prettier than "string.Format" if I'm only dealing with a single parameter. The extension to make this happen looks like this:


public static string FormattedWith(this string src, string template)
{
    return string.Format(template, src);
}

Now that we have a tag, we can create a new module and get it wired in. I created a new project as a Silverlight Class Library (sorry, this example doesn't do any fancy dynamic module loading), built a folder for views, and tossed in a view. The view simply contains a grid with some text:


<Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Text="I am in ModuleOne." Grid.Row="0"/>
        <TextBlock Text="I want to be at the top left." Grid.Row="1"/>
    </Grid>

Tagging the view was simple. I went into the code-behind, added a using statement to reference the common project where my custom attribute is defined and then tagged the view with the attribute. Here's the code-behind with the tag:


namespace ViewDiscovery.ModuleOne.Views
{
    [Region(Regions.TopLeft)] 
    public partial class View : UserControl
    {
        public View()
        {
            InitializeComponent();
        }       
    }
}

So now it's clear where we want the view to go. Now how do we get it there?

Discovering the Views

The pattern in PRISM for injecting a module is for the module to have an initialization class that implements IModule and then adds the views in the module to the region. We want to do this through discovery. To facilitate this, I created a base abstract class for any module that wants auto-discovered views. The class looks like this:


public abstract class ViewModuleBase : IModule
{
    protected IRegionManager _regionManager;

    public ViewModuleBase(IRegionManager regionManager)
    {
        _regionManager = regionManager;
    }

    #region IModule Members

    public virtual void Initialize()
    {
        IEnumerable<Type> views = GetType().Assembly.GetTypes().Where(t => t.HasRegionAttribute());

        foreach (Type view in views)
        {
            RegionAttribute regionAttr = view.GetRegionAttribute(); 
            _regionManager.RegisterViewWithRegion(regionAttr.Region, view); 
        }
    }

    #endregion
}

The code should be very readable. We enforce that the region manager must be passed in by creating a constructor that takes it and stores it. We implement Initialize as virtual so it can be overridden when needed. First, we get the assembly the module lives in, then grab a collection of types that have our custom attribute. Yes, our fluent interface makes this obvious because we can do type.HasRegionAttribute(). The extension method looks like this:


public static bool HasRegionAttribute(this Type t)
{
    return t.GetCustomAttributes(true).Where(a => a is RegionAttribute).Count() > 0; 
}

This takes the type, grabs the collection of custom attributes (using inheritance in case we're dealing with a derived type) and returns true if the count of our attribute, the RegionAttribute, is greater than zero.

Next, we iterate those types and get the region attribute, again with a nice, friendly interface (GetRegionAttribute) that looks like this:


public static RegionAttribute GetRegionAttribute(this Type t)
{
    return (RegionAttribute)t.GetCustomAttributes(true).Where(a => a is RegionAttribute).SingleOrDefault();
}

Now we have exactly what we need to place the view into the region: the region it belongs to, and the type. So, we register the view with the region and we're good to go!

In my module, I add a class for the module initializer called ModuleInit. I'm only using the auto-discovery so there is nothing more than an implementation of the base class that passes the region manager down:


namespace ViewDiscovery.ModuleOne
{
    public class ModuleInit : ViewModuleBase
    {
        public ModuleInit(IRegionManager regionManager)
            : base(regionManager)
        {
        }
    }
}

Now we go back to the main project and wire in the module catalog. I'm not using dynamic modules so I just reference my modules from the main project and register them by type:


protected override IModuleCatalog GetModuleCatalog()
{
    return new ModuleCatalog()
        .WithModule(typeof(ModuleOne.ModuleInit).AssemblyQualifiedName.AsModuleWithName("Module One"));            
}      

OK, so I had some fun here as well. I wanted to extend the module catalog to allow chaining WithModule for adding multiple modules, and be able to take a type name as a string, then make it a module with a name. Working backwards, we turn a string into a named ModuleInfo class like this:


public static ModuleInfo AsModuleWithName(this string strType, string moduleName)
{
    return new ModuleInfo(moduleName, strType);
}

Next, we extend the catalog to allow chaining on new modules like this:


public static ModuleCatalog WithModule(this ModuleCatalog catalog, ModuleInfo module)
{
    catalog.AddModule(module);
    return catalog;
}

Notice this simply adds the module then returns the original catalog.

At this point, we can run the project and see that the view appears in the upper left.

View Discovery with One View

I then added a second view with a rectangle:


<UserControl x:Class="ViewDiscovery.ModuleOne.Views.Rectangle"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    >
    <Grid x:Name="LayoutRoot" Background="White">
        <Rectangle Width="100" Height="100" Fill="Red" Stroke="Black"/>
    </Grid>
</UserControl>

... and tagged it:


namespace ViewDiscovery.ModuleOne.Views
{
    [Region(Regions.TopRight)] 
    public partial class Rectangle : UserControl
    {
        public Rectangle()
        {
            InitializeComponent();
        }
    }
}

An finally compiled and re-ran it. The rectangle shows up in the upper right, as expected:

View Discovery with Two Views

Next, I added a second module with several views ... including a few registered to the same cell. Adding the new module to the catalog was easy with the extension for chaining modules:


protected override IModuleCatalog GetModuleCatalog()
{
    return new ModuleCatalog()
        .WithModule(typeof(ModuleOne.ModuleInit).AssemblyQualifiedName.AsModuleWithName("Module One"))
        .WithModule(typeof(ModuleTwo.ModuleInit).AssemblyQualifiedName.AsModuleWithName("Module Two"));            
}   

Compiling and running this gives me the final result:

View Discovery with Multiple Views

And now we've successfully created auto-discoverable views that we can strongly type to a region and feel confident will end up being rendered where they belong.

Download the source code for this example

Jeremy Likness