Announcing a Prism, Unity, WPF, MVVM Training Event

May 7, 2011

Save the dates for a 3 day patterns & practices Prism, Unity, WPF, MVVM training event, 27-29 June in Boise, ID.

Join three Prism Team members Bob Brumfield (lead developer), Geoff Cox (developer), and myself (program manager) for an information packed 2 days of instruction followed up by a day of pair-programming.

Day one will consist of WPF and MVVM topics; day two Prism 4.0 and Unity; day three is dedicated to pair-programming, getting your questions answered, and an opportunity for you to apply the last two days’ training against your scenarios and programming style. The pair-programming day is always so much fun along with some wicked coding.

This is a free event for 75 attendees. Each seat has a desktop, power and wireless.

Registration will open soon and will be announced on my blog and twitter.

Very much looking forward to spending time with developers and taking in the beauty of Idaho.

Have a great day,

Just a grain of sand on the worlds beaches.


Various Clients and Forms Authentication

April 25, 2011

Conceptual

Scenarios

In each of the below scenarios, forms authentication is used to secure access to the ASP.NET MVC endpoints and WCF services.

  • WPF accessing WCF services
  • WPF accessing MVC endpoints
  • Windows Phone 7 accessing WCF services
  • Desktop and mobile browsers accessing ASP.NET MVC website pages
  • jQuery accessing MVC endpoints

While I have not included the code for a Windows Phone 7 to access MVC endpoints that is a supported scenario as well.

Requirements

  • Visual Studio 2010
  • SQL Express 2008
  • Windows Phone 7 tools
    • If you don’t have these and don’t want to see this project, you can just remove the Windows Phone 7 project from the solution.

Background

I’ve been working on Stuff v2; a movie, game, and books application. Its primary use case is, "I’m at the store and don’t remember if I have a particular movie, game, or book. I need to determine if I have it; if not, then check the online price and ratings before making the purchase."

Given the varied application clients and devices, ASP.NET forms authentication seemed like the natural choice for authentication for the website, MVC3 JSON endpoints, and WCF services.

The reason I have varied client software and devices is more of a learning experience than an application requirement. I have other applications I want to write that will need to access the application from all my devices.

When I started programming the WPF client, I ran into a stone wall with respect to WPF accessing WCF services that are secured by forms authentication. This blog post is about getting over that stone wall.

Identifying the Problem Space

At the end of the day, the problem that needs solving is managing the forms authentication cookie or ticket.

Managing means, that after authenticating, the client must be able to retrieve the ticket returned in the response and include it in future requests to secured resources.

As you will see, client API’s vary across scenarios not only in coding patterns but in complexity as well.

Regardless of which client is accessing resources that require forms authentication, the following steps outline the required workflow:

  • Log in
  • Cache the ticket returned in the response
  • Include the ticket in subsequent requests

Setting up Forms Authentication

When I created the ASP.NET MVC3 application, VariousClients.Web, I used the MVC3 Internet template with the Razor view engine. This template sets up forms authentication and provides a pretty good out-of-box SQL Express membership system for you.

The below snippet from the web.config shows a few required changes:

<authentication mode="Forms">
    <!-- cookieless="UseCookies" is required by non-browser clients
                to authenticate using forms authentication-->
    
    <!-- production applications, change to requiresSSL="true"-->
    <forms timeout="2880" cookieless="UseCookies" loginUrl="~/Account/LogOn"
            requireSSL="false" />
</authentication>

Setting up the AuthenticationService

The System.Web.ApplicationServices.AuthenticationService is a built-in service that you can expose as a service endpoint on your website. This service exposes log in, log out methods for clients that access WCF endpoints requiring forms authentication. This service uses the membership provider defined in the web.config. After logging in, the service returns a ticket in the response, similar to forms authentication log in.

Adding the service is easy. First add a folder to the root of the website named, "Services". Into that folder, add a WCF service named Authentication.svc. Delete the generated service contract and code-behind files. Next replace the contents of the Authentication.scv file with the below code snippet.

<%@ ServiceHost Language="C#" Service="System.Web.ApplicationServices.AuthenticationService" %>

Now add the following to your web.config:

<system.web.extensions>
    <scripting>
        <webServices>
            <!-- for production applications, change to requiresSSL="true"-->
            <authenticationService enabled="true" requireSSL="false"/>
        </webServices>
    </scripting>
</system.web.extensions>

Rebuild your web application.

The Authentication.svc will now appear in the Add Service Reference dialog when adding service references in your client applications.

AddServiceReference

Browsers, Web pages, and MCV3 Controller Methods

Controller classes or controller action methods can be decorated with the Authorize attribute to require that client browsers or JavaScript accessing them be authenticated.

After logging in, the browser automatically manages the authentication ticket and includes it with all future requests to the website.

The below GetTime method requires authentication:

using System;
using System.Web.Mvc;

namespace VariousClients.Web.Controllers {

    public class CloudDataController : Controller {

        [Authorize]
        public JsonResult GetTime() {
            return Json(DateTime.Now.ToLongDateString(), JsonRequestBehavior.AllowGet);
        }
    }
}

WPF and MVC3 Controller Methods

The following section applies equally to WPF, Windows Forms, console, and test projects.

Server-Side

I’ve added a RemoteLogOn method to the AccountController that is used by non-browser clients when logging in. The method signature and implementation is slightly different from the LogOn method.

        [HttpPost]
#if (!DEBUG)
        [RequireHttps]
#endif
        public Boolean RemoteLogOn(LogOnModel model) {
            if(ModelState.IsValid) {
                if(Membership.ValidateUser(model.UserName, model.Password)) {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    return true;
                }
            }
            return false;
        }

CookieAwareWebClient

Remember, the purpose of the above RemoteLogOn is to get the ticket returned in the response. To simplify client programming, a CookieAwareWebClient wrapper can be used to execute WebClient requests while at the same time handling including the ticket in requests.

using System;
using System.Net;

namespace VariousClients.Common.Net {

    public class CookieAwareWebClient : WebClient {

        public CookieContainer CookieContainer { get; private set; }

        public CookieAwareWebClient()
            : this(new CookieContainer()) {
        }

        public CookieAwareWebClient(CookieContainer cookieContainer) {
            if (cookieContainer == null) throw new ArgumentNullException("cookieContainer");
            this.CookieContainer = cookieContainer;
        }

        protected override WebRequest GetWebRequest(Uri address) {
            if(this.CookieContainer == null) {
                throw new InvalidOperationException("CookieContainer is null");
            }
            var request = base.GetWebRequest(address);
            if (request is HttpWebRequest) {
                (request as HttpWebRequest).CookieContainer = this.CookieContainer;
            } return request;
        }
    }
}

Client-Side

void btnMvcLogIn_Click(Object sender, RoutedEventArgs e) {

    _cookieJar = new CookieContainer();
    var client = new CookieAwareWebClient(_cookieJar) { Encoding = Encoding.UTF8 };

    client.UploadValuesCompleted += (s, args) => {
        this.lblMvcResult.Content =
            args.Error == null ? Encoding.UTF8.GetString(args.Result) : args.Error.Message;
    };

    var nvc = new NameValueCollection { { "UserName", Credentials.UserName }, 
                                        { "Password", Credentials.Password }, 
                                        { "RememberMe", "true" } };
    client.UploadValuesAsync(
        new Uri("http://localhost:1668/Account/RemoteLogOn"), "POST", nvc);
}

void btnMvcGetData_Click(Object sender, RoutedEventArgs e) {

    this.lblMvcResult.Content = "calling cloud service...";
    var client = new CookieAwareWebClient(_cookieJar);

    client.DownloadStringCompleted += (s, args) => {
        this.lblMvcResult.Content = args.Error == null ? args.Result : args.Error.Message;
    };

    client.DownloadStringAsync(new Uri("http://localhost:1668/CloudData/GetTime"));
}

In the above code, the _cookieJar is scoped at module level. The important concept is to use the same instance of the CookieAwareWebClient for all calls because it manages the ticket for you. As an alternative, you could retrieve the CookieContainer value after logging in and pass it in the constructor when creating new CookieAwareWebClient instances.

The btnMvcGetData_Click code looks like a typical WebClient call. The CookieAwareWebClient makes calling endpoints secured by forms authentication painless.

WPF and WCF Service Methods

The following section applies equally to WPF, Windows Forms, console, and test projects.

WPF consuming WCF services secured with forms authentication requires a bit of extra code to manage the ticket because WCF does not provide a simple API to add or retrieve it when making service calls that use the generated proxies.

If you contrast the WPF and Windows Phone 7 calls to the same WCF service you’ll see exactly what I mean. The Windows Phone 7 proxy exposes a CookieContainer object making it easy to capture or include the ticket in all service calls.

Before you can call the AuthenticationService, you’ll need to add a service reference to the Authentication service. When adding the service reference, I changed the namespace to AuthenticationService like the below image:

AddServiceReference

FormsAuthenticationAssistant

The FormsAuthenticationAssistant is a façade for WPF clients making WCF service calls secured with forms authentication. It provides automatic ticket management for making service calls.

// Many thanks to Jonas Follesoe for this post:  
// http://jonas.follesoe.no/2008/09/12/wcf-authentication-services-silverlight-and-smelly-cookies/
// I learned how to extract the forms authentication cookie from the AuthenticationService and how to 
// reapply it subsequent service calls.

using System;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace VariousClients.Common.ServiceModel {

    public class FormsAuthenticationAssistant {

        public String TicketCookie { get; private set; }

        public FormsAuthenticationAssistant() { }

        public FormsAuthenticationAssistant(String ticket) {
            if (String.IsNullOrWhiteSpace(ticket)) throw new ArgumentNullException("ticket");
            this.TicketCookie = ticket;
        }

        public Boolean Login(Func<Boolean> method, IContextChannel serviceInnerChannel) {
            if (method == null) throw new ArgumentNullException("method");
            if (serviceInnerChannel == null) throw new ArgumentNullException("serviceInnerChannel");

            using (new OperationContextScope(serviceInnerChannel)) {
                if (!method()) {
                    this.TicketCookie = null;
                    return false;
                }
                var properties = OperationContext.Current.IncomingMessageProperties;
                var responseProperty = 
                    (HttpResponseMessageProperty)properties[HttpResponseMessageProperty.Name];
                this.TicketCookie = responseProperty.Headers[HttpResponseHeader.SetCookie];
                return true;
            }
        }

        public T Execute<T>(Func<T> method, IContextChannel serviceInnerChannel) {
            if (method == null) throw new ArgumentNullException("method");
            if (serviceInnerChannel == null) throw new ArgumentNullException("serviceInnerChannel");
            if (String.IsNullOrWhiteSpace(this.TicketCookie)) {
                throw new InvalidOperationException(
                    "Currently not logged in. Must Login before calling this method.");
            }

            using (new OperationContextScope(serviceInnerChannel)) {
                var requestProperty = new HttpRequestMessageProperty();
                OperationContext.Current.OutgoingMessageProperties.Add(
                    HttpRequestMessageProperty.Name, requestProperty);
                requestProperty.Headers.Add(HttpRequestHeader.Cookie, this.TicketCookie);
                return method();
            }
        }

        public void Execute(Action method, IContextChannel serviceInnerChannel) {
            if (method == null) throw new ArgumentNullException("method");
            if (serviceInnerChannel == null) throw new ArgumentNullException("serviceInnerChannel");
            if (String.IsNullOrWhiteSpace(this.TicketCookie)) {
                throw new InvalidOperationException(
                    "Currently not logged in. Must Login before calling this method.");
            }

            using (new OperationContextScope(serviceInnerChannel)) {
                var requestProperty = new HttpRequestMessageProperty();
                OperationContext.Current.OutgoingMessageProperties.Add(
                    HttpRequestMessageProperty.Name, requestProperty);
                requestProperty.Headers.Add(HttpRequestHeader.Cookie, this.TicketCookie);
                method();
            }
        }
    }
}

The above Login method invokes the method passed in the method argument. If the log in is successful, the ticket is extracted from the response and cached in the TicketCookie property and true is returned.

The above two Execute methods invoke the method passed in the method argument and add the TicketCookie to the request.

Your application can interface with the FormsAuthenticationAssistant in one of two ways. One is to create a single instance of the FormsAuthenticationAssistant and use that instance for all service calls. This is how the demo WPF application is written.

Another is to save the value of the TicketCookie property after a successful log in, then create a new instance of FormsAuthenticationAssistant for each call and pass the saved TicketCookie value in the constructor.

Once you’re comfortable with routing your service proxy calls through the FormsAuthenticationAssistant, you’ll notice very little differences between using this façade and calling the service proxy methods directly. Don’t forget, in real-world applications you’ll want to make these service calls or calls to the façade asynchronous so the UI thread is not blocked.

Server-Side

The PrincipalPermission attribute can be used on WCF service methods to restrict access to authenticated users. This is similar to using the Authorize attribute on the MCV3 controller action methods. Follow the three steps below:

using System;
using System.Security.Permissions;
using System.ServiceModel.Activation;
using System.Threading;
using System.Web;

namespace VariousClients.Web.Services {

    //STEP 1 - required for interop with ASP.NET
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class CloudData : ICloudData {

        public CloudData() {
            //STEP 2 - pass caller principal to executing threads principal 
            Thread.CurrentPrincipal = HttpContext.Current.User;
        }

        //STEP 3 - verify caller is authenticated
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public String GetTime() {
            return DateTime.Now.ToLongDateString();
        }
    }
}

Client-Side

In the below code, we will first log in against the AuthenticationService, cache the ticket, then call CloudData.GetTime.

void btnServiceLogIn_Click(Object sender, RoutedEventArgs e) {
    this.lblServiceResult.Content = "calling cloud service...";
    var authenticationService = new AuthenticationServiceClient();
    if(_faa.Login(() => authenticationService.Login(
                    Credentials.UserName, Credentials.Password, String.Empty, true),
                    authenticationService.InnerChannel)) {
        this.lblServiceResult.Content = "Log in sucessful.";
    } else {
        this.lblServiceResult.Content = "Bummer, log in not sucessful.";
    }
}

void btnServiceGetData_Click(Object sender, RoutedEventArgs e) {
    this.lblServiceResult.Content = "calling cloud service...";
    var cloudDataService = new CloudDataClient();
    try {
        this.lblServiceResult.Content = 
            _faa.Execute<String>(cloudDataService.GetTime, cloudDataService.InnerChannel);
    } catch(System.ServiceModel.Security.SecurityAccessDeniedException ex) {
        // three conditions could cause this
        //  1. client has never logged in
        //  2. ticket is expired
        //  3. instance of _faa was not the same instance used to log in
        // when this happens in your client code, re-authenticate to get a ticket
        this.lblServiceResult.Content = ex.Message;
    } catch(Exception ex) {
        this.lblServiceResult.Content = ex.Message;
    }
}

This above code is straightforward and very familiar to developers making service calls. The paradigm change is the forwarding of WCF service proxy calls through the FormsAuthenticationAssistant instance (_faa) which manages the ticket.

Windows Phone 7 and WCF Service Methods

Before you can call the AuthenticationService, you’ll need to add a service reference to the Authentication service. When adding the service reference, I changed the namespace to AuthenticationService like the below image:

AddServiceReference

For each service reference you add, you must also edit the ServiceReferences.ClientConfig file binding entry and set the enableHttpCookieContainer property to true as done below.

The Visual Studio tooling for adding service references chokes when the enableHttpCookieContainer property is set on a binding and displays a bizarre error message when adding or updating service references.

So… add all your service references, and then edit the ServiceReferences.ClientConfig file.

If you have to subsequently add, delete or modify a service reference, you’ll need to remove these properties, use the tooling and re-add the properties.

<bindings>
    <basicHttpBinding>
        <binding name="BasicHttpBinding_AuthenticationService" maxBufferSize="2147483647"
            maxReceivedMessageSize="2147483647" enableHttpCookieContainer="true">
            <security mode="None" />
        </binding>
        <binding name="BasicHttpBinding_ICloudData" maxBufferSize="2147483647"
            maxReceivedMessageSize="2147483647" enableHttpCookieContainer="true">
            <security mode="None" />
        </binding>
    </basicHttpBinding>
</bindings>

Calling the AuthenticationService Login method is just like calling other WCF service methods with a minor exception; the CookieContainer property must be set to a new instance of the CookieContainer class prior to making the call. If you forget to populate this property, the ticket will not be returned in the response.

void btnLogin_Click(Object sender, RoutedEventArgs e) {
    this.tbResult.Text = "Attempting to log in...";
    _cookieJar = new CookieContainer();
    var authenticationService = new AuthenticationServiceClient();
    authenticationService.CookieContainer = _cookieJar;
    authenticationService.LoginCompleted += (s, args) => {
        if(args.Error == null) {
            this.tbResult.Text = "Login sucessful.";

            // CookieJar can be persisted without an exception being thrown
            // either when toomstonned or shutdown.  
            // Yes, it can be read from the below stores also.
            // If required for your application, move this code to the appropriate location
            // for launching, closing, activating, and deactivating.
            //
            // uncomment to test
            // PhoneApplicationService.Current.State.Add("CookieJar", _cookieJar);
            // IsolatedStorageSettings.ApplicationSettings.Add("CookieJar", _cookieJar);

        } else {
            this.tbResult.Text = "Login failed: " + args.Error.Message;
        }
    };
    authenticationService.LoginAsync(Credentials.UserName, Credentials.Password, String.Empty, true);
}

In the above code I’ve created a module level variable to hold the CookieContainer (_cookieJar). The same CookieContainer instance must be passed in subsequent calls to other WCF service endpoints.

With Windows Phone 7 programming core concepts like tombstoning and launching must be addressed. In the above code snippet you’ll see a section of comments showing the CookieContainer persisted to storage. Based on your application needs and security requirements, you’ll need to determine when and how to persist your CookieContainer so that your users will not have to repeatedly log in.

void btnGetServiceData_Click(Object sender, RoutedEventArgs e) {
    this.tbResult.Text = "Calling service...";
    var cloudDataService = new CloudDataClient { CookieContainer = _cookieJar };
    cloudDataService.GetTimeCompleted += (s, args) => {
        if(args.Error == null) {
            this.tbResult.Text = args.Result;
        } else {
            if(args.Error is System.ServiceModel.Security.SecurityAccessDeniedException) {
                // three conditions could cause this
                //  1. client has never logged in
                //  2. ticket is expired
                //  3. the _cookieJar instance is not the same instance used when logging in
                // when this happens in your client code, re-authenticate to get a ticket
                this.tbResult.Text = args.Error.Message;
            } else {
                this.tbResult.Text = "Error: " + args.Error.Message;
            }
        }
    };
    cloudDataService.GetTimeAsync();
}

In the above code, the _cookieJar is assigned to the CookieContainer property. Contrast this API with the WPF API for the same call, this API is much simpler. It would be nice to have this exposed in the desktop API’s as well.

Running the Application

  • Set the VariousClients.Web project as the startup project.
  • Run the application (this will create your membership SQL Express database.)
  • When the below page is displayed, click the Register link.

RunningFirstTime

  • When completing the Registration page, you need to use the user name and password specified in the below Credentials class. This class provides the user name and password for the WPF and Windows Phone 7 projects when making service calls.

Credentials

  • After completing a registration page you will be redirected to the page that demonstrates making a jQuery AJAX call to a secured MVC endpoint.
  • To run the WPF and Windows Phone 7 applications, set them as the startup projects.

Download

The demo solution can be downloaded from my Sky Drive:

Various Clients Solution (1.7 MB)

Close

Hope this helps when writing your own desktop, phone and web applications that use forms authentication.

Have a great day,

Just a grain of sand on the worlds beaches.


Extending Mole 2010’s Reach – Mole Type Loader

April 4, 2011

Since the first version of Mole was released in December 2007, the number one support question has been, “I installed Mole but I can’t start it; how do I start Mole?” With the launch of Mole 2010, this has not changed.

When are Types are Listed in a Data Tip?

An important distinction that causes some confusion with visualizers is, “Mole can visualize any type, however not all types are registered with Visual Studio to launch the Mole visualizer.”  In order for Visual Studio to launch a visualizer, the visualizer must be listed in a Data Tip for a type at a break point.

All versions of Mole have been able to visualize any .NET type.  Internally, Mole works with System.Object.  It’s this capability of Mole that allows it to drill around the managed heap, displaying information at debug-time about your application’s types because all types are internally treated equally.

When a debugging sessions begins, Visual Studio reflects all .dll assemblies located in the two well known visualizer folders and builds a cache of types specified in the DebuggerVisualizer attributes that decorate these  assemblies.

The well know visualizer folder locations are:

  • {Visual Studio 2010 install location}\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\Visualizers
  • {User Documents folder}\Visual Studio 2010\Visualizers

Visual Studio uses the type and visualizer specified the DebuggerVisualizer attribute to build a cache of types and the visualizers that can visualizer specified types.  In many cases, registering a base type using the DebuggerVisualizer attribute will cause Visual Studio to associate the base type and all super types, but not in all cases.

The below code snippet shows how the generic List<T> or List(Of T) is registered with Visual Studio, specifying Mole as the visualizer.  This attribute, along with many others decorates the Mole 2010 visualizer assembly.

[assembly: System.Diagnostics.DebuggerVisualizer(
        typeof(Mole.EntryPoint), 
        typeof(Mole.BackEnd.MoleVisualizerObjectSource), 
        Target = typeof(System.Collections.Generic.List<>), 
        Description = "Mole 2010")]

When at a breakpoint, hovering over a variable will bring up the Data Tip and any visualizers that have registered for this type will be listed as in the image below.

datatip

Selecting the Mole 2010 visualizer will launch Mole pictured below.

visualizingGenerics

As you can see, there is a direct correlation between the types registered in visualizer assemblies and the types that have a visualizer listed in the Data Tip.

Mole 2010 version 1.2 ships with 1801 DebuggerVisualizer attributes decorating the Mole visualizer assembly.  All of the 1801 types registered with Mole 2010 are all .NET Framework types.

So the question is, how can a developer launch Mole for a type that does not have a specified type?

System.WeakReference Wrapper Technique

The below screen shot is taken from the Mole 2010 Read Me page.

systemweakreference

Extending Mole 2010’s Reach by Registering Your Types With Visual Studio

Using the above WeakReference technique is a good solution for one-off types you would like to visualize.  But what about types you need to visualize on a daily basis that are not part of the 1801 types pre-registered by Mole?  For example Prism types, Enterprise Library types or types in frameworks that you develop.

I have been thinking about this problem for a while now and did a spike last week to prove that an assembly could register types for another visualizer assembly.

The below image shows the installation location for my copy of Mole 2010 that has the 1801 DebuggerVisualizer attributes.

moleinstallfolder

The below image shows the location of an assembly that has many DebuggerVisualizer attributes that specify types that I want to have a Data Tip for that lists the Mole 2010 visualizer.

moletypeloader

The below image shows the Mole Type Loader UI.  This utility program allows developers to select .NET assemblies and have their types used to create the above custom type loader .dll.  From the list on the left, you can see I’ve elected to load up the Prism and Ocean assemblies and have their types registered with Visual Studio. 

The reason the custom type loader .dll file is under the Documents folder instead of the Visual Studio installation folder is because of write permissions.  Users have write permissions under their Documents folder but not under Program Files without changing permissions.  Also, I didn’t want to have the executable in a different folder than the data file.  Of course, you can modify the code to change the location of the data file if you want.

Mole.TypeLoaderUI

The below code snippet is from the generated custom type loader assembly.

[assembly: System.Diagnostics.DebuggerVisualizer(
    "Mole.EntryPoint, Mole.Visualizer.VS2010, Version=1.2.0.0, ...", 
    "Mole.BackEnd.MoleVisualizerObjectSource, Mole.Visualizer.VS2010, Version=1.2.0.0, ...", 
    TargetTypeName = "Ocean.DataGeneration.DataGenerator, Ocean", 
    Description = "Mole 2010")]

As you can see in the below image, Visual Studio displays a Data Tip for the Mole 2010 visualizer when hovering over an Ocean DataGenerator variable while at a break point.

This was made possible by the above custom type loader .dll having the assembly decorated with a DebuggerVisualizer attribute that specified the DataGenerator and pointed to the Mole 2010 visualizer.

dataGenerator

The Fine Print

Ok, it’s time for the fine print. 

First, although we have tested this utility program, this is an experiential technique for registering additional types (your types) with Visual Studio.  This is not part of the Mole 2010 offering nor is it supported by Molosoft.  If you have a question or issue, please leave a comment on this blog post.

Second, in order for this to work, Mole 2010 and associated assemblies must be installed in the GAC. See Requirements below.

Mole 2010 Type Loader

Purpose

Provides a utility application that can discover types in an assembly, store those types in a local data tile and then create a custom type loader .dll that contains DebuggerVisualizer attributes for each type that has been loaded.

Setup

I recommend that your perform a Release build of the Mole.TypeLoader project and then copy the files to a folder under your Documents folder structure.  This will allow the application to write its data file without a permissions issue.

Next, add the Mole.TypeLoader.exe application to your start menu for quick access.

Requirements

Important: You can’t have any active debug sessions running when running the Mole.TypeLoader.exe application.  Visual Studio locks the Mole.TypeLoader.exe output file during debugging sessions and you will not be able to create a new one while a debugging sessions is running.

There are four requirements or actions that must be followed otherwise you’ll get unexpected results. 

  • Requires Mole 2010 version 1.2 or later.  See Molosoft news.
  • All Mole 2010 assemblies must be installed into the GAC
  • Each time a new version of Mole 2010 is installed you must:
    • Edit the Mole.TypeLoader.exe.config and update two settings
    • Run Mole.TypeLoader and execute the “Create Mole Types assembly” menu command

While not required by the Mole.TypeLoader application, all Mole 2010 .dll’s must be installed into the GAC so that when the Mole.Visualizer.VS2010.CustomTypeLoader.dll is created and the Mole visualizer is specified as the visualizer for the types, Visual Studio will be able to start the Mole 2010 visualizer.

This requirement is part of the above, “fine print.”  Despite the fact that that the Mole.Visualizer.VS2010.CustomTypeLoader.dll is located in a well known visualizers folder, its DebuggerVisualizer attributes specify an assembly by strong name, but not by the full path name.  Unless the Mole 2010 assemblies are in the GAC, the .NET Framework will not be able to locate and load the assemblies at debug time.  This is why the Mole 2010 assemblies must be installed into the GAC.

To install Mole 2010 assemblies into the GAC:

  • Open a Visual Studio 2010 command prompt, be sure to “Run as administrator”
  • Navigate to the folder where the Mole 2010 assemblies are installed and execute the following commands:
    • gacutil /i Mole.Visualizer.VS2010.dll
    • gacutil /i Microsoft.Licensing.Permutation_0e3eb_2.0.dll
    • gacutil /i Microsoft.Licensing.Runtime2.0.dll
    • gacutil /i Microsoft.Licensing.Utils2.0.dll

To uninstall Mole 2010 assemblies from the GAC:

  • Open a Visual Studio 2010 command prompt, be sure to “Run as administrator”
  • Navigate to the folder where the Mole 2010 assemblies are installed and execute the following commands:
  • gacutil /u Mole.Visualizer.VS2010
  • gacutil /u Microsoft.Licensing.Permutation_0e3eb_2.0
  • gacutil /u Microsoft.Licensing.Runtime2.0
  • gacutil /u Microsoft.Licensing.Utils2.0

Each time you install a new version of Mole 2010, you must update two settings in the Mole.TypeLoader.exe.config file, MoleAssemblyName and MoleObjectSource. 

You must ensure that the Version in the .config file matches the version of Mole 2010 you have installed.  The version can be viewed in the Mole 2010 About dialog, can be obtained by viewing the Mole 2010 visualizer assembly file properties in Windows Explorer, or can be viewed in Reflector.

<setting name="MoleAssemblyName" serializeAs="String">
    <value>Mole.EntryPoint, Mole.Visualizer.VS2010, Version=1.2.0.0, Culture=neutral, …
</setting>
<setting name="MoleObjectSource" serializeAs="String">
    <value>Mole.BackEnd.MoleVisualizerObjectSource, Mole.Visualizer.VS2010, Version=1.2.0.0, …
</setting>

The below Mole 2010 About dialog displays the version of Mole 2010 that is installed.

moleabout

You can also right click on the Mole 2010 visualizer assembly and view the File version.  This matches the above Mole assembly Version.

moleproperties

If you forget to update the .config file or don’t run the Mole.TypeLoader.exe and create a new Mole Types assembly after updating the .config file, you’ll get an error dialog when you attempt to view a custom type that was loaded by the Mole.TypeLoader utility.

Mole.TypeLoader Command Line Mode

The Mole 2010 Type Loader can be used in two modes; command line or as a normal WPF application.

When used as a command line application the following command line parameter are supported:

  • Mole.TypeLoader /?
    • This will display the command line usage in a console window
  • Mole.TypeLoader {folder to load}
    • This command line will load types from all .dll and .exe files in the specified folder.  This feature is useful when you are developing a custom framework or custom application and you want all types in the framework or application to automatically be available to start Mole 2010.
    • This can easily be accomplished by adding a Post-build event like so:
      • {folder where Mole.TypeLoader.exe is}\Mole.TypeLoader $(TargetDir)
      • The $(TargetDir) is a Visual Studio build event macro that returns the output folder

The Mole Type Loader does not load types so re-running of the Mole.TypeLoader.exe as a post-build event will not cause any problems.

When used in command line mode, the Mole.TypeLoader will inspect each .dll and .exe assembly in the specified folder, load its types, save the data file and then create a new Mole.Visualizer.VS2010.CustomTypeLoader.dll.

If an error occurs during this processing, a MessageBox will display with the error information.  Using a MessageBox as opposed to outputting information to a console window allows a developer to see any problems when the application is being run as a post-build task in Visual Studio.

Mole.TypeLoader WPF Application Mode

When Mole.TypeLoader.exe is executed without any command line arguments the WPF version of the application executes.

If you select an assembly from the left side list box, the data grid will be filtered to only display types from that assembly.

When opened, types in the right side data grid will be sorted by AssemblyName and TypeName.  You can change sorting by clicking or SHIFT clicking on the data grid column headers.

The initial status bar message displays the version information from the .exe.config file so that you know what version of Mole the outputted assembly will be targeting.

You can also click on the hyperlink in the lower right corner to visit the Molosoft.com web site.

moletypeloadertwo

To remove one or more types, select the row in the data grid and press the Delete key.  To remove all types from a single assembly, select the assembly name in the left side list box, then select all types in the data grid and press the Delete key.

To add one or more assemblies, use the File menu and select, “Select assemblies to load.”  When the files dialog appears, navigate to the desired folder and select one or more .dll or .exe files to load types from.

To create a new Mole.Visualizer.VS2010.CustomTypeLoader.dll assembly, use the File menu and select, “Create Mole Types assembly.”

If you add or remove types and forget to create the assembly, it will automatically be created for you.

fileMenu

Application Settings in Mole.TypeLoader.exe.config

LastFolder – this saves the last folder that assemblies were load from.  No reason to change this value.

OutputAssemblyName – this is the name of the assembly that will created that contains the DebuggerVisualizer attributes for all loaded types.  No reason to change this value.

OutputFolderName – this is the folder name where the assembly is outputted.  If this setting is blank (the default) the Mole.Visualizer.VS2010.CustomTypeLoader.dll will be outputted to {Documents}\Visual Studio 2010\Visualizers folder. 

If you change this setting to output to the {Visual Studio 2010 install location}\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\Visualizers folder, you must ensure that you set write permissions on the file, otherwise write errors will occur.

MoleAssemblyName – this is the entry point and the Mole 2010 assembly strong name.  This value will need to be updated each time a new version of Mole 2010 is installed.  You should only have to update the Version as described above.

MoleObjectSource – this is the object source and the Mole 2010 assembly strong name. This value will need to be updated each time a new version of Mole 2010 is installed. You should only have to update the Version as described above.

MoleDescription – this is the visualizer name that will appear in the Data Tip. No reason to change this value.

DataStoreFileName – this is the name of the file that the Mole.TypeLoader.exe saves its data to.   No reason to change this value.

Downloads

Mole Type Loader Source (295KB) can be downloaded from my Sky Drive.

Close

I realize there are a few moving parts to this solution.  However, once set up, its very easy to maintain and easily add and remove types from the custom types assembly that is created.

Feedback welcome.

Have a great day,

Just a grain of sand on the worlds beaches.


Mole 2010 v1.2 Released

April 3, 2011

Molosoft has been hard at work. We incorporated some customer feedback into Mole 2010, added a killer new feature for WPF and Windows Forms developers, and fixed a few minor issues. Read more about it and download the Mole 2010 v1.2 installer here.

Have a great day,

Just a grain of sand on the worlds beaches.


New Book Available: Developer’s Guide to Microsoft Prism 4

March 25, 2011

Last fall patterns & practices shipped Prism 4.

 

Today we are announcing the availability of the “Developer’s Guide to Microsoft Prism 4” book.

 

This book is available from O’Reilly or Amazon.

 

The eBook will be available for download shortly.

 

The MSDN online content is available here.

PrismBookCover
   
PrismSubwayMap

What’s In The Book?

Prism helps you to design and build flexible and maintainable WPF and Silverlight applications by using design patterns that support important architectural design principles, such as separation of concerns and loose coupling.

This guide will show you how to use Prism to implement the Model-View-ViewModel (MVVM) pattern in your applications, and how to use it along with commands and interaction requests to encapsulate application logic and make it testable.

It will show you how to split an application into separate functional modules that can communicate through loosely coupled events, and how to integrate those modules into the overall application.

It will show you how to dynamically construct a flexible user interface by using regions, and how to implement rich navigation across a modular application.

Have a great day,

Just a grain of sand on the worlds beaches.


Prism 4 Region Navigation with Silverlight Frame Navigation and Unity

March 10, 2011

I have blogged how to use the Unity Container with Prism 4 Region Navigation and the Silverlight Frame Navigation API’s.

While the sample code for the post is Silverlight, the Unity Configuration requirements are the same for WPF.

Have a great day,

Just a grain of sand on the worlds beaches.


Mole 2010 Demo Released

March 6, 2011

Many developers have asked for a demo version of Mole 2010.  We have just released it at http://www.molosoft.com/demo/.

Sorry it has taken an extra week to release.  I’ve been sick for the last 10 days and have not been able to work or attend the Boise or Dallas Code Camps I really wanted to attend.  I’m hoping I’m out of the woods.

In the mean time, Josh has posted two nice blog posts on using Mole 2010 here:

Have a great day,

Just a grain of sand on the worlds beaches.

 


Follow

Get every new post delivered to your Inbox.

Join 241 other followers