Archive for October 18, 2011

Creating Generic MVC Controllers

Based on my previous posting regarding Generic Repositories, I decided to take this approach a step further and create Generic Controllers. The idea is simple: create a Generic Controller which can handle all of the CRUD operations by default. If we need to override or extend these methods, we can create a controller which inherits from this Generic Controller. We will also need to create a Controller Factory which will first look for a derived class, if it cannot find one, it will automatically instantiate an instance of the Generic Controller and use this instance as the controller.

First we must create a Generic Controller, capable of handling all of the CRUD requests. Below is my implementation.

public class ApplicationController<T> : Controller<T> where T: class
{
        protected ApplicationRepository<T> Repository { get; set; }
        private string[] _strLockedProperties = new string[] {
            "Id",
            "CreatedOn",
            "CreatedBy",
            "ModifiedOn",
            "ModifiedBy"
        };

        protected virtual string[] LockedProperties
        {
            get
            {
                return _strLockedProperties;
            }
        }

        public ApplicationController()
        {
            Repository = new ApplicationRepository<T>();
        }

        public virtual ActionResult Index()
        {
            return View(Repository.GetAll());
        }

        public virtual ActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public virtual ActionResult Create(T record)
        {
            if (ModelState.IsValid)
            {
                Repository.Insert(record);
                Repository.Save();
            }

            return RedirectToAction("Index");
        }

        public virtual ActionResult Details(Guid id)
        {
            return View(Repository.Get(id));
        }

        public virtual ActionResult Edit(Guid id)
        {
            return View(Repository.Get(id));
        }

        [HttpPost]
        public virtual ActionResult Edit(Guid id, T record)
        {
            var properties = typeof(T).GetProperties();
            var fields = new List<string>();
            foreach (var prop in properties)
            {
                if (!LockedProperties.Contains(prop.Name))
                {
                    fields.Add(prop.Name);
                }
            }
            var allowed = fields.ToArray();
            var existing = Repository.Get(id);

            if (TryUpdateModel(existing, allowed))
            {
                Repository.Save();
                return RedirectToAction("Index");
            }

            return View(record);
        }

        public virtual ActionResult Delete(Guid id)
        {
            return View(Repository.Get(id));
        }

        [HttpPost]
        public virtual ActionResult Delete(Guid id, string confirm)
        {
            Repository.Delete(Repository.Get(id));
            Repository.Save();

            return RedirectToAction("Index");
        }

This class will be able to handle all of the default CRUD operations without worrying about the actual data types. Based on the previous posting, even the repositories will be automatically generated.

If you need any special functionality for a controller, simply create a derived class.

public class UserController : ApplicationController<UserAccount>
{
    public override ActionResult Edit(Guid id)
    {
        //Special code here.
    }
}

Now lets wire up our Controller Factory. We need to create a factory which first looks for a strongly typed controller. If it cannot find that strongly typed controller it will automatically instantiate a new Generic Controller and return this instance.

public class ApplicationControllerFactory : IControllerFactory
    {
        private string Namespace
        {
            get
            {
                return this.GetType().Namespace;
            }
        }

        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            if (string.IsNullOrEmpty(controllerName))
                throw new ArgumentNullException("controllerName");

            Type cType = Type.GetType(Namespace + ".Controllers." + controllerName + "Controller");

            if (cType == null)
            {
                cType = Type.GetType(Namespace + ".Library.ApplicationController`1[" + Namespace + ".Models." + controllerName + "]");
            }

            return Activator.CreateInstance(cType) as Controller;
        }

        public void ReleaseController(IController controller)
        {
            if (controller is IDisposable)
                (controller as IDisposable).Dispose();
            else
                controller = null;
        }

        public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
        {
            return System.Web.SessionState.SessionStateBehavior.Default;
        }
    }

Now register the Controller Factory in your Global.asax.cs file.

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    ControllerBuilder.Current.SetControllerFactory(new ApplicationControllerFactory());
}

The effects on development speed of this approach is pretty profound. Essentially you have a Controller and Repository layer which is completely dynamic, powered only by the meta data of the data layer. All that must be done is creating the views, and overriding your controllers and repositories where necessary.

SQL to Delete All Users from Membership Provider

The .NET Membership Provider provides us with a stored procedure ‘aspnet_Users_DeleteUser’ to delete a user from a particular application. There are problems with this. What if you have a user who is allocated to many applications? What if you need to delete more than one user? I came up with the following script to completely remove all users (except the admin) from all applications.

DECLARE user_cursor CURSOR FOR
SELECT ApplicationName AS field1, Username AS field2, UserId AS field3
FROM aspnet_Users CROSS JOIN dbo.aspnet_Applications
WHERE username != 'admin'

OPEN user_cursor
DECLARE @field1 NVARCHAR(256)
DECLARE @field2 NVARCHAR(256)
DECLARE @field3 UNIQUEIDENTIFIER

FETCH NEXT FROM user_cursor
	INTO @field1, @field2, @field3
	WHILE @@FETCH_STATUS = 0
	BEGIN
	    PRINT @field1 + ':' + @field2
	    DELETE FROM dbo.aspnet_UsersInRoles WHERE UserId = @field3
		EXEC dbo.aspnet_Users_DeleteUser @ApplicationName = @field1,
		    @UserName = @field2,
		    @TablesToDeleteFrom = 50,
		    @NumTablesDeletedFrom = NULL
		DELETE FROM dbo.aspnet_Users WHERE UserId = @field3
		FETCH NEXT FROM user_cursor
		INTO @field1, @field2, @field3
	END
DEALLOCATE user_cursor;

The script works by first cross-joining applications and users, giving us a full list of every user to every application. We then use a cursor to loop the given set, and run our deletes against the set. This saved me countless hours of manual labor.

Repository Pattern, Lazy Style

One of the most annoying things when working with MVC is repeating the same code over and over again at each layer. We can try to abstract our classes, but it still only gets us so far, a lot of the code must still be manually typed or templated. I found myself particularly tired of creating repository objects for each of my database tables. Sure, I was inheriting from a generic base class, but a lot of the implementation I couldn’t get away from.

Using Linq2Sql was one of the reasons for my headaches. Types aren’t so easy to get at, and queries cannot be created dynamically at runtime–or could they? Dynamic Linq to the rescue. Microsoft has a seperate library available for download which actually allows you to run dynamic queries at runtime. Once added to your project, the dynamic functions are added through class extensions to the standard Linq classes.

I decided that I would start by creating a generic, templated, repository layer which could be extended if necessary, but would by default contain all of the necessary functions to interact with the model layer.

using System.Linq.Dynamic;

public abstract class Repository<R> where R : class
{
    public virtual DataContext Context { get; protected set; }

    public Repository() { }

    public Repository(DataContext context)
    {
        Context = context;
    }

    public virtual void Insert(R record)
    {
        Context.GetTable<R>().InsertOnSubmit(record);
    }

    public virtual void Delete(R record)
    {
        Context.GetTable<R>().DeleteOnSubmit(record);
    }

    public virtual void Update(R record)
    {
        return;
    }

    public virtual IEnumerable<R> GetAll()
    {
        var records = from r in Context.GetTable<R>()
                        select r;

        return records;
    }

    public virtual void Save()
    {
        Context.SubmitChanges();
    }

    public virtual void Revert(R record)
    {
        Context.Refresh(RefreshMode.OverwriteCurrentValues, record);
    }
}

Then create a class which inherits from your template, and code in all of the functions which are application specific.

public class ApplicationRepository<R> : Repository<R> where R: class
{
    public ApplicationDataContext AppContext
    {
        get
        {
            return AppContext as ApplicationDataContext;
        }
    }

    public ApplicationRepository()
    {
        AppContext = new ApplicationDataContext();
    }

    public virtual R Get(Guid Id)
    {
        var record = (from  r in AppContext.GetTable<R>().Where("Id = @0", Id)
                        select r).Single();

        return record;
    }

    public virtual IEnumerable<R> GetAll(string clause, params object[] args)
    {
        var records = from  r in AppContext.GetTable<R>().Where(clause, args)
                        select r;

        return records;
    }

    public override void Insert(R record)
    {
        var d = record as dynamic;
        d.Id = Guid.NewGuid();
        d.CreatedOn = DateTime.Now;
        d.CreatedBy = "System";

        base.Insert(record);
    }

    public override void Update(R record)
    {
        var d = record as dynamic;
        d.ModifiedOn = DateTime.Now;
        d.ModifiedBy = "System";

        base.Update(record);
    }
}

In my case, I added a narrowing ApplicationDataContext and some additional functionality. One of the key functions is the GetAll(string, param object[]) function. This allows me to essential run any queries against my database using that Dynamic Linq library. All of the functionality that I need from a repository layer will most likely already exist in this implementation. Anything else that is needed can be added later by inheriting from the ApplicationRepository class. This is going to save me a great deal of time.