Using in an ASP MVC Application

An easy way to implement this easily across your application is by subclassing Controller to handle common needs for your application (in this example, we'll call that ApplicationController), then subclassing that controller for your actual controllers. So, you end up with a structure similar to the following:
 Controller
 +-- ApplicationController
     +-- ExampleController
     +-- AnotherController

What we'll put in the ApplicationController is a method that will get us a new data connection.

ApplicationController.cs
namespace DocExample.Controllers
{
    using System.Configuration;
    using System.Web.Mvc;
    using DatabaseAbstraction.Interfaces;
    using DatabaseAbstraction.Utils;

    /// <summary>
    /// This class serves as a superclass for all DocExample controllers
    /// </summary>
    public abstract class ApplicationController : Controller
    {
        /// <summary>
        /// Get a new connection to the data store
        /// </summary>
        public static IDatabaseService NewDataConnection()
        {
            var config = ConfigurationManager.ConnectionStrings["MyDatabase"];
            return DbUtils.CreateDatabaseService(config.ConnectionString,
                config.ProviderName);
        }
    }
}
TIP: Making this public static means that anywhere in our web application, we can call this to get a connection.

We could also make this return an asynchronous implementation:
namespace DocExample.Controllers
{
    using System.Configuration;
    using System.Web.Mvc;
    using DatabaseAbstraction.Async;
    using DatabaseAbstraction.Async.Interfaces;
    using DatabaseAbstraction.Utils;

    /// <summary>
    /// This class serves as a superclass for all DocExample controllers
    /// </summary>
    public abstract class ApplicationController : Controller
    {
        /// <summary>
        /// Get a new connection to the data store
        /// </summary>
        public static IDatabaseServiceAsync NewDataConnection()
        {
            var config = ConfigurationManager.ConnectionStrings["MyDatabase"];
            return new DatabaseServiceAsync(
                DbUtils.CreateDatabaseService(config.ConnectionString,
                    config.ProviderName));
        }
    }
}

Then, in a controller, we can actually implement this.

ExampleController.cs
namespace DocExample.Controllers
{
    using DocExample.Models;
    using DocExample.Services;
    using System.Web;
    using System.Web.Mvc;

    /// <summary>
    /// This controller handles manipulation of Examples
    /// </summary>
    public class ExampleController : ApplicationController
    {
        //
        // GET: /Example
        [HttpGet]
        public ActionResult Index()
        {
            using (var database = NewDataConnection())
                return View(new ExampleService(database).GetAllExamples());
        }

        //
        // GET: /Example/Edit
        [HttpGet]
        public ActionResult Edit(int id)
        {
            Example model = null;

            if (0 < id)
                using (var database = NewDataConnection())
                    model = new ExampleService(database).GetExample(id);

            if (null == model)
                model = new Example();

            return View(model);
        }

        //
        // POST: /Example/Save
        [HttpPost]
        public ActionResult Save (Example model)
        {
            if (!ModelState.IsValid)
                return View("Edit", model);

            using (var database = NewDataConnection())
            {
                var service = new ExampleService(database);

                if (0 == model.ID)
                    service.InsertExample(model);
                else
                    service.UpdateExample(model);
            }

            return RedirectToAction("Index");
        }
    }
}

...or, asynchronously...

namespace DocExample.Controllers
{
    using DocExample.Models;
    using DocExample.Services;
    using System.Threading.Tasks;
    using System.Web;
    using System.Web.Mvc;

    /// <summary>
    /// This controller handles manipulation of Examples
    /// </summary>
    public class ExampleController : ApplicationController
    {
        //
        // GET: /Example
        [HttpGet]
        public async Task<ActionResult> Index()
        {
            using (var database = NewDataConnection())
                return View(await new ExampleService(database).GetAllExamples());
        }

        //
        // GET: /Example/Edit
        [HttpGet]
        public async Task<ActionResult> Edit(int id)
        {
            Example model = null;

            if (0 < id)
                using (var database = NewDataConnection())
                    model = await new ExampleService(database).GetExample(id);

            if (null == model)
                model = new Example();

            return View(model);
        }

        //
        // POST: /Example/Save
        [HttpPost]
        public async Task<ActionResult> Save (Example model)
        {
            if (!ModelState.IsValid)
                return View("Edit", model);

            using (var database = NewDataConnection())
            {
                var service = new ExampleService(database);

                if (0 == model.ID)
                    await service.InsertExample(model);
                else
                    await service.UpdateExample(model);
            }

            return RedirectToAction("Index");
        }
    }
}

TIP: This illustrates using the using keyword on the database connection instances; doing this ensures that the runtime calls Dispose() when the reference goes out of scope. IDatabaseServiceAsync calls Dispose() on the concrete instance used when it is instantiated.

TIP: With the data access code abstracted, and the data access implementation abstracted further still, the controller itself is clean; all the controller does is retrieve the data from the data store and send it to the presentation layer, or receive data from the presentation layer and send it to the data store. Validation or other server-side manipulation may still be necessary, but it should be easy to spot and maintain among the few calls to the data store.

<<

Last edited Apr 2, 2013 at 1:33 AM by danielsummers, version 8

Comments

No comments yet.