Changing The FluentNHibernate Id Conventions

FluentNhibernate provides a bunch of Convention interfaces and base classes to override the default conventions. In this case our database naming requires Id columns to include the table name like ProductId for the Products table. Also, we’re using the HiLo algorithm. This can be done with a simple class the implements IIdConvention.

public class FullIdNameConvention : IIdConvention
{
    public void Apply(IIdentityInstance instance)
    {
        instance.Column(instance.EntityType.Name + "Id");
        instance.GeneratedBy.HiLo("100");
    }
}

The convention also required referenced id to be named as Id where the default is _id. This can be changed with the follow two classes.

public class ManyToManyIdNameConvention : IHasManyToManyConvention
{
    public void Apply(IManyToManyCollectionInstance instance)
    {
        instance.Key.Column(instance.EntityType.Name + "Id");
        instance.Relationship.Column(instance.Relationship.StringIdentifierForModel + "Id");
    }
}
  
public class ReferenceIdNameConvention : IReferenceConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        instance.Column(instance.Name + "Id");
    }
}

Some cases may require other interface implementations.

Lastly, FluentNhibernate needs to know about these conventions which can be on the AutoPersistenceModel class passed to the NHibernate configuration. This is done in an implementation of IConfigurationBuilder passed to the Castle NHibernate Facility.

var model = new AutoPersistenceModel()
    .AddEntityAssembly(typeof(Product).Assembly)
    .Where(t => t.Namespace.StartsWith(typeof(Product).Namespace))
    .Conventions.AddFromAssemblyOf<FullIdNameConvention>()
    .UseOverridesFromAssemblyOf<ProductMapping>()
    ;
  
configuration.AddAutoMappings(model);

More info can be found on the FluentNHibernate wiki.


NServiceBus 1.9 to 2.0 Upgrade Issues

Here’s some notes about breaking changes we ran into upgrading from 1.9 to 2.0 of NServiceBus.

  • The distributor. This was mostly due to the fact that we had our own TopShelf implementation and had to remove that stuff.
  • The auto loading of message handlers now throws on dll’s and exe’s that are not .net assemblies. I think this is better, but some of our projects reference native dll’s and so we changed our code to explicitly load the needed assemblies with the Configure.With(params Assemblies[] assemblies) overload.
  • Configuration Files. A lot of code was moved from NServiceBus.dll to NServiceBus.Core.dll and the config references need to be updated to reflect that. This was often resulting in “ComponentActivator: could not instantiate NServiceBus.Unicast.UnicastBus” errors. Mostly this was a problem for us regarding logging, but I think many of the other configuration section handlers moved to NServiceBus.Core too.
    • Common.Logging.ConfigurationSectionHandler, NServiceBus.Core
    • Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, NServiceBus.Core
  • Installing into our existing WindsorContainer. This was a fairly easy and welcome change, consisting of mostly deleting code and passing our container in the Configure.With().CastleWindsorBuilder(containerInstance) method.

Overriding NServiceBus Configuration

I needed to override the default NServiceBus configuration (app.config/web.config). This turns out to be really easy with the 2.0 NServiceBus release.

First, when setting up the Bus I needed to call CustomConfigurationSource(myCustomSource) like this:

var unicastBusConfig = configure.CastleWindsorBuilder(container) 
      .CustomConfigurationSource(myCustomSource)
      .XmlSerializer("http://tempuri.com")
      .MsmqTransport()
          .PurgeOnStartup(purgeOnStartup)
      .UnicastBus();

Second, I needed to implement IConfigurationSource on my myCustomSource class. This default implementation takes the passed in type and creates the configuration section handler of that type. To override a specific configuration section you can create an instance of that type, set it’s properties and return it. Otherwise, create and return the class without overriding any values.

There are four types of configuration sections used in NServiceBus currently, MsmqSubscriptionStorageConfig, DBSubscriptionStorageConfig, MsmqTransportConfig, and UnicastBusConfig.

public T GetConfiguration() where T : class
{
    if (typeof(T) == typeof(MsmqSubscriptionStorageConfig))
        return ConfigurationManager.GetSection(typeof(T).Name) as T;
  
    if (typeof(T) == typeof(DBSubscriptionStorageConfig))
        return ConfigurationManager.GetSection(typeof(T).Name) as T;
  
    if (typeof(T) == typeof(MsmqTransportConfig))
        return MsmqTransportConfiguration() as T;
  
    if (typeof(T) == typeof(UnicastBusConfig))
        return UnicastBusConfiguration() as T;
  
    return null;
}

Finally, the MsmqTransportConfiguration method creates a instance of MsmqTransportConfig and sets it’s values. In this case to fields that are passed in to the constructor, but it could be some other strategy or custom settings class.

private MsmqTransportConfig MsmqTransportConfiguration()
{
    return new MsmqTransportConfig
               {
                   ErrorQueue = errorQueue, 
                   InputQueue = inputQueue,
                   MaxRetries = maxRetries, 
                   NumberOfWorkerThreads = numberOfWorkerThreads
               };
}

Setting the Powershell Console’s Title to the Current SVN URL

I’m testing out branching per feature, as such I wanted a way to know where my working directory was pointing. Since I’m using power shell I added some functions to my profile script to set the window title to the svn url. This doesn’t auto update w/ an svn switch, but set-svntitle can be called manually.

Anyway, here’s the script.

$projects = "C:\data\working"
function set-title{Param([string] $title); $Host.Ui.RawUi.WindowTitle = $title}

function set-svntitle
{
  $currentsvn = svn info $projects | select-string &quot;URL: &quot;
  set-title $currentsvn 
}

set-svntitle 

NServiceBus Distributor Overview

Overview

The client sends messages to the distributors input queue on a remote machine. The server (or receiver) contacts the distributor asking for messages. As messages are sent to the distributor, it looks up the message endpoint in its configuration and sends the message to one of the servers waiting for work. It won’t send more to that server until it calls back to the distributor asking for more work. This stops those servers from ending up with a ton of unprocessed messages. Ayende has a good review of the Distributor here. The Colour Coding blog and this post on the Mailing list have more information about getting the samples working.

Client

The client configures the Message to go to the distributor data bus. This will be a remote queue in a distributed system.

  <MsmqTransportConfig
    InputQueue="client"
    ErrorQueue="error"
    NumberOfWorkerThreads="1"
    MaxRetries="5"
  />
  
  <UnicastBusConfig 
      DistributorControlAddress="" 
      DistributorDataAddress="">
    <MessageEndpointMappings>
      <add Messages="Messages" Endpoint="distributordatabus@xxxxxx0032" />
    </MessageEndpointMappings>
  </UnicastBusConfig>

Server

The server configures the Distributor control and data addresses on the UnicastBusConfig.

  <MsmqTransportConfig
    InputQueue="messagebus"
    ErrorQueue="error"
    NumberOfWorkerThreads="1"
    MaxRetries="5"
  />
  
  <UnicastBusConfig 
      DistributorControlAddress="distributorcontrolbus@xxxxxx0032" 
      DistributorDataAddress="distributordatabus@xxxxxx0032">
    <MessageEndpointMappings>
    </MessageEndpointMappings>
  </UnicastBusConfig>

Distributor

This distributor using the distributor control bus for it’s input. Thd distributor data bus in setup in the appSettings along with the distributor storage queue. The UnicastBusConfig need to have the message objects it will receive with the input queue of the server, messagebus in this case. This value should not be a remote value as the server will contact the distributor asking for work. It’s important for the DistributorControlAddress and DistributorDataAddress to be empty otherwise the Distributor will be in an endless loop sending stuff to itself. It would seem that the distributor would know which workers can handle which messages, but it seems like that is not the case. In other words, if you want the server to be a client in some cases with the client being the server in those cases, you need to setup another distributor. It helps to think of the Distributor as the Distributor for a specific service. Like the Business Process 1 Distributor.

  <MsmqTransportConfig
      InputQueue="distributorControlBus"
      ErrorQueue="error"
      NumberOfWorkerThreads="1"
      MaxRetries="5"
  />
  
  <UnicastBusConfig DistributorControlAddress="" DistributorDataAddress="">
    <MessageEndpointMappings>
      <add Messages="Messages" Endpoint="messagebus" />
    </MessageEndpointMappings>
  </UnicastBusConfig>
  
  <appSettings>
    <add key="DataInputQueue" value="distributorDataBus"/>
    <add key="NumberOfWorkerThreads" value="1"/>
    <add key="ErrorQueue" value="error"/>
    <add key="StorageQueue" value="distributorStorage"/>
    <add key="NameSpace" value="http://www.UdiDahan.com"/> <!&mdash; relevant for a Serialization of "interfaces" or "xml" &mdash;>
    <add key="Serialization" value="xml"/> <!&mdash; can be either "xml", or "binary" &mdash;>
  </appSettings>


N2cms Navigation Options on a MVC Site

Add the n2 SlidingCurtain control with a DragDropControlPanel control inside it after the opening body tag. This will link to the editing system of n2cms.

<n2:SlidingCurtain ID="SlidingCurtain1" runat="server">
    <n2:DragDropControlPanel ID="DragDropControlPanel1" runat="server" />
</n2:SlidingCurtain>

Now there are a bunch of N2 functions that can be used to interface with the navigation system.

To setup the menu the following can be used, the first list item shows a link to the home page. The second list item shows the sub pages.

<ul id="menu">
    <li><a href="<%= N2.Find.StartPage.Url %>">Home</a></li>
    <%= N2.Web.Tree.From(N2.Find.StartPage, 2).Filters(new N2.Collections.NavigationFilter()).ExcludeRoot(true)%>
</ul>

Next to setup the sub navigation something like this could be used.

<div class="leftColumn" style="border:solid 1px black">
    <h2><%= N2.Utility.Evaluate(N2.Find.AtLevel(N2.Find.CurrentPage, N2.Find.StartPage, 2), "Title") %></h2>
    <ul>
        <%= N2.Web.Tree.Between(N2.Find.CurrentPage, N2.Find.StartPage, true, 2).Filters(new N2.Collections.NavigationFilter()).ExcludeRoot(true) %>
    </ul>
</div>

Bread crumbs can be setup using.

<% foreach(N2.ContentItem item in N2.Find.EnumerateBetween(N2.Find.StartPage, N2.Find.CurrentPage, false)) { %>
    <%= N2.Web.Link.To(item) %> /
<% } %>
<%= N2.Utility.Evaluate(N2.Find.CurrentPage, "Title") %>

Lastly, you can update the page title using something similar to what’s been used above.

<title><%= N2.Utility.Evaluate(N2.Find.CurrentPage, "Title") %><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>

Setup N2Cms to Use the Asp.Net Providers for Authentication and Authorization

</p>

Continued from Setup N2Cms on an Asp.Net MVC

Setup the data

Add the asp.net sql tables by executing aspnet_regsql.exe

aspnet_regsql.exe -C "data source=.\SQLEXPRESS;Integrated Security=SSPI ;User Instance=true" -A all -d c:\projects\red27\app_data\red27.mdf

http://weblogs.asp.net/lhunt/archive/2005/09/26/425966.aspx

Next add the Administrators and Editors roles to the db using the aspnet_Roles_CreateRole stored procedure.

aspnet_Roles_CreateRole &lsquo;/&rsquo;, &lsquo;Administrators&rsquo; <br />aspnet_Roles_CreateRole &lsquo;/&rsquo;, &lsquo;Editors&rsquo;

Next update the web config roleManager to be enabled and remove all but the AspNetSqlRoleProvider provider.

http://code.google.com/p/n2cms/wiki/WebConfig

<roleManager enabled="true">
  <providers>
    <clear />
    <add connectionStringName="N2CMS" applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </providers>
</roleManager>

Create the admin account

Now create a new user by going to the /Account/Register page. Then log off.

Log in to the /edit section of the site using the credentials found in the forms authentication section.

<authentication mode="Forms">
  <forms loginUrl="edit/login.aspx" protection="All" timeout="30000" path="/">
    <credentials passwordFormat="Clear">
      <user name="admin" password="changeme"/>
    </credentials>
  </forms>
</authentication>

Click on Manage Users and then edit your newly created account, adding it to the Administrators and Editors roles. Log off and back on with your new account.

Clean Up

Now remove the credentials section from the forms authentication section.

<authentication mode="Forms">
  <forms loginUrl="edit/login.aspx" protection="All" timeout="30000" path="/"/>
</authentication>

Open the web.config in the Edit directory and remove the users attribute from the authorization section.

<authorization>
  <allow roles="Administrators,Editors"/>
  <deny users="*"/>
</authorization>

Brutalist Framework