Web Application Architectures

I continue to be interested in the architecture of the plain, standard, web application. Each of the web application frameworks defines an architecture for the plain web application. Think of Rails and Django (MVC + Active Record), or sharp architecture and Codebetter.Canvas (Asp.net MVC + NHibernate + DDD). This is a starting point from which more advanced and specialised web applications can grow.

Damian Maclennan, or as these guys might say (2:50) 'some guy',  presented a simple framework for web applications at Sydney Alt.Net. Damian's example mixes Asp.Net MVC, Fluent NHibernate and Structure Map. 

The Good Parts

My favourite part is the way that NHibernate is configured with the IoC container. The author inherits from the Structure Map Registry class and creates a registry called NHibernateRegistry

internal class NHibernateRegistry : Registry
    {
        public NHibernateRegistry()
        {
            ForRequestedType<ISessionFactory>()
                .CacheBy(InstanceScope.Singleton)
                .TheDefault.Is.ConstructedBy(() => new NHibernateSessionFactory().GetSessionFactory());

            ForRequestedType<ISession>()
                .CacheBy(InstanceScope.Hybrid)
                .TheDefault.Is.ConstructedBy(x => x.GetInstance<ISessionFactory>().OpenSession());
        }
    }

I think this is a neat way to group IoC registrations. The NHibernateRegistry registers NHibernateSessionFactory as a singleton, which is important because NHibernate requires that the session factory is at application scope. The scope for ISession is InstanceScope.Hybrid which means that the scope of an ISession is one HTTP request, exactly what is required for normal NHibernate usage. 

The Missing Parts

It is usually desirable to begin a transaction for each ISession and close the transaction prior to the ISession being closed. If the example is extended to include database writes it will fail without transactions. NHProf recommends that transactions be used even for read-only sessions.

Security can be a challenge in Asp.Net MVC. I would like to see how Damian prefers to secure controllers. 

The Repository<T> class currently only supports querying by Id. If a more complicated query is required where should it go? The two popular options are: specialised repositories (PostRepository : IRepository<Post>) with query methods and query objects where each query is encapsulated in an object. 

Fluent NHibernate is nice but I wonder why auto mapping was not used. It would work nicely for the domain in the example. 

Jerry's Final Thoughts

It's good to see the production of this kind of useful guidance. Someone new to the technologies could easily use Damian's example as a starting point for a well designed Asp.Net MVC application. It is certainly a much more helpful starting point than the Visual Studio template. 

Until next time, take care of yourselves and each other.


Resize and Save Images with .NET

In this post I will present a service class for resizing and saving an image. The service has one public method, ResizeAndSave() which accepts a stream, a filename and a directory to save the file to. It uses a simple algorithm to rescale the image to fit into a maximum rectangle and then performs the actual resize using System.Drawing, and returns the dimensions of the resized image.

    public class ImageService : IImageService
    {
        private readonly IFileSystem fileSystem;
        private const int LARGEST_WIDTH = 400;
        private const int LARGEST_HEIGHT = 500;

        public ImageService(IFileSystem fileSystem)
        {
            this.fileSystem = fileSystem;
        }

        public Rectangle ResizeAndSave(Stream input, string filename, string toDirectory)
        {
            using (Image image = Image.FromStream(input))
            {
                Rectangle scaledRectangle = (image.Width > LARGEST_WIDTH)
                    ? ScaleByWidth(image.Width, image.Height, LARGEST_WIDTH)
                    : new Rectangle(0, 0, image.Width, image.Height);
                
                if (scaledRectangle.Height > LARGEST_HEIGHT)
                {
                    scaledRectangle = ScaleByHeight(scaledRectangle.Width, scaledRectangle.Height, LARGEST_HEIGHT);
                }

                Bitmap newImage = new Bitmap(scaledRectangle.Width, scaledRectangle.Height, image.PixelFormat);
                Graphics toDrawOn = Graphics.FromImage(newImage);
                toDrawOn.CompositingQuality = CompositingQuality.HighQuality;
                toDrawOn.SmoothingMode = SmoothingMode.HighQuality;
                toDrawOn.InterpolationMode = InterpolationMode.HighQualityBicubic;
                toDrawOn.DrawImage(image, scaledRectangle);
                
                fileSystem.Write(ConvertImageToMemoryStream(newImage).ToArray(), toDirectory, filename);
                newImage.Dispose();
                toDrawOn.Dispose();
                return scaledRectangle;
            }
        }

        private static MemoryStream ConvertImageToMemoryStream(Image image)
        {
            var stream = new MemoryStream();
            image.Save(stream, image.RawFormat);
            return stream;
        }

        private static Rectangle ScaleByWidth(int originalWidth, int originalHeight, int newWidth)
        {
            float scalingFactor = (float)newWidth / (float)originalWidth;
            float newHeight = originalHeight * scalingFactor;
            return new Rectangle(0, 0, newWidth, (int)newHeight);
        }

        private static Rectangle ScaleByHeight(int originalWidth, int originalHeight, int newHeight)
        {
            float scalingFactor = (float)newHeight / (float)originalHeight;
            float newWidth = originalWidth * scalingFactor;
            return new Rectangle(0, 0, (int)newWidth, newHeight);
        }

    }

The actual file writing is delegated to the IFileSystem service, which is implemented like so:

    public class FileSystem : IFileSystem
    {
        public void Write(byte[] data, string directoryPath, string fileName)
        {
            if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath);
            File.WriteAllBytes(directoryPath + fileName, data);
        }
    }

 


NHibernate Session-Per-Request with ASP.NET MVC

UPDATE: Don't use my SessionPerRequest filter. Apparently NHibernate should always have an explicit transaction. For the record, Sharp Architecture disagrees so maybe the jury is still out?

Session-per-request is an ORM pattern that means a new session is created for each request and terminated at the end of the request. I have also implemented a transaction-per-request option, by which I mean that a transaction is created for each request and committed (or rolled back) at the end of the request. Using transaction-per-request I can read, insert update and delete as much as I like during the action execution and at the end NHibernate will synchronize the changes to the database.

Because I am a big fan of simplicity I have chosen to implement these patterns using plain Asp.Net MVC action filters. This is actually not a bad approach because the choice between readonly or persistent session must be made for each request anyway, therefore there is no point hiding this decision.

Here is my Session-Per-Request implementation:

    /// <summary>Use this filter for read-only actions.</summary>
    public class SessionPerRequest : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            // use this method instead of OnResultExecuted if the session does not
            // need to be open for the view rendering.
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            NHibernateHelper.DisposeSession();
        }
    }

This filter simply handles the disposal of the session at the end of the request. I do not have to explicitly open the session because this is handled elsewhere the first time that the session is accessed. This filter can be used like this:

        [SessionPerRequest]
        public ActionResult Index()
        {
            // readonly code here
            return View();
        }

For actions that need to persist state changes a different filter is required. The TransactionPerRequest filter opens a transaction before the action is executed and commits the transaction when the view has been rendered.

    /// <summary>
    /// Use this filter for actions that need to persist state.
    /// </summary>
    public class TransactionPerRequest : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            NHibernateHelper.BeginTransaction();
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            // use this method instead of OnResultExecuted if the transaction / session 
            // does not need be open for the view rendering.
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            if (filterContext.Exception == null)
                NHibernateHelper.CommitTransaction();
            
            NHibernateHelper.DisposeSession();
        }
    }

Usage of TransactionPerRequest is the same as for SessionPerRequest. Both of these action filters defer NHibernate access to a class called NHibernateHelper. NHibernate is a simple wrapper that manages access to an ISessionFactory singleton, and instances of ISession.

    public class NHibernateHelper
    {
        private static ISessionFactory sessionFactory;

        /// <summary>
        /// SessionFactory is static because it is expensive to create and is therefore at application scope.
        /// The property exists to provide 'instantiate on first use' behaviour.
        /// </summary>
        private static ISessionFactory SessionFactory
        {
            get
            {
                if (sessionFactory == null)
                {
                    sessionFactory = new Configuration().Configure().AddAssembly(typeof(Models.Store).Assembly).BuildSessionFactory();
                }
                return sessionFactory;
            }
        }

        public static ISession GetCurrentSession()
        {
            if (!CurrentSessionContext.HasBind(SessionFactory))
            {
                CurrentSessionContext.Bind(SessionFactory.OpenSession());
            }
            return SessionFactory.GetCurrentSession();
        }

        public static void DisposeSession()
        {
            var session = GetCurrentSession();
            session.Close();
            session.Dispose();
        }

        public static void BeginTransaction()
        {
            GetCurrentSession().BeginTransaction();
        }

        public static void CommitTransaction()
        {
            var session = GetCurrentSession();
            if (session.Transaction.IsActive)
                session.Transaction.Commit();
        }

        public static void RollbackTransaction()
        {
            var session = GetCurrentSession();
            if (session.Transaction.IsActive)
                session.Transaction.Rollback();
        }
    }

The GetCurrentSession method ensures that an existing session is returned if one exists, otherwise a new session is created. By using NHibernate's CurrentSessionContext singleton the scoping of sessions is controlled by the NHibernate current_session_context_class property. In my web application I configure the property like this:

        web

In my test project I will change the value of the current_session_context_class property to call so that NHibernateHelper can function without a HttpContext.

I am sure there are better ways to do what I am trying to achieve, so if you see any areas for improvement please leave a comment.

 

kick it on DotNetKicks.com


First Experience With NHibernate

Today I started experimenting with NHibernate. As I have become more interested in TDD, BDD, SOLID, DDD and other upercase acronyms I am incre

asingly seeing NHibernate as the only viable option for persistence. NHibernate will be the third ORM tool that I have learnt. The first two were Wilson ORMapper and Linq-to-sql. Unfortunately for me, both Wilson ORMapper and Linq-to-sql have been killed off by their respective authors. Initially I thought that because I understand ORM tools learning NHibernate would be trivial, but it has turned out to be far more complicated than either Wilson ORMapper or Linq-to-sql.

So far I do not like NHibernate. It is the opposite of convention over configuration. There are ten different ways to do anything, which contributes to its already poor and distributed documentation. It is great to have choices but in the case of NHibernate I think it really weakens the experience. At the very least there should be some kind of out-of-the-box experience that uses a default strategy that just works (ala RoR). Here are some of the areas where a user has to choose how to use NHibernate:

  • Mapping Strategy - NHibernate supports mapping by attributes, xml files or a fluent interface. The fluent interface seems to be the way to go but I could not get it to work. Even the demo app on the fluent nhibernate site does not work. Therefore, I went back to the xml mapping strategy.
  • Configuration - Configure in code, hibernate.cfg.xml file, app.config or the fluent interface.
  • Query Strategy - There are three different techniques for querying: HQL, Criteria (detached and attached) and Linq-to-Nhibernate. From what I can gather Linq-to-Nhibernate is not really production ready. HQL does not have any compile-time checking so I am leaning towards a query strategy based on detached criteria.
  • Session Management - I will be using NHibernate in a web environment so I plan to implement the session-per-request pattern. This means that my ISessionFactory will be application scope and ISession will be scoped to an individual HTTP request.
  • Architectural Patterns - Ayende's excellent article Repository is the new Singleton describes two different data access patterns that both apply to NHibernate: DAO/Repository and Specification. He contends that DAO services don't provide any value and we should access ISession directly and encapsulate querys into query objects (or specifications). I'm not sure what to do here.

The book, NHibernate in Action is the most useful NHibernate documentation that I have. Its obsolescence shows NHibernate's rapid recent change. Despite the book being only a few months old it is hopelessly out of date. The book documents NHibernate 1.2 but NHibernate 2.0 is the current version. Major features such as fluent nhibernate and Linq-to-nhibernate are not mentioned in the book.

Maybe I'll try the entity framework...

 


Excommunicating Your God Classes

God classes are classes that have too many responsibilities. They do too much and have too much knowledge of other parts of the application. I'm not going to explain what dependencies are. :)

I have realised that I tend to create god classes with too many dependencies because I have a strong subconcious desire to avoid ending up with lots of classes. So I try to group things into related classes, even when they are not very closely related (low cohesion).

Consider the example of a fleet tracking system. I have to add functionality to allow the user to dial a vehicle. I already have a VehicleController so my instinct is to create a VehicleController.Dial(vehicleIdentifier) action. The trouble is that dialling actually has very little to do with vehicles. Dialling is accomplished by making a http GET request to a third party. The Dial action method does not require any of the dependencies that the VehicleController class already has.

My final design has a new controller, DiallingController with a Dial action method. DiallingController has just one dependency, System.Net.HttpWebRequest to make the request. This design has higher cohesion and is easier to test. The downside is that it does lead to lots of classes, but I think that is the cost of good design and it is well worth the price.

Here is my new rule:

never add code to a class unless the code requires most of the dependencies of the class.