Wednesday, April 29, 2009

Everything I know about SSRS Reports and ReportViewer

Today, I was struggling with the ReportViewer control.

Actually, that's not entirely true. I've been struggling with it for some time.

We were wrapping the control in our own to paint parameters because the original implementation was so buggy. It would die if you tried to render it inside of a DIV that was not absolutely positioned and then if you tried any of the numerous workarounds, it would offset drop-downs and behave horribly.

The first solution I found was straightforward. There is a new control, and many of the bugs have been fixed. It's a beauty!

Grab the Microsoft Report Viewer Redistributable 2008, uninstall the old one, and get this one in as quickly as possible. You'll love it. Be sure to update your references to point to 9.0.x version instead of 8.0.x version. This can be in references, web.config, and the register assembly directives in your pages.

If you don't like the vertical scrollbar, set asnychronous rendering to false. It will postback when the user navigates, but it will also allow the control to size the page appropriately for the browser window.

Finally, if you get the quirky Microsoft JScript runtime error: 'this._postBackSettings.async' is null or not an object in your browser when using it, don't despair. Fire up the code behind for the page the control lives on, and add this code snippet to disable partial rendering in the ScriptManager:

protected void Page_Init(object sender, EventArgs e)
{
    ScriptManager sm = ScriptManager.GetCurrent(this); 
    if (sm != null)
    {
        sm.EnablePartialRendering = false;
    }
}

(It's important to do it in Init, so it can go into your control if you are wrapping the control, but then you must make sure that dynamic controls are injected in Init or you'll miss the boat).

There we go. Now you know everything that I do about report viewer.

Friday, April 24, 2009

Simplified Mocking with Dependency Injection for Unit Testing

Today I was working on a module that actually had quite a good bit of business logic wrapped up in the business tier. This business class depended on other classes that made calls to other classes, the database, so on and so forth. We are not using a dependency injection framework currently (we are very aware of it and are looking into performance and other concerns before we implement one) but we use the factory pattern. It occurred to me as I was writing my unit tests that I shouldn't have to know about a database or provider layer or even set up a single row in a single table to make sure it all worked. What I needed was some good old-fashioned mock objects to do what I wanted, and some dependency injection to stuff them into my other classes.

Many people think of dependency injection in terms of frameworks such as Unity or StructureMap, rather than as a concept that can be implemented in some cases with very little overhead.

Let's take my example from today. The names have been changed to protect the innocent.

We'll start with some simple classes. I have contact in my system:

namespace ContactProject
{
    public class ContactEntity
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Building { get; set; }
        public string Floor { get; set; }
    }
}

Some of my contacts can actually sign into the system, so they have user accounts. The simple result looks like this:

Now we have some business classes. We are good developers and we interface those to expose the appropriate services. I have one that loads the user by the username. The username in turn calls the contact business object to load the contact information. When it's all said and done, we have something else. Now I know there are many, many things wrong with this example, so please just help me get to where I'm going with the mocking and the injection. Let's pretend I have a user business class that talks to a user data handler to get a user object, and also to get a contact first name and last name if we want that. It can then talk to the contact business to get the full contact with the first name and last name. That's my example and I'm sticking to it, because my point is you will end up with objects talking to factories and instantiated other classes, etc. Let's assume this:

namespace ContactProject
{
    public class UserBusiness : IUserBusiness
    {
        public UserEntity Load(string username)
        {
            IUserDataHandler dataHandler = DataFactory.GetUserDataHandler();
            UserEntity retVal = dataHandler.Load(username); 
            if (retVal != null && !string.IsNullOrEmpty(retVal.Username))
            {
                string firstName;
                string lastName;

                if (GetContactKey(username, out firstName, out lastName))
                {
                    IContactBusiness contactBusiness = BusinessFactory.GetContactBusiness();
                    retVal.Contact = contactBusiness.Load(firstName, lastName);
                }
            }
            return retVal; 
        }

        public bool GetContactKey(string username, out string firstName, out string lastName)
        {
            // do something
            firstName = "John";
            lastName = "Doe";
            return true;
        }
    }
}

So now I have another business class that takes a document for a user and saves it to disk. Let's say we are always saving it to d:\users\ but then the path should be organized by building, level, last name, and first name. Because I want to separate my concerns, I'll have one class worry about the logic to construct the path and let another class worry about persisting it to disk. I end up with this ...

namespace ContactProject
{
    public class PathMaker
    {
        public string GetPathForUser(string username)
        {
            //did the caller honor our contract?
            if (string.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }

            IUserBusiness userBusiness = BusinessFactory.GetUserBusiness();
            UserEntity user = userBusiness.Load(username);

            if (user == null || string.IsNullOrEmpty(user.Username))
            {
                throw new Exception("User did not load.");
            }

            if (user.Contact == null)
            {
                throw new Exception("Contact information did not load.");
            }

            return string.Format(@"d:\test\{0}\{1}\{2}\{3}\",
                                 user.Contact.Building,
                                 user.Contact.Floor,
                                 user.Contact.LastName,
                                 user.Contact.FirstName);
        }
    }
}

Now I start to write my unit tests. This is when I start to get into trouble. The first issue I have is that, in order to control my results, I have to have something actually in my database. I might do something like use LINQ or SSIS to throw in a "known" user and a known contact, and then I could write a test to make sure my path is as expected. Doesn't seem quite right, does it?

So let's go back to my business class. Assume it's used all over the place and I haven't received approval to load an external framework like Unity. What do I do? First, we can refactor the class a bit so it behaves exactly as everyone expects it to, BUT allows for us to extend it a bit for testing.

namespace ContactProject
{
    public class PathMaker
    {
        private IUserBusiness _userBusiness; 

        public PathMaker()
        {
            _userBusiness = BusinessFactory.GetUserBusiness();
        }

        public PathMaker(IUserBusiness userBusiness)
        {
            _userBusiness = userBusiness; 
        }

        public string GetPathForUser(string username)
        {
            //did the caller honor our contract?
            if (string.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }

            UserEntity user = _userBusiness.Load(username);

            if (user == null || string.IsNullOrEmpty(user.Username))
            {
                throw new Exception("User did not load.");
            }

            if (user.Contact == null)
            {
                throw new Exception("Contact information did not load.");
            }

            return string.Format(@"d:\test\{0}\{1}\{2}\{3}\",
                                 user.Contact.Building,
                                 user.Contact.Floor,
                                 user.Contact.LastName,
                                 user.Contact.FirstName);
        }
    }
}

See what I've done? The factory is still called and still gives us our interface to work with, but I've added a new constructor that lets me inject my own implementation. Now we can stub out a test user business class ...

namespace ContactTestProject
{
    public class UserBusinessTest : IUserBusiness 
    {
        public UserEntity Load(string username)
        {
            return new UserEntity
                       {
                           Username = username,
                           Password = "testpassword",
                           Contact = new ContactEntity
                                         {
                                             FirstName = "John",
                                             LastName = "Doe",
                                             Building = "Administration",
                                             Floor = "B1"
                                         }
                       };
        }

        public bool GetContactKey(string username, out string firstName, out string lastName)
        {
            throw new NotImplementedException();
        }
    }
}

And then test our path ...

        [TestMethod]
        public void TestValidPath()
        {
            // we expect the path to be d:\test\Administration\B1\Doe\John\ 

            string target = @"d:\test\Administration\B1\Doe\John\";

            PathMaker pathMaker = new PathMaker(new UserBusinessTest());

            Assert.AreEqual(target,pathMaker.GetPathForUser("JohnDoe"));
        }

That got me a nice green checkbox, but there are a few things that feel really wrong about this.

First, I have a nice comment about the expected path ... but how do I know that's the expected path? It seems like my "UserBusinessTest" is a blackbox now. I have to make some assumptions about it. What if someone else decides they need a test for level B2 and changes my test object? It will break my unit test ... but that's not the point! The test is that a valid path is made given any sort of user input, and shouldn't have to depend on a static user. I could add a switch statement and return a specific user for "JohnDoe" and comment my code to say, "Don't touch this user! Make your own!" but that's hardly enforceable.

It's time to mock!

Now before we get too excited and start looking at mocking frameworks, downloading them and reading the help text ... why not start by making our own? C# is the perfect language for building these without having to drag around a huge framework. We can get there eventually, but right now we just need to test a path. We already tackled dependency injection without having to get rid of our factory pattern or lug in an "Inversion of Control Framework" ... what can we do with Mock?

Let's roll up our sleeves and get started. What I want is a business object I can inject, but that gives me flexibility to predict and change my results. This sounds like a perfect case for using delegates. I can implement my well-known interface, then extend my object to expose delegates that let my test framework inject the desired results! Let's see what this looks like:

namespace ContactProject
{
    public class UserBusinessMock : IUserBusiness 
    {
        public delegate UserEntity TestLoad(string username);

        public delegate bool TestGetContactKey(string username, out string firstName, out string lastName);

        public TestLoad OverrideLoad { get; set; }
        public TestGetContactKey OverrideGetContactKey { get; set; }

        public UserEntity Load(string username)
        {
            if (OverrideLoad != null)
            {
                return OverrideLoad(username);
            }
            throw new NotImplementedException();
        }

        public bool GetContactKey(string username, out string firstName, out string lastName)
        {
            if (OverrideGetContactKey != null)
            {
                return OverrideGetContactKey(username, out firstName, out lastName);
            }
            throw new NotImplementedException();
        }
    }
}

Obviously this class won't do much for me right now - in fact, if I try to use it, I'll get plenty of errors. Following the tenants of test-driven design (TDD) we'll go ahead and plug it in, run it, and sure enough, our test fails. That's fine, now we must refactor.

What I want to do is let my TEST control the input, so that my TEST can control the expected result. In my class, I marked delegates that match the signature of the methods on the interface. Then I exposed those delegates. First, I must update my class to use them. I'll simply delegate the "load" method to return the user I want.

[TestMethod]
public void TestValidPath()
{
    // we expect the path to be d:\test\Administration\B1\Doe\John\ 

    string target = @"d:\test\Administration\B1\Doe\John\";

    UserBusinessMock
        userBusinessMock =
            new UserBusinessMock
                {
                    OverrideLoad =
                        username =>
                        new UserEntity
                            {
                                Username = username,
                                Password = "testpassword",
                                Contact =
                                    new ContactEntity
                                        {
                                            FirstName = "John",
                                            LastName = "Doe",
                                            Building =
                                                "Administration",
                                            Floor = "B1"
                                        }
                            }
                };

    PathMaker pathMaker = new PathMaker(userBusinessMock);

    Assert.AreEqual(target, pathMaker.GetPathForUser("JohnDoe"));
}

I run my test ... and it's green! Keep in mind, too, this method will allow chaining, i.e. going as deep as you need by injecting up the chain for your tests. My business logic shouldn't care about the database, so I don't have to worry about dependencies on data handlers and factories, I just mock what I need and test what is important: the algorithm. The fetch from the database is handed off to another layer, and the unit test for that belongs there.

There it is ... and you thought delegates for just for events or callbacks! I've improved my unit tests by creating my own "mock" type class, delegates, and dependency injection ... but here's the best part. I didn't have to download anything from the web or figure out how to set up an XML configuration file just to wire in my dependencies ... nor did I have to go and refactor my production code because that all still runs "as is" blissfully ignorant of my ability to inject mocks for testing purposes.

Tuesday, April 14, 2009

Using an extension method to strongly type your navigation

After writing a very large web-based application with lots of pages, I realized that I was falling into a trap.

Magic strings were going to be the death of me!

If you are not familiar with what a "magic string" is, it is really any type of string in your application that is not strongly typed somehow. For example, if you write a paragraph like this:

...
lblParagraph.Text = "<p>This is a paragraph."; 
...

You have a lot of string magic going on! You probably would want to refactor that to have a strongly typed object that implies you are dealing with a paragraph, and then refer to the text based on its source, whether it's a constant, resource, or other way to inject the information without making it magically reside in the code.

So what is a common pattern in our web sites (this is addressed in MVC, by the way, I'm talking the old WebForms engine)?

...
Response.Redirect("~/Some/Page.aspx"); 
...

This seems fine until you end up refactoring the page or splitting it up, etc. Isn't there a better way?

My first step was to start to use constants like this:

const string NAVIGATE_SOME_PAGE = "~/Some/Page.aspx"; 
...
Response.Redirect(NAVIGATE_SOME_PAGE); 

This was a little more satisfying, until I realized that I was dotting my entire application with multiple "NAVIGATE_SOME_PAGE" references. I could have hacked it by referencing them publicly, but was that really the right way?

Fortunately, our application follows strict naming conventions including adhering to proper namespace use. We don't create a folder called "foo" and then stick an entity in that folder into namespace "bar."

So, I decided to come up with an extension method. Why an extension method? Because I couldn't think of some dummy utility class to paste then on when it really is a function of the "Page" knowing where "it" is. So I extended page, and did this:

/// <summary>
///    Contains extension methods for System.Web.UI.Page
/// </summary>
public static class PageExtensions
{
   /// <summary>
   ///     Gets the redirect url based on type
   /// </summary>
   /// <typeparam name="T">The type of the page</typeparam>
   /// <returns>The path to the page</returns>
   public static string GetRedirect<T>(this System.Web.UI.Page page) where T : BaseController
   {
       const string ROOT_NAMESPACE = "MyNamespace.Web";

       string str = typeof(T).FullName;

       // remove the prefix 
       str = str.Replace(ROOT_NAMESPACE, "~");

       // build the path
       str = str.Replace(".", "/");

       // append the suffix 
       str += ".aspx";

       return str;
    }
}

Note: this implies you inherit your pages from BaseController .. you could just as easily make it System.Web.UI.Page.

Now, when I want to redirect, I do this:

...
Response.Redirect(Page.GetRedirect<Some.Page>());
...

And the best part? If I delete the page, my compiler throws errors. If I refactor the page, all of the redirects will get refactored with it.

(I realize hacking the namespace to make a path doesn't seem the most elegant solution, but it's the best I could come up with ... I'm very open to other ideas on how to tackle this).

Jeremy Likness