Creating an MVC5 App with Unity, SLAB and Attribute Routing

This posts explains how to set up an MVC5 application using Unity 3 and Semantic Logging (SLAB). Attribute Routing is used for the controllers.

Code: https://github.com/damienbod/MVC5UnitySlab

Adding Unity 3 to the MVC5 project

Add the NuGet packages to the MVC5 project.
Mvc5UnitySlab01

Now add the start up logic in the UnityConfig file in the App_Start folder.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Practices.Unity;
using MVC5UnitySlab.Business.Attributes;

namespace MVC5UnitySlab.App_Start
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        private const string ClassesToScan = "MVC5UnitySlab";

        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        /// <summary>
        /// Gets the configured Unity container.
        /// </summary>
        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion

        public static IEnumerable<Type> GetTypesWithCustomAttribute<T>(Assembly[] assemblies)
        {
            foreach (var assembly in assemblies)
            {
                foreach (Type type in assembly.GetTypes())
                {
                    if (type.GetCustomAttributes(typeof(T), true).Length > 0)
                    {
                        yield return type;
                    }
                }
            }
        }

        /// <summary>Registers the type mappings with the Unity container.</summary>
        /// <param name="container">The unity container to configure.</param>
        /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
        /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
        public static void RegisterTypes(IUnityContainer container)
        {
            var myAssemblies =
                AppDomain.CurrentDomain.GetAssemblies()
                    .Where(a => a.FullName.StartsWith(ClassesToScan))
                    .ToArray();

            container.RegisterTypes(
                UnityConfig.GetTypesWithCustomAttribute<UnityIoCContainerControlledAttribute>(myAssemblies),
                WithMappings.FromMatchingInterface,
                WithName.Default,
                WithLifetime.ContainerControlled,
                null
                ).RegisterTypes(
                    UnityConfig.GetTypesWithCustomAttribute<UnityIoCTransientLifetimeAttribute>(myAssemblies),
                    WithMappings.FromMatchingInterface,
                    WithName.Default,
                    WithLifetime.Transient);
        }
    }
}

This start up configuration uses a scan method to search for interfaces and classes to be registered with unity. The scan method uses attributes to define the lifetime of each class.

namespace MVC5UnitySlab.Business.Attributes
{
    [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]
    public class UnityIoCContainerControlledAttribute : System.Attribute
    {
        public double version;

        public UnityIoCContainerControlledAttribute()
        {
            version = 1.0;
        }
    }
}

These attributes are applied to the different classes which are to be registered with the IoC.

  [UnityIoCTransientLifetime]
    public class BusinessClass : IBusinessClass
    {
        private IUnitOfWorkExample _unitOfWorkExample;

        public BusinessClass(IUnitOfWorkExample unitOfWorkExample)
        {
            _unitOfWorkExample = unitOfWorkExample;
            UnityEventLogger.Log.CreateUnityMessage("BusinessClass");
        }

Now the business classes can be used in any controller.

 public class HomeController : Controller
    {
        private IBusinessClass2 _businessClass2;
        private IBusinessClass _businessClass;

        public HomeController(IBusinessClass2 businessClass2, IBusinessClass businessClass)
        {
            _businessClass = businessClass;
            _businessClass2 = businessClass2;
        }

        public ActionResult Index()
        {
            _businessClass.Hello();
            _businessClass2.Hello();
            _businessClass2.SayHello("using unity happily");
            return View();
        }

Using Out-Of-Process Semantic Logging (SLAB)

Add the Semantic logging NuGet package to the MVC5 project.

Mvc5UnitySlab02

Add an EventSource class and write some logs.

using System.Diagnostics.Tracing;

namespace MVC5UnitySlab.Business.Logging
{
    [EventSource(Name = "UnityLogger")]
    public class UnityEventLogger : EventSource
    {
        public static readonly UnityEventLogger Log = new UnityEventLogger();

        private const int createUnityMessageEventId = 1;
        private const int disposeUnityMessageEventId = 2;
        private const int logUnityMessageEventId = 3;

        [Event(createUnityMessageEventId, Message = "CreateUnityMessage: {0}", Level = EventLevel.Informational)]
        public void CreateUnityMessage(string message)
        {
            if (IsEnabled()) WriteEvent(createUnityMessageEventId, message);
        }

        [Event(disposeUnityMessageEventId, Message = "DisposeUnityMessage {0}", Level = EventLevel.Informational)]
        public void DisposeUnityMessage(string message)
        {
            if (IsEnabled()) WriteEvent(disposeUnityMessageEventId, message);
        }

        [Event(logUnityMessageEventId, Message = "{0}", Level = EventLevel.Informational)]
        public void LogUnityMessage(string message)
        {
            if (IsEnabled()) WriteEvent(logUnityMessageEventId, message);
        }
    }
}

Here’s a log example.

UnityEventLogger.Log.CreateUnityMessage("BusinessClass2");

Install the Semantic Logging OUT-OF-PROCESS service and add your logs to the xml see Enterprise Library 6, Semantic Logging, Part 2, OUT-OF-PROCESS

Edit the SemanticLogging-svc.xml as required.

<sqlDatabaseSink name="myDb" instanceName="UnityCreateDisposeTest" connectionString="Data Source=.;Initial Catalog=Logging;Integrated Security=True">
     <sources>
	  <eventSource name="UnityLogger" level="LogAlways"/>
     </sources>
</sqlDatabaseSink>

Here’s a database sink result:
Mvc5UnitySlab03

Using Attribute Routing

Change the RouteConfig class in the App_Start folder. Add the MapMvcAttributeRoutes method and remove the old routing.

using System.Web.Mvc;
using System.Web.Routing;

namespace MVC5UnitySlab
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapMvcAttributeRoutes();   
        }
    }
}

Add the routing attributes to the controller as required:

 [RoutePrefix("MyHome")] 
    public class HomeController : Controller
    {
        private IBusinessClass2 _businessClass2;
        private IBusinessClass _businessClass;

        public HomeController(IBusinessClass2 businessClass2, IBusinessClass businessClass)
        {
            _businessClass = businessClass;
            _businessClass2 = businessClass2;
        }

         [Route("{Index}")] 
        public ActionResult Index()
        {
            _businessClass.Hello();
            _businessClass2.Hello();
            _businessClass2.SayHello("using unity happily");
            return View();
        }

This routing is then used:
Mvc5UnitySlab04
Links:

http://www.asp.net/mvc/tutorials/mvc-5

http://entlib.codeplex.com/

http://unity.codeplex.com/

http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx

http://sampathloku.blogspot.ch/2013/11/attribute-routing-with-aspnet-mvc-5.html

4 comments

  1. sahilabhishek777 · · Reply

    Reblogged this on Crazy Developer.

  2. Gordon Hickley · · Reply

    UnityIoCTransientLifetimeAttribute is not defined

    1. This is defined in the business assembly. For large projects, I define these attributes in a common utility class.

      https://github.com/damienbod/MVC5UnitySlab/blob/master/MVC5UnitySlab.Business/Attributes/UnityIoCTransientLifetimeAttribute.cs

      greetings Damien

  3. Keith · · Reply

    Thanks damienbod for this article, I found below blog post about Unity.Mvc5 Library example with sample code.
    MVC 5 with Unity for Dependency Injection

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: