Archive

Archive for the ‘LINQ’ Category

Adding Parameters to the Generic BindListControl Method

March 25, 2008 Comments off

Yesterday, I blogged about a generic method I created that could take a series of parameters and bind most any type of IEnumerable data source to most any type of DataBoundControl control.  I needed a simple and portable method (so that I could eventually toss it into the base helper library I use).

Unfortunately, the post didn’t cover something quite common—what happens when your data methods have parameters?  Integers, strings, even objects (passing a User object, etc).

For this, I’ll be modifying our “third attempt,” which, for now is, is the final version of the code.  Here’s the change. 

protected void BindDataControl

<TDataControlType, TEnumerableType, TDataSourceClass>

       (bool hasBeenModified, string sessionVariable,

              TDataControlType dataControl,

string dataSourceMethod,

              TDataSourceClass dataSourceClass,

object[] methodArguments)

where TDataControlType : DataBoundControl,

              new() where TEnumerableType : IEnumerable,

             new() where TDataSourceClass : class

{

// If session is null or has been modified

       // (thus invalidated), update the session state.

       if (Session[sessionVariable] == null || hasBeenModified)

       {

              // Invoke the specified method that

//creates our data source.

             var data = dataSourceClass.GetType().InvokeMember(

                     dataSourceMethod,

                    BindingFlags.InvokeMethod |

                    BindingFlags.NonPublic |

                    BindingFlags.Public |

                    BindingFlags.Instance,

                    null,

dataSourceClass, methodArguments);

// Add it to session.

             Session.Add(sessionVariable, data);

}

 

// Read the data from session and bind the data control.

dataControl.DataSource =

(TEnumerableType)Session[sessionVariable];

 

dataControl.DataBind();

}

Pay close attention to the new methodArguments object array.  I’ve bolded them in the code above.  The InvokeMember reflection method allows for arguments to be passed, so I simply opened that up to the calling method.

To use this, here’s an example that takes the Page.User property and passes it to a LINQ data context method:

BindDataControl<ListView, List<Gallery>, WebGalleryDataContext>

(true,

       “GalleryList”,

       GalleriesList,

       “GetGalleriesByRole”,

       db,

       new [] { Page.User });

or, pulling from the QueryString:

BindDataControl<ListView, List<WebFile>, WebGalleryDataContext>

(true,

       “CurrentGallery”,

       lv,

       “GetWebFilesByGalleryName”,

       db,

new [] {Request.QueryString[“id”]});

and passing multiple arguments with different base types:

BindDataControl

<ListView, List<IGrouping<Gallery, WebFile>>,

WebGalleryDataContext>

       (true,

       “ChangesSinceLastVisit”,

       listViewTest,

       “GetAllSinceLastVisit”,

       db,

       new object[]

{Convert.ToDateTime(Session[“LastLoginDate”]),

Page.User});

Cool.

Using Generics to Update DataBoundControls – A Prototype

March 24, 2008 1 comment

NOTE: This is a prototype, an idea, a random thought expressed aloud (well, in type).  The code explains a concept and isn’t “tested” or production worthy (in my opinion). 

Feedback is always appreciated. :)  This is also what happens when I have a week off work and come back with ‘ideas.’

I find that a few of my projects, like the WebGallery2, all have a similar functionality.  On pages with GridViews, ListViews (which, I’m slowly replacing all my GridViews with), or other DataBoundControls, I follow a common theme for data binding:

If the data set will be cached or in session, is that session/cache null OR has the data set been explicitly modified?

  1. true – regenerate the data set and repopulate session/cache.
  2. false – read the current data set from session/cache to the control.

In a single instance, the code to do this might look like:

private void BindList(bool hasBeenModified, string sessionVariable)

{

       // If our session variable is null or the data has

// been explicitly modified, then rebuild the session variable.

if (Session[sessionVariable] == null || hasBeenModified)

              Session[sessionVariable] =

db.GetWebFilesByGalleryName(this.Id);

 

resultsListView.DataSource =

Session[sessionVariable] as List<WebFile>;

 

resultsListView.DataBind();

}

This would then be called with:

BindList(true, “CurrentGallery”);

However, this code really bothers me. 

The data source (the db.GetWebFilesByGalleryName method), data bound control (the resultsListView), and the type of the data source (List<WebFile>) are all hard coded.

How could this helper method use generics to add a bit of resuability?  What about when I want to use a GridView instead of a ListView, or have a List<Gallery>, List<String>, string[] of information?

First Attempt

The first attempt works.  It takes the generics as anticipated and is rather easy to use.

protected void BindDataControl<TDataControlType, TEnumerableType>

(bool hasBeenModified, string sessionVariable,

              TDataControlType dataControl, TEnumerableType dataSource)

where TDataControlType : DataBoundControl,

              new() where TEnumerableType : IEnumerable

{

// Add the dataSource to session.

       if (Session[sessionVariable] == null || hasBeenModified)

              Session.Add(sessionVariable, dataSource);

 

// Read the data from session and bind the data control.

       dataControl.DataSource =

(TEnumerableType)Session[sessionVariable];

       dataControl.DataBind();

}

The constructor here has both generic parameters and standard parameters.

  • TDataControlType has a generic constraint that requires it to be part of or a subclass of DataBoundControl (GridView, ListView, etc).
  • TEnumerableType requires the source to inherit from IEnumerable (List, Array, etc).

Here are a few examples of using it this bit of code:

var gv = new GridView();

this.Page.Controls.Add(gv);

BindDataControl<GridView, Array>(

true,   // this is new, so build a session variable.

       “test”, // the session variable

       gv,     // the Id of our GridView

       new[]   // The data source, an array.

              { “hello”, “world” });

When rendered, we have a simple GridView with our two data items.

GridView and Array data source.

What about a more complicated example using collections and a ListView? On the current build of the WebStorage2 project, the galleries are built in a similar method (see this post for more details).  I could just as easily replace the logic in Show.aspx’s Page_PreRender with:

BindDataControl<ListView, List<WebFile>>(

true,

       “CurrentGallery”,

       lv,

       db.GetWebFilesByGalleryName(Request.QueryString[“id”]));

So what’s the downfall to this method? 

Downfall #1: It’s a performance nightmare. AFAIK, when passing a method (which GetWebFilesByGalleryName is a method from my LINQ DataContext), it is evaluated immediately.  So, with that in mind, the hasBeenModified is irrelevant—it may not NEED to update the session, but the method will still go out, search the database, and return the results.  That’s a bad deal.

What I don’t know and am not sure how to check is whether or not the lazy/delayed loading in LINQ would balance out this at all.  Ideas?

Second Attempt

The second attempt adds in a bit more “generic” and a lot more reflective.  By adding a reference to System.Reflection, we can simply pass a string reference to a “builder” method rather than the method it self—thus saving the prefabrication of the data source when it’s not really needed.

protected void BindDataControl<TDataControlType, TEnumerableType>

(bool hasBeenModified,

              string sessionVariable,

             TDataControlType dataControl,

             string dataSourceMethod)

where TDataControlType : DataBoundControl,

              new() where TEnumerableType : IEnumerable

{

// If session is null or has been modified (thus invalidated),

       // update the session state.

       if (Session[sessionVariable] == null || hasBeenModified)

       {

              // Invoke the specified method that

// creates our data source.

             var data = Page.GetType().InvokeMember(

dataSourceMethod,.

BindingFlags.InvokeMethod |

                    BindingFlags.NonPublic |

                    BindingFlags.Instance,

                    null, this, null);

 

// Add it to session.

             Session.Add(sessionVariable, data);

}

 

// Read the data from session and bind the data control.

       dataControl.DataSource =

(TEnumerableType)Session[sessionVariable];

      

dataControl.DataBind();

}

In this method, the Page.GetType().InvokeMember method iterates through the methods on the page, finds the one that matches the string name passed to it, and executes it. 

Then, with our “data” results, the rest is the same as the previous method.

Unfortunately, I cannot pass the LINQ direct lookup anymore because the scope of InvokeMember is limited to the calling page.  I’ll need to create another little method, called GetResults in this case, to do the query for me.

protected List<WebFile> GetResults()

{

return db.GetWebFilesByGalleryName(Request.QueryString[“id”]);

}

And the updated BindDataControl method:

BindDataControl<ListView, List<WebFile>>(
  false,
  “CurrentGallery”,
  lv,
  “GetResults”);

Now, since our constructor does not contain the method to fetch our data, simply a string, the results are not refetched each time the method is called—only when the requirements are met further in the code.

Downfall #1: This method requires an additional “helper” method on every page to fetch the data.  You can’t access methods outside of the page—or can you?

Downfall #2: What happens if you need to pass parameters to your InvokeMember?  You CAN, but the syntax is nasty and becomes even more difficult if the parameters are not always in the same order (which doubtfully they would be if you’re using generics).

Third Attempt

The third attempt looks more like the signature from Hell than a real method.  There had to be a way around the “stuck on this page” snafu with the second attempt… and there was, by specifying the class too using a generic.

protected void BindDataControl

<TDataControlType, TEnumerableType, TDataSourceClass>

(bool hasBeenModified, string sessionVariable,

              TDataControlType dataControl,

string dataSourceMethod,

TDataSourceClass dataSourceClass)

where TDataControlType : DataBoundControl,

              new() where TEnumerableType : IEnumerable,

             new() where TDataSourceClass : class

{

// If session is null or has been modified

// (thus invalidated), update the session state.

       if (Session[sessionVariable] == null || hasBeenModified)

       {

              // Invoke the specified method that

// creates our data source.

             var data = dataSourceClass.GetType().InvokeMember(

dataSourceMethod,

                     BindingFlags.InvokeMethod |

                    BindingFlags.NonPublic |

                    BindingFlags.Public |

                    BindingFlags.Instance,

                    null, dataSourceClass, null);

 

// Add it to session.

Session.Add(sessionVariable, data);

}

 

// Read the data from session and bind the data control.

dataControl.DataSource =  

(TEnumerableType)Session[sessionVariable];

 

dataControl.DataBind();

}

Good grief. 

This method adds a third generic to the constructor—TDataSourceClass—as well as the additional constraint requirement.  I’ve also added an additional BindingFlag—Public—since most of the methods in LINQ DataContext classes are decorated public.

Rather than pulling from this.Page, we’re now calling InvokeMember from the parameter class and returning the results to the calling page.  There’s one other change—rather than looking at “this” as the Binder parameter, we’re referencing the class passed along in the constructor—the dataSourceClass.

BindDataControl<ListView, List<WebFile>, WebGalleryDataContext>(
    true,
    “CurrentGallery”,
    lv,
    “GetWebFiles”,
    db);

Here we have two additional parameters, the generic parameter, TDataSourceClass, that I’ve passed the LINQ Data Context into to define the Type of the dataSourceClass parameter passed later in the constructor. 

“Verbalized”, the method’s generics read: BindDataControl to a ListView with the expected data format of a List<WebFile> using the WebGalleryDataContext class. 

The parameters (which could be reordered to make better sense) read: the data is new or has changed, so store the results in “CurrentGallery” and return them to ‘lv’ (the ListView object on the web form).  Fetch the data with GetWebFiles from the instance of db (the WebGalleryDataContext object instanciated previously in the page).

Downfall #1: Methods are still required—you cannot pass a simple data source to the BindDataControl method.

Downfall #2: Additional coding on the BindDataControl methods required to handle parameters.

This third attempt handles our most complex request—but what about the original “hello”/”world” array request?  It can be done, but, as previously mentioned, requires extracting the array list outside of the method constructor.

 

protected void Page_Load(object sender, EventArgs e)

{

var gv = new GridView();

       this.Page.Controls.Add(gv);

 

BindDataControl<GridView, ArrayList, Page>(

true, “junk”, gv, “Get”, this.Page);    

}

 

protected ArrayList Get()

{

return new ArrayList {“hello”, “world”};

}

To reference methods that exist in the same code-behind page, this.Page and the Page class offer the correct class access.

So, is this the best way to do it?  Probably not!  How would you tidy this up or rewrite it?  I’m interested!

Exploring the ASP.NET MVC Preview 2 – Tests and Mocks

March 21, 2008 Comments off

The changes made around testing and mocking are a big step in the right direction from Preview 1. 

Mocking Controller Tests

In Preview 1, it was more common to create subclass testers for each Controller object—a very time consuming tasks.  Mocks “worked”—but, honest, just acted a bit odd.  Our ViewEngine still requires faking out, but Moq helps us along with the rest.

To start off, we’ll “Moq” up a Contact view and get the test to fail, then fix it (aka: implement it) to pass the test.

[TestMethod]

public void Contact_ReturnsContactView()

{

// Create a Moq instance of our HomeController.

       var controller = new Mock<HomeController>();

 

       // Create an instance of our FakeViewEngine.

       // There has got to be a way to do this without

       // ‘faking’ it. :(

var fakeViewEngine = new ViewHelper.FakeViewEngine();

 

       // Set the ViewEngine of our mock object to the fakeViewEngine.

       controller.Object.ViewEngine = fakeViewEngine;

 

       // Using the extension method from the MvcMockHelpers class,

       // set the controller context.

       controller.Object.SetFakeControllerContext();

 

       // Invoke the “Index” method.

       controller.Object.Contact();

 

       // Assert that Index() actually returned a view named Index.

       Assert.AreEqual(

              “Contact”,

             fakeViewEngine.ViewContext.ViewName);

}

This is part of the unit testing I still don’t like—that FakeViewEngine class.  The class consists of a ViewContext and get/set properties because, by default, IViewEngine can only RenderData()—it doesn’t allow direct access to the ViewContext. 

I suppose you could override IViewEngine and implement your own—but, for testability, is there harm in exposing those as read-only?

At this point, our Contact() method call is invalid (as it doesn’t exist in the HomeController class.

For now, so our test will run, we’ll add in an empty method to the HomeController class.

public void Contact()

{

           

}

Now, we can run the test.  As expected, it fails because the object (the ViewPage) doesn’t exist yet.

Test method Contact_ReturnsContactView threw exception:  System.NullReferenceException: Object reference not set to an instance of an object..

Now, to set off to resolve the error. 

Note: The templates are very precise.  This is a content page (linked to a master page) and a view page rendering the view of a MVC controller.  Be sure to pick the right item template for your task.

In our Views > Home directory, we need to add a new MVC View Content Page item named Contact.

After the View page itself has been added, implement the RenderView method in the HomeController class by modifying the empty method added earlier.

public void Contact()

{

RenderView(“Contact”);      

}

Now, rerun our test!

Testing Routes

There isn’t any mocking (yet) in our Route tests; however, we do use some of the helper methods Scott Hanselman wrote about and that I prepackaged up (see First Glance post for downloads).  I’ve created two quick and simple tests:

  • Does RegisterRoutes work successfully register routes to the RouteTable?
  • Does the Default.aspx mapping work at the root?

Before we get started, the tests require a simple TestInitialize (or SetUp, depending on your testing tool) to initialize the RouteCollection object.

private RouteCollection routes;

 

[TestInitialize()]

public void TestInitialize()

{

routes = new RouteCollection();

}

RegisterRoutes()

Our RegisterRoutes test method is extremely easy:

[TestMethod]

public void RoutesRegistered()

{

Assert.IsTrue(routes.Count == 0);

RouteManager.RegisterRoutes(routes);

Assert.IsTrue(routes.Count > 0);

}

Simply initialized, our RouteCollection should be empty (Count == 0) and, after RegisterRoutes is called, should be populated with routes.  Easy enough and ensures that our RegisterRoutes method is doing it’s job.

ContactRoot_MapsToHomeView()

To test our routes, we must do two things: register our route and then fake the navigation to a specific URL—in this example, “~/Contact.aspx”.   This is really useful during transitions from other frameworks to MVC—especially if you have preprinted letterhead, business cards, etc. with a specific URL on it. :)

To bypass the default “controller/action/id” logic of the MVC framework, we can specify exact names, paths, etc. 

First, let’s build our test.

[TestMethod]

public void ContactRoot_MapsToHomeView()

{

RouteManager.RegisterRoutes(routes);

RouteData routeData =

              routes.GetRouteData(

MockHelper.FakeHttpContext(“~/Contact.aspx”));

           

// Check to see if a route exists for the specified URL.

Assert.IsNotNull(routeData);

      

// Check to see that the controller matches our expectation.

Assert.AreEqual(“Home”, routeData.Values[“Controller”]);

 

// Check to see that the action matches our expectation.

Assert.AreEqual(“Contact”, routeData.Values[“Action”]);

}

This test checks three things to pass:

  • does the URL specified exist in the route data (is there a valid route?),
  • does it call the anticipated controller,
  • and does it call the anticipated action?

All three are required to pass as a “valid route”.

When we try to run the test, the first to fail is our Assert.IsNotNull—a route does not exist for our Default.aspx page.  So let’s add a route to get this test to pass.

routes.Add(new Route(“Contact.aspx”, defaultRouteHandler)

{

Defaults =

              new RouteValueDictionary(

                     new

                    {

controller = “Home”,

action = “Contact”,

id = “”

}),

});

Success!

Working with tests for both Controllers and Routes is quite a bit easier now—both due to continued improvement to the MVC framework and the work in the community with helper and extension methods.

For more details on MVC Testing, check out Scott Hanselman’s great webcast on asp.net.

Edit: Don’t bother with the asp.net web site with IE 8–-it’s totally borked up and, even worse, Silverlight won’t load properly in FireFox 2 (it’s an invalid browser).  Break out IE7 for this venture.

Exploring the ASP.NET MVC Preview 2 – First Glance

March 21, 2008 1 comment

Download(s): MvcMockHelpers rev. 3

Better late than never, I suppose.  Between my home computer going on the fritz and the BEAUTIFUL weather making me want to just sit outside, this article has taken me nearly three days. 

A few months ago, I wrote a series of articles evaluating Preview 1 of the MVC Framework with rave results.  After working with Java for a while, I was thrilled to see MVC patterns hit .NET WITHOUT the sometimes painful manual implementations that I had been using to-date. 

Preview 2 builds on a few of those expectations, fixes some bugs, addresses a bit of testability, and, generally, just works. 

Starting Off

After installing Preview 2, you’ll notice that the project templates have changed around a bit.  Thankfully, they’ve separated out the MVC Web Application and MVC Test templates into their correct project types classifications.  What’s even better?  When adding a MVC Web Application, it now PROMPTS you to build in your tests.

MVC Preview 2 - Unit Test Selector

ImportantImportant: I’d like to point out that the “Create Test Project” dialog only shows up when you are initially adding the ASP.NET MVC Web Application.  If you choose “No, do not generate a unit test project” and later try to add a new MVC Test Project, you will not have the option to select the testing framework.  I truly hope this changes in future builds. :)

Another great feature is that the ‘Test Framework’ is fully configurable.  The folks at MbUnit have already built a preinstaller package to integrate with the MVC Framework.  You can read about it here.  If you use NUnit, XUnit, or another testing framework or you wish to build your own, customized testing framework, Joe Cartano has a great walkthrough on creating the project template packages.

MVCPreview2 SolutionFor these examples, I’ll use the Microsoft VSTS Testing Framework (built into VS2008, easy, simple, and integrated) and Moq (Scott Hanselman has a great post with some Moq Helpers on it—the Moq helpers will need a bit of tweaking due to casing, but work very well!).  I’ve taken the helpers that Scott (and community) have put together and tied them into a MvcMockHelpers library for my own usage.  If you’d like the source code and the libraries, you can download them here.  The current library includes Moq and RhinoMocks.

I’d like to point out that I’m not an expert with Moq by any stretch of the imagination—I’m sure there are better, faster, more Moq’able ways of doing the Unit Testing… :)  Feel free to comment and let me know. ;)  I like the framework and would appreciate any tips and tricks.

Out of the box, we have a nice framework of our MVC web and testing projects.  I’ll use good, old reliable Northwind for this example (recent examples have used my Photo Gallery as a data prototype, this is a nice change).

“First Glance”

At first glance, the MVC package and solution templates look much the same.  Index and About are still prefab’d and based on a single Site.Master page.  Routes are still, by default, managed in Global.asax.

So, what’s different at 10,000’?  Here’s a brief list and some descriptive information from the gurus.

  • Separation of Routing from the MVC Framework itself.  Phil Haack explains the separation details here.
  • Controller actions no longer require the redundant ControllerAction attribute. Brilliant.
  • The ‘MVCToolkit’ that Rob Conery had developed is now integrated into System.Web.Mvc as HtmlHelper.
  • Views are generated with code-behind pages now (no longer requiring you to right-click > Convert to Web Application on each that has code-behind coding).

There are a few things that still, in my opinion, should be worked on.

  • Extracting the routing from Global.asax as a practice and placing them in an external “RouteManager” class that is either prefab’d from the template.  I’m not sure why, but having a few hundred lines in Global.asax bugs me.
  • Mocking, as we’ll see in the next posts, still requires faking out some objects, like the Views.

In upcoming posts, I’ll dig into changes in testing, routing, and a bit into using the new HtmlHelpers for generating clean, XHTML compliant code.

From the Forums – Casting XML Elements in LINQ-to-XML

March 13, 2008 3 comments

There was a post earlier today on the Microsoft asp.net forums of a user receiving a common error in LINQ-to-XML:

“At least one object must implement IComparable”

The LINQ query they were using was correct, except missing a very important bit of casting:

var allPersonsInOrderOfAge =
   from person in myXml.Descendants(“person”)
   orderby person.Element(“age”)
   select person;

We know that using the ‘where’ clause requires explicit casting when comparing against XML elements. 

However, the ‘orderby’ clause works the same way—if the compiler unsure of the type, it can’t compare them and thus cannot order them.  The error message thrown is correct at the compiler level, but totally useless to a developer.

To fix this, simply cast (bolded and larger below):

var allPersonsInOrderOfAge =

from person in myXml.Descendants(“person”)

       where (int)person.Element(“age”) >= 32

       orderby (int)person.Element(“age”) descending

       select person;

Or, for those interested, the Lambda expression version:

var allPersonsInOrderOfAgeLambda =

myXml.Descendants(“person”)

             .Where(x => (int)x.Element(“age”) >= 32)

             .OrderByDescending(x => (int)x.Element(“age”));

Now that the LINQ compiler knows that age is an integer, it can order it accordingly.

 

WebGallery 2.0 #5 – CSS Friendly and W3C Compliant

In the fifth, and final, segment on the WebGallery 2.0 project, I wanted to touch on the CSS Friendly Adapters and work that went into creating a fully W3C compliant project.

In previous posts, we’ve discussed:

#1 – Introduction
#2 – HttpHandler and LINQ Data Model
#3 – Building the Galleries
#4 – Adding Admin Tools

NOTE: Code downloads are available on the Introduction post.

Read more…

WebGallery 2.0 – #4 – Adding Admin Tools

February 25, 2008 12 comments

So far, we’ve discussed:

  1. Creating the basic data model for the WebGallery.
  2. Changes to the HttpHandler to increase speed and efficiency.
  3. Building and viewing the individual galleries–created using clean, simple HTML code.

Our galleries are now visible; however, we need a few administration tools to handle changes, such as updating the title and description or fixing a broken thumbnail (since they’re pre-generated now). 

#1 – Introduction
#2 – HttpHandler and LINQ Data Model
#3 – Building the Galleries

NOTE: Code downloads are available on the Introduction post.

This post will cover the topic of using the ModalPopupExtender to manage files once their added into the galleries.

Read more…

Follow

Get every new post delivered to your Inbox.