NServiceBus for dummies who want to be smarties 5… fifth post, this time with an example on how sagas can be used to implement a workflow in ASP.NET MVC.

One of the typical workflows in web applications is when someone signs up for an account, but the web site wants to check if the email address is valid. Let’s look at an example that goes like this:

  1. User enters email address as a signup request
  2. Web application sends email with a “secret” confirmation link
  3. User visits the secret link, thereby activating the account

To keep things simple, I have made a simple page containing two forms: one for the email address, and one that simulates visiting a secret link by letting us enter a “ticket”. The view looks like this:

<p>
  Enter your email address to begin registration
</p>
 
<form method="post" action="!{Url.Action("BeginRegistration")}">
  Email: <input name="email" type="text" />
  <input type="submit" value="Begin registration" />
</form>
 
<p>
  - or enter your ticket to confirm your email
</p>
 
<form method="post" action="!{Url.Action("ConfirmRegistration")}">
  Ticket: <input name="ticket" type="text" />
  <input type="submit" value="Confirm registration" />
</form>

And then I have made this simple controller to handle the posts from the registration page:

  public class RegistrationController : TxBaseController
  {
    readonly IBus bus;
 
    public RegistrationController(IBus bus)
    {
      this.bus = bus;
    }
 
    public ViewResult Index()
    {
      return View();
    }
 
    public RedirectToRouteResult BeginRegistration(string email)
    {
      bus.Send(new RequestRegistration {Email = email});
 
      return RedirectToAction("Index");
    }
 
    public RedirectToRouteResult ConfirmRegistration(int ticket)
    {
      bus.Send(new ConfirmRegistration {Ticket = ticket});
 
      return RedirectToAction("Index");
    }
  }

Now, to model this workflow we need some kind of persistence on our backend, which is where sagas come into the picture. Sagas is the built-in mechanism in NServiceBus that helps in building stateful services. Stateful services are, as the word implies, services that preserve some kind of state between receiving messages.

The NServiceBus saga is a nifty way to declare what that state should contain (by letting a class implement ISagaEntity) and – given a message that the saga can handle – how to retrieve that saga (by overriding ConfigureHowToFindSaga and setting up which properties to compare).

Lets start out by specifying that NServiceBus should take care of persisting the saga entity (which will by done through Fluent NHibernate/NHibernate/SQLite under the hood)… that can easily be achieved by changing our backend’s endpoint configuration to this:

      Configure.With()
        .CastleWindsorBuilder(container)
        .Sagas()
        .NHibernateSagaPersisterWithSQLiteAndAutomaticSchemaGeneration()
        .XmlSerializer();

This will make NServiceBus persist ongoing sagas in an SQLite db file called “NServiceBus.Sagas.sqlite” inside the backend’s execution directory. If you omit the NHibernateSagaPersisterWithSQLiteAndAutomaticSchemaGeneration() thing, NServiceBus will store ongoing sagas by using its InMemorySagaPersister, which – surprise! – stores sagas in memory.

I had some problems with the in-memory persister however, as I could not make it correlate messages with my saga unless I correlated with interned strings only, by implementing getters on my messages like so:

public string Email
{ 
    get { return string.Intern(email); }
    set { email = value; }
}

I imagine this has to do with a deserializer somewhere, somehow generating strings that are not interned, although I have not verified this – I am only guessing! No biggie though, as long as the SQLite saga persister is so easy to use.

In my example the saga is initiated by the RequestRegistration message which contains only an email. When the saga receives that message, the email is stored, and a secret ticket is generated, emailed to the user, and stored in the saga data. The saga is completed when it receives a ConfirmRegistration message with the right ticket.

Let’s specify what will constitute the saga data:

  public class UserRegistrationSagaData : ISagaEntity
  {
    public virtual Guid Id { get; set; }
    public virtual string Originator { get; set; }
    public virtual string OriginalMessageId { get; set; }
 
    public virtual string Email { get; set; }
    public virtual int Ticket { get; set; }
  }

The first three properties come from the ISagaEntity interface – and then come my two properties for storing the email and the ticket.

Please do remember to mark all the properties of your saga data as virtual! Otherwise, Fluent NHibernate will throw some stupid exception, saying that “Database was not configured through Database method” (wtf?) (thanks to this post for sorting that one out!). The exception is fair though, as NHibernate would complain about not being able to create proxies if there were un-interceptable properties on the data class – the error message is just weird…

To create a saga, you let a class inherit from Saga<TSagaEntity> where TSagaEntity would be UserRegistrationSagaData in my example… and then we implement ISagaStartedBy and IMessageHandler where the two TMessage type parameters should be filled out with RequestRegistration and ConfirmRegistration respectively. Like so:

  public class UserRegistrationSaga : Saga<UserRegistrationSagaData>,
    ISagaStartedBy<RequestRegistration>,
    IMessageHandler<ConfirmRegistration>
  {
     //...
  }

- and then – given the two kind of messages my saga can handle – how to correlate the messages with my saga:

    public override void ConfigureHowToFindSaga()
    {
      ConfigureMapping<RequestRegistration>(saga => saga.Email, message => message.Email);
      ConfigureMapping<ConfirmRegistration>(saga => saga.Ticket, message => message.Ticket);
    }

Even though my saga is initiated by RequestRegistration, I set up a mapping that ensures that a new saga will not be created if someone requests registration twice with the same email.

Lastly, the actual logic carried out by the saga – the two message handlers (note that MailSender and NewUserService are application services that are automagically injected becuase they’re public properties of the saga):

    public void Handle(RequestRegistration message)
    {
      // generate new ticket if it has not been generated
      if (Data.Ticket == 0)
      {
        Data.Ticket = NewUserService.CreateTicket();
      }
 
      Data.Email = message.Email;
 
      MailSender.Send(message.Email,
                      "Your registration request",
                      "Please go to /registration/confirm and enter the following ticket: " + Data.Ticket);
 
      Console.WriteLine("New registration request for email {0} - ticket is {1}", Data.Email, Data.Ticket);
    }
 
    public void Handle(ConfirmRegistration message)
    {
      Console.WriteLine("Confirming email {0}", Data.Email);
 
      NewUserService.CreateNewUserAccount(Data.Email);
 
      MailSender.Send(Data.Email,
                      "Your registration request",
                      "Your email has been confirmed, and your user account has been created");
 
      // tell NServiceBus that this saga can be cleaned up afterwards
      MarkAsComplete();
    }

Note how I mark the saga as complete by calling MarkAsComplete(), thus allowing the saga data to be deleted. This could also be a nifty place to save the time of when the last registration email was sent to a particular address in order to disallow sending another registration email for the next hour or so, to avoid people spamming each other by using our web site.

Now, if I fire up my backend and request registration with the email omg@wtf.com, it looks like this:

Submitting email as a registration request
The result on the backend showing that the message was properly received

Then, if I request registration with laterz@hax0rz.com followed by omg@wtf.com, I can verify that a new saga is only created for laterz@hax0rz.com:

Submitting the same email twice results in the same ticket being sent out

And then, when I confirm a registration request, it looks like this:

Submitting one of the 'secret' tickets
The result on the backend after having submitted on of the tickets

Isn’t that great? I cannot imagine a framework with an API more elegant and terse than this.

Conclusion

That was the fifth post in my “NServiceBus for dummies who want to be smarties” series. Sixth and last post will be about our backend publishing messages whenever interesting stuff happens. This will provide a message based interface for interested parties to subscribe to.

NServiceBus for dummies who want to be smarties 4… fourth post, this time on how to incorporate NServiceBus as a backend in an ASP.NET MVC application.

How to create the projects

First, create a new ASP.NET MVC project. I assume you know how to use an IoC container to instantiate controllers, and that you know how to configure your container (otherwise, there are plenty of information available – e.g. here and here), so I will just show this simple snippet on how to build the bus and put it in the container:

In Application_Start:

ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(CreateWindsorContainer()));

- and then the container can be created like this:

    IWindsorContainer CreateWindsorContainer()
    {
      var container = new WindsorContainer();
 
      // register controllers and other stuff here
 
      Configure.WithWeb()
        .CastleWindsorBuilder(container)
        .XmlSerializer()
        .MsmqTransport()
          .IsTransactional(true)
          .PurgeOnStartup(true)
        .MsmqSubscriptionStorage()
        .UnicastBus()
        .CreateBus()
        .Start();
 
      return container;
    }

Notice the call to the extension method CastleWindsorBuilder? It comes from the assembly NServiceBus.ObjectBuilder.CastleWindsor.dll which is included with NServiceBus – it provides the adapters necessary for NServiceBus to a) register everything it discovers (like e.g. all your implementations of IMessageHandler<>), and b) pull instances when needed thus supplying dependencies during object activation. This way of supporting multiple IoC containers just plain ROCKS!

At this point NServiceBus has registered itself and resolved all message handlers found in the current web application’s bin directory (Configure.WithWeb() as opposed to Configure.With()) in the supplied IoC container, and since I am pulling all my controllers from Windsor, I can jump directly to implementing my HomeController:

  public class HomeController : TxBaseController
  {
    readonly IBus bus;
 
    public HomeController(IBus bus)
    {
      this.bus = bus;
    }
 
    [AcceptVerbs(HttpVerbs.Post)]
    public RedirectToRouteResult DoSomething(string text)
    {
      bus.Send(new SomethingHappened {Message = text});
 
      return RedirectToAction("Index");
    }
 
    [AcceptVerbs(HttpVerbs.Post)]
    public RedirectToRouteResult DoSomethingBad(string text)
    {
      bus.Send(new SomethingHappened { Message = text });
 
      throw new ApplicationException("oh noes!");
    }
 
    public ViewResult Index()
    {
      return View();
    }
  }

As you can see, I implemented two actions responding to a HTTP post, both sending a message to the backend, but DoSomethingBad throws an exception, in which case i do not want the message to actually be sent.

My view is just a trivial (Spark) view with two forms:

<use master="Site"/>
 
<h1>DoSomething</h1>
<form method="post" action="!{Url.Action("DoSomething")}">
  Enter text: <input type="text" name="text" />
  <input type="submit" value="Send" />
</form>
 
<h1>DoSomethingBad</h1>
<form method="post" action="!{Url.Action("DoSomethingBad")}">
  Enter text: <input type="text" name="text" />
  <input type="submit" value="Send" />
</form>

And then I made a simple backend with one message handler:

  public class HandleSomethingHappened : IMessageHandler<SomethingHappened>
  {
    public void Handle(SomethingHappened message)
    {
      Console.WriteLine("Something happened: {0}", message.Message);
    }
  }

Now, to check if things work, I navigate to /home/index, which on my computer looks like this:

dosomething

- and then I enter the text “WHEE!” into the first text field and press “Send”, yielding the following in my backend’s console window:

fantastic

Which is great! My backend receives messages from my web application, so now I can put all kinds of heavy calculations and processesing and whatnot in there, to be computed outside of web requests.

Now, what if something bad happens during the web request, and we do not want any messages to actually be sent? Well, if I enter a text into the other text field and submit it (to the DoSomethingBad action of my HomeController), nothing happens on the backend! Why is that?

Simply because I have started a TransactionScope in my controller layer supertype, TxBaseController, ensuring that all controller actions are run inside a (possibly distributed) transaction! It looks like this:

  public abstract class TxBaseController : Controller
  {
    TransactionScope currentTx;
 
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      currentTx = new TransactionScope();
 
      base.OnActionExecuting(filterContext);
    }
 
    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
      base.OnActionExecuted(filterContext);
 
      var exceptionHappened = filterContext.Exception != null;
      var exceptionWasHandled = filterContext.ExceptionHandled;
 
      if (!exceptionHappened || exceptionWasHandled)
      {
        currentTx.Complete();
      }
 
      currentTx.Dispose();
    }
  }

- and since message queueing plays along nicely with the currently ongoing ambient transaction (which e.g. the incredible NHibernate ALSO does), this transaction scope will make sure that everything just works!

Conclusion

That concludes today’s “NServiceBus for dummies who want to be smarties”. This one was on how to actually put NServiceBus to use as a simple backend for an ASP.NET MVC web application. Freaking easy, right?! Next time I will show how to put sagas to use by implementing one of the workflows of a typical web application.

NServiceBus for dummies who want to be smarties 3… third post on how to do some more stuff with NServiceBus.

But where do the messages go?

Well, where did you tell the framework to send them?

The answer to this question is deferred until the last meaningful moment, i.e. the moment when the generic host starts up and reads its app.config.

How do I receive messages?

The answer is simple: use the MsmqTransportConfig section to tell NServiceBus where this service can be reached. If the specified queue does not exist, it will be created. E.g. like so:

  <MsmqTransportConfig InputQueue="client"
                       ErrorQueue="error"
                       NumberOfWorkerThreads="1"
                       MaxRetries="5" />

How do I send messages?

This question is a bit harder to answer. First, it can be specified in the UnicastBusConfig/MessageEndpointMappings element, for each message type, or for an entire assembly at a time. E.g. like so:

  <UnicastBusConfig>
    <MessageEndpointMappings>
      <add Messages="Messages" Endpoint="someService" />
      <add Messages="MessagesRootNamespace.SomeSpecificMessage, Messages" Endpoint="anotherService" />
    </MessageEndpointMappings>
  </UnicastBusConfig>

In the example above, I have configured that all messages from the assembly Messages except SomeSpecificMessage will be routed to someService, whereas SomeSpecificMessage has its own destination in the queue anotherService.

Note that this section is not required if the service is a publisher, because then it will know where to send messages because other services have subscribed, and in the process they leave the name of the queue where they can be found.

Conclusion

That concludes today’s “NServiceBus for dummies who want to be smarties”. This was about where messages go. Next post will be an example with a simple infrastructure for an ASP.NET MVC backend running on NServiceBus, accepting subscriptions from other services. It’s going to be hot!

NServiceBus for dummies who want to be smarties 2… second post, this time on how to do some more stuff with NServiceBus.

How to do stuff when the service starts

Make a class implement IWantToRunAtStartup, e.g. like so:

public class BuildPoolOfExpensiveObjects : IWantToRunAtStartup
{
    public void Run()
    {
        // build that pool
    }
 
    public void Stop()
    {
        // dispose it properly
    }
}

How to speed up delivery of messages that are transient in nature

If your message contents get stale after a short period of time, it makes no sense to use reliable messaging where messages are written to disk before the message queueing service attempts to deliver the messages to their destination. Therefore, to be true to the transient nature of the messages and speed up delivery, you can decorate some of your messages with the [Express] attribute. E.g. like so:

[Express]
public class SomeFrequentlyChangingValueJustChanged : IMessage
{
    public double Value { get; set; }
}

How to make messages expire after some amount of time

If you know your message content does not make sense after some period of time, say one hour, just decorate your message with the [TimeToBeReceived] attribute – e.g. like so:

[TimeToBeReceived]("01:00:00")]
public class AnotherPeriodicallyChangingValueJustChanged : IMessage
{
    public double Value { get; set; }
}

Note that the argument to the attribute must be Parseable – unfortunately C# does not allow for calling e.g. TimeSpan.FromHours(1) in the attribute initializer.

How to stop logging all kinds of noise to the console

Logging is good, but not all the time. To disable all of NServiceBus’ logging, just make your endpoint config implement the interface IWantCustomLogging and do nothing in the Init method – e.g. like so:

public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomLogging
{
    public void Init()
    {
        // ... do nothing here =)
    }
}

Conclusion

That concludes today’s “NServiceBus for dummies who want to be smarties”. This was about how to add some more life to your service. Next post will be about the question: where do the messages go?

NServiceBus for dummies who want to be smarties 1… first post: on how to get started creating services with NServiceBus.

How to create messages

Creating messages with NServiceBus consists of performing the following steps:

  1. Create a new project of type “Class Library”
  2. Make the project reference NServiceBus.DLL (“Get it now”)
  3. Create a class for each message, “tagging” each message class with the IMessage interface – see example below
public class CreateNewUserRequest : IMessage
{
    public string Username { get; set; }
}

Note that IMessage is just a marker interface, so it does not require you to implement anything.

How to create a service

Creating a service with NServiceBus consists of performing the following steps:

  1. Create a new project of type “Class Library”
  2. Make the project reference all the DLLs AND NServiceBus.Host.exe from the ZIP file
  3. Make the project reference the message DLL from above
  4. Make a class implement IConfigureThisEndpoint – see example below
  5. Make the endpoint configuration class implement either AsA_Client, AsA_Server, or AsA_Publisher
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server
{
}

How to run that service

Make each service project run the referenced NServiceBus.Host.exe inside its bin\Debug directory – e.g. CustomerService should, as its debug action, run the external program SolutionDir\CustomerService\bin\Debug\NServiceBus.Host.exe.

NServiceBus.Host.exe, referred to as “the generic host”, is actually a Windows service, that uses reflection to pick up all the assemblies that surround it, and use them to build a service.

This is why you need to implement IConfigureThisEndpoint – it’s a marker interface that tells the generic host to look for configuration in that class.

A nifty thing to do at this point, is to set your solution to debug multiple projects when you press F5 – do this by right clicking on the top node in solution explorer, select “Set startup projects…”, and make all your service projects start up when debugging.

How to do stuff in a service

Make a class in a service that implements IMessageHandler<TMessage>. This requires you to implement one function, Handle. See example below:

public class HandleCreateNewUserRequest : IMessageHandler<CreateNewUserRequest>
{
    public void Handle(CreateNewUserRequest message)
    {
        // ..... do stuff
    }
}

But how does the service get access to the bus?

NServiceBus defaults to using Spring for DI, so dependencies are automagically resolved – which also includes the bus! Which in turn means that the following code snippet can send messages by using the bus:

public class HandleCreateNewUserRequest : IMessageHandler<CreateNewUserRequest>
{
    public IBus Bus { get; set; }
 
    public void Handle(CreateNewUserRequest message)
    {
        Bus.Send(new DoSomethingSomewhere());
    }
}

Ok, but where does the message go?

Well, that depends – for this stuff to run, we need to do a tad more configuration by supplying each service with an app.config. E.g. like so:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="MsmqTransportConfig" type="NServiceBus.Config.MsmqTransportConfig, NServiceBus.Core" />
    <section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
  </configSections>
 
  <MsmqTransportConfig InputQueue="client"
                       ErrorQueue="error"
                       NumberOfWorkerThreads="1"
                       MaxRetries="5" />
 
  <UnicastBusConfig>
    <MessageEndpointMappings>
      <add Messages="Messages" Endpoint="server" />
    </MessageEndpointMappings>
  </UnicastBusConfig>
</configuration>

In this XML file, I am configuring the following things:

  • The MsmqTransportConfig section tells the generic host that this service can be reached at client, which is just the name of a private message queue, which the framework will automatically create for us
  • The UnicastBusConfig/MessageEndpointMappings section tells the framework that all message types from the assembly Messages should be sent to the message queue server

Please pay some respect and awe to the MaxRetries, ErrorQueue, and NumberOfWorkerThreads attributes – how cool is that?! It means that all exceptions that may happen inside your message handlers should not be handled by you, just let them bubble up to the framework and let it retry delivery up to 5 times until successful, or else the message will go to the error queue. That totally rids you of handling those pesky exceptions coming from your database transaction (hopefully rarely, or else your database is a bottleneck) being selected as the deadlock victim, temporarily unavailable external services unable to communicate, etc. Handling those things is truly the job of a framework.

Conclusion

That concludes today’s “NServiceBus for dummies who want to be smarties”. This was how to go about creating a simple service which is capable of receiving a message, and in the message handler it can send a message.

Nov 112009

I have probably only scratched the surface of the goodies that JetBrains have added to the new ReSharper 5, but here’s two nifties I discovered today: F12 jumps from the redirect string to the corresponding action method in my controller (the light arrow), and F12 on a view result method gives me the ability to jump to the corresponding view (the gray arrow). That’s just neat!

resharper_aspnet_mvc

Did you ever sit with Visual Studio and R# writing tests, wondering if you could run tests without touching your mouse? I did that all the time, until I found out that you could go to Tools => Options => Environment => Keyboard and filter the list by “Resharper.Resharper_Unit”, giving access to keyboard shortcuts to run the current test context, debug the current test context + more.

resharper_keyboard_shorts

I have assigned Ctrl + Alt + Enter to run my current test context and Shift + Ctrl + Alt + Enter to run my current test session.

R# FTW

nifty, r# Comments Off
Oct 222009

Recently I made a post because I was experiencing a moment of silent awe with R#.

R# 5 is on its way, and the feature list is impressive! I am excited about the call and value tracking features, because that’s basically all I do in one particular huge legacy system I am working on.

I am going to wait a few days, and then I will download one of the nightly builds and go check it out – I almost cannot wait!

…and it’s going to be great!

I am looking forward to too many presentations to mention! My only limitation is that I am confined to the “Programming languages” track on Monday afternoon, because I am supposed to function as a track manager there, so unfortunately I will miss the CouchDB from 3333 km presentation.

The rest of the time, however, I will check out all kinds of great presentations. But what I like the most, is that I am always filled with inspiration and creative drive after attending JAOO.

See you there!

One of the things you usually end up wanting to configure on a case-to-case basis when using NHibernate is cascading – i.e. which relations should NHibernate take responsiblity for saving.

An example could be in DDD terms where you have an aggregate root, that contains some stuff. Let’s take an example with a Band which is the subject of the BandMember role, which in turn references another aggregate root, User, that is the object of the band member role.

It is OK for us that we need to save a User and a Band in a repository, that’s the idea when dealing with aggregate roots. But everything beneath an aggregate root should be automatically persisted, and the root should be capable of creating/deleting stuff beneath itself without any references to repositories and stuff like that.

So how do we do that with NHibernate? Well, it just so happens that NHibernate can be configured to cascade calls to save, delete, etc. through relations, thus allowing the aggregate root to logically “contain” its entities.

This is all fine and dandy, but when Fluent NHibernate is doing its automapping, we need to be able to give some hints when we want cascading to happen. I usually want to be pretty persistence ignorant, BUT sometimes I just want to be able to do stuff quickly and just get stuff done, so I usually end up “polluting” my domain model with a few attributes that give hints to a convention I use.

Consider this:

public class Band : EntityBase
{
	public Band()
	{
		BandMembers = new List<BandMember>();
	}
 
	public virtual string Name { get; set; }
 
	[Cascade]
	public virtual IList<BandMember> BandMembers { get; set; }
 
	public virtual void AddBandMember(User user, BandMemberType bandMemberType)
	{
		var bandMember = FindExistingBandMember(user) ?? new BandMember(user);
		bandMember.BandMemberType = bandMemberType;
	}
 
	public virtual void RemoveBandMember(User user)
	{
		BandMembers.Remove(FindExistingBandMember(user));
	}
 
	BandMember FindExistingBandMember(User user) 
	{
		return BandMembers.ToList().Find(b => b.User == user);
	}
}
 
public enum BandMemberType 
{
	Member, Administrator
}
 
public class BandMember : EntityBase
{
	public BandMember(User user)
	{
		User = user;
	}
 
	public virtual BandMemberType BandMemberType { get; set; }
 
	public virtual User User { get; set; }
}
 
public class User : EntityBase
{
	public virtual string Name { get; set; }
}

Notice that little [Cascade]-thingie in there? It’s implemented like this:

public class CascadeAttribute : Attribute
{
}

Trivial – but I want that to be spotted by Fluent NHibernate to make the BandMembers collection into a cascade="all-delete-orphan", which in turn will cause the methods AddBandMember and RemoveBandMember to be able to update the DB.

I do this with a CascadeConvention, which is my implementation of the IHasManyConvention and IReferenceConvention interfaces. It looks like this:

public class CascadeConvention : IHasManyConvention, IReferenceConvention
{
	public void Apply(IManyToOneInstance instance)
	{
		var property = instance.Property;
 
		if (!HasAttribute(property)) return;
 
		Console.WriteLine("CascadeAll on {0}.{1}", property.DeclaringType.Name, property.Name);
 
		instance.Cascade.All();
	}
 
	public void Apply(IOneToManyCollectionInstance instance)
	{
		var property = instance.Member;
 
		if (!HasAttribute(property)) return;
 
		Console.WriteLine("CascadeAllDeleteOrphan on {0}.{1}", property.DeclaringType.Name, property.Name);
 
		instance.Cascade.AllDeleteOrphan();
	}
 
	bool HasAttribute(ICustomAttributeProvider provider)
	{
		return provider.GetCustomAttributes(typeof(CascadeAttribute), false).Length == 1
	}
}

What is left now is to make sure Fluent NHibernate picks up my convention and uses it. I usually do this by throwing them into the same assembly as my entities and do something like this when configuring FNH:

new AutoPersistenceModel()
        // (...)
        .Conventions.Setup(s => s.AddFromAssemblyOf<EntityBase>())
        .Configure(configuration);

- which will cause all conventions residing in the same assembly as EntityBase to be used.

This works really good for me, because it makes it really easy and quick to configure cascading where it’s needed – I don’t have to look deep into an .hbm.xml file somewhere or try to figure out how cascading might be configured somewhere else – the configuration is right where it’s relevant and needed.

Extremist PI-kinds-of-guys might not want to pollute their domain models with attributes, so they might want to use another way of specifying where cascading should be applied. Another approach I have tinkered with, is to let all my entities be subclasses of an appropariate base class – like e.g. AggregateRoot (implies no cascading), Aggregate (implies cascading), and Component (implies that the class is embedded in the entity).

The great thing about Fluent NHibernate is that it’s entirely up to you to decide what kind of intrusion offends you the least :)

© 2010 mookid on code Suffusion WordPress theme by Sayontan Sinha