Mis feeds sobre NHibernate y ASP.NET MVC

Hace tiempo que tengo un par de feeds en Google Reader que me gustaría compartir con todo el mundo que le puedan interesar.

El primero es sobre NHibernate y el segundo sobre ASP.NET MVC, dos temas que sigo de cerca porque los uso diariamente en mi trabajo, recogiendo noticias que van apareciendo en los blogs a los que estoy suscrito. Por supuesto hay muchas en inglés porque la mayoría de la información se publica en este idioma aunque intento poner cosas en español también:

Espero que resulten de utilidad.

NHibernate Validator custom messages

After an interesting thread in nhusers, I wrote this is a small post explaining how you can create a simple interpolator for NHibernate Validator that replaces the default messages for your customized ones and as well treats messages for your custom validators. Everything with internationalization using resources.

The first part is to create your own interpolator:

    using System.Globalization;
    using System.Reflection;
    using System.Resources;
    using NHibernate.Validator.Engine;

    public class CustomMessageInterpolator : IMessageInterpolator
    {
        private readonly string ResourceBaseName = "Project.Properties.Validator";

        private readonly ResourceManager resMan;

        public CustomMessageInterpolator()
        {
            this.resMan = new ResourceManager(this.ResourceBaseName, Assembly.GetExecutingAssembly());
        }

        public string Interpolate(string message, IValidator validator, IMessageInterpolator defaultInterpolator)
        {
            var s = GetMessage(message);

            return defaultInterpolator.Interpolate(s, validator, defaultInterpolator);
        }

        private string GetMessage(string message)
        {
            // It's a tempate
            if (!message.StartsWith("{") && !message.EndsWith("}"))
            {
                return message;
            }

            var resource = message.Substring(1, message.Length - 2);

            var m = this.resMan.GetString(resource, CultureInfo.CurrentCulture);

            if (string.IsNullOrEmpty(m))
            {
                // Returns the original message
                return message;
            }

            return m;
        }
    }

I use the same notation as the original project, putting the resource name between { and }. I try to get the string from Validator.resx in the Properties folder of the project and if not found I return the original message. This way, you can override the default messages with your own ones only if you want.

At the end, all messages are passed to the defaultInterpolator, that manages the rest of the substitutions (for example {Max} and {Min} are replaced by the attribute values).

Finally, you have to configure the interpolator in the .config file (it only worked for me in App.config, not in nhvalidator.cfg.xml):

<configuration>
  <configSections>
    <section name="nhv-configuration" type="NHibernate.Validator.Cfg.ConfigurationSectionHandler, NHibernate.Validator" />
  <nhv-configuration xmlns="urn:nhv-configuration-1.0">
    <property name="message_interpolator_class">Project.Validation.CustomMessageInterpolator, Project.Validation</property>
    <mapping assembly="Project.Domain" />
  </nhv-configuration>
  </configSections>
</configuration>

And that’s it. I hope it helps.

NHibernate Burrow and NHibernate Search

Spanish version

In this post I’m going to explain how I managed to make these projects to work together using NHibernate events instead of the classic interceptors. Through these events, we tell NHibernate.Search to index the elements marked for that purpose without touching the session. We only need to get it in order to perform a search in the index and we get it from NHibernate.Burrow.
The first thing we need is to configure the application properly (App.config):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="NHibernate.Burrow" type="NHibernate.Burrow.Configuration.NHibernateBurrowCfgSection, NHibernate.Burrow" />
    <section name="nhs-configuration" type="NHibernate.Search.Cfg.ConfigurationSectionHandler, NHibernate.Search" />
  </configSections>
  <NHibernate.Burrow>
<persistenceUnits>
      <add name="PersistenceUnit1"
           nh-config-file="hibernate.cfg.xml" />
    </persistenceUnits>
  </NHibernate.Burrow>

  <nhs-configuration xmlns='urn:nhs-configuration-1.0'>
    <search-factory>
<property name='hibernate.search.default.directory_provider'>NHibernate.Search.Store.RAMDirectoryProvider, NHibernate.Search</property>
<property name='hibernate.search.default.indexBase'>~/Index</property>
    </search-factory>
  </nhs-configuration>
</configuration>

NHibernate.Search does not manage the configuration section properly, so it looks for a section called nhs-configuration, so don’t change the name. On the other side, we should provide a valid hibernate.cfg.xml with NHibernate configuration. For example, for testing you can use an in-memory SQLite database:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
<property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
<property name="connection.connection_string">Data Source=:memory:;Version=3;New=True;</property>
<property name="connection.release_mode">on_close</property>-->
<mapping assembly="Mapped.Assembly" />
<mapping assembly="Mapped.Assembly2" />

  </session-factory>
</hibernate-configuration>

Don’t forget to add all the assemblies in the mapping-assembly sections.
After that, the most interesting part is Burrow session initialization in order to add reference to the events. For example, this is what I have at the beginning of each test case that hits the database:

            var framework = new BurrowFramework();

            Configuration config = framework.BurrowEnvironment.GetNHConfig("PersistenceUnit1");

            // Poner los EventListeners
            config.SetListener(ListenerType.PostDelete, new FullTextIndexEventListener());
            config.SetListener(ListenerType.PostInsert, new FullTextIndexEventListener());
            config.SetListener(ListenerType.PostUpdate, new FullTextIndexEventListener());

            framework.BurrowEnvironment.RebuildSessionFactories();

The last line is important because it updates the session with the changes made. Ok, this may not be the best approach and adding the events in the nhibernate.cfg.xml would be better. It’s up to you. It should be something like this (the code goes into the session-factory section):

<listener class="NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search" type="post-update" />
<listener class="NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search" type="post-insert" />
<listener class="NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search" type="post-delete" />

With this code you don’t need to rebuild the session factory.
With this configuration, the indexable entities (see Dario Quintana’s post on NHibernate.Search) are managed automatically by the library without doing anything manually and in a transparent manner.
Finally, you only need to test the search over the indexes. In the simple test below, the code creates a NHibernate.Search session and makes a search over an indexed entity, following Dario’s example:

        [Test]
        public void SearchIndexedUser()
        {
            var session = Search.CreateFullTextSession(new BurrowFramework().GetSession());

            var qp = new QueryParser("UserName", new StopAnalyzer());
            var nhQuery = session.CreateFullTextQuery(qp.Parse("test"), typeof(User));

            var results = nhQuery.List();

            Assert.AreEqual(1, results.Count);
        }

You must take in account on important thing: NHibernate.Search uses the current transaction if there’s one and NHibernate.Burrow makes use of them, so if you want to persist the indexes before making the search, it’s not enough evicting the entity. You should do the following:

            new BurrowFramework().CloseWorkSpace();
            new BurrowFramework().InitWorkSpace();

With this piece of code we finish Burrow’s pending transaction and create a new one in order to persist all the index changes.
And this is all. With this samples you can integrate in a simple manner two interesting projects on top of NHibernate, that can be a bit tricky if you need to deal directly with the session and are using Burrow. As well, using the new event system introduced in the 2.0 branch of NHibernate avoids the use of interceptors that in many cases was painful.
Note that both projects were compiled from the trunk of nhcontrib against NHibernate 2.0.1GA.
I’ll be waiting for your comments.