Art website – Data model

Now I have the basic structure for the website in place, it’s time to look at the data that needs to be displayed. There are three types of images (painting, drawings and photos) and one textual type (links). I’ll focus on paintings here, but the other types are very similar.

Data model

Since the amount of data was fairly limited, I decided not to use a real database, but just serialize the information to XML files and store the images as files in a folder. An example of the XML contents is listed below.

         1: <?xml version="1.0" encoding="utf-8"?>
         2:<ArrayOfPainting xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
         3:<Painting>
         4:     <Id>1</Id>
         5:     <Name>Dynamic</Name>
         6:     <Year>2012</Year>
         7:     <Filename>IMG_3927.JPG</Filename>
         8:     <Notes>
         9:         <Note language="nl">
        10:         Acryl, 61 x 61 x 4 cm
        11:         </Note>
        12:         <Note language="en">
        13:         Acrylic, 24 x 24 x 1.5 inch
        14:         </Note>
        15:     </Notes>
        16:</Painting>

Below is the data model definition for the Painting class. It’s different from the serialized painting as it only exposes the notes in a single (current) language.

         1: public class Painting
         2: {
         3:     public int Id { get; set; }
         4:     public string Name { get; set; }
         5:     public int Year { get; set; }
         6:     public string Filename { get; set; }
         7:     public string Notes { get; set; }
         8: }

In the HomeController, the ‘Paintings’ action uses the _artCollection dependency to retrieve the collection of paintings, which it then passes on to the view as the model.

         1: public ActionResult Paintings()
         2: {
         3:     var paintings = _artCollection.GetPaintings();
         4:     return View(paintings);
         5: }

The _artCollection is an object implementing the IArtCollection interface which is defined (for now) like this:

         1: public interface IArtCollection
         2: {
         3:     IEnumerable<Painting> Paintings { get; }
         4: }

The ArtCollection class takes has a dependency on the PaintingRepository to provide the data. Later on, it will also expose drawings and photos.

         1: public class ArtCollection : IArtCollection
         2: {
         3:     private IPaintingRepository _paintingRepository;
         4:     private IEnumerable<Painting> _paintings;
         5:
         6:     public ArtCollection(IPaintingRepository paintingRepository)
         7:     {
         8:         _paintingRepository = paintingRepository;
         9:     }
        10:
        11:     public IEnumerable<Painting> Paintings
        12:     {
        13:         get
        14:         {
        15:             if (_paintings == null)
        16:             {
        17:                 _paintings = _paintingRepository.Read();
        18:             }
        19:             return _paintings;
        20:         }
        21:     }
        22: }

The data model classes and interfaces live in their own class library called ‘Core’. This class library does not take any external dependencies. It only references ‘System’ assemblies (and one Utilities assembly where I collect some general utility classes). The classes implementing the interfaces and using the data model classes live in an assembly called ‘Infrastructure’. It references many external assemblies as it uses external libraries to create the concrete classes.

Dependency Injection

I use constructor injection to pass in the IArtCollection dependency to the HomeController. This presents a problem because now the MVC framework can no longer instantiate the controller for me. It gives me an error saying “No parameterless constructor defined for this object”.


image

To make MVC instantiate the HomeController with its dependencies passed in to the HomeController, I need to tell MVC to use a custom controller factory instead of its own. You can do this by calling the SetControllerFactory method on the ControllerBuilder Singleton object.

         1: public class MvcApplication : System.Web.HttpApplication
         2: {
         3:     protected void Application_Start()
         4:     {
         5:         DependencyInjectionConfig.Register(ControllerBuilder.Current, Server);
         6:
         7:         AreaRegistration.RegisterAllAreas();
         8:
         9:         WebApiConfig.Register(GlobalConfiguration.Configuration);
        10:         FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        11:         RouteConfig.RegisterRoutes(RouteTable.Routes);
        12:         BundleConfig.RegisterBundles(BundleTable.Bundles);
        13:         DisplayConfig.RegisterDisplayModes(DisplayModeProvider.Instance.Modes,
        14:             new DeviceDetectorFactory());
        15:     }

I extracted that code into a separate class called DependencyInjectionConfig that I use from the Application_Start method of the HttpApplication class. This class also becomes the composition root for the entire application. It uses Unity as the dependency injection container.

         1: public class DependencyInjectionConfig
         2: {
         3:     internal static void Register(ControllerBuilder controllerBuilder, HttpServerUtility httpServer)
         4:     {
         5:         controllerBuilder.SetControllerFactory(ConfigureFactory(httpServer));
         6:     }
         7:
         8:     private static IControllerFactory ConfigureFactory(HttpServerUtility httpServer)
         9:     {
        10:
      // composition root, register all types with IoC container here.
        11:         var container = new UnityContainer();
        12:
        13:         container.RegisterType<IRedirectionManager, RedirectionManager>();
        14:
        15:         string dataPath = httpServer.MapPath("~/App_Data/");
        16:         container.RegisterInstance<IArtCollection>(new ArtCollection(dataPath));
        17:
        18:         return new UnityControllerFactory(container);
        19:     }
        20: }

The SetControllerFactory method expects an object that implements the IControllerFactory interface. The easiest way to create such a class is to derive from the DefaultControllerFactory class and override the GetControllerInstance method.

         1: public class UnityControllerFactory : DefaultControllerFactory
         2: {
         3:     private IUnityContainer _container;
         4:
         5:     public UnityControllerFactory(IUnityContainer container)
         6:     {
         7:         _container = container;
         8:     }
         9:
        10:     protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        11:     {
        12:         if (controllerType == null)
        13:         {
        14:             return null;
        15:         }
        16:
        17:         return (IController)this._container.Resolve(controllerType);
        18:     }
        19: }

The UnityControllerFactory class uses the adapter pattern to make the Unity interface conform to what MVC expects. Before I can compile these classes, I need to install the Unity package via the package manager. Now when I run the project, MVC will use the UnityControllerFactory, which will defer the creation to Unity to create the HomeController passing in a brand new ArtCollection object to its constructor.

Paintings Razor view

The last thing I need to show you is the Razor view invoked by the controller action. It’s a strongly typed view against IEnumerable<Painting> and just iterates over the collection and puts the output in a table.

         1: @model IEnumerable<Website.Model.Painting>
         2:
         3: @{
         4:     ViewBag.Title = "Paintings";
         5: }
         6:
         7: <h2>Paintings</h2>
         8:      <table>
         9:      <tr>
        10:      <th></th>
        11:      <th>
        12:             @Html.DisplayNameFor(model => model.Name)
        13:      </th>
        14:      <th>
        15:             @Html.DisplayNameFor(model => model.Year)
        16:      </th>
        17:      <th></th>
        18:      </tr>
        19:
        20: @foreach (var item in Model) {
        21:      <tr>
        22:      <td>
        23:      <imgsrc      ="@item.ImageUrl"      />
        24:      </td>
        25:      <td>
        26:             @Html.DisplayFor(modelItem => item.Name)
        27:      </td>
        28:      <td>
        29:             @Html.DisplayFor(modelItem => item.Year)
        30:      </td>
        31:      </tr>
        32: }
        33:      </table>

Now the website can display the meta data for a list of paintings from a local XML file. Next time we’ll look at how to add management pages for the collection of paintings.

Leave a comment