A former twenty something in technology

All posts tagged dotnetnuke

Something that I thought was missing from DNN’s DAL2 was a generic implementation of it’s repository base class that you could inherit from instead of repeating more boiler plate.

Ultimately why this is important should be apparent when you see the implementation below. But spoiler alert: It’s very little code!

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;

namespace Components.Data
{
    public abstract class RepositoryImpl<T> : IRepository<T> where T : class
    {

        public virtual void Delete(T item)
        {
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                repo.Delete(item);
            }
        }

        public virtual void Delete(string sqlCondition, params object[] args)
        {
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                repo.Delete(sqlCondition, args);
            }
        }

        public virtual IEnumerable<T> Find(string sqlCondition, params object[] args)
        {
            IEnumerable<T> list = default(IEnumerable<T>);
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                list = repo.Find(sqlCondition, args);
            }
            return list;
        }

        public virtual IPagedList<T> Find(int pageIndex, int pageSize, string sqlCondition, params object[] args)
        {
            IPagedList<T> list = default(IPagedList<T>);
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                list = repo.Find(pageIndex, pageSize, sqlCondition, args);
            }
            return list;
        }

        public virtual IEnumerable<T> Get()
        {
            IEnumerable<T> list = default(IEnumerable<T>);
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                list = repo.Get();
            }
            return list;
        }

        public virtual IEnumerable<T> Get<TScopeType>(TScopeType scopeValue)
        {
            IEnumerable<T> list = default(IEnumerable<T>);
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                list = repo.Get<TScopeType>(scopeValue);
            }
            return list;
        }

        public virtual T GetById<TProperty>(TProperty id)
        {
            T item = default(T);
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                item = repo.GetById<TProperty>(id);
            }
            return item;
        }

        public virtual T GetById<TProperty, TScopeType>(TProperty id, TScopeType scopeValue)
        {
            T item = default(T);
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                item = repo.GetById<TProperty, TScopeType>(id, scopeValue);
            }
            return item;
        }

        public virtual IPagedList<T> GetPage(int pageIndex, int pageSize)
        {
            IPagedList<T> list = default(IPagedList<T>);
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                list = repo.GetPage(pageIndex, pageSize);
            }
            return list;
        }

        public virtual IPagedList<T> GetPage<TScopeType>(TScopeType scopeValue, int pageIndex, int pageSize)
        {
            IPagedList<T> list = default(IPagedList<T>);
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                list = repo.GetPage<TScopeType>(scopeValue, pageIndex, pageSize);
            }
            return list;
        }

        public virtual void Insert(T item)
        {
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                repo.Insert(item);
            }
        }

        public virtual void Update(T item)
        {
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                repo.Update(item);
            }
        }

        public virtual void Update(string sqlCondition, params object[] args)
        {
            using (IDataContext db = DataContext.Instance()) {
                dynamic repo = db.GetRepository<T>();
                repo.Update(sqlCondition, args);
            }
        }
    }
}

What this class will allow you to do is create a simple class that inherits RepositoryImpl and gain access to all the CRUD operations.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using DotNetNuke.Data;

namespace Components.Data
{

    public interface IAnyEntityRepository : IRepository<AnyEntityName>
    {
    }

    public class AnyEntityRepository : RepositoryImpl<AnyEntityName>, IAnyEntityRepository
    {
    }
}

Additionally this structure will allow you to use dependency injection like Ninject to inject the concrete class using the IAnyEntityRepository interface.

Dependency injection (DI) has several advantages that I myself haven’t fully wrapped my head around all the use cases. But this article isn’t going to be focused on explaining why DI is important but rather how you can implement it in DNN.

Getting Started

Using nuget you can install ninject into your module.

Install-Package ninject

Searching the internet you may find a package called Ninject.Web and may find yourself thinking this is exactly what I need!. Unfortunately this extension assumes that you have a standard user control or access directly to the page and does not allow you inherit from PortalModuleBase

The primary abstraction in Ninject.Web is the creation of a KernelContainer which is a static class to broker all your DI interactions. So you will need to create that class.

using Ninject;

sealed class KernelContainer
{

     private static IKernel _kernel;

     public static IKernel Kernel {
          get { return _kernel; }

          set {
               if (_kernel != null) {
                    throw new NotSupportedException("The static container already has a kernel associated with it!");
               }

               _kernel = value;
          }
     }

     public static void Inject(object instance)
     {
          if (_kernel == null) {
               throw new InvalidOperationException(String.Format("The type {0} requested an injection, but no kernel has been registered for the web application. Please ensure that your project defines a NinjectHttpApplication.", instance.GetType()));
          }

          _kernel.Inject(instance);
     }
}

Next we must new up an instance of the kernel by hooking into the application start pipeline. An easy way to do this is with the WebActivatorEx library that comes with ninject. This will fire once at application start and create a static instance of your KernalContainer and assign a new instance of StandardKernel. Finally you write up or bind if you will all of your interfaces to their concrete classes.

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Components.DI.Bindings), "RegisterServices")]
namespace Components.DI
{
	public static class Bindings
	{
		public static void RegisterServices()
		{
			KernelContainer.Kernel = new StandardKernel();
			KernelContainer.Kernel.Bind<IDataRepository>().To<DataRepository>().InSingletonScope();

		}
	}

}

After that we need to tell the KernelContainer that our module user control may have classes that need to be injected. This is done by adding an abstraction to the PortalModuleBase. I call mine CustomModuleBase but you can call yours whatever you like.

using System.Web.UI;
using DotNetNuke.Entities.Modules;

public class CustomModuleBase : PortalModuleBase
{
		public CustomModuleBase()
		{
			KernelContainer.Inject(this);
		}
}

Now you can utilize the ninject inject attribute on any constructor, method, or property in your class and it will inject that class into into the interface.

public class Main : CustomModuleBase
{
	[Inject()]
	public IDataRepository_repo { get; set; }
}