Tags: , , , , , , | Categories: ASP.Net, C#, Fluent, MVC, NHibernate, Ninject, NHibernate,Validator Posted by Admin on 9/14/2011 4:26 PM | Comments (1)

Eventually (after lots of google searches and putting together snippets from here, there and, everywhere) we now have Fluent NHibernate, NHibernate.Validator and Ninject all playing together.

First, we configure NHibernate using Fluent NHibernate passing the configuration to NHibernate.Validator so that it can configure the NHibernateSharedEngineProvider - this is important as Ninject will use the NHibernateSharedEngineProvider.

public static class Database
{
    private static ISessionFactory sessionFactory = null;

    public static ISessionFactory CreateSessionFactory()
    {
        var config = new AutoMappingConfiguration();
        ValidatorEngine validatorEngine = null;
        if (sessionFactory == null)
        {
                sessionFactory = Fluently
                .Configure()
                .Database(
                    MsSqlConfiguration
                    .MsSql2008
                    .ConnectionString(c => c.Server("").Database("").TrustedConnection()))
                .Mappings(
                    m => m.AutoMappings.Add(
                        AutoMap.AssemblyOf<EntityBase>(config)
                        .Override<EntityBase>(n => n.IgnoreProperty(c => c.ValidationErrors))
                        .Override<Country>(n => n.IgnoreProperty(c => c.DisplayName))
                        ))
                .ExposeConfiguration(c => { 
                    validatorEngine = ConfigureNHibernateValidator(c); 
                    BuildSchema(c); 
                })
                .BuildSessionFactory();
        }

        return sessionFactory;
    }

    public static ValidatorEngine ConfigureNHibernateValidator(Configuration nhibernateConfiguration)
    {
        NHibernate.Validator.Cfg.Environment.SharedEngineProvider = new NHibernateSharedEngineProvider();
        var validatorConfiguration = new NHibernate.Validator.Cfg.Loquacious.FluentConfiguration();
        validatorConfiguration
            .SetDefaultValidatorMode(ValidatorMode.UseAttribute)
            .Register(Assembly.Load("models").ValidationDefinitions())
            .IntegrateWithNHibernate
            .ApplyingDDLConstraints()
            .RegisteringListeners();
        var validatorEngine = NHibernate.Validator.Cfg.Environment.SharedEngineProvider.GetEngine();
        validatorEngine.Configure(validatorConfiguration);
        ValidatorInitializer.Initialize(nhibernateConfiguration, validatorEngine);
        return validatorEngine;
    }

    private static void BuildSchema(Configuration config)
    {
        new SchemaUpdate(config).Execute(false, true);
    }
}

Then we configure Ninject

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IEntityManager>().To<EntityManager>().InRequestScope();
    kernel.Bind<ISessionFactory>().ToMethod(x => Database.CreateSessionFactory()).InSingletonScope();
    kernel.Bind<ISession>().ToMethod(x => kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
    kernel.Bind<ISharedEngineProvider>().ToMethod(x => NHibernate.Validator.Cfg.Environment.SharedEngineProvider).InSingletonScope();
}

Then we inject both ISession and ISharedEngineProvider into our EntityManager via the .ctor. We then check the Entity is valid before saving.

public class EntityManager : IEntityManager
{
    private ISession session = null;
    private ISharedEngineProvider validator = null;

    public EntityManager(ISession session, ISharedEngineProvider validator)
    {
        this.session = session;
        this.validator = validator;
    }

    public T Save<T>(T item) where T : EntityBase
    {
        item.ValidationErrors.Clear();
        ValidatorEngine ve = this.validator.GetEngine();
        if (!ve.IsValid(item))
        {
            foreach (var invalidValue in ve.Validate(item))
            {
                item.ValidationErrors.Add(new ValidationError() { PropertyName = invalidValue.PropertyName, Message = invalidValue.Message });
            }
        }
        else
        {   
            try
            {
                this.session.SaveOrUpdate(item);
                this.session.Flush();
            }
            catch (InvalidStateException ise)
            {
                item.ValidationErrors.Clear();
                foreach (var invalidValue in ise.GetInvalidValues())
                {
                    item.ValidationErrors.Add(new ValidationError() { PropertyName = invalidValue.PropertyName, Message = invalidValue.Message });
                }
            }
        }

        return item;
    }
}

Note that within EntityManager we use ISharedEngineProvider.GetEngine() to get our pre-configured Validator. The try { ... } catch { ... } around this.Session.SaveOrUpdate(item) isn't really required but better to be safe than sorry!

Tags: , , , , , , | Categories: ASP.Net, C#, MVC, NHibernate, Ninject Posted by Admin on 6/13/2011 12:55 PM | Comments (12)

We eventually managed to get Ninject,Fluent NHibernate, NHibernate.Linq and MVC3 to play nicely together. Each of these libraries has its issues when it comes to playing nicely mainly due to dependencies mis-matches or due to a lack of instruction.

Firstly, Ninject. We installed Ninject into our sample application using the Package Manager Console.

Install-Package Ninject
Install-Package Ninject.Web
Install-Package Ninject.MVC3

We missed Ninject.MVC3 first time around which cost us about two hours of head scratching so remember to install it.

Once all three Ninject libraries are installed into your application you should have a new generated file App_Start/NinjectMVC3.cs, this is where you load your Ninject Module(s) into your application and where the magic construction injection takes place for your controllers (amongst other things).

The next step seems to be widely documented on the net pointless if you're using NinjectMVC3; modifying your Global.asax file to enable Ninject to do its thing is no longer required and to configure NHibernate fluently.

public class MvcApplication : HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Person", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

    }
}

Next we need to configure Ninject so that it knows what concrete implementations of interfaces to inject. This is done by inheriting from NinjectModule and overriding the Load() method.

public override void Load()
{
    this.Bind<IRepository>().To<NHRepository>().InRequestScope(); //.InSingletonScope(); <-- Singleton scope doesn't work with ISession in request scope!
    this.Bind<ISessionFactory>().ToMethod(x => Database.CreateSessionFactory()).InSingletonScope();
    this.Bind<ISession>().ToMethod(x => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
    this.Bind<PersonController>().ToSelf();
}

In this case whenever a constructor requires an implementation of IRepository the same an instance of NHRepository is supplied by the InSingletonScope modifier. We're also binding our NHibernate ISession to the GetCurrentSessionOpenSession() method of the ISessionFactory (which being static prevents re-initialization of SessionFactory - a very expensive operation) and binding the PersonController to itself.

Finally we need Ninject to load our module into the application when the application starts, this is done in NijnectMVC.cs by modifying the CreateKernel method.

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel(new MvcApplicationNinjectModule());
    RegisterServices(kernel);
    return kernel;
}

As far as Ninject is concerned we're all sorted. We just need to create IRepository and implement this in NHRepository which is where NHibernate.Linq comes into the mix and then create our controller to call the repository.

We won't go into the details of IRepository and NHRepository other than to point out that Ninject injects our NHibernate Session into NHRepository in the constructor.

public interface IRepository
{
    IQueryable<T> Get<T>();
    IQueryable<T> Get<T, TKey>(params OrderByClause<T, TKey>[] orderBy);
    IQueryable<T> Get<T>(int pageSize, int pageIndex, out int recordCount);
    IQueryable<T> Get<T, TKey>(int pageSize, int pageIndex, out int recordCount, params OrderByClause<T, TKey>[] orderBy);
}
public class NHRepository : IRepository
{
private ISession session = null;

public IQueryable<T> Get<T>()
{
    return this.session.Query<T>();
}

public IQueryable<T> Get<T, TKey>(params OrderByClause<T, TKey>[] orderBy)
{
    var query = this.session.Query<T>();
    foreach (var order in orderBy)
    {
        switch (order.Direction)
        {
            case OrderByDirection.Descending:
                query = query.OrderByDescending(order.Expression);
                break;
            default:
                query = query.OrderBy(order.Expression);
                break;
        }
    }

    return query;
}

public IQueryable<T> Get<T>(int pageSize, int pageIndex, out int recordCount)
{
    recordCount = this.session.Query<T>().Count();
    return this.session.Query<T>().Skip(pageSize * pageIndex).Take(pageSize);
}

public IQueryable<T> Get<T, TKey>(int pageSize, int pageIndex, out int recordCount, params OrderByClause<T, TKey>[] orderBy)
{
    recordCount = this.session.Query<T>().Count();
    var query = this.session.Query<T>();
    foreach (var order in orderBy)
    {
        switch (order.Direction)
        {
            case OrderByDirection.Descending:
                query = query.OrderByDescending(order.Expression);
                break;
            default:
                query = query.OrderBy(order.Expression);
                break;
        }
    }

    return query.Skip(pageSize * pageIndex).Take(pageSize);
}

public NHRepository(ISession session)
{
    this.session = session;
}

Finally we come to the controller which needs an instance of IRepository to fetch its data from.

public class PersonController : Controller
{
    private IRepository repository;

    public PersonController(IRepository repository)
    {
        this.repository = repository;
    }

    [HttpGet]
    public ActionResult Index(int? pageIndex)
    {
        int actualPageIndex = pageIndex.GetValueOrDefault(0);
        int recordCount = 0;
        var people = this.repository.Get<Person, dynamic>(10, actualPageIndex, out recordCount, new OrderByClause<Person, dynamic>(c => c.DateOfBirth.Value, OrderByDirection.Descending), new OrderByClause<Person, dynamic>(c => c.Surname, OrderByDirection.Ascending), new OrderByClause<Person, dynamic>(c => c.Forename, OrderByDirection.Ascending));
        int pageCount = (int)Math.Ceiling((double)recordCount / 10);
        return View(new PagedListViewModel<Person>(people.ToList(), actualPageIndex, pageCount));
    }

}

Ninject is again doing its magic by injecting an (singleton) instance of NHRepository into our constructor for us.

So where were the issues? Well if you use the package manager to get all the Fluent NHibernate and NHibernate.Linq libraries you'll see that Fluent NHibernate uses version 3.1 of NHibernate but NHibernate.Linq is complied against version 2.1, and NHibernate.Linq is complied against version 3.5 of System.Xml.Linq whereas our application is using version 4.0. To fix these mis-matches we can configure our application to substitute any request for a dependancy with a newer version of the same library. This is done in web|app.config

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
      <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="System.Xml.Linq" publicKeyToken="b77a5c561934e089" />
      <bindingRedirect oldVersion="1.0.0.0-3.5.0.0" newVersion="4.0.0.0" />
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" />
      <bindingRedirect oldVersion="2.1.0.4000-2.1.2.4000" newVersion="3.1.0.4000" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>