Seed Users and Roles with MVC 4, SimpleMembershipProvider, SimpleRoleProvider, Entity Framework 5 CodeFirst, and Custom User Properties

I’ve been Googling over the weekend and so far didn’t find any articles out there on how integrate EF5 CodeFirst nicely with SimpleMembership and at the same time, seeding some of your users, roles and associating users to roles while supporting custom fields/properties during registration, hence this blog post.

I think this is a nice to have, especially during PoC development where you could be developing features that depend on authentication and authorization while making schema changes with EF CodeFirst. The last thing you want to do is run update-database for migrations and have to manually re-insert/re-seed all your users, roles and associating the two every time you ran migrations (e.g. update-database -force from the Package Manager Console).

First, create an “Internet Application” ASP.NET MVC4 Project, because this is the only out of the box MVC template that has the new SimpleMembershipProvider wired up out of the box. One of the features I like the most about the SimpleMembershipProvider is it gives you total control of the highly requested “User” table/entity. Meaning you integrate SimpleMembershipProvider with your own user table, as long as it has a UserId and UserName fields in your table.

Obviously there are many more features in SimpleMembership provider, here are some links in this regard:

Explicitly wire up the providers even though this is implied, so that when do run the “update-database” command from the Package Manager Console for migrations we can use the native “Roles” Api.

In the “System.Web” Section add:


    <roleManager enabled="true" defaultProvider="SimpleRoleProvider">
      <providers>
        <clear/>
        <add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData"/>
      </providers>
    </roleManager>
    <membership defaultProvider="SimpleMembershipProvider">
      <providers>
        <clear/>
        <add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
      </providers>
    </membership>

Let’s add a custom field to the User table by adding a Mobile property to the UserProfile entity (MVC4SimpleMembershipCodeFirstSeedingEF5/Models/AccountModel.cs).


    [Table("UserProfile")]
    public class UserProfile
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
        public string UserName { get; set; }
        public string Mobile { get; set; }
    }

Enable EF5 CodeFirst Migrations

Seed your Roles and any Users you want to provision, also note the WebSecurity.InitializeDatabaseConnection method we are invoking. This method is what tells SimpleMembership which table to use when working with Users and which columns are for the UserId and UserName. I’m also going to demonstrate how you can hydrate additional custom columns such as requiring a User’s mobile number when registering on the site.


#region

using System.Data.Entity.Migrations;
using System.Linq;
using System.Web.Security;
using MVC4SimpleMembershipCodeFirstSeedingEF5.Models;
using WebMatrix.WebData;

#endregion

namespace MVC4SimpleMembershipCodeFirstSeedingEF5.Migrations
{
    internal sealed class Configuration : DbMigrationsConfiguration<UsersContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
        }

        protected override void Seed(UsersContext context)
        {
            WebSecurity.InitializeDatabaseConnection(
                "DefaultConnection",
                "UserProfile",
                "UserId",
                "UserName", autoCreateTables: true);

            if (!Roles.RoleExists("Administrator"))
                Roles.CreateRole("Administrator");

            if (!WebSecurity.UserExists("lelong37"))
                WebSecurity.CreateUserAndAccount(
                    "lelong37",
                    "password",
                    new {Mobile = "+19725000000"});

            if (!Roles.GetRolesForUser("lelong37").Contains("Administrator"))
                Roles.AddUsersToRoles(new[] {"lelong37"}, new[] {"Administrator"});
        }
    }
}

Now, run the update-database -verbose command from Package Manager Console, we are using the -verbose switch so that we can get better visibility on what’s getting executed on SQL. Notice the Mobile field is being created.

Let’s go ahead and do a sanity check and make sure all of our Users and Roles were provisioned correctly from the Seed method in our migration configuration, by executing a few queries.


SELECT TOP 1000 [UserId]
      ,[UserName]
      ,[Mobile]
  FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[UserProfile]
  
  SELECT TOP 1000 [RoleId]
      ,[RoleName]
  FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[webpages_Roles]
  
  SELECT TOP 1000 [UserId]
      ,[RoleId]
  FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[webpages_UsersInRoles]

Results

  • Users were inserted
  • Roles were provisioned
  • The user “LeLong37” was added and associated to the Administrator role

Finally for a sanity check, let’s go ahead and run the app and sign-in with the provisioned user from our Seed method.

Successfully authenticated with our seeded provisioned user (thought I’d add a blue star badge to the screenshot to add some humor 😛 )!

One last thing, let’s go ahead and modify our Register view, Register model and AccountController to gather the user’s mobile number during registration.

Register View (Register.cshtml)


@model MVC4SimpleMembershipCodeFirstSeedingEF5.Models.RegisterModel
@{
    ViewBag.Title = "Register";
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
    <h2>Create a new account.</h2>
</hgroup>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary()

    <fieldset>
        <legend>Registration Form</legend>
        <ol>
            <li>
                @Html.LabelFor(m => m.UserName)
                @Html.TextBoxFor(m => m.UserName)
            </li>
            <li>
                @Html.LabelFor(m => m.Password)
                @Html.PasswordFor(m => m.Password)
            </li>
            <li>
                @Html.LabelFor(m => m.ConfirmPassword)
                @Html.PasswordFor(m => m.ConfirmPassword)
            </li>
            <li>
                @Html.LabelFor(m => m.Mobile)
                @Html.TextBoxFor(m => m.Mobile)
            </li>
        </ol>
        <input type="submit" value="Register" />
    </fieldset>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}


Register model (AccountModel.cs)


    public class RegisterModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }

        [Required]
        [DataType(DataType.PhoneNumber)]
        [Display(Name = "Mobile")]
        public string Mobile { get; set; }
    }


Register Action (AccountController.cs)


        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                try
                {
                    WebSecurity.CreateUserAndAccount(
                        model.UserName, 
                        model.Password, 
                        new { Mobile = model.Mobile }, 
                        false);

                    WebSecurity.Login(model.UserName, model.Password);
                    return RedirectToAction("Index", "Home");
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

Finally, let’s register.

Let’s go ahead and run our SQL queries again and make sure the mobile number was actually saved to our UserProfile table during the registration.

Sweet! Registration successful, with mobile number saved to the UserProfile table.

Happy Coding…!

Download Sample Application: http://blog.longle.net/2012/09/26/multi-step-asp-net-mvc-4-registration-with-sms-using-twilio-cloud-communication-and-simplemembershipprovider-for-increased-user-validity/

Declaritively and Programitcally Subscribing to the Windows Azure Service Bus Relay with WCF

Preferably I like to have most of the configuration for WCF in my config file(s), however when PoC’ing and time is of essence, spending time troubleshooting your config file(s) can be frustrating, for example:

Web.config ‘TransportClientEndPointBehavior‘ element is not recognized when trying to configure your service/application to wire up to Windows Azure Service Bus so that you can push messages on to it, so that you can start relaying.

Error squiggly (message):

“The element ‘behavior’ has invalid child element ‘transportClientEndpointBehavior’. List of possible elements expected: ‘clientVia, callbackDebug, callbackTimeouts, clear, clientCredentials, transactedBatching, dataContractSerializer, dispatcherSyncronization, remove, synchronousRecieve, enableWebScript, webHttp, endpointDiscovery, soapProcessing’.”

Spent some time Googling and regretfully didn’t find any documentation out there on how subscribe to Windows Azure Service Bus 100% programitcally, so hence this blog post. So, let’s get started on how to wire up to Azure’s Service Bus with both approaches.

If you need to know how to setup the Windows Azure Service Bus in the Azure Portal please read https://www.windowsazure.com/en-us/develop/net/how-to-guides/service-bus-relay/.

First, let’s review how to push messages onto the Windows Azure Service Bus for relaying.

Programitically (zero configuration in your .config file)

  • Create an interface that implements IAzureTunnelService, IClientChannel.

    
        public interface IAzureTunnelServiceChannel : IAzureTunnelService, IClientChannel
        {
        }
    
    
  • Wire up to push messages on Windows Azure Service Bus for relay.

    
                var serviceUri = ServiceBusEnvironment
                    .CreateServiceUri("sb", "yournamespace", "relaystatus");
    
                var sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
    
                var tokenProvider = TokenProvider
                    .CreateSharedSecretTokenProvider("owner", "secretkey");
    
                sharedSecretServiceBusCredential.TokenProvider = tokenProvider;
    
                var endpoint = new ServiceEndpoint(
                    ContractDescription.GetContract(typeof(IAzureTunnelService)),
                    new NetTcpRelayBinding(
                        EndToEndSecurityMode.Transport, 
                        RelayClientAuthenticationType.None),
                        new EndpointAddress(serviceUri));
    
                var channelFactory = new ChannelFactory<IAzureTunnelService>(endpoint);
                channelFactory.Endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
                var channel = channelFactory.CreateChannel();
                var result = channel.RelayRequest(yourmodel);
    
    

Declaritively

  • web.config/app.config (system.serviceModel section)

    In the config we are introducing all known service bus extensions. You can remove the ones you don’t need.

    
      <system.serviceModel>
        <client>
          <endpoint name="relayrequest" contract="YourNameSpace.AzureTunnel.Common.Contracts.IAzureTunnelService" binding="netTcpRelayBinding" address="sb://yourSBnamespace.servicebus.windows.net/relayrequest" behaviorConfiguration="sbTokenProvider" />
        </client>
        <behaviors>
          <endpointBehaviors>
            <behavior name="sbTokenProvider">
              <transportClientEndpointBehavior>
                <tokenProvider>
                  <sharedSecret issuerName="owner" issuerSecret="yoursecretykeygoeshere" />
                </tokenProvider>
              </transportClientEndpointBehavior>
            </behavior>
          </endpointBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
        <extensions>
          <!-- In this extension section we are introducing all known service bus extensions. User can remove the ones they don't need. -->
          <behaviorExtensions>
            <add name="connectionStatusBehavior" type="Microsoft.ServiceBus.Configuration.ConnectionStatusElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="transportClientEndpointBehavior" type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="serviceRegistrySettings" type="Microsoft.ServiceBus.Configuration.ServiceRegistrySettingsElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          </behaviorExtensions>
          <bindingElementExtensions>
            <add name="netMessagingTransport" type="Microsoft.ServiceBus.Messaging.Configuration.NetMessagingTransportExtensionElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="tcpRelayTransport" type="Microsoft.ServiceBus.Configuration.TcpRelayTransportElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="httpRelayTransport" type="Microsoft.ServiceBus.Configuration.HttpRelayTransportElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="httpsRelayTransport" type="Microsoft.ServiceBus.Configuration.HttpsRelayTransportElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="onewayRelayTransport" type="Microsoft.ServiceBus.Configuration.RelayedOnewayTransportElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          </bindingElementExtensions>
          <bindingExtensions>
            <add name="basicHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.BasicHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="webHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WebHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="ws2007HttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WS2007HttpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="netTcpRelayBinding" type="Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="netOnewayRelayBinding" type="Microsoft.ServiceBus.Configuration.NetOnewayRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="netEventRelayBinding" type="Microsoft.ServiceBus.Configuration.NetEventRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            <add name="netMessagingBinding" type="Microsoft.ServiceBus.Messaging.Configuration.NetMessagingBindingCollectionElement, Microsoft.ServiceBus, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          </bindingExtensions>
        </extensions>
      </system.serviceModel>
    
    
  • C# Code

    
                var channelFactory = new ChannelFactory<IAzureTunnelServiceChannel>("relayrequest");
                using (var channel = channelFactory.CreateChannel())
                {
                    return channel.RelayRequest(url, myModel);
                }
    
    

Note: To shortcut some of this configuration you can add the appropriate references and config configurations by using NuGet and installing the Windows Azure Service Bus package.


Finally, let’s wire up to receive messages off the Windows Azure Service Bus that we relayed earlier (consumer, demonstrated with a console app) programatically.

  • Service Interface

    
        [ServiceContract(Namespace = "urn:ps")]
        public interface IAzureTunnelService
        {
            [OperationContract]
            XElement RelayRequest(string url, YourModel yourModel);
        }
    
    
  • Service Implementation

    
        public class AzureTunnelService : IAzureTunnelService
        {
            public XElement RelayRequest(string url, YourModel yourModel)
            {
                Console.WriteLine("{0,13}|{1,13}", 
                  yourModel.yourProperty1, 
                  yourModel.yourProperty2);
            }
        }
    
    
  • Host the WCF Service

    
            private static void Main(string[] args)
            {
                var serviceHost = new ServiceHost(typeof (AzureTunnelService));
    
                serviceHost.AddServiceEndpoint(
                    typeof (IAzureTunnelService), 
                    new NetTcpBinding(), "net.tcp://localhost:9385/relayrequest");
    
                serviceHost.AddServiceEndpoint(
                    typeof(IAzureTunnelService), 
                    new NetTcpRelayBinding(),
                    ServiceBusEnvironment
                        .CreateServiceUri("sb", "yourSBnamespace", "relayrequest"))
                        .Behaviors.Add(new TransportClientEndpointBehavior
                            {
                                TokenProvider = TokenProvider
                                    .CreateSharedSecretTokenProvider(
                                        "owner", 
                                        "yoursecretkey"
                                    )
                            });
    
                serviceHost.Open();
                Console.WriteLine("Press ENTER to close.");
                Console.ReadLine();
                serviceHost.Close();
            }
    
    

Yes, we have configuration in code, however push comes to shove, it’s always good to have an alternative solution. Being pragmatic about this, how often are you going to need to change your configuration on how your are communicating with Windows Azure Service Bus anyway?

Happy Coding…! 🙂

Building a Composite ASP.NET MVC Application with Pluggable Areas from External Projects and Assemblies

Update: 10/25/2012

  1. Resolved rendering issues from a Plugin, when controllers names are not unique
  2. Added support for strongly typed views for Plugin views to support Entity Framework scaffolding and/or model binding
  3. Decommissioned custom Razor View Engine, moving to convention over configuration, approach
  4. Updated (sourcecode) sample application download link with latest code base

I recently did a post on Building a Composite MVC3 Application with Ninject, this post we will achieve the same goals with a much more simplistic approach using MV3 Areas.

This provides separation of concerns and loose coupling, helping you to design and build applications using loosely coupled components that can evolve independently which can be easily and seamlessly integrated into the overall application. These types of applications are known as composite applications.

So the problem is that the MVC3 runtime only scans the current executing assembly for IControllers, classes that implement AreaRegistration (to load and register MVC Areas), etc. The key here is to get the MVC3 runtime to scan other assemblies as well so that we can have external projects/assemblies so that we can scale the application horizontally without creating one large monolithic web project which also serves lends it self well when having multiple teams working in parrallel on the same project.

So let’s start! How do we get the MVC runtime to scan external assemblies as it does witht he current executing assembly of our Web project/assembly?

Open up your AssemblyInfo.cs class and add this attribute at the very end:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Web;
using MvcApplication8.Web;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle(&quot;MvcApplication8.Web&quot;)]
[assembly: AssemblyDescription(&quot;&quot;)]
[assembly: AssemblyConfiguration(&quot;&quot;)]
[assembly: AssemblyCompany(&quot;HP&quot;)]
[assembly: AssemblyProduct(&quot;MvcApplication8.Web&quot;)]
[assembly: AssemblyCopyright(&quot;Copyright © HP 2012&quot;)]
[assembly: AssemblyTrademark(&quot;&quot;)]
[assembly: AssemblyCulture(&quot;&quot;)]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid(&quot;cdb134c0-92a4-4fe4-a7dc-6ea3e4a88bcc&quot;)]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Revision and Build Numbers 
// by using the '*' as shown below:
[assembly: AssemblyVersion(&quot;1.0.0.0&quot;)]
[assembly: AssemblyFileVersion(&quot;1.0.0.0&quot;)]

[assembly: PreApplicationStartMethod(
  typeof(PluginAreaBootstrapper), &quot;Init&quot;)]

Note: This is letting the runtime know that before loading the MVC3 Web project assembly please invoke the “Init” method the class named “PluginAreaBootStrapper” where we will dynamically scan for our MVC3 Plugin assemblies so that the MVC runtime can scan them as well
http://msdn.microsoft.com/en-us/library/system.web.preapplicationstartmethodattribute.aspx.

Let’s take a look at what the PluginAreaBootstrapper.Init() method is doing:

    public class PluginAreaBootstrapper
    {
        public static readonly List&lt;Assembly&gt; PluginAssemblies = new List&lt;Assembly&gt;();

        public static List&lt;string&gt; PluginNames()
        {
            return PluginAssemblies.Select(
                pluginAssembly =&gt; pluginAssembly.GetName().Name)
                .ToList();
        }

        public static void Init()
        {
            var fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, &quot;Areas&quot;);

            foreach (var file in Directory.EnumerateFiles(fullPluginPath, &quot;*Plugin*.dll&quot;))
                PluginAssemblies.Add(Assembly.LoadFile(file));

            PluginAssemblies.ForEach(BuildManager.AddReferencedAssembly);
        }
    }

Note: We are simply scanning the Areas directory in our main MV3 web app for any plugin assemblies that we are dropping the the [Areas] (MvcApplication8.Web/Areas) folder and adding our external Plugin assemblies with BuildManager.AddReferencedAssembly (http://msdn.microsoft.com/en-us/library/system.web.compilation.buildmanager.addreferencedassembly.aspx) before our main(host) MVC3 Web App gets started.

You can setup break points on PluginAreaBootstrapper.Init() and Global.asax.cs.ApplicationStart() and see that the PluginAreaBootstrapper.Init() (where we are loading our external Plugin assemblies) method is invoked before Global.asax.cs.ApplicationStart().

Add a custom Razor View Engine

This is so that our MVC3 application will know where to go (physical location) to retrieve views from our plugins. We are copying each of our plugins to a folder named after the plugin assembly name under the [Areas] folder from our main web app e.g. MvcApplication8.Web/Areas/MvcApplication8.Web.MyPlugin1.


    public class PluginRazorViewEngine : RazorViewEngine
    {
        public PluginRazorViewEngine()
        {
            AreaMasterLocationFormats = new[]
            {
                &quot;~/Areas/{2}/Views/{1}/{0}.cshtml&quot;,
                &quot;~/Areas/{2}/Views/{1}/{0}.vbhtml&quot;,
                &quot;~/Areas/{2}/Views/Shared/{0}.cshtml&quot;,
                &quot;~/Areas/{2}/Views/Shared/{0}.vbhtml&quot;
            };

            AreaPartialViewLocationFormats = new[]
            {
                &quot;~/Areas/{2}/Views/{1}/{0}.cshtml&quot;,
                &quot;~/Areas/{2}/Views/{1}/{0}.vbhtml&quot;,
                &quot;~/Areas/{2}/Views/Shared/{0}.cshtml&quot;,
                &quot;~/Areas/{2}/Views/Shared/{0}.vbhtml&quot;
            };

            var areaViewAndPartialViewLocationFormats = new List&lt;string&gt;
            {
                &quot;~/Areas/{2}/Views/{1}/{0}.cshtml&quot;,
                &quot;~/Areas/{2}/Views/{1}/{0}.vbhtml&quot;,
                &quot;~/Areas/{2}/Views/Shared/{0}.cshtml&quot;,
                &quot;~/Areas/{2}/Views/Shared/{0}.vbhtml&quot;
            };

            var partialViewLocationFormats = new List&lt;string&gt;
            {
                &quot;~/Views/{1}/{0}.cshtml&quot;,
                &quot;~/Views/{1}/{0}.vbhtml&quot;,
                &quot;~/Views/Shared/{0}.cshtml&quot;,
                &quot;~/Views/Shared/{0}.vbhtml&quot;
            };

            var masterLocationFormats = new List&lt;string&gt;
            {
                &quot;~/Views/{1}/{0}.cshtml&quot;,
                &quot;~/Views/{1}/{0}.vbhtml&quot;,
                &quot;~/Views/Shared/{0}.cshtml&quot;,
                &quot;~/Views/Shared/{0}.vbhtml&quot;
            };

            foreach (var plugin in PluginAreaBootstrapper.PluginNames())
            {
                masterLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/{1}/{0}.cshtml&quot;);
                masterLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/{1}/{0}.vbhtml&quot;);
                masterLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/Shared/{1}/{0}.cshtml&quot;);
                masterLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/Shared/{1}/{0}.vbhtml&quot;);

                partialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/{1}/{0}.cshtml&quot;);
                partialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/{1}/{0}.vbhtml&quot;);
                partialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/Shared/{0}.cshtml&quot;);
                partialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/Shared/{0}.vbhtml&quot;);

                areaViewAndPartialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/{1}/{0}.cshtml&quot;);
                areaViewAndPartialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Views/{1}/{0}.vbhtml&quot;);
                areaViewAndPartialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Areas/{2}/Views/{1}/{0}.cshtml&quot;);
                areaViewAndPartialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Areas/{2}/Views/{1}/{0}.vbhtml&quot;);
                areaViewAndPartialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Areas/{2}/Views/Shared/{0}.cshtml&quot;);
                areaViewAndPartialViewLocationFormats.Add(
                    &quot;~/Areas/&quot; + plugin + &quot;/Areas/{2}/Views/Shared/{0}.vbhtml&quot;);
            }

            ViewLocationFormats = partialViewLocationFormats.ToArray();
            MasterLocationFormats = masterLocationFormats.ToArray();
            PartialViewLocationFormats = partialViewLocationFormats.ToArray();
            AreaPartialViewLocationFormats = areaViewAndPartialViewLocationFormats.ToArray();
            AreaViewLocationFormats = areaViewAndPartialViewLocationFormats.ToArray();
        }
    }

Note: Lines 45-77 is where we iterate through each of our plugin assemblies and register their physical location(s) of their views.

Let’s create our external VS MVC3 Web Project for our Plugin

  1. Add a MVC3 Project to our solution e.g. MVCApplication8.Web.MyPlugin1
  2. Create a controller named MyPlugin1Controller.cs

    #region
    
    using System.Web.Mvc;
    
    #endregion
    
    namespace MvcApplication8.Web.MyPlugin1.Controllers
    {
        public class MyPlugin1Controller : Controller
        {
            public ActionResult Index()
            {
                return View();
            }
        }
    }
  3. Add a View (Index.cshtml)

    
    @{
        ViewBag.Title = &quot;Index&quot;;
        Layout = &quot;~/Views/Shared/_Layout.cshtml&quot;;
    }
    
    &lt;h2&gt;Hello! This is a Razor View from MvcApplication8.Web.MyPlugin1&lt;/h2&gt;
    
    
    
  4. Add some xcopy commands to our Plugin project build post events

    MyPlugin1 post build event

    xcopy “$(ProjectDir)\Views” “$(TargetDir)\MyPlugin1\Views\” /s /i /y
    xcopy “$(ProjectDir)\Areas” “$(TargetDir)\MyPlugin1\Areas\” /s /i /y
    xcopy “$(ProjectDir)\Content” “$(TargetDir)\MyPlugin1\Content\” /s /i /y

    MyPlugin2 post build event

    xcopy “$(ProjectDir)\Views” “$(TargetDir)\MyPlugin2\Views\” /s /i /y
    xcopy “$(ProjectDir)\Areas” “$(TargetDir)\MyPlugin2\Areas\” /s /i /y
    xcopy “$(ProjectDir)\Content” “$(TargetDir)\MyPlugin2\Content\” /s /i /y

    Note: this is to copy our plugin views under the [Areas] folder of our main web app (MvcApplication8.Web), the folder name that the plugins are copied to must match the AreaName being registered by the plugin.

  5. Set the output path for our assemblies to place the compiled assemblies from our plugins under the [Areas] folder in our main host web app e.g. MvcApplication8.Web\Areas.

Now let’s run our application and type in the url prefixed with the controller from our plugin e.g. (http://localhost:48733/MyPlugin1)

Voila.., Our controller and view from an external MVC3 project/assembly loads…!

We’ll go ahead and repeat the steps creating a second plugin just for a sanity check and run the app one more time with the url prefixed with the controller from the second plugin e.g. (http://localhost:48733/MyPlugin2)

Voila.., Our controller and view from our second plugin MVC3 project/assembly loads…!

Quick review on our Solution structure

  1. Our plugin folders that are copied to the [Area] folder of our main MVC3 web app
  2. MyPlugin1 controller from our first plugin
  3. MyPlugin2 controller from our second plugin

Registering Routes from Plugins

In order to Register Routes you have to traditionally do this in the Global.asax.cs RegisterRoutes(RouteCollection routes) method in host web application (MvcApplication.Web). There can only be one Global.asax.cs for any given site. So, how can we register Routes from our Plugins when our host web app and Plugins are now completely decoupled?! Meaning they really have no dependencies and are completely ignorant of eachother (which was our goal to begin with, which was to create a “true” decoupled MVC Pluggable architecture).

This was a great question raised by Basem, so let’s dive into the solution for this. When the MVC runtime starts up our application it scans the current executing assembly as well as our Plugin assemblies thanks to our MvcApplication8.Web.PluginAreaBootstrapper.cs implementation. Meaning it scans for implementations of IController, IDependencyResolver, IControllerFacotry, RazorViewEngines and (whats relevant to our solution at hand) any classes that implement AreaRegistration. If we decompose this implementation you will see that there are two overrides that we must implement:

  • AreaName
  • RegisterArea(AreaRegistration context)

So what we need to do here is add an implementation of AreaRegistration to each of our Plugins.

MvcApplication8.Web.MyPlugin1.MyPlugin1AreaRegistration.cs


namespace MvcApplication8.Web.MyPlugin1
{
    public class MyPlugin1AreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return &quot;MyPlugin1&quot;; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                &quot;MyPlugin1_default&quot;,
                &quot;MyPlugin1/{controller}/{action}/{id}&quot;,
                new {action = &quot;Index&quot;, id = UrlParameter.Optional}
                );
        }
    }
}

MvcApplication8.Web.MyPlugin2.MyPlugin2AreaRegistration.cs


namespace MvcApplication8.Web.MyPlugin2
{
    public class MyPlugin2AreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get { return &quot;MyPlugin2&quot;; }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                &quot;MyPlugin2_default&quot;,
                &quot;MyPlugin2/{controller}/{action}/{id}&quot;,
                new {action = &quot;Index&quot;, id = UrlParameter.Optional}
                );
        }
    }
}

Now if we set up a few break points in our implementations of AreaRegistration we will notice that when the application initially starts up (you may have to close out any Casini instances or restart your site in IIS, to ensure that it is the absolute first time your app is being started) the MVC runtime will scan both of our Plugin assemblies and will read the AreaName and invoke the RegisterArea methods in them. Great, now we can add any Routes from our Plugins into the body of the RegisterArea(AreaRegistrationContext context) methods…!

Happy Coding…! 🙂

Download sample application: https://skydrive.live.com/redir?resid=949A1C97C2A17906!2600&authkey=!ANP30kAEhO6QSfs

Building a Composite MVC3 Application with Ninject

Update: 05/04/2012 – Preferred alternative approach without using IoC for Plugins (http://blog.longle.net/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas/).

So there’s great support in Prism to building composite applications with Silverlight with the notion of Prism modules. They have a nice discovery approach for dynamically discovering modules when loading XAPs and assemblies during runtime for all the different modules your Silverlight app may need. You can load them during start-up or on demand so that you don’t have to download the entire application at one time.

When building an enterprise MVC application, I wanted to borrow some of the ideas and architecture of the Prism extensible plug and play concepts to provide the ability to build modules (areas) of your MVC application outside of your core MVC application.

For example if you had a MVC application and it’s primary role is an E-Commerce site (core site), however you have this new requirement to build a integration point to show customers all their tracking statuses for their orders. Now you have to ramp up a development team as quick as possible so that they can build out this feature, however you now find yourself giving them a full blown training and overview of your core MVC application, full source control of your entire VS Solution set which could have up to 20-30 projects in it.

Now when devs from the team compile it’s taking forever…! Here we can easily see that our MVC app’s footprint is getting to large and somewhat difficult to manage. So here is now the need to break it down into blocks that can be injected into the app during runtime so that development for these different pieces, blocks, or modules can happen in parallel with your core MVC application (loose coupling, modularity and extensibility).

My preference here is to actually use Mef since I have experience with it and the great support for MVC3 and Mef now. However, I’ve been given the opportunity to be engaged on a project that uses Ninject. With this being the situation at hand I wanted to explore and see if we could borrow the some concepts from Prism, and incorporate them using what was out of the box with Ninject. Some of these concepts include separation of concerns and loosely coupled components (modules) that can evolve independently but can be easily and seamlessly integrated into the overall application, which is also known as a composite application.

With a little bit of Googling I stumbled upon this article http://www.thegecko.org/index.php/2010/06/pluggable-mvc-2-0-using-mef-and-strongly-typed-views/ which was pretty much what we were looking for however it just needed to be ported from MVC2 to MVC3, use Ninject instead of Mef and just a tad bit of polishing.

So after a little bit of poking around with Ninject, I quickly found that Ninject also has a notion of Modules, NinjectModules, or classes that implement the INinjectModule interface. You can ask the Ninject Kenerl (container) to scan an assembly and it will scan for all any classes that implement INinjectModule, this can be done directly by implementing the actual interface or inheriting their out of the box NinjectModule abstract class.

So rather than starting from ground zero here, I’m going to continue with the project from my last post http://blog.longle.net/2012/02/15/wrapping-the-ninject-kernel-with-servicelocator/.

Quick breakdown on the VS Solution structure:

  • MvcApplication

    This is our main MVC application which will host all the Plugins

  • MvcApplication.Plugin.Framework

    This is a C# class library where all the plugin infrastructure classes will reside

  • MvcApplicationA.Plugin

    Example PluginA

  • MvcApplicationA.Plugin

    Example PluginB

  • MvcApplicationA.Plugin

    Example PluginB

Let’s take a quick look at some of the classes in the MvcApplication.PluginFramework VS Project.

  • MyController.cs (implements IMyController)

    All controllers from plugins will need to inherit MyController, this provides some meta-data so that we can infer the correct type of a plugin Controller from our IoC that was requested.

  • MyPlugin.cs

    There will be one class in each plugin that must inherit MyPlugin, this class provides meta-data about the plugin, e.g. PluginName, AssemblyName, etc.. It also gives us the overidable Load operation where we can setup our Ninject bindings e.g. Controller and plugin bindings.

  • MyControllerFactory.cs

    We inherit the DefaultControllerFactory and override the GetControllerType method so that when a user is routed to a controller that is in a plugin, we can help the MVC runtime derive what it’s type is by scanning our IoC for registered instances for that a given Controller and return it’s type.

    
        public class MyControllerFactory : DefaultControllerFactory
        {
            protected override Type GetControllerType(RequestContext requestContext, 
                string controllerName)
            {
                var controllerType = base.GetControllerType(requestContext, controllerName);
    
                if (controllerType == null)
                {
                    var controller = ServiceLocator.Current.GetAllInstances<IController>().ToList()
                    .OfType<IMyController>()
                    .SingleOrDefault(c => c.ControllerName == controllerName);
    
                    if (controller != null)
                    {
                        return controller.GetType();
                    }
                }
    
                return controllerType;
            }
        }
    
    
  • MyRazorViewEngine (MyViewEngine.cs)

    Custom RazorViewEngine so that we can properly return Views *.cshtml (Razor) that have been copied to our Plugins directory in our main app (MvcApplication/Plugins).

  • MyWebFormEngine (MyViewEngine.cs)

    Custom WebFormViewEngine so that we can properly return MVC *.aspx (non-Razor) Views that have been copied to our Plugins directory in our main app (MvcApplication/Plugins).

  • MyPluginBootstrapper.cs and yes, I borrowed the name from Prism :p

    • Scans the “MvcApplication/Plugin” directory and loads all of our plugins
    • Register’s any custom routes from our plugins
    • Register’s our MyControllerFactory with the MVC runtime
    • Register’s our MyWebFormViewEngine with the MVC runtime
    • Register’s our MyRazorViewEngine with the MVC runtime
    
        public class MyPluginBootstrapper : NinjectModule
        {
            private const string _pluginPath = "Plugins";
            private readonly string _fullPluginPath;
            private const string _defaultMaster = "Site";
            private const string _defaultRazorMaster = "_Layout";
    
            public MyPluginBootstrapper()
            {
                _fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _pluginPath);
            }
    
            public override void Load()
            {
                var assemblies = new List<Assembly>();
    
                // Discover  Modules in plugin directory (e.g. site/plugins)
                foreach (var file in Directory.EnumerateFiles(_fullPluginPath, "*.Plugin.dll"))
                    assemblies.Add(Assembly.LoadFile(file));
    
                Kernel.Load(assemblies);
    
                //  plugins discovery
                var plugins = new List<IMyPlugin>();
                foreach (IMyPlugin plugin in ServiceLocator.Current.GetAllInstances<IMyPlugin>())
                {
                    plugins.Add(plugin);
                    plugin.RegisterRoutes(RouteTable.Routes);
                }
    
                // Register ControllerFactory with site
                IControllerFactory myControllerFactory = new MyControllerFactory();
                ControllerBuilder.Current.SetControllerFactory(myControllerFactory);
    
                // Setup ViewEngines
                var myWebFormViewEngine = 
                    new MyWebFormViewEngine(_pluginPath, plugins, _defaultMaster);
    
                var myRazorViewEngine = 
                    new MyRazorViewEngine(_pluginPath, plugins, _defaultRazorMaster);
    
                // Register ViewEngines with site
                ViewEngines.Engines.Clear();
                ViewEngines.Engines.Add(myWebFormViewEngine);
                ViewEngines.Engines.Add(myRazorViewEngine);            
            }
        }
    
    

So what’s all required to setup an MVC plugin now?

  1. Create a regular MVC3 app project to be the plugin
  2. Assembly name must match this pattern *.Plugin.dll, yes we are using convention for this.
  3. Must have one class that inherits MyPlugin.cs

    
        public class PluginA : MyPlugin
        {
            public override void Load()
            {
                Bind<IMyPlugin>().To<PluginA>();
                Bind<IController>().To<PluginAController>()
                    .Named(GetControllerName<PluginAController>());
            }
        }
    
    
  4. Setup binding for the plugin e.g. IMyPlugin -> PluginA

    
        public class PluginA : MyPlugin
        {
            public override void Load()
            {
                Bind<IMyPlugin>().To<PluginA>();
                Bind<IController>().To<PluginAController>()
                    .Named(GetControllerName<PluginAController>());
            }
        }
    
    
  5. Setup bindings for any Controllers for the plugin e.g. IController -> PluginAController
    
        public class PluginA : MyPlugin
        {
            public override void Load()
            {
                Bind<IMyPlugin>().To<PluginA>();
                Bind<IController>().To<PluginAController>()
                    .Named(GetControllerName<PluginAController>());
            }
        }
    
    
  6. All plugin Controllers must inherit MyController.cs
    
        public class PluginAController : MyController
        {
            public ActionResult Index()
            {
                return View();
            }
        }
    
    

Wrapping up, we have addressed the following concerns:

  • Loose coupling
  • Separation of concerns
  • Application modularity
  • Building our application from partitioned components
  • IoC & Dependency Injection
  • ServiceLocation with ServiceLocator and/or Ninject’s IKernel
  • Composite pattern

As requirements changed and the project matures, it will be helpful that we can change parts of the application without having these changes cascade throughout the system. Modularizing an application allow you to build application components separately (and loosely coupled) and to change whole parts of your application without affecting the rest of your code base.

Happy coding…! 🙂

Inject (IoC) my MVC3 Application in less than 5 minutes…!

Quickest way to get your MVC3 application up and running with IoC (Inverse of Control) pattern. So let’s start off by first choosing an IoC framework, for this example we will use Ninject, however your more than welcome to choose other IoC frameworks such as Unity, Mef, AutoFac, etc.. I personally prefer Mef, however in this example we will use Ninject so that we can demonstrate how to implement the ServiceLcoator interface to wrap your chose of Ninect container which is accessed by Ninject Kernel, this can come in handy later if you ever decide to switch out your choice of IoC framework.

So let’s start with a fresh new MVC3 application, the first thing on our TODO list is to add Ninject, we are in luck here since we can easily add this with NuGet.

  1. Right click references in your MVC3 project and choose Manage NuGet Packages
  2. Search for “Ninject” in the Search textbox
  3. Your application should be wired up with the Ninject reference added to your project
  4. Add a class named “MyDependencyResolver.cs” anywhere in your MVC3 project, and have it impelment the IDependencyResolver interface. This will allow you to plug pretty much anything into the MVC runtime. The System.Web.Mvc.IDependencyResolver will have two methods that you will need to implement GetService and GetServices.
    
        public class MyDependencyResolver : IDependencyResolver
        {
            public object GetService(Type serviceType)
            {
                throw new NotImplementedException();
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                throw new NotImplementedException();
            }
        }
    
    
  5. Now let’s wire up our Ninject Kernel (container) in this class MyDependencyResolver.cs
    
        public class MyDependencyResolver : IDependencyResolver
        {
            private readonly IKernel _kernel;
    
            public MyDependencyResolver(IKernel kernel)
            {
                _kernel = kernel;
            }
    
            public object GetService(Type serviceType)
            {
                return _kernel.TryGet(serviceType, new IParameter[0]);
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                return _kernel.GetAll(serviceType, new IParameter[0]);
            }
        }
    
    

    We create a constructor that accepts IKernel as a parameter, this is where and how the Ninject Kernel will be injected into this class.

  6. Now what we need to do is register MyDependencyResolver with the MVC runtime so that it knows to use it. So let’s head over to Application_Start() in our Global.asax class to wire this up. Here we add a helper method “RegisterMyDependencyResolver” which we will instantiate a new instance of StandardKernel and register it with the MVC runtime using DependencyResolver.SetResolver method which accepts a parameter of IDependencyResolver which our MyDependencyResolver class implemeneted.
    
            protected void Application_Start()
            {
                RegisterMyDependencyResolver();            
                AreaRegistration.RegisterAllAreas();
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
            }
    
            private void RegisterMyDependencyResolver()
            {
                var standardKernel = new StandardKernel();
                DependencyResolver.SetResolver(new MyDependencyResolver(standardKernel));
            }
    
    
  7. Now if we setup a breakpoint on our GetService method we will see that the MVC runtime will first request an instance of System.Web.Mvc.IControllerFactory, now since we haven’t registered or bound an actual class which implements the IControllerFactory interface, our GetService method will just return null, and the MVC runtime will just default to the default ControllerFactory. Now if we had a custom ControllerFactory and had it registered, this would have returned our own instance.

    As you break on on the GetService method, you will notice that the MVC runtime will also request an instance of IControllerActivator, HomeController, IViewPageActivator, Home_Index_cshtml.

  8. Now let’s demonstrate a simple HelloWold injection example. First we want to program against an interface, IHelloWorld with the a method Hello(string message).

    
        public interface IHelloWorldService
        {
            string Hello(string message);
        }
    
    
    

    Now let’s implement this interface, create a HelloWorldService.cs class and implement this interface.

    
        public class HelloWorldService : IHelloWorldService
        {
            public string Hello(string message)
            {
                return message;
            }
        }
    
    
  9. Now we have to register our concrete implementation HelloWorldService to our IHelloWorldService with our container (Kernel), will do this in our Global.asax where we originally fired up our Kernel.
    
            private void RegisterMyDependencyResolver()
            {
                var standardKernel = new StandardKernel();
                standardKernel.Bind<IHelloWorldService>().To<HelloWorldService>();
                DependencyResolver.SetResolver(new MyDependencyResolver(standardKernel));
            }
    
    
  10. Now if we setup a breakpoint in the constructor of our HomeController we will see that the IHomeController parameter will be hydrated by our GetService method of our MyDependencyResolver.GetService method which we registerd as our DependencyResolver with the MVC runtime, this is DependencyInjection.

Download sample: https://skydrive.live.com/redir.aspx?cid=949a1c97c2a17906&resid=949A1C97C2A17906!370&parid=949A1C97C2A17906!361

Stay tuned for Part 2, where we will wire up the ServiceLocator to wrap how we retrieve registered instances so in the event where we wanted to switch out our IoC framework (e.g. Unity, Mef, AutoFac, StructureMap) we would have very little refactoring and code change.

Quick Review on the Strategy Pattern…!

So you have a set of similar classes where you want to encapsulate a family of related algorithms. Each the classes have different variations of a similar algorithm or business rules and they need a way to evolve separately from the classes that are using (consuming) them. In this fictitious example we are a phone retailer, could be a system we use online as well as the POS system that is used at an actual brick and mortar store. Now when selling phones you have to order phones from different distributors or manufactures, each manufacture having different business rules and services you may need to call in order to for the manufacture’s distribution center to fulfill your order. The Strategy Pattern comes in handy here so that we can effectively manage these different types of custom implementations for ordering from all these different types of manufactures while not having to rebuild, or compile our OrderService every time we start doing business with new phone manufacture. Last but not least it makes managing our code with all these different manufactures a whole heck of a lot easier…!

So in this example our manufactures will be Apple, HTC, Nokia, and Sony. Each will have their own processes and business rules to adhere to when placing order and getting your phone order fulfilled for your customers.

Our domain model (pretty self-explanatory, so I won’t will dive into any details on this)

1-30-2012 6-07-40 PM

Let’s take a look at what are implementation would like in order to handle all the different manufactures in our domain before implementing the Strategy Pattern.

So we have our OrderService, a class that handles all the heavy lifting for ordering from any given manufacture we do business with. Each case in our switch statement having custom implementation for that given manufacture, I’ve kept this pretty simple to get the point across however in the real world you could probably expect to do specific validation, business rules, executing different back-end services, etc… for a given manufacture.

VSProject: BeforeStrategyPattern, Class: OrderService.cs

      

    public class OrderService
    {
        public ManufactureInvoice OrderProduct(Product product)
        {
            switch (product.Manufacture)
            {
                case Manufacture.Sony:
                    // call Sony webservices, etc...
                    return new ManufactureInvoice
                    {
                        Cost = product.Cost,
                        EstimatedArrivalDate = DateTime.Now.AddDays(5),
                        EstimatedShippedDate = DateTime.Now,
                        Tax = product.Cost * .07M,
                        Manufacture = Manufacture.Sony
                    };

                case Manufacture.Apple:
                    // call Apple webservices, etc...
                    return new ManufactureInvoice
                    {
                        Cost = product.Cost,
                        EstimatedArrivalDate = DateTime.Now.AddDays(5),
                        EstimatedShippedDate = DateTime.Now,
                        Tax = product.Cost * .07M,
                        Manufacture = Manufacture.Apple
                    };

                case Manufacture.Nokia:
                    // call Nokia webservices, etc...
                    return new ManufactureInvoice
                    {
                        Cost = product.Cost,
                        EstimatedArrivalDate = DateTime.Now.AddDays(5),
                        EstimatedShippedDate = DateTime.Now,
                        Tax = product.Cost * .07M,
                        Manufacture = Manufacture.Nokia
                    };

                case Manufacture.Htc:
                    // call Htc webservices
                    return new ManufactureInvoice
                    {
                        Cost = product.Cost,
                        EstimatedArrivalDate = DateTime.Now.AddDays(5),
                        EstimatedShippedDate = DateTime.Now,
                        Tax = product.Cost * .07M,
                        Manufacture = Manufacture.Htc
                    };

                default:
                    throw new UnknownManufactureException();
            }
        }
    }


So just by looking at this class we can already see that if we were to making any changes to any of the implementation for any of these distributors we would have to making changes to this class because of the tight coupling of the OrderService and our ordering algorithms for each individual manufactures.

Let’s see what the Strategy Pattern can do for us, first we are going to add a few an interface and a few class which will implement this interface (VS Project: AfterStrategyPatternA)

Each of the classes that implement the IManufactureOrderStrategy interface which will be an ordering strategy for that manufacture, where you could call different services, business rules, validation, etc… They all related, in which they all order a phone from a manufacture and fulfill our order, however the only difference is they way they may behave for a given manufacture. Now we will make changes to our OrderService class where our clunky switch statement was earlier

VS Project: AfterStrategyPatternA, Class: OrderService.cs


    class OrderService
    {
        public readonly IOrderingStrategy _manufactureOrderingStrategy;

        public OrderService(IOrderingStrategy manufactureOrderingStrategy)
        {
            _manufactureOrderingStrategy = manufactureOrderingStrategy;
        }

        public ManufactureInvoice OrderProductFromManufacture(Product product)
        {
            return _manufactureOrderingStrategy.OrderProduct(product);
        }
    }

As you can see, instead of the OrderService containing the actual business logic and implementation for ordering with each of our manufactures, we are now passing this into the OrderService class. Let’s take a quick look on how what the consumer code would look
like using our new decoupled OrderingService.

VS Project: AfterStrategyPatternA, Class: OrderProductFromManufacture_Test.cs


    [TestClass]
    public class OrderProductFromManufacture_Test
    {
        [TestMethod]
        public void When_Manufacture_is_From_Apple()
        {
            var _order = MockOrderPipeline.CreateOrder();
            
            var appleProduct = _order.OrderDetails
                .Where(o => o.Product.Manufacture == Manufacture.Apple)
                .Single()
                .Product;

            var appleOrderStrategy = new AppleOrderStrategy();
            var manufactureOrderingService = new OrderService(appleOrderStrategy);
            var manufactureInvoice = manufactureOrderingService.OrderProductFromManufacture(appleProduct);

            Assert.AreEqual(manufactureInvoice.Manufacture, Manufacture.Apple);
        }

        [TestMethod]
        public void When_Manufacture_is_From_Htc()
        {
            var _order = MockOrderPipeline.CreateOrder();
            var htcProductFromOrder = _order.OrderDetails
                .Where(o => o.Product.Manufacture == Manufacture.Htc).Single().Product;

            var htcOrderStrategy = new HtcOrderStrategy();
            var manufactureOrderingService = new OrderService(htcOrderStrategy);
            var manufactureInvoice = manufactureOrderingService.OrderProductFromManufacture(htcProductFromOrder);

            Assert.AreEqual(manufactureInvoice.Manufacture, Manufacture.Htc);
        }

        [TestMethod]
        public void When_Manufacture_is_From_Nokia()
        {
            var _order = MockOrderPipeline.CreateOrder();
            var nokiaProductFromOrder = _order.OrderDetails.Where(o => o.Product.Manufacture == Manufacture.Nokia).Single().Product;

            var nokiaOrderStrategy = new NokiaOrderStrategy();
            var manufactureOrderingService = new OrderService(nokiaOrderStrategy);
            var manufactureInvoice = manufactureOrderingService.OrderProductFromManufacture(nokiaProductFromOrder);

            Assert.AreEqual(manufactureInvoice.Manufacture, Manufacture.Nokia);
        }

        [TestMethod]
        public void When_Manufacture_is_From_Sony()
        {
            var _order = MockOrderPipeline.CreateOrder();
            var sonyProductFromOrder = _order.OrderDetails.Where(o => o.Product.Manufacture == Manufacture.Sony).Single().Product;

            var sonyOrderStrategy = new SonyOrderStrategy();
            var manufactureOrderingService = new OrderService(sonyOrderStrategy);
            var manufactureInvoice = manufactureOrderingService.OrderProductFromManufacture(sonyProductFromOrder);

            Assert.AreEqual(manufactureInvoice.Manufacture, Manufacture.Sony);
        }
    }

Note that for each of these calls we are passing a custom implementation (e.g. AppleOrderStrategy, HtcOrderStrategy, NokiaOrderStrategy, SonyOrderStrategy) of for each of the manufactures who all implement the IOrderingStategy interface. So now our OrderingService class adheres to the “open close principle”, where our OrderingService should be open for extension, but closed for modification.

Finally, let’s take a look a different form of using the Strategy Pattern using Funcs, delegates and lambdas (VS Project: AfterStrategyPatternB, class: OrderProductFromManufacture_Test).

First let’s take a quick look at our enhanced OrderingService.

VS Project: AfterStrategyPatternB, Class: OrderService.cs


    public class OrderService
    {
        public ManufactureInvoice OrderProduct(Product product, 
            Func<Product, ManufactureInvoice> orderingStrategy)
        {
            return orderingStrategy(product);
        }
    }

Notice how we are now passing in a generic func vs. a class that, and the func expects the Product to be ordered to be passed into it where it will then return a ManufactureInvoice for the product that was ordered and to be fulfilled.

Now let’s take a the new OrderService consuming code, notice how we can now still pass in our implementation as long as we are compliant with the generic func parameter of our OrderServce.OrderProduct method. We can somewhat think of the generic func as our new contract, contract meaning we have to pass in a Product entity and we have to return a ManufactureInvoice after we have completed the ordering process.

VS Project: AfterStrategyPatternB, Class: OrderProductFromManufacture_Test.cs


    [TestClass]
    public class OrderProductFromManufacture_Test
    {        
        [TestMethod]
        public void When_Manufacture_is_Apple()
        {
            // using lambda expression
            Func<Product, ManufactureInvoice> appleStrategy = product => 
                new ManufactureInvoice { 
                    Cost = product.Cost, 
                    EstimatedArrivalDate = DateTime.Now.AddDays(5), 
                    EstimatedShippedDate = DateTime.Now, 
                    Tax = product.Cost * .07M, 
                    Manufacture = Manufacture.Apple };

            var _order = MockOrderPipeline.CreateOrder();

            var appleProduct = _order.OrderDetails
                .Where(o => o.Product.Manufacture == Manufacture.Apple)
                .Single()
                .Product;

            OrderService orderService = new OrderService();
            orderService.OrderProduct(appleProduct, appleStrategy);
        }

        [TestMethod]
        public void When_Manufacture_is_Sony()
        {
            // using delegate
            Func<Product, ManufactureInvoice> sonyStrategy = 
                delegate(Product product) { return new ManufactureInvoice { 
                    Cost = product.Cost, 
                    EstimatedArrivalDate = DateTime.Now.AddDays(5), 
                    EstimatedShippedDate = DateTime.Now, 
                    Tax = product.Cost * .07M, 
                    Manufacture = Manufacture.Sony }; };

            var _order = MockOrderPipeline.CreateOrder();

            var sonyProduct = _order.OrderDetails
                .Where(o => o.Product.Manufacture == Manufacture.Sony)
                .Single()
                .Product;

            OrderService orderService = new OrderService();
            orderService.OrderProduct(sonyProduct, sonyStrategy);
        }

        [TestMethod]
        public void When_Manufacture_is_Nokia()
        {            
            var _order = MockOrderPipeline.CreateOrder();
            
            // using inline lambda expression (fluent)
            var sonyProduct = _order
                .OrderDetails
                .Where(o => o.Product.Manufacture == Manufacture.Sony)
                .Single()
                .Product;

            OrderService orderService = new OrderService();

            orderService.OrderProduct(sonyProduct, product =>
            {
                return new ManufactureInvoice { 
                    Cost = product.Cost, 
                    EstimatedArrivalDate = DateTime.Now.AddDays(5), 
                    EstimatedShippedDate = DateTime.Now, 
                    Tax = product.Cost * .07M, 
                    Manufacture = Manufacture.Sony };
            });
        }

        [TestMethod]
        public void When_Manufacture_is_Htc()
        {
            var _order = MockOrderPipeline.CreateOrder();
            
            // using anonymous method
            var htcProduct = _order
                .OrderDetails
                .Where(o => o.Product.Manufacture == Manufacture.Htc)
                .Single()
                .Product;

            OrderService orderService = new OrderService();
            orderService.OrderProduct(htcProduct, OrderProductFromHtc);
        }

        private ManufactureInvoice OrderProductFromHtc(Product product)
        {
            // e.g. invoke htc webservices, invoke order services, invoke dropshipment services, publish events to service
            return new ManufactureInvoice { 
                Cost = product.Cost, 
                EstimatedArrivalDate = DateTime.Now.AddDays(5), 
                EstimatedShippedDate = DateTime.Now, 
                Tax = product.Cost * .07M, 
                Manufacture = Manufacture.Htc };
        }
    }


Download the Strategy Pattern sample VS Solution: https://skydrive.live.com/embed?cid=949A1C97C2A17906&resid=949A1C97C2A17906%21369&authkey=AD0Eu1b0USnB5do

Printing from DevExpress ASPxPopupControl

Googled and googled and couldn’t find an aricle on this so here it is a quick and easy way to print the contents from a DX ASPxPopupControl!

  1. Add an empty IFrame control to your page.
    <iframe id=”printIFrame” src=”#” style=”width: 0px; height: 0px”></iframe>
  2. Add a print button to the footer template of your ASPxPopupControl.
             <dx:ASPxPopupControl ID="rewardASPxPopupControl" runat="server" AllowDragging="True"             AllowResize="True" CloseAction="CloseButton" ContentUrl="~/Images/PoweredbyDevExpress.png"             EnableViewState="False" PopupHorizontalAlign="Center" PopupVerticalAlign="Middle"             ShowFooter="True" FooterText="Try to resize the control using the resize grip or the control's edges"             HeaderText="blog.longle.me" ClientInstanceName="rewardASPxClientPopupControl"             EnableHierarchyRecreation="True">             <ContentStyle HorizontalAlign="Center" VerticalAlign="Middle">                 <Paddings Padding="0px"></Paddings>             </ContentStyle>             <FooterTemplate>                 <div style="padding: 10px; text-align: right">                     <dx:ASPxButton ID="printASPxButton" runat="server" Text="Print" AutoPostBack="false"                         ClientInstanceName="printClientASPxButton">                         <ClientSideEvents Click="function(s,e){ printClientASPxButton_Click(s,e); }" />                     </dx:ASPxButton>                 </div>             </FooterTemplate>         </dx:ASPxPopupControl>
  3. Wire up your client side Click event on your Print button, all we are doing here is extracting the Html from the ASPxPopupControl and injecting this into the empty IFrame from step 1 and loading it, once loaded the onload event in the body tag will be raised bringing focus to this IFrame and then the .print() method will get invoked.
    function printClientASPxButton_Click(s, e) {
        var oIframe = document.getElementById('printIFrame');
        var oContent = '' +
            rewardASPxClientPopupControl.GetContentHtml() + '';
        var oDoc = (oIframe.contentWindow || oIframe.contentDocument);
        if (oDoc.document) oDoc = oDoc.document;
        oDoc.write(oContent);
        oDoc.close();
    }
  4. You should get a nice print dialog now.2-28-2011 10-11-08 PM
  5. I selected for it to print to my PDF print driver, and here is snapshot of the print out (obviously only of the content inside of the ASPxPopupControl.2-28-2011 10-17-54 PM

Example source code download:

http://cid-8ad26411740e6091.office.live.com/self.aspx/Source%20Code/ASPxPopupControlPrinting.zip