The Inquisitive Coder - Davy Brion’s Blog

Trying to walk that thin line between intelligence and ignorance

Archive for October, 2008

LINQ To SQL On The Way Out

Posted by Davy Brion on 31st October 2008

On October 20th, i wrote this in a comment:

i have zero interest in LINQ To Sql because i think it will ultimately be neglected (or even dropped) by Microsoft to increase adoption of Entity Framework

And there we go.

Share/Save/Bookmark

Posted in Entity Framework, Software Development | 6 Comments »

Bulk Data Operations With NHibernate’s Stateless Sessions

Posted by Davy Brion on 30th October 2008

In my previous post, i showed how you can configure NHibernate to batch create/update/delete statements and what kind of performance benefits you can get from it. In this post, we’re going to take this a bit further so we can actually use NHibernate in bulk data operations, an area where ORM’s traditionally perform pretty badly.

First of all, let’s get back to our test code from the last post:

            var testObjects = CreateTestObjects(500000);

 

            var stopwatch = new Stopwatch();

            stopwatch.Start();

 

            using (ITransaction transaction = Session.BeginTransaction())

            {

                foreach (var testObject in testObjects)

                {

                    Session.Save(testObject);

                }

 

                transaction.Commit();

            }

 

            stopwatch.Stop();

            var time = stopwatch.Elapsed;

The only thing that changed since the previous post is the amount of objects that are created. In the previous post we only created 10000 objects, whereas now we’ll be creating 500000 objects.

The batch size is configured like this:

    <property name="adonet.batch_size">100</property>

This means that NHibernate will send its DML statements in batches of 100 statements instead of sending all of them one by one. The above code runs in 2 minutes and 24 seconds with a batch size of 100.

However, if we use NHibernate’s IStatelessionSession instead of a regular ISession, we can get some nice improvements. First of all, here’s the code to use the IStatelessSession:

            var testObjects = CreateTestObjects(500000);

 

            var stopwatch = new Stopwatch();

            stopwatch.Start();

 

            using (IStatelessSession statelessSession = sessionFactory.OpenStatelessSession())

            using (ITransaction transaction = statelessSession.BeginTransaction())

            {

                foreach (var testObject in testObjects)

                {

                    statelessSession.Insert(testObject);

                }

 

                transaction.Commit();

            }

 

            stopwatch.Stop();

            var time = stopwatch.Elapsed;

As you can see, apart from the usage of the IStatelessSession instead of the regular ISession, this is pretty much the same code.

With a batch-size of 100, this code creates and inserts the 500000 records in 1 minute and 26 seconds. While not a spectacular improvement, it’s definitely a nice improvement in duration.

The biggest difference however is in memory usage while the code is running. A regular NHibernate ISession keeps a lot of data in its first-level cache (this enables a lot of the NHibernate magical goodies). The IStatelessSession however, does no such thing. It does no caching whatsoever and it also doesn’t fire all of the events that you could usually plug into. This is strictly meant to be used for bulk data operations.

To give you an idea on the difference in memory usage, here are the memory statistics (captured by Process Explorer) after running the original code (with the ISession instance):

And here are the memory statistics after running the modified code (with the IStatelessSession instance):

Quite a difference for what is essentially the same operation. We could even improve on this because the code in its current form keeps all of the object instances in its own collection, preventing them from being garbage collected after they have been inserted in the database. But i think this already demonstrates the value in using the IStatelessSession if you need to perform bulk operations.

Obviously, this will never perform as well as a bulk data operation that directly uses low-level ADO.NET code. But if you already have the NHibernate mappings and infrastructure set up, implementing those bulk operations could be cheaper while still being ‘fast enough’ for most situations.

Share/Save/Bookmark

Posted in NHibernate, Performance | 4 Comments »

Some Info About Upcoming Content

Posted by Davy Brion on 28th October 2008

Just wanted to give you guys a bit of a heads up about some of the upcoming content i’ve got planned for this blog. I’ve been posting more about NHibernate lately, and i’ve actually got 12 other NHibernate-related posts planned for the coming weeks/months. For those of you who aren’t really interested in the NHibernate-related content, i hope you bear with me and keep reading for the other stuff as well. I write all of this stuff in my spare time, so naturally i always pick subjects that i like to spend that spare time on. Right now, NHibernate is at the top of that list but i’ll obviously keep covering other topics as well :)

And since the subscriber count finally surpassed 600 today, i guess this is a good time to thank all of you who’ve started following this blog, and obviously everyone who’s been reading for a while now. So thanks, and i hope you enjoy your stay :)

Share/Save/Bookmark

Posted in About The Blog | 4 Comments »

Batching NHibernate’s DML Statements

Posted by Davy Brion on 27th October 2008

An oft-forgotten feature of NHibernate is that of batching DML statements. If you need to create, update or delete a bunch of objects you can get NHibernate to send those statements in batches instead of one by one. Let’s give this a closer look.

I have an ‘entity’ with the following mapping:

  <class name="CrudTest" table="CrudTest">

    <id name="Id" column="Id" type="guid" >

      <generator class="assigned" />

    </id>

 

    <property name="Description" column="Description" type="string" length="200" not-null="true" />

 

  </class>

Nothing special here, just a Guid Id field and a string Description field.

First, let’s see how much time it takes to create 10000 records of this without using the batching feature. I use the following method to create a bunch of dummy objects:

        private IEnumerable<CrudTest> CreateTestObjects(int count)

        {

            List<CrudTest> objects = new List<CrudTest>(count);

 

            for (int i = 0; i < count; i++)

            {

                objects.Add(new CrudTest { Id = Guid.NewGuid(), Description = Guid.NewGuid().ToString() });

            }

 

            return objects;

        }

Then, the code to persist these objects:

            var testObjects = CreateTestObjects(10000);

 

            var stopwatch = new Stopwatch();

            stopwatch.Start();

 

            using (ITransaction transaction = Session.BeginTransaction())

            {

                foreach (var testObject in testObjects)

                {

                    Session.Save(testObject);

                }

 

                transaction.Commit();

            }

 

            stopwatch.Stop();

Without enabling the batching, this code took 23 seconds to run on my cheap MacBook. Now let’s enable the batching in the hibernate.cfg.xml file:

    <property name="adonet.batch_size">5</property>

A batch size of 5 is still very small, but for this test it means that it only has to do 2000 trips to the database instead of the original 10000. The code above now runs in 5.5 seconds. Setting the batch size to 100 made it run in 1.8 seconds. Going from 23 to 1.8 seconds with a small configuration change is a pretty nice improvement with very little effort. Obviously, these aren’t real benchmarks so your results may vary but i think it does show that you can easily get some performance benefits from it.

You can get performance benefits like this whenever you need to create/update/delete a bunch of records simply by enabling this setting. Keep in mind that this batching of statements doesn’t apply to select queries… for that you need to use NHibernate’s MultiCriteria or MultiQuery features :)

Another thing to keep in mind is that for this test i used the ‘assigned’ Id generator… which means that the developer is responsible for providing the Id value for new objects. One of the consequences of this is that NHibernate does not have to go to the database to retrieve the Id values like it would have to do if you were using (for instance) Identity Id values. If you were using the Identity Id generator, this configuration setting would have no effect whatsoever for inserts, although the benefits would still apply to update and delete statements.

Note that this approach is good for regular applications, but it’s still not good enough if you need to process very large data sets (like import processes and things of that nature). Obviously, an ORM isn’t well suited for those purposes, but we will examine another NHibernate feature in a future post which makes it possible to use NHibernate in such bulk operations with a pretty low performance overhead.

Share/Save/Bookmark

Posted in NHibernate, Performance | 3 Comments »

Exploring NHibernate Statistics, Part 1: Simple Data Fetching

Posted by Davy Brion on 26th October 2008

One of the new features that NHibernate 2.0 introduced is NHibernate Statistics. This feature can be pretty useful during development (or while debugging) to keep an eye on what NHibernate is doing. Not a lot of people know about this feature, so i’ve decided to write a short series of posts about it. In this first episode, we’ll explore some stats which can show you some useful information regarding the efficiency of your (simple) data fetching strategies. Later episodes will cover insert/update/delete statistics, query specific statistics and caching statistics. I don’t know yet when the other episodes will be posted, but they are definitely on my TODO list so they will get written eventually ;)

First of all, here’s how you can enable this feature. In your hibernate.cfg.xml file, you can add the following setting within the session-factory element.

    <property name=generate_statistics>true</property>

Now, there are two levels of statistics. The first is at the level of the SessionFactory. These statistics basically keep count of everything that happens for each Session that was created by the SessionFactory. You can access these stats through the Statistics property of the SessionFactory instance, which you can access from your Session instance if you don’t have a reference to the SessionFactory, for instance:

            var count = Session.SessionFactory.Statistics.EntityFetchCount;

To give you an idea of what kind of stats are available on the SessionFactory level, here’s a quick listing of most of the available properties: EntityDeleteCount, EntityInsertCount, EntityLoadCount, EntityFetchCount, EntityUpdateCount, QueryExecutionCount, QueryExecutionMaxTime, QueryCacheHitCount, QueryCacheMissCount, QueryCachePutCount, FlushCount, ConnectCount, SecondLevelCacheHitCount, SecondLevelCacheMissCount, SecondLevelCachePutCount, SessionCloseCount, SessionOpenCount, CollectionLoadCount, CollectionFetchCount, CollectionUpdateCount, CollectionRemoveCount, CollectionRecreateCount, SuccessfulTransactionCount, TransactionCount, PrepareStatementCount, CloseStatementCount, OptimisticFailureCount.

There are even more properties and methods available. For instance to retrieve the executed queries, statistics for a specific query, statistics for a specific entity type, for a specific collection role, and to get the second level cache statistics for a specific cache region.

As you can see, lots of useful properties to help you examine where your NHibernate usage might not be the way it should be. Or just useful in case you’re tying to figure out what kind of stuff NHibernate is doing behind the scenes for features you don’t fully understand and want to experiment with. There’s also a useful LogSummary() method which (obviously) logs a summary of these stats to NHibernate’s logger.

Let’s get into a couple of examples that will tell us more about the efficiency of our simple data access strategies. We’ll start with some really simple stuff, and then move to some more interesting statistics.

For brevity, i’m using the following simple property to quickly access the SessionFactory’s statistics:

        private IStatistics GlobalStats

        {

            get { return Session.SessionFactory.Statistics; }

        }

For the first example, we’ll retrieve all of the records in the Product table. After fetching this result, the EntityLoadCount statistic will reflect the number of entities we’ve loaded:

        [Test]

        public void TestEntityLoadCount()

        {

            long entityLoadCountBefore = GlobalStats.EntityLoadCount;

            var allProducts = Session.CreateCriteria(typeof(Product)).List<Product>();

            Assert.AreEqual(entityLoadCountBefore + allProducts.Count, GlobalStats.EntityLoadCount);

        }

What happens if we start using NHibernate’s lazy loading features? For instance, if we access a Product’s Category reference NHibernate has to retrieve that record from the database if it’s not already loaded. Does this count as an EntityLoad, or an EntityFetch? It counts as both an EntityLoad and an EntityFetch actually:

        [Test]

        public void TestEntityFetchCountForManyToOnePropertiesWithLazyLoading()

        {

            long entityLoadCountBefore = GlobalStats.EntityLoadCount;

            long entityFetchCountBefore = GlobalStats.EntityFetchCount;

            var allProducts = Session.CreateCriteria(typeof(Product)).List<Product>();

 

            foreach (var product in allProducts)

            {

                // this makes NHibernate fetch the Category from the database

                var categoryName = product.Category.Name;

            }

 

            var entitiesFetched = GlobalStats.EntityFetchCount - entityFetchCountBefore;

            Assert.AreEqual(entityLoadCountBefore + allProducts.Count + entitiesFetched, GlobalStats.EntityLoadCount);

            Assert.That(entitiesFetched != 0);

        }

With the data in my database, this test loads 77 Product entities, and fetches 8 Categories for a total of 85 loaded entities. The Product entities are loaded in one roundtrip, but for each Category another roundtrip is performed which is not ideal from a performance perspective. The stats actually reflect that through the PrepareStatementCount property. Let’s modify the previous test to highlight this:

            var entitiesFetched = GlobalStats.EntityFetchCount - entityFetchCountBefore;

            Assert.AreEqual(entityLoadCountBefore + allProducts.Count + entitiesFetched, GlobalStats.EntityLoadCount);

            Assert.AreEqual(entitiesFetched + 1, GlobalStats.PrepareStatementCount);

            Assert.That(entitiesFetched != 0);

We get the count of the fetched entities, and add 1 to it to reflect the roundtrip to fetch all the products. This total equals the value of the PrepareStatementCount property.

This example shows that it can be pretty important to try to keep the EntityFetchCount and PrepareStatementCount property values as low as possible when you need to fix a performance problem. Let’s give it a shot:

        [Test]

        public void TestEntityFetchCountForManyToOnePropertiesWithoutLazyLoading()

        {

            long entityFetchCountBefore = GlobalStats.EntityFetchCount;

 

            var allProducts = Session.CreateCriteria(typeof(Product))

                .CreateCriteria("Category", JoinType.InnerJoin)

                .List<Product>();

 

            foreach (var product in allProducts)

            {

                // the Categories have already been retrieved, so this doesn’t cause a db roundtrip

                var categoryName = product.Category.Name;

            }

 

            var entitiesFetched = GlobalStats.EntityFetchCount - entityFetchCountBefore;

            Assert.AreEqual(1, GlobalStats.PrepareStatementCount);

            Assert.AreEqual(0, entitiesFetched);

        }

Instead of fetching all of the Products and then relying on NHibernate’s lazy loading to fetch the Categories, we fetch all of them in one go. The result is that NHibernate only performs one DB statement and it still loads all 85 records.

These statistics are nice if you just want to get information about loading entities, but what about collections? Well, we can use the CollectionLoadCount and CollectionFetchCount properties for this:

        [Test]

        public void TestCountsForOneToManyPropertyWithLazyLoading()

        {

            var loadCountBefore = GlobalStats.EntityLoadCount;

            var collectionLoadCountBefore = GlobalStats.CollectionLoadCount;

            var collectionFetchCountBefore = GlobalStats.CollectionFetchCount;

            var prepareStatementCountBefore = GlobalStats.PrepareStatementCount;

            var allRegions = Session.CreateCriteria(typeof(Region)).List<Region>();

            var territoryCount = 0;

 

            foreach (var region in allRegions)

            {

                // uses lazy-loading to fetch the Territories for this region

                territoryCount += region.Territories.Count();

            }

 

            Assert.AreEqual(loadCountBefore + allRegions.Count + territoryCount, GlobalStats.EntityLoadCount);

            Assert.AreEqual(collectionLoadCountBefore + allRegions.Count, GlobalStats.CollectionLoadCount);

            Assert.AreEqual(collectionFetchCountBefore + allRegions.Count, GlobalStats.CollectionFetchCount);

            Assert.AreEqual(prepareStatementCountBefore + allRegions.Count + 1, GlobalStats.PrepareStatementCount);

        }

Btw, using the Count() result of the Territories property is something i’d never do, but i’m just using it here to illustrate these stats. In this case, we have 4 Regions, which we retrieve in one roundtrip, and then we fetch each Region’s Territories in seperate trips which brings the total of PrepareStatementCount up to 5. As you can see, the CollectionLoadCount is equal to the CollectionFetchCount. In some cases, it can be better to retrieve the Territories while we’re also retrieving the Regions:

        [Test]

        public void TestCountsForManyToOnePropertyWithoutLazyLoading()

        {

            var loadCountBefore = GlobalStats.EntityLoadCount;

            var collectionLoadCountBefore = GlobalStats.CollectionLoadCount;

            var collectionFetchCountBefore = GlobalStats.CollectionFetchCount;

            var prepareStatementCountBefore = GlobalStats.PrepareStatementCount;

 

            var allRegions = Session.CreateCriteria(typeof(Region))

                .SetFetchMode("Territories", FetchMode.Join)

                .SetResultTransformer(CriteriaUtil.DistinctRootEntity)

                .List<Region>();

 

            var territoryCount = 0;

 

            foreach (var region in allRegions)

            {

                // the Territories have already been retrieved, so this doesn’t use lazy-loading

                territoryCount += region.Territories.Count();

            }

 

            Assert.AreEqual(loadCountBefore + allRegions.Count + territoryCount, GlobalStats.EntityLoadCount);

            Assert.AreEqual(collectionLoadCountBefore + allRegions.Count, GlobalStats.CollectionLoadCount);

            Assert.AreEqual(collectionFetchCountBefore, GlobalStats.CollectionFetchCount);

            Assert.AreEqual(prepareStatementCountBefore + 1, GlobalStats.PrepareStatementCount);

        }

With this code, there’s only one roundtrip, yet all of the Regions and their Territories are loaded. This approach won’t always be better than retrieving the collections seperately though… it kinda depends on the size and shape of the resultset of the joined query compared to the size and shapes of the resultsets of retrieving the root entities and their child collections seperately.

This post only showed a couple of the (many) interesting statistics that NHibernate can give you, but it could already help you troubleshoot bad-performing parts of your application. Keep an eye on those EntityFetchCount and PrepareStatementCount values… If the EntityFetchCount is rather low compared to the total EntityLoadCount, then there’s probably nothing bad going on. If the EntityFetchCount is a rather large percentage of the total EntityLoadCount value, then you can be pretty sure that you can get some solid performance improvements in the code that drives up the EntityFetchCount value.

Share/Save/Bookmark

Posted in NHibernate | 2 Comments »

New Version Of CopySourceAsHtml Available

Posted by Davy Brion on 26th October 2008

CopySourceAsHtml is a great Visual Studio plugin that i use to post my source code on this blog. The author has recently released a version that fully supports Visual Studio 2008. You could already use the old version with VS2008, but you had to do some things manually to get it working… this new version comes with an installer and some nice new features too. If you need to display source code from Visual Studio in HTML form, this plugin is exactly what you need :)

Share/Save/Bookmark

Posted in Off Topic | No Comments »

Career Advice For Young Developers

Posted by Davy Brion on 25th October 2008

Over the past few years, i’ve seen a few young developers make some not-so-smart decisions about their careers and futures. I’ve always found situations like that frustrating because i hate seeing good developers make bad choices. So i decided to write down a bit of career advice for young developers:

Make sure you like doing your job

To me, one of the most important parts of a job is the fact that you should enjoy doing it. If you do the math, you’ll quickly realize that you’ll spend somewhere around half of your active adult life at your job, so you might as well try to make the most of it. If you’re unhappy or frustrated at your job, you’re essentially wasting a large part of your life so you’re better off trying to find something that you actually enjoy doing.

Make sure you get satisfaction out of your job

A lot of people want different things out of their job, so it’s hard to quantify those. For some people it’s really important that their work is actually useful or helpful to others. Other people might get more satisfaction out of the fact that they are continuously increasing their skills. Other people want to make sure they work on very profitable stuff. Whatever it is that satisfies you in your job, make sure you get it. It keeps you motivated, it keeps you sharp and it helps in keeping you happy in general. Keep in mind though that there will always be days or short periods of time where you don’t feel like you’re getting that satisfaction out of your job. It’s only natural that this happens once in a while, but if you feel like that on a regular basis, you’re probably better off looking elsewhere for something that suits you more.

Choose between actual jobs, not companies

If you have to choose between jobs, go for the job that seems the most interesting and fulfilling. Do not base your decision on the actual companies offering the jobs. Always keep in mind that there are plenty of developer jobs out there (especially if you’re good) so you don’t really need to focus on stuff like job security. This can be different if you already have a family to feed, but then again, this advice is targeted to young developers. Go for the job that interests you the most, it will usually enable you to grow as a developer and increase your skill level substantially (which in the long run is the only true way to achieving job security anyway… more on that later).

If you like developing software, then keep working as a developer!

Developers that start working for larger companies often feel the need to climb up the corporate ladder to achieve some sort of management job. Because managers are important right? If you want to make it into management, you better be very sure that it’s really something you want to do. Be prepared to be stuck in meeting rooms with people who often don’t really know what they’re talking about and are often only interested in advancing their careers, even if that means if it has to be at the cost of others. If you’re a good developer and you like developing, there’s absolutely nothing wrong with staying a developer. There are far too few good senior developers, and those people are always in heavy demand.

Don’t put up with being a Code Monkey

Some developers are often considered as Code Monkeys, and they don’t really get a lot of respect. Those developers can be just as valuable as any other developer, so if you ever feel like people look at you as just a Code Monkey, there’s no reason to put up with that. You’d be better off finding a job where the developers are treated and appreciated as the valuable resources that they are.

Learn from your co-workers

Make sure you can learn from the people you’re working with. If you’re stuck in a place where you feel that you aren’t learning anything new from your co-workers, you can quickly become demotivated, which is a terrible way to spending large parts of your days. A job where you frequently learn new things from your co-workers is really a blessing. Not only are you getting better at what you do, you’re basically getting better for free, without having to invest your personal time into it.

Keep up with new technologies and ways of working

As i just mentioned, it’s very important that you learn from your co-workers. But that doesn’t mean you shouldn’t spend a bit of your own time into improving your skills. You don’t need to spend hours a day outside of work on getting better, but a couple of hours here or there could really make a big difference into increasing your skills. Not only do you get better from it, it also enables you to improve the skills of your co-workers, which in turn makes you a more valuable developer. Learning from people is important, but allowing people to learn from you is just as important.

Don’t focus on job security

I used to work at a large company in the financial industry. I was there as a contractor, so i wasn’t a ‘real’ employee of the company. I did meet some young developers there that only started working there because it was a large company where they had job security and a chance to build a career for themselves. The thing is though, those large companies usually aren’t a very satisfying place to work. Things take a long time to get done, and the bureaucracy alone is enough to drain you mentally after a few years. If that happens, you’ve probably found other ways to get some satisfaction and happiness out of your life, usually outside of your work hours. Odds are that you haven’t really invested much in your technical skills, and before you know it, your skills are pretty much outdated, and you become less attractive as a potential hire for other companies. At that point, you’re pretty much stuck at a crappy job. The job security you wanted at first is there, but you’ve lost a lot of options for you personally and you’re now stuck in a crappy job. If you want long-term job security, the best way to achieve that is to just make sure that you’re very good at what you do, and that you love doing it. If you’re a great developer, you will always find a great job somewhere. Yes, even when things in this business aren’t going too great. Great developers will always be in demand.

Don’t let money dominate your decisions

I’ve seen promising developers leaving their jobs just so they could make more money somewhere else. Now, if you’re sure that you’re going to like the new job more, then you’ve obviously made a good choice. But it’s important to be careful. You can always make more money somewhere else, but you often don’t know what kind of crap you’ll have to put up with to get that extra money. If you let money be the deciding factor, you might end up in situations where the only benefit of the job is the paycheck. If making money is your only goal in life, then you probably don’t mind too much. If you want to enjoy your career, you’re probably better off choosing the interesting jobs over the higher paying ones.

Always make sure you can leave your job if you’re not happy there

A lot of companies offer nice benefits to their employees. Some of those benefits could tie you into the company for the long term and you should be careful about those. No matter how much you like a job, one bad management decision could change everything. If something like that happens, and you suddenly aren’t happy in your job anymore, it really would be a shame if you feel like you can’t leave due to financial consequences of having to drop those benefits. Financial institutions are especially good at this… they typically offer employee benefits for their financial products, and if those products (like a loan for a house) tie you into the company for a long time (like, 20 years or so) it might become hard to leave that job due to the extra money it’ll cost you. Make sure you don’t get caught up in a situation like that, and make sure you become great at what you do. If you are great, you’ll usually end up with more financial flexibility anyway ;)

In conclusion

I’m not going to claim that the advice outlined above is a guaranteed way of having a successful career as a software developer. Most of it is entirely up to you and the amount of work you’re willing to put into it. I do think that the advice above can definitely help you avoid some bad situations that could otherwise sneak up on you.

If you want to add some advice to the list, or think i’m wrong about something, be sure to tell us in the comments :)

Share/Save/Bookmark

Posted in Opinions | 38 Comments »

What NHibernate Related Topics Would You Like To Read About?

Posted by Davy Brion on 12th October 2008

I currently have the following NHibernate related topics on my list of posts to write:

1) Exploring NHibernate Statistics
2) Getting Up To Speed With The Second Level Cache
3) Using NHibernate’s Stateless Sessions Instead Of Regular Sessions

I might also write something about NHibernate’s Event Listeners…

So anyways, what would you like to learn more about? If you have some suggestions, be sure to leave a comment and i might write a post about it.

Obviously, i can’t promise these posts in a certain time frame, but the interesting ones will be written sooner or later ;)

Share/Save/Bookmark

Posted in NHibernate | 11 Comments »

Looking For More NHibernate Information?

Posted by Davy Brion on 12th October 2008

For those of you who are using NHibernate (or are interested in using it, and you should be), you should check out NHibernate Forge. It’s basically a community site with a blog, a wiki, and lots of other NHibernate related goodies. My NHibernate related posts are also posted there, as well as other people’s NHibernate related posts.

So if you want to learn more about NHibernate, be sure to check that site out and keep an eye on it. Also, if you’re already using NHibernate and want to share your experiences with the rest of us, i encourage you all to start writing posts about it. You can put your posts on your own blog as well as on NHibernate Forge. I even include a link to the original post on my blog whenever i put one of the posts on NHibernate Forge so you could do that as well.

Another good place to learn more about NHibernate is the NHUsers mailing list on Google Groups. It’s a bit high-traffic, but a lot of interesting things are discussed there and it’s a great place to ask for help.

Share/Save/Bookmark

Posted in NHibernate | No Comments »

How To Write Testable ASP.NET UserControls

Posted by Davy Brion on 11th October 2008

Ever since i wrote my How To Write Testable ASP.NET WebForms post i’ve had people asking me how to make it work with UserControls. I pretty much avoided UserControls with this approach for as long as i could, but for our current project we really had a need for it. So i started implementing this together with a coworker, and this is the solution we came up with.

Note: if you haven’t read that post on how to write testable ASP.NET WebForms, be sure to read it first because this approach is very similar and i won’t repeat all of the general concepts of the approach here.

In the implementation for WebForms, we call the pages Views, and they all implement their own interface which inherits from our own IView interface. Now we wanted something that would work both with UserControls and Web Parts. So we figured we should call both of them ViewParts and we have the following base interface that each ViewPart should implement:

    public interface IViewPart

    {

        bool IsPostBack { get; }

        IDictionary State { get; }

    }

If you need more operations that each ViewPart should be able to offer, you can obviously just add whatever you want to this interface.

We also want each ViewPart to have its own Controller, which we call PartControllers. Since we want to be able to test both the ViewParts and their containing Views in isolation, each View’s Controller can never communicate directly with the specific PartController(s) of the ViewPart(s) that it contains. So we first need the following base interface for each PartController:

    public interface IPartController

    {

        IDispatcher Dispatcher { get; set; }

        void AddInitialRequests();

        void GetInitialResponses();

    }

In our case, each PartController will need an IDispatcher instance to be able to communicate with our Request/Response Service Layer. So the IDispatcher reference is only necessary if you’re using that as well. The idea is that the containing View’s Controller needs to provide its IDispatcher instance to each contained ViewPart’s PartController so the initial requests of each ViewPart can be sent to the service layer together with whatever initial requests the containing View’s Controller needs to send when the View is loaded. That’s basically what the AddInitialRequests and GetInitialResponses methods are for. Again, this is very specific to the usage of the Request/Response Service Layer, so you might want to put some entirely different basic operations in your base IPartController interface.

We need to be able to ask each ViewPart for its typed PartController, so we also have this interface:

    public interface IViewPart<TPartController> : IViewPart

        where TPartController : IPartController

    {

        TPartController GetPartController(IDispatcher dispatcher);

    }

We also need to be able to ask each PartController for a typed instance of its ViewPart, so we also have the following interface:

    public interface IPartController<TViewPart> : IPartController

        where TViewPart : IViewPart

    {

        TViewPart ViewPart { get; }

    }

And then our PartController base class looks like this:

    public abstract class PartController<TViewPart> : IPartController<TViewPart> where TViewPart : IViewPart

    {

        protected PartController(TViewPart viewPart)

        {

            ViewPart = viewPart;

        }

 

        public TViewPart ViewPart { get; private set; }

        public IDispatcher Dispatcher { get; set; }

 

        public virtual void AddInitialRequests() {}

        public virtual void GetInitialResponses() {}

    }

Now, when we want to write UserControls that can work with this approach, we need to inherit from the following UserControl base class:

    public class UserControl<TPartController> : System.Web.UI.UserControl, IViewPart<TPartController>

        where TPartController : IPartController

    {

        protected TPartController Controller { get; private set; }

 

        protected UserControl()

        {

            Controller = IoC.Container.Resolve<TPartController>(new { ViewPart = this });

        }

 

        public TPartController GetPartController(IDispatcher dispatcher)

        {

            Controller.Dispatcher = dispatcher;

            return Controller;

        }

 

        public IDictionary State

        {

            get { return ViewState; }

        }

    }

When the UserControl is constructed, we retrieve an instance of the specific PartController through the IOC container, and we pass the newly created instance of our UserControl as the ViewPart dependency of the PartController.

What you’ve seen so far is all very abstract, so let’s go over a small example. Suppose we have a View (DummyPage) which contains a ViewPart (DummyPart). First, let’s create the DummyPart:

    public partial class DummyPart : UserControl<IDummyViewPartController>, IDummyViewPart

    {

    }

Our DummyPart (the ViewPart) inherits from our UserControl base class and passes the interface type of our PartController as the type parameter of the UserControl. It also implements the IDummyViewPart interface (which is empty in this simple example):

    public interface IDummyViewPart : IViewPart<IDummyViewPartController>

    {

    }

The IDummyViewPartController interface looks like this:

    public interface IDummyViewPartController : IPartController<IDummyViewPart>

    {

        void SomeSpecificOperationForTheDummyViewPart();

    }

The implementation of the DummyPartController looks like this:

    public class DummyViewPartController : PartController<IDummyViewPart>, IDummyViewPartController

    {

        public DummyViewPartController(IDummyViewPart viewPart) : base(viewPart) {}

 

        public override void AddInitialRequests()

        {

            // add some initial requests to the IDispatcher

        }

 

        public override void GetInitialResponses()

        {

            // retrieve the responses for the initial requests from the IDispatcher

        }

 

        public void SomeSpecificOperationForTheDummyViewPart()

        {

            // do something specific to the IDummyViewPart

        }

    }

So what do we have now? A reusable UserControl which has its own controller where the actual logic of the UserControl will be implemented. We can write unit tests for all of the logic that the UserControl needs to have. We can also reuse this UserControl in a Page, and do so in a manner which enables us to fake the implementation of the UserControl for the tests we’ll write for the logic in that Page.

Suppose we have a DummyPage which contains the DummyPart UserControl. Our DummyPage implements the following interface:

    public interface IDummyView : IView

    {

        IDummyViewPart DummyPart { get; }  

    }

The code of our actual DummyPage looks like this:

    public partial class DummyPage : Page<DummyController>, IDummyView

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            Controller.Load();

        }

 

        public IDummyViewPart DummyPart

        {

            get { return dummyPart; }

        }

    }

And the code of the DummyController looks like this:

    public class DummyController : Controller<IDummyView>

    {

        private IDummyViewPartController partController;

 

        public DummyController(IDummyView view) : base(view)

        {

        }

 

        public void Load()

        {

            partController = View.DummyPart.GetPartController(Dispatcher);

 

            if (!View.IsPostBack)

            {

                partController.AddInitialRequests();

                SendOurOwnRequestsAndGetTheResponses();

                partController.GetInitialResponses();

            }

        }

 

        private void SendOurOwnRequestsAndGetTheResponses()

        {

            // this method would send some requests through the IDispatcher and

            // retrieve the responses

        }

    }

In the Load method of the DummyController, we retrieve the DummyPartController and we can communicate with it. And since we’re talking to an interface type, we can easily provide a mocked IDummyPartController instance for our unit tests.

This approach makes it possible to create UserControls which you can easily write unit tests for, and you can reuse the UserControls in containing pages while remaining the flexibility to write unit tests for those containing pages without being dependent on the actual implementation of the UserControl.

Share/Save/Bookmark

Posted in ASP.NET, Test Driven Development | 3 Comments »