Generic Repository for Entity Framework for Pluralized Entity Set

by Mikael Henriksson 5. April 2010 00:13

UPDATE: I must apologize for the previously incomplete version of this class. I failed to see that in the case where we don’t have an instantiated entity there is a null EntityKey of course. This is an easy fix with extensions on the object context.

using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
public static class ObjectContextExtensions
{
	internal static EntitySetBase GetEntitySet<TEntity>(this ObjectContext context)
	{
		EntityContainer container = 
				context.MetadataWorkspace
					.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
		Type baseType = GetBaseType(typeof(TEntity));
		EntitySetBase entitySet = container.BaseEntitySets
			.Where(item => item.ElementType.Name.Equals(baseType.Name))
			.FirstOrDefault();

		return entitySet;
	}

	private static Type GetBaseType(Type type)
	{
		var baseType = type.BaseType;
		if (baseType != null && baseType != typeof(EntityObject))
		{
			return GetBaseType(type.BaseType);
		}
		return type;
	}
}

A while back I wrote a post about a generic repository for Entity Framework. That post was intended for version 1 of the framework and it had a big big flaw. It doesn’t take in consideration that the EntitySetName might not be the same as the name of the Entity. Let me try to explain, with the soon to be release of the Entity Framework they have added pluralization to the names of the entity sets. This means that our entity set of “Product” most likely becomes “Products”. At least I just ran in to this issue :)

The fix though is not far away. All we need to do is add a restriction to the generic parameter and we get direct access to the EntitySetName. All our entities (at least with letting EF handle the generation of the entities from database) inherits from IEntityWithKey that is just the property EntityKey which in turn has a property named EntitySetName that we can use.

The updated code will look like below. I do Activator.CreateInstance<T> because I need an instantiated object to be able to get the EntityKey (it was the first thing that sprung to mind). This is of course only done when no entity is passed in as a parameter. Also the generic constraint in the top of the class.

public class Repository<T> 
	where T : IEntityWithKey
{
	public int Add(T entity)
	{
		var context = GetObjectContext();
		context.AddObject(context.GetEntitySet<T>().Name, entity);
		int saveValue = context.SaveChanges();
		ReleaseObjectContextIfNotReused();

		return saveValue;
	}

	public long Count()
	{
		var context = GetObjectContext();
		int count = context
			.CreateQuery<T>("[" + context.GetEntitySet<T>().Name + "]")
			.Count();
			
		ReleaseObjectContextIfNotReused();

		return count;
	}

	public long Count(Expression<Func<T, bool>> criterion)
	{
		var context = GetObjectContext();
		int count = context
			.CreateQuery<T>("[" + context.GetEntitySet<T>().Name + "]")
			.Count(criterion);
		ReleaseObjectContextIfNotReused();
		return count;
	}

	public int Delete(T entity)
	{
		var context = GetObjectContext();

		object originalItem;
		EntityKey key = context.CreateEntityKey(entity.EntityKey.EntitySetName, entity);
		if (context.TryGetObjectByKey(key, out originalItem))
		{
			context.DeleteObject(originalItem);
		}
		int returnValue = context.SaveChanges();
		ReleaseObjectContextIfNotReused();

		return returnValue;
	}

	public IList<T> GetAll()
	{
		var context = GetObjectContext();
		var entities = context
			.CreateQuery<T>("[" + context.GetEntitySet<T>().Name + "]")
			.ToList();
		ReleaseObjectContextIfNotReused();

		return entities;
	}

	public IList<T> GetAll(Expression<Func<T, bool>> criterion)
	{
		var context = GetObjectContext();
		var entities = context
			.CreateQuery<T>("[" + context.GetEntitySet<T>().Name + "]")
			.Where(criterion)
			.ToList();
			
		ReleaseObjectContextIfNotReused();

		return entities;
	}

	public T GetSingle(Expression<Func<T, bool>> criterion)
	{
		var context = GetObjectContext();
		T entity = context
			.CreateQuery<T>("[" + context.GetEntitySet<T>().Name + "]")
			.First(criterion);
		ReleaseObjectContextIfNotReused();

		return entity;
	}

	public int Update(T entity)
	{
		var context = GetObjectContext();

		object originalItem;
		Type type = typeof (T);


		EntityKey key = context.CreateEntityKey(entity.EntityKey.EntitySetName, entity);

		if (context.TryGetObjectByKey(key, out originalItem))
		{
			context.ApplyPropertyChanges(key.EntitySetName, entity);
		}
		int returnValue = context.SaveChanges();
		ReleaseObjectContextIfNotReused();

		return returnValue;
	}
}

Tags:

Entity Framework

Conquering NServiceBus

by Mikael Henriksson 1. April 2010 16:09

This is an NServiceBus series I have been working on with a different approach. I often find when searching the internet that the information is written for a “senior” audience and I wanted to leave behind a simpler and more practical approach to SOA and NServiceBus (sharing the little knowledge I have sort of speak). If you have used NServiceBus or any of the competitors you probably should look elsewhere for fun reading since it is very basic stuff in these posts. Anyway, here goes:

    This post is part of a series and the source code can be found at http://github.com/MikaelHenrixon/ConqueringNServiceBus

    1. Conquering NServiceBus part 1 – Getting Started
    2. Conquering NServiceBus part 2 – Initial configuration
    3. Conquering NServiceBus part 3 – A simple Saga
    4. Conquering NServiceBus part 4 – Testing
    5. Conquering NServiceBus part 5 – Troubleshooting DTC
    6. Conquering NServiceBus part 6 – Upgrading StructureMap

Tags:

NServiceBus

Conquering NServiceBus part 5 – Troubleshooting DTC

by Mikael Henriksson 1. April 2010 15:50

This post is part of a series and the source code can be found at http://github.com/MikaelHenrixon/ConqueringNServiceBus

  1. Conquering NServiceBus part 1 – Getting Started
  2. Conquering NServiceBus part 2 – Initial configuration
  3. Conquering NServiceBus part 3 – A simple Saga
  4. Conquering NServiceBus part 4 – Testing
  5. Conquering NServiceBus part 5 – Troubleshooting DTC
  6. Conquering NServiceBus part 6 – Upgrading StructureMap

NServiceBus uses Distributed Transactions Coordinator to manage the messages from when they arrive in the queue to when the Unibus has completed the handling and in the Sagas case moved them to at least a temporary storage of your choosing. This is great because you can specify how many times a message will be retried before moved to the error queue. It can also be a major pain in the ass if the storage of your choosing happens to be on another server. Personally I’d recommend setting up some sort of virtual environment to test on in case you fudged up something and don’t know what to restore. Fortunately it ships some tools to help you out with NServiceBus what you should be looking for is a folder called “msmqutils”. Inside this folder is an executable called "Runner”. This will uninstall DTC and MSMQ if anything is incompatible with NServiceBus and install it so that it works however it does not solve all problems but first things first. If you have a problem with DTC this is where you should start. The next thing I’d like to recommend is to download a copy of DTCPing. This is a great tool for tracking down DTC issues.

So how do you really make things work? Well there is obviously a lot more to it that I can possibly cover in one blog post but let me walk you through how I got DTC to work over the internet.

First thing I did was to run RunMeFirst.bat and it did not look like below image. I had all kinds of incompatible things running on my servers. The below is how you WANT it to look. It could be that you actually need a restart after this so save your work.

output from the msmqutils runner when successful and compatible

Very verbose and clear.

From here on I went down a completely wrong path. I tried about every possible wrong and unrelated thing I could think of until NH Prof saved my ass with a message about failing transactions actually at this time NServiceBus spammed my server with about 1MB of debug messages per second but the message was not one I could make much sense of and the mere size of the log made it impossible to open when I finally found out that something was terribly wrong. Obviously I need to try something new so i fire up DTCPing. The image below from DTCPing was NOT the image I was looking at. At that time there was a message about the RPC Endpoint Mapper not being available so I had to Google it.

this is what you the initial DTCPing window to look like.

Google is great! I found tons of articles about DTC and ping so I started with firing up “d comcnfg” from the cmd prompt. And according to articles I found on the internet there was a few steps to follow. After you start dcomcnfg you should be faced with something like image 1. From here I chose to address the web server first. What is needed is to open a few ports (a thousand ports actually… just to be sure!) by right clicking on “My Computer” and selecting properties  see image 2.

1. this is the component services and dtc configuration 

2. dtc_dcomcnfg_2

 

 

If this does not work you can also modify the registry to achieve the same. One thing to note though is that you really really REALLY need to restart your computer for this to take but wait until you have completed the security settings of the Local DTC. I spent a good few minutes trying to figure out why my new settings did not work even though I was promised it should work. On a side note it’s probably a really bad idea to open up one thousand ports like this so try and keep it to a hundred!

Click ok two times and then right click, select properties on local DTC. Your settings should probably equal mine.

dtc security settings

Time to restart the computer!

DTCPing is still not working, now I do all the other necessary things like open the firewall for necessary ports. I even remove the DTC exceptions in the firewall and add them fresh just to make sure. Eventually I got a message from DTCPing about finding the name but not reaching it! Let me recommend that the first thing you do when trying to debug TCP/IP problems is to do a simple ping you know fire up the command prompt and do “ping computer_name”. Here I discover that my web server has a problem with a DNS entry because it cannot be reached by ping and had I used the computer name instead of the IP address for my remote desktop I would have also discovered this a bit earlier. Come to think of it I remember changing the remote desktop session to use the ip address when we changed IP on the server a few weeks ago thinking that the DNS issue would resolve itself automatically after a few reboots and what not…. Computer problems usually don’t solve themselves all of a sudden and it caused me a couple of hours or more in debugging and tweaking but I am relieved I finally made it work on the web server so I move on to the database server. Repeat the steps above for the db server and restart the computer.  I was still not done though, I forgot to check the ports in use on the server and the database was configured for TCP port 5000 so I switched the db server to port 4000 and finally after a long time made everything run in transactional!

Tags: , ,

NServiceBus | SQL Server | Windows Server

Conquering NServiceBus part 4 – Testing

by Mikael Henriksson 1. April 2010 15:48

This post is part of a series and the source code can be found at http://github.com/MikaelHenrixon/ConqueringNServiceBus

  1. Conquering NServiceBus part 1 – Getting Started
  2. Conquering NServiceBus part 2 – Initial configuration
  3. Conquering NServiceBus part 3 – A simple Saga
  4. Conquering NServiceBus part 4 – Testing
  5. Conquering NServiceBus part 5 – Troubleshooting DTC
  6. Conquering NServiceBus part 6 – Upgrading StructureMap

This is probably the easiest thing with NServiceBus which hints that testing is extremely important  to the creators. I don’t know the implementation details of the testing but I expect some mocking tool is used for this. It will however totally run your code and if you add a bit of logging inside the Handle(TMessage) you should be be able to follow the flow of events.

To get started we need to add a new assembly to our test project (NServiceBus.Testing). Next thing to do is to initialize the testing. This is preferably done once for every fixture:

 

[TestFixtureSetUp]
public void SetUp()
{
    var assemblies = new[]
                         {
                             typeof (IStandardMessage).Assembly,
                             typeof (BeginSagaMessage).Assembly,
                             typeof (PersistSagaMessage).Assembly,
                             Assembly.Load("NServiceBus"),
                             Assembly.Load("NServiceBus.Core")
                         };

    Test.Initialize(assemblies);
}

 

The easiest thing to get going with is an ordinary message handler and for tutorial purposes I am going to keep the messages really lightweight. The details of my saga is not important and the SagaId you can spot below is mainly for logging purposes.  My PersistSagaMessage sends all the standard messages to another endpoint for processing. The reason why I do this is so that the real (time consuming) work takes place as far away from where the server/client communication takes place. In other words. Every part of the system will do one specific thing only.

public interface IStandardMessage
{
	int Id { get; set; }
	string Msg { get; set; }
}

public class StandardMessage : IStandardMessage
{
	public int Id { get; set; }
	public string Msg { get; set; }
}

public class PersistSageMessage : IMessage
{	
	public int SagaId { get; set; }
	public IList<IStandardMessage> Messages { get; set; }
}

 

And here is an example on how a test for that persistence message handler could look like.

[Test]
public void Verify_that_PersistSagaMessages_are_handled_properly()
{
    Test.Handler<PersistenceMessageHandler>()
        .OnMessage<PersistSagaMessage>(x => { 
            x.SagaId = Guid.NewGuid();
            x.Messages.Add(new StandardMessage
            {
                Id = 1,
                Msg = "First Message"
            });
            x.Contacts.Add(new StandardMessage
            {
                Id = 2,
                Msg = "Second Message"
            });
        });
}

What the test does is the following. It creates a message, wires it to the correct endpoint and runs the correct Handle(TMessage). It’s nice to see the following in the output window:

Persistence: Message received for Saga : 873f2f44-4a79-42ff-b153-5761ca4f97a4 
Persistence: Message processed for Saga : 873f2f44-4a79-42ff-b153-5761ca4f97a4


Actually, when having a look in NH Prof I can see that everything that is not NServiceBus (like my own database calls) runs like a charm. What is happening in the background is that NServiceBus has been mocked out so that there is no need for queues etc and this is as good as integration testing in my opinion. If these tests turn green on me I know the problem is with a name of or permissions to a queue. One thing I also learned while playing around with this is that it’s actually nice to have the message return an integer as soon as possible. This way it’s quite easy to confirm that we hit our target both while testing and running in production.

Now to test saga’s there is a bit more to it and there is of course a lot going on inside the saga handlers. Let’s start with some code. This time I include some expectations and I’ll get to the details of those in just a sec.

[Test]
public void Saga_should_be_complete_after_receivng_complete_command()
{
	Guid sagaId = Guid.NewGuid();
	Test.Saga<AutosyncSaga>(sagaId)
		.ExpectReturn(x => x == 0)
		.ExpectSend<PersistSagaMessage>(x =>
			x.BackupId == sagaId &&
			x.Messages.Count == 1)
		.ExpectPublish<ClearCacheMessage>(x =>
			x.SagaId == sagaId &&
			x.Reason == Reason.Completed)
		.When(x =>
		{
			x.Handle(new BeginSagaMessage
			{
				SagaId = sagaId
			});
			x.Handle(new SomeMessage
			{
				SagaId = sagaId,
				IStandardMessage = new StandardMessage
				{
					Id = 1,
					Msg = "Some stupid message"
				}
			});
			x.Handle(new EndSagaMessage
			{
				SagaId = sagaId,
				Command = Command.Complete,
				MsgCount = 1
			});
		})
		.AssertSagaCompletionIs(true);
}
        

When takes a delegate (action) and there are not many such in the Saga<T> :)  Handle is of course the first thing we want to verify is working. The english version of that code is something like: “When saga handles EndSagaMessage expect that the saga sends PersistSagaMessage and verify that the saga has been completed”. I am not hundred percent sure my code is best practice but what I want to do here is to make sure that the saga is completed after all messages has been handled.

In case the saga did not receive all the messages and there is a count mismatch Bus.Return will be –1 (minus because we are missing messages) what I am using it for now I am just going to delete the whole saga and force the user to restart. I also expect the saga to send a PersistSagaMessage with all the necessary data from the Saga to the endpoint I was talking about earlier.

A quick look in the console output window of Visual Studio gives be the following beautiful result:

Saga: 873f2f44-4a79-42ff-b153-5761ca4f97a4 started
Saga: 873f2f44-4a79-42ff-b153-5761ca4f97a4 received a message with Id : 1
Saga: 873f2f44-4a79-42ff-b153-5761ca4f97a4 data passed on to Persistence 
Saga: 873f2f44-4a79-42ff-b153-5761ca4f97a4 complete

Tags: ,

NServiceBus | Testing

Conquering NServiceBus part 3 – A simple Saga

by Mikael Henriksson 1. April 2010 15:44

This post is part of a series and the source code can be found at http://github.com/MikaelHenrixon/ConqueringNServiceBus

  1. Conquering NServiceBus part 1 – Getting Started
  2. Conquering NServiceBus part 2 – Initial configuration
  3. Conquering NServiceBus part 3 – A simple Saga
  4. Conquering NServiceBus part 4 – Testing
  5. Conquering NServiceBus part 5 – Troubleshooting DTC
  6. Conquering NServiceBus part 6 – Upgrading StructureMap

Ok, so we have configured a way of sending and receiving messages but it’s still very basic. How can I achieve what I was originally raving about with pushing many small messages to somewhere and keeping it alive for a certain given period after which it should be either finalized and passed on to another endpoint or invalidated and deleted. Preferably with some sort of message going out about what happened but you can probably figure that out yourself but we will come to that.

Most of what we need for the saga is located in “NServiceBus.Saga”. Lets try and make this really simple the basic needs are:

  1. A message to begin the saga
  2. A message that continues the saga
  3. A message that ends the saga
  4. Message handler for all the saga messages
  5. A class to handle the data for the saga

Let us begin with the messages that, without those the rest is not important.

public class BeginSagaMessage : IMessage
{
	public int SomeProcessId {get;set;}
	public DateTime BeginDate {get;set;}	
}

public class ContinueSagaMessage : IMessage
{
	public int SomeProcessId {get;set;}
	public int Foo {get;set;}
	public string Bar {get;set;}	
}

public class EndSagaMessage : IMessage
{
	public int SomeProcessId {get;set;}
	public string Message {get;set;}
}

 

These are three very simple messages and I suppose it does not make sense at the moment for such a simple scenario but stay with me. It’s really easy to complicate things but before we do we should make it work.

So the above messages will be sent from wherever need to be and in the previous post in the series I talked about how to send messages. To me it is much easier to start there since it’s less work getting that working. Now comes the time to configure the receiving end. Now we need to create a new MessageHandler but this time we will make it a bit special.

public class MySaga : Saga<MySagaData>
                      , IAmStartedByMessages<BeginSagaMessage>
                      , IHandleMessages<ContinueSagaMessage>
                      , IHandleMessages<EndSagaMessage>
{

    public void Handle(BeginSagaMessage message)
    {
        Data.BeginDate = message.BeginDate;
        Data.SomeProcessId = message.SomeProcessId;
    }

    public void Handle(ContinueSagaMessage message)
    {
        var child = new Child
        {
            Foo = message.Foo,
            Bar = message.Bar
        };
        Data.AddChild(child);
    }

    public void Handle(EndSagaMessage message)
    {
        Data.CompletionMessage = message.Message;
        MarkAsComplete();
    }
}

The first thing that is important to notice is  that we inherit from the base class Saga<T> which provides functionality for handling the saga information (persisting it to the chosen storage etc). I will go through how to customize pretty much everything to suite your needs.

Next thing is that we specify what messages start the saga. This is important because if the saga does not exist for when this type of message is received a new Saga will be created. If a message of other types come a Saga won’t be created. The only thing that happens then is that a message is logged that the Saga could not be found.  As you can see above It looks like magic at first glance. This is a big win for convention over configuration. I remember the first time I had a look at NServiceBus it looked a lot different :)

All the processing and persistence is handled in the background and by default NServiceBus does a good job of AutoMapping “YourSagaData” class to a database of your choosing but I was not happy with that. Mostly because I was curious to how it works (and partly because I had to follow DBA guidelines).

Let’s start with the persistent objects then.

public class MySagaData : IContainSagaData
{
    public virtual int SomeProcessId { get; set; }
    public virtual DateTime BeginDate { get; set; }
    public virtual ICollection<Child> Children { get; set; }
    public virtual string CompletionMessage { get; set; }

    /// <summary>
    ///     The 3 last properties belong to the 
    ///     SagaData and is intented for internal use 
    ///     only
    /// </summary>
    public virtual Guid Id { get; set; }

    public virtual string Originator { get; set; }
    public virtual string OriginalMessageId { get; set; }

    public virtual void AddChild(Child child)
    {
        child.Parent = this;
        Children.Add(child);
    }
}

public class Child
{
    public virtual int InternalId { get; set; }
    public virtual MySagaData Parent { get; set; }
    public virtual int Foo { get; set; }
    public virtual string Bar { get; set; }
}

Nothing really special, implement interface IContainsSagaData gives you 3 properties that you should treat as non existing. These are used by NServiceBus internally. Getting this far is not a problem. We can run the saga with Production profile which should AutoMap the classes above to a database and then the only thing we need to do is provide a connection string.

What next then if I want to handle persistence myself?

public class MySagaDataMap : ClassMap<MySagaData>
{
    public MySagaDataMap()
    {
        Id(x => x.Id);
        Map(x => x.OriginalMessageId);
        Map(x => x.Originator);

        Map(x => x.SomeProcessId);
        Map(x => x.BeginDate);
        Map(x => x.CompletionMessage);

        HasMany(x => x.Children)
            .KeyColumn("SomeProcessId")
            .Cascade.All()
            .Inverse();
    }
}

public class ChildMap : ClassMap<Child>
{
    public ChildMap()
    {
        Id(x => x.InternalId);
        Map(x => x.Foo);
        Map(x => x.Bar);

        References(x => x.Parent)
            .Column("SomeProcessId");
    }
}

That gives us the mappings we need but we need more! Let’s create a SagaPersister and implementing ISagaPersister should be straightforward.

public class MySagaPersister : ISagaPersister
{
    public MySagaPersister(ISessionFactory sessionFactory)
    {
        SessionFactory = sessionFactory;
    }

    public ISessionFactory SessionFactory { get; set; }

    public void Save(ISagaEntity saga)
    {
        var session = SessionFactory.GetCurrentSession();
        session.Save(saga);
    }

    public void Update(ISagaEntity saga)
    {
        var session = SessionFactory.GetCurrentSession();
        session.Merge(saga);
    }

    public T Get<T>(Guid sagaId) where T : ISagaEntity
    {
        return SessionFactory.GetCurrentSession().CreateCriteria(typeof (T), "b")
            .Add(Restrictions.Eq("b.SomeProcessId", sagaId))
            .SetFetchMode("b.Children", FetchMode.Eager)
            .SetCacheable(true)
            .SetCacheMode(CacheMode.Normal)
            .UniqueResult<T>();
    }

    public T Get<T>(string property, object value) where T : ISagaEntity
    {
        return SessionFactory.GetCurrentSession().CreateCriteria(typeof (T), "b")
            .Add(Restrictions.Eq("b." + property, value))
            .SetFetchMode("b.Children", FetchMode.Eager)
            .UniqueResult<T>();
    }

    public void Complete(ISagaEntity saga)
    {
        SessionFactory.GetCurrentSession().Delete(saga);
    }
}

EDIT 2010-08-23 : This IS in the scope of NServiceBus and I’ll make a couple of suggestions here. The reason for the constructor dependency is to force whatever container to inject a SessionFactory into the class. This can be done through registering the persister with NServiceBus own API like below;

public static class Extensions
{
    public static Configure SetSagaPersister(this Configure config, IContainer container)
    {
        config.Configurer.RegisterSingleton(typeof (ISagaPersister),
            new MySagaPersister(container.GetInstance<ISessionFactory>()));

        return config;
    }
}

This extension method would be use at configuration time. Just add it after adding the sagas and you are good to go. Next up finding sagas…

The first alternative is to override ConfigureHowToFindSaga in the MySaga class.

public override void ConfigureHowToFindSaga()
{
	ConfigureMapping<ContinueSagaMessage>(t => t.SomeProcessId, m => m.SomeProcessId);
	ConfigureMapping<EndSagaMessage>(t => t.SomeProcessId, m => m.SomeProcessId);
}
This is what happens above:
protected void ConfigureMapping<TMessage>(
		Expression<Func<T, object>> sagaEntityProperty, 
		Expression<Func<TMessage, object>> messageProperty) 
	where TMessage : IMessage;

You pass in the MessageType and and then specify what properties should be compared for equality. This happens in the background and you will never see this taking place. It works fine for most scenarios but I wanted to eagerly load my “children” and wanted to prematurely optimize things a bit so I decided to go for another approach  which is to create my own Finder and it’s actually not that hard.

public class MySagaFinder :
    IFindSagas<MySagaData>.Using<ContinueSagaMessage>
    , IFindSagas<MySagaData>.Using<EndSagaMessage>
{
    public ISessionFactory SessionFactory { get; set; }
    public ISagaPersister Persister { get; set; }

    public MySagaData FindBy(ContinueSagaMessage message)
    {
        return FindBy(message.SomeProcessId);
    }
    
    public MySagaData FindBy(EndSagaMessage message)
    {
        return FindBy(message.SomeProcessId);
    }

    public MySagaData FindBy(Guid id)
    {
        return SessionFactory.GetCurrentSession().QueryOver<MySagaData>()
			.Where(x => x.SomeProcessId == id)
			.Fetch(x => x.Children)
			.Eager
			.Cacheable()
			.SingleOrDefault();
    }
}

 

It don’t get much easier than that. Just creating this class and putting it in your assembly should cause NServiceBus to use the “MySagaFinder”. Now we need to change the endpoint config a little to make use of  the latest changes (read previous post). We could end up with something like:

public class EndpointConfig : IConfigureThisEndpoint, IWantCustomInitialization
{
    private readonly IEnumerable<Assembly> _assemblies = new List<Assembly>
    {
        typeof (BeginSagaMessage).Assembly,
        typeof (EndpointConfig).Assembly,
        Assembly.Load("NServiceBus"),
        Assembly.Load("NServiceBus.Core"),
        Assembly.Load("NServiceBus.Host")
    };

    private IContainer _container;

    public void Init()
    {
        var file = new FileInfo("log4net.config");
        if (file.Exists) {
            XmlConfigurator.Configure(file);
        }

        InitializeSagaConnection();
        InitializeNServiceBus();
    }

    private void InitializeSagaConnection()
    {
        ObjectFactory.Initialize(x => x.AddRegistry<SagaRegistry>());
        _container = ObjectFactory.Container;
    }

    private void InitializeNServiceBus()
    {
        Configure.With(_assemblies)
            .StructureMapBuilder(_container)
            .Log4Net()
            .XmlSerializer()
            .MsmqTransport()
                .IsTransactional(true)
                .IsolationLevel(IsolationLevel.RepeatableRead)
            .UnicastBus()
                .LoadMessageHandlers()
            .Sagas()
            .SetSagaPersister(_container);
    }
}

SagaRegistry is just a place to initialize the MySaga NHibernate configuration and add what’s needed to the StructureMap container.

public class SagaRegistry : Registry
{
    public SagaRegistry()
    {
        Config = Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008.ConnectionString(x => x.FromConnectionStringWithKey(Environment.MachineName))
                          .Cache(c =>
                                 c.UseQueryCache()
                                     .QueryCacheFactory<StandardQueryCacheFactory>()
                                     .ProviderClass<HashtableCacheProvider>()
                                     .UseMinimalPuts())
                          .UseReflectionOptimizer()
                          .MaxFetchDepth(2)
                          .AdoNetBatchSize(24)
                          .CurrentSessionContext<ThreadStaticSessionContext>()
            ).Mappings(m => m.FluentMappings.AddFromAssemblyOf<MySagaDataMap>()).BuildConfiguration();
        Config.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true");
        Config.SetProperty(NHibernate.Cfg.Environment.PropertyUseReflectionOptimizer, "true");

        ForSingletonOf<Configuration>()
            .Use(x => Config);

        Factory = Config.BuildSessionFactory();
        ForSingletonOf<ISessionFactory>()
            .Use(x => Factory)
            .WithName(Environment.MachineName);
    }

    public Configuration Config { get; set; }
    public ISessionFactory Factory { get; set; }
}

here I specify that when ISessionFactory is requested from the container the one I just created is returned and I chose to handle the containers choice of ISagaPersister here as well since that is very much tied to my NHibernate configuration.

Unfortunately this is not the end of things. Now you have all the parts in place, you have truly customized the way NServiceBus works but this won’t be done unless you create a profile and tell NServiceBus to run only that profile. If you would start NServiceBus like this it would run the default profile which is integration  with SQLite database with automatic schema generation for storage. It is time to specify what profile to run.

public class MyProfile : IProfile
{
}

Now when you start the debugger you just add the full name (including namespaces)

vs2008_debug_options

Hope this helps!

Tags:

NServiceBus

About the author

Life architect specialized in programming