Posted by: dotnetninja | May 14, 2008

Dependency Injection With Unity And Asp.Net

For two months ago pattern and practice team has released Unity 1.0 (Unity Application Block) which is, as they write, a lightweight dependency injection injection container. More information and download http://www.codeplex.com/unity.
More information about dependency injection can be found in this article http://martinfowler.com/articles/injection.html.

I got some free time to “play” with it and to compare with Spring.Net because I have been using Spring.Net before. Mostly I was curious how p&p team have implemented DI and what is the difference with in this case Spring.Net.

Examples that are following with Unity did not have an example how to use it with configuration file. Some examples and explanations can be found here http://www.pnpguidance.net/.

Because I was working on Web project I wanted to test Unity with Asp.Net 2.0 (3.5) and to implement dependency injection.

Here comes an simple example how to do it (with configuration file :) ). I an going to create an N-Tier application, not one project with bunch of code files, (separation…) which will retrieve menu from the database for specific user and show it on the page.
Data access is done with help of the Enterprise library 3.1.

Source code

Check updated article for adding DI to the page:V1.1

After creating basic code structure for the project here is the picture.

image
Figure 1. Solution project structure

UnityTest.Interfaces contains interfaces for class implementations of the BLLayer and DALayer. UnityTest.Core contains helper classes like Extension methods more on that later, UnityTest.BLayer is implementation of the business logic and DALayer is database access layer.

After that I am adding Microsoft.Practices.ObjectBuilder2.dll, Microsoft.Practices.Unity.dll and Microsoft.Practices.Unity.Configuration.dll to the UnityTest.WebApp. These files can be found in the bin directory of the Unity 1.0.

Now we have to define interfaces for Data Access Layer and Business Logic Layer.

image
Figure 2. Interfaces

Here is and example of the Menu model and IMenuDAL.cs with just one method :).

Menu.cs

namespace UnityTest.Models
{
    public class Menu
    {
        public decimal Id { get; set; }
        public string MenuText { get; set; }
        public string Description { get; set; }
        public decimal ParentId { get; set; }
        public string Url { get; set; }
    }
}

IMenuDAL.cs

namespace UnityTest.Interfaces
{
    public interface IMenuDAL
    {
        //string ConnectionString { get; set; }
        /// <summary>
        /// Gets the user menu from the database.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        System.Collections.Generic.List<UnityTest.Models.Menu> GetUserMenuDB(string userName);
    }
}

BLayer project

image
Figure 3. Business layer, implementation of the menu.

Code for MenuBL.cs

namespace UnityTest.BLayer
{
    public class MenuBL:UnityTest.Interfaces.IMenuBL
    {
        #region Properties

public UnityTest.Interfaces.IMenuDAL DALayer { get;set; }

        #endregion

        #region IMenuBL Members

        /// <summary>
        /// Gets the user menu from data access layer.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public List<UnityTest.Models.Menu> GetUserMenuBL(string userName)
        {
            userName.IsEmptyOrNull("userName");
            try
            {
                return DALayer.GetUserMenuDB(userName);
            }
            catch (CoreException)
            { throw; }
            catch (Exception)
            { throw; }

        }

        #endregion
    }
}
 

Code for MenuDB.cs

 

namespace UnityTest.DALayer
{
    public class MenuDB:UnityTest.Interfaces.IMenuDAL
    {
        #region Properties

        Database _db = null;
        public Database DB
        {
            get
            {
                if (_db == null)
                    _db = DatabaseFactory.CreateDatabase(this.ConnectionString);
                return _db;
            }
        }
        public string ConnectionString { get; set; }

        #endregion

        public MenuDB(string connString)
        {
            if (connString != String.Empty)
            {
                this.ConnectionString = connString;
            }
            else
                //here using resource strings...
                throw new CoreException("DALayer.Resources.DBException.ConnectionStringEmpty");
        }
        #region IMenuDAL Members

        /// <summary>
        /// Gets the user menu from the database.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public List<UnityTest.Models.Menu> GetUserMenuDB(string userName)
        {
            //here using Extension method
            userName.IsEmptyOrNull("userName");
            try
            {
                List<UnityTest.Models.Menu> menuCollection = new List<UnityTest.Models.Menu>();

                //Store Procedure name should be on one place ex. in resource
                //string for easier change avoid harcoding!!
                //Menu.GetMenusForUser
                System.Data.Common.DbCommand cmd = DB.GetStoredProcCommand("Menu.GetMenusForUser", new object[] { userName });
                DB.AddParameter(cmd, "@RETURN_VALUE", DbType.Int32, ParameterDirection.ReturnValue, "", DataRowVersion.Current, null);
                using (System.Data.IDataReader dr = DB.ExecuteReader(cmd))
                {
                    while (dr.Read())
                    {
                        UnityTest.Models.Menu menu = new UnityTest.Models.Menu
                        {
                            Id = dr.GetDecimal(0),
                            MenuText = dr.IsDBNull(1) ? String.Empty : dr.GetString(1),
                            Description = dr.IsDBNull(2) ? String.Empty : dr.GetString(2),
                            ParentId = dr.IsDBNull(3) ? -1 : dr.GetDecimal(3),
                            Url = dr.IsDBNull(4) ? String.Empty : dr.GetString(4)
                        };
                        menuCollection.Add(menu);
                    }
                }
                if (menuCollection.Count == 0)
                {
                    int returnValue = (int)DB.GetParameterValue(cmd, "RETURN_VALUE");
                    if (returnValue == -10001)
                        throw new CoreException("Resources.Exceptions.UserResponsibleNotExists");
                }
                return menuCollection;

            }
            catch (CoreException)
            { throw; }
            catch(Exception)
            { throw; }
        }

        #endregion

    }
}

Observe yellow mark. This property will we set with property injection, and with constructor injection will we set value of the connString in the MenuDB constructor.

Now to be able to inject dependent object in our Web application first we need to define (write) in formation in the Web.Config.

	<configSections>
		<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
			<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
				<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
				<sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
					<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
					<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
					<section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
					<section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
				</sectionGroup>
			</sectionGroup>
		</sectionGroup>
		<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
	</configSections>
	<unity>
		<containers>
			<container>
				<types>
					<type type="UnityTest.Interfaces.IMenuBL,UnityTest.Interfaces" mapTo="UnityTest.BLayer.MenuBL,UnityTest.BLayer">
						<typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement,Microsoft.Practices.Unity.Configuration">
							<property name="DALayer" propertyType="UnityTest.DALayer.MenuDB,UnityTest.DALayer"/>
						</typeConfig>
					</type>
					<type type="UnityTest.Interfaces.IMenuDAL,UnityTest.Interfaces"
                mapTo="UnityTest.DALayer.MenuDB,UnityTest.DALayer">
            <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement,
                                     Microsoft.Practices.Unity.Configuration">
              <constructor>
                <param name="connString" parameterType="System.String">
                  <value value="LFConnectionString"/>
                </param>
              </constructor>
            </typeConfig>
          </type>
				</types>
			</container>
		</containers>
	</unity>
	<appSettings/>
 

Then add Global.asax to Web project and in the Application_start configure our container.

private static Microsoft.Practices.Unity.IUnityContainer _container = null;
        public static Microsoft.Practices.Unity.IUnityContainer Container { get { return _container; } }
        protected void Application_Start(object sender, EventArgs e)
        {
            if (_container == null)
                _container = new Microsoft.Practices.Unity.UnityContainer();
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers.Default.Configure(_container);
        }
        protected void Application_End(object sender, EventArgs e)
        {
            _container.Dispose();
        }

Now we need can show our menu on the Page. Page will have an simple ListView and data will be populate in the code behind.

public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!this.IsPostBack)
            {
                UnityTest.Interfaces.IMenuBL ser = Global.Container.Resolve<UnityTest.Interfaces.IMenuBL>();
                var mnuItems = ser.GetUserMenuBL(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
                lvMenu.DataSource = mnuItems;
                lvMenu.DataBind();
            }
        }
    }

image
Figure 4. Menu with Dependency Injection.

Source Code is here.

About these ads

Responses

  1. You are the man. I find your blog contents really helpful and simplify my understanding on many advanced concepts. Wish you all good lucks and the best happenings in your life.


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

Categories

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: