Try-Catch-FAIL

Failure is inevitable.

MLSharp 1.0 Alpha Released

clock February 7, 2010 05:41 by author Matt

I’ve finally written a little bit of documentation on MLSharp, fixed a few bugs/glitches, and packaged it all up into the first official release.  I consider the software Alpha quality (meaning it has known bugs, limitations, may set fire to your house, etc), but I have used it in several projects successfully.  Please give it a look, and let me know if you find it useful. 

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


A Newbie’s Experiences with NDepend

clock February 4, 2010 11:10 by author Matt

Disclaimer: Yes, I was given a pro license to NDepend.  However, what follows are my honest impressions of version 2.12.1 of the tool on a real .NET 3.5 project.  I have not evaluated the recent beta, so some of the issues noted below may be fixed in a more recent build. 

To Patrick Smacchia: I apologize for taking so long to provide feedback on NDepend.  I hope you find the feedback below useful.  Thanks for giving me the chance to check out this cool tool!

NDependHome

NDepend is a complex and powerful tool for static code analysis.  The basic idea is that you feed it your .NET assemblies, then you use the rich set of visualizations, Code Query Language (CQL) reports, and code coverage tools to analyze your codebase.  When I say “rich set of visualizations,” I mean it.  There are a slew of reports that are both eye-candy and useful at the same time.  Within a few minutes of analyzing my first project, I had already discovered useful information, including an obsolete class as well as a unit test that was missing it’s Test attribute. 

The power NDepend comes at a cost.  The interface is immediately overwhelming, and though there is ample documentation available online, it still takes a while to discover all the tool’s capabilities.  It also has a few quirks that can be irritating, and the UI feels a bit “glitchy” at times.  Despite these weaknesses, I found the tool to be immensely powerful (CQL is awesome), and I can definitely see where it will be handy in the future.  Read on if you want to know more.

Getting Started

When I launched NDepend, I notice that it looked and felt a lot like Visual Studio.  It had the familiar “Recent Projects” pane on the left as well as links to common actions.  There was a “Getting Started” pane with links to NDepend screencasts, and a button to install Visual Studio and Reflector integration.  It also had a pane that to let you know if an update is available, a small but nice touch.  I really like it when an application makes it easy for me to stay up to date.

Creating a new project was easy enough.  After creating my project, I was able to add assemblies using any of several methods.  I could drag-and-drop assemblies directly from Windows Explorer, I could add them manually by browsing, or (my favorite) I could add them by specifying a Visual Studio solution file.

Things took a turn for the strange here.  At first, NDepend reported that it was unable to load any of the assemblies for my solution.  It was nice enough to indicate why, apparently there were multiple versions of the assemblies buried in my solution.  After some digging, I discovered that I had built my solution under the AnyCpu platform a loooooooong time ago.  I had since switched to targeting the x86 platform, so I had some obsolete build output nested under my projects.  This same “error” occurred even when trying to load the assemblies manually; apparently NDepend was still detecting assemblies with the same name but different versions.  Once I figured it out, resolving the issue was easy: I just removed the obsolete output directories.  It would be nice if NDepend was a little smarter about loading assemblies, but at least it has good error messages.   

Even after resolving the version conflicts, I had trouble getting NDepend to load the console application from my solution.  I had to manually drag-and-drop the exe into the assembly list, at which point it recognized it just fine.

The “Getting Started” experience is flexible and intuitive, but there are enough issues to make the process mildly frustrating for a first time user. 

The Analysis

Running an analysis was surprisingly fast.  Granted, I’m on a hefty workstation, but it still seemed blazingly fast considering what it was doing.  The analysis generated an HTML report that included metrics, visualizations, graphs, tables, and the results of numerous CQL queries. 

The HTML report is great for sharing the output of NDepend or for reviewing the analysis offline, but the NDepend tool itself enables you to interactively analyze your application.  Be warned, though, that the default view can be overwhelming at first:

AnalysisHome

Even with high resolution monitors and the window maximized, this view is probably not going to be all that useful.  Instead, you will likely find one of the configured alternative views more useful, such as the Dependency Matrix view:

DependencyMatrix

I still found this view to be too cluttered, but like Visual Studio, NDepend’s UI is very customizable.  However, unlike Visual Studio, it took a lot of trial and error to get things laid out the way I liked.  The docking behavior seemed much more finicky than Visual Studio, and on multiple occasions attempting to pin/unpin an item would cause the layout to shift in unexpected ways.  Even resizing the window caused strange behaviors at times.  Still, after some massaging, I arrived at a less overwhelming layout:

SimplifiedView

One feature I’d like to see in NDepend is a “Save Custom View” command, that way I can save and restore my preferred layout for use in the future.  Why is this feature important?  Because it took me all of about 5 minutes to screw something up after getting my view the way I liked it, requiring me to “Reset Views” back to the default. :(

Overall, in my opinion the UI itself is the weakest area of NDepend.  Yes, it’s functional, but there are some very noticeable usability problems here.  I’m sure it is quite challenge to develop and maintain a UI that exposes all the capabilities of NDepend, but I think some additional work is warranted here.

Visualizations

While the UI might need some work, it doesn’t detract (too much) from what NDepend actually does really well, and that’s analyze your code base.  The “Metrics” visualization gives you a map of sorts depicting your project by whatever metric you are interested in.  Want to see your types by number of instructions?

TypeByInstructions

How about your methods by lines of code?

MethodByLinesOfCode

Or by cyclomatic complexity?

MethodByComplexity

I can also generate a nice map of my project dependencies (again, I can customize the visualization to emphasize different metrics):

DependencyGraph

These visualizations make it very easy to find areas of your project that warrant attention by simply glancing at the graphics.  Unfortunately, the usability elephant raises his head here.  A few things stick out worse than others.  First, the behavior of the “Export to PNG” button is consistently inconsistent between the visualizations.  On one view, the button brings up a dialog to save a snapshot to the file of your choosing.  On another, it instantly exports the file and loads it up in Windows Media Viewer.  I also had to make frequent use of the “Fit to Window” command on the Metrics visualization because I would accidentally click on the visualization, causing it to scroll unintentionally.  These aren’t things that are going to turn someone off of using the tool, but they are still problems that should be addressed. 

The rich visualizations make it easy to spot areas of your code base that need attention.  While there are some usability problems here, they’re pretty minor and easy to overlook.

Code Query Language

The final piece that I want to talk about is CQL and the library of built-in constraints and checks that ship with NDepend.  According to the website, there are 83 metrics available in CQL, and NDepend ships with queries to help you find potentially problematic areas quickly: 

CqlReports

As you can see, this particular project has quite a few issues I might want to look into further. :)  A cool feature of the CQL queries pane is that selecting one will update the “Metrics” visualization, with types matching the query highlighting blue as in the following screenshot:

CqlMetrics

This lets you quickly assess how wide-spread an issue is in your codebase.  For details, you can use the CQL Query results window.  Double-clicking an item in the results will open the corresponding location in your source code, so it’s very quick and easy to drill down from a CQL query to the underlying code.

One thing to note: many of the constraints that I checked were actually configured only to return the top 10 methods/types/whatever, so a constraint with a “10” next to it usually means “at least 10”. Keep that in mind as you are glancing through the constraints. 

NDepend does seem to count properties as methods.  While technically true (even auto properties are implemented as a pair of methods that access an automagically generated field), this can lead to unexpectedly high values for metrics such as “lack of cohesion” on types that expose many properties (such as view models in an ASP.NET MVC application). 

There were a few things that I couldn’t figure out how to do (yet).  For example, I wanted to build a CQL query to find all public methods that were part of a class marked with the NUnit TestFixture attribute who didn’t have a Test attribute applied to them.  I suspect that there is a way to express this query, it just requires someone better with CQL than I am. :)

The built-in CQL queries can help you find trouble areas in your code base as well as determine how systemic a problem is.  The syntax is clean and SQL-like.  There are a few things that are difficult (at least for a novice) to express using the language, but the built-in queries are likely to cover 90% of what you would want to look at anyway.

Things I haven’t tried yet…

My review focused on the visual version of NDepend.  NDepend also has a command-line version, an MSBuild task, and a NAnt task.  There’s also an XLST transform for using NDepend output with CruiseControl.NET.  Since NDepend generates a nice HTML report, it can easily be integrated into other CI servers as well, such as TeamCity.

NDepend also has Visual Studio and Reflector integration.  While I use both tools, I did not (yet) test out the integration. 

Overall

NDepend is a very deep tool with a lot of functionality.  I feel like I’ve just scratched the surface.  You will probably be hearing more about NDepend in the future as I continue to dig deeper into its capabilities. 

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


The trials and tribulations of using MSDeploy with PowerShell

clock February 1, 2010 09:21 by author Matt

I can sum my experience with trying to use MSDeploy and Powershell together with a single word: hell.  MSDeploy.exe does not play nicely with PowerShell, but thanks to some help from James and a lot of trial-and-error, I’ve got it sort-of working now.  Here’s a tail of my journey.  Hopefully you, brave reader, will learn from my mistakes.  THAR BE DRAGONS HERE.

It began with the automation of deployments

This journey started from a desire to automate our deployment processes.  We have three different software applications that we host under a SaaS model, and only one of those has a deployment that even remotely qualifies as semi-automated.  Making deployment less painful typically leads to more frequent deployments and happier developers, so I set out to automate things.  I have previously used MSBuild and PowerShell to automate things, but that was several years ago, and the tools have changed.  Today, we have a new tool to help with deploying web applications: the Microsoft Web Deployment Tool, or MSDeploy. FTA:

The Web Deployment Tool simplifies the migration, management and deployment of IIS Web servers, Web applications and Web sites.

Basically, MSDeploy gives us some great functionality for remote deployments.  With it, I can deploy files, execute commands remotely, run SQL scripts, etc.  On paper, this seemed like a great tool.  Using it, I should be able to deploy applications without having to log on to the target servers at all

So, with MSDeploy installed and ready, I decided I would use PowerShell to drive things instead of MSBuild or batch scripting.  After all, PowerShell is the future of the Windows Shell. And MSDeploy is new hawtness.  So the two will surely play nice together, right?  Right?

You seek the 2.0 shell?

Before starting, I decided I would install PowerShell 2.0.  It was required for one of the tools I was using (which I’ll cover in a future post).  I was running Vista with PowerShell 1.0 installed.  So I hit up Google to find the 2.0 release:

PowerShellGoogle

Hmm, none of the top results looked like a download page for the final version.  I didn’t want a CTP, I wanted the final version.  Bing was not much better:

PowerShellBing

Bing returned a blog post indicating that the RTW version shipped, but no link in the first few results (yes, I am one of those searchers who only scans the first few hits before abandoning my query and trying a different one).  I finally found the PowerShell portal on TechNet, which did include a link to download PowerShell 2.0.  PS2 is part of the Windows Management Framework, which is intuitively* disguised as KB968929. Suggestion to Microsoft: how about making it a little less difficult to find PowerShell?

*SarcasmLevel = int.MaxValue;

There can be no alliance between PS and MSDeploy

Despite the initial frustration of finding and installing the latest PowerShell, I had high hopes that things were going to go smoother now.  I had numerous examples of how to use MSDeploy.exe from the command-line, and the documentation actually seemed pretty solid.  You can imagine my surprise when I tried running a simple example and was greeted by the following:

powershellFail

Note: The comments are mine, not MSDeploy output.  There is no MSDeploy output.  Nothing.  At all.  Until I forcibly end msdeploy, I can type whatever I want, and it just sits there quietly.

I’m not a PowerShell guru, but I don’t think that is normal behavior.  I found a handful of blog and message forum posts scattered across the web reporting similar behavior when using MSDeploy with PowerShell.  After reading the IIS blog, I started to suspect that using MSDeploy with PowerShell, at least through the command line, was actually not supportedThis really dashed my hopes:

And let us know if you want to use Web Deploy with PowerShell, we're interested in hearing about what tasks you'd like to accomplish and why!

I bet the use cases for MSDeploy with PowerShell are the same as using MSDeploy from the old CMD shell.  I’m really surprised that PowerShell is apparently not fully supported right out of the box.  I think Microsoft did realize that people might want to use the tools together. Why else would they have had PowerShell cmdlets in the early preview releases?  Unfortunately, these cmdlets were removed from the final version (see the last comment).

More digging around led me to some actual working examples of using MSDeploy with PowerShell, but it seemed a lot less elegant than running msdeploy.exe. 

An old friend comes to the rescue!

Despite this setback, I wasn’t ready to give up yet.  My initial solution was to wrap msdeploy.exe in a (very) simple batch script that I could invoke from PowerShell, but James gave me a better solution: invoke msdeploy.exe through cmd.exe directly!  I created a function to wrap the invocation, like so:

function PushToTarget([string]$server, [string]$remotePath, [string]$localPath) {
    cmd.exe /C $("msdeploy.exe -verb:sync -source:contentPath=`"{0}`" -dest:computerName=`"{1}`",contentPath=`"{2}`" -whatif" -f $localPath, $server, $remotePath )
}

Now I can use MSDeploy to sync files to my production servers.  In a future post, I’ll show you how capability fits in to our larger deployment process.

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Using liteGrid with ASP.NET MVC, Part 2 – The LiteGridUpdater

clock January 28, 2010 10:54 by author Matt

Part 1 – The LiteGridJsonResult

In the last post, I showed how we use a custom JsonResult to send data to liteGrid.  Displaying data is great and all, but liteGrid supports client-side editing as well.  With the BatchSaveModule, liteGrid will batch up all the client-side changes and send them to the server in one big lump.  We need an easy, reusable way to process and apply those changes server-side.  Thankfully we now have the LiteGridUpdater class:

public abstract class LiteGridUpdater<TModel, TTarget> 
    where TModel : ILiteGridUpdateModel<TTarget> 
    where TTarget : class, new()
{
    /// <summary>
    /// Applies updates from the view models.
    /// </summary>
    /// <param name="models">The models containing changes.</param>
    /// <returns>The view models that were applied to the targets.  IDs for new entities
    /// will be synchronized to the real objects.</returns>
    public TModel[] ApplyUpdates(TModel[] models)
    {
        ...
    }

    /// <summary>
    /// Moves the object to a new parent.
    /// </summary>
    /// <param name="model"></param>
    protected virtual void MoveToNewParent(TModel model)
    {
        throw new NotImplementedException("Moving items to a new parent is not supported.");
    }

    /// <summary>
    /// Derived classes can implement this if they want to support
    /// adding new items from liteGrid.  Implementors must perform
    /// three actions: create a new TTarget; apply the updates
    /// from model to the new TTarget; synchronize the ID of the
    /// new TTarget with the model.
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    protected virtual TTarget CreateAndUpdate(TModel model)
    {
        throw new NotImplementedException("Adding new items is not supported.");
    }

    /// <summary>
    /// Derived classes can implement this if they want to support deletes.
    /// If implemented, this should delete the specified target.
    /// </summary>
    /// <param name="model">The view model.</param>
    /// <param name="target">The object that should be deleted.</param>
    protected virtual void DoDelete(TModel model, TTarget target)
    {
        throw new NotImplementedException("Deleting items is not supported.");
    }

    /// <summary>
    /// Called before a model is updated.  You can transform the 
    /// model by overriding this method.
    /// </summary>
    /// <param name="model"></param>
    protected virtual void BeforeUpdateModel(TModel model)
    {
    }

    /// <summary>
    /// Implemented by derived classes, used to find the specific object
    /// that should be updated. 
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    protected abstract TTarget GetTarget(TModel model);
}

This generic abstract class will take the data from liteGrid in the form of view models and apply the changes to your “backend” data types.  There are only two restrictions.  First, the view model must implement the ILiteGridUpdateModel interface (shown below), and the backend type must have a parameterless constructor. 

The LiteGridUpdater is implemented using the Template Method Pattern.  The core logic of applying the updates is implemented in LiteGridUpdater:

public TModel[] ApplyUpdates(TModel[] models)
{
    if (models == null)
    {
        throw new ArgumentNullException("models", "No models were received by the server.  Please try again.");
    }

    //First, apply any updates and moves. Note that because liteGrid sends things in order,
    //we are guaranteed to add a new object before we'll process anything that was added as a child
    //to the new object.
    foreach (var updatedModel in models)
    {
        BeforeUpdateModel(updatedModel);

        //Get the existing object or create a new one.
        TTarget target = GetTarget(updatedModel);

        if (target != null)
        {
            updatedModel.MapTo(target);
        }
        else
        {
            CreateAndUpdate(updatedModel);
        }

        //Apply any moves
        if (updatedModel is ILiteGridMovableModel<TTarget>
            && ((ILiteGridMovableModel<TTarget>)updatedModel).NewParentId.HasValue)
        {
            MoveToNewParent(updatedModel);
        }
    }

    //Now apply any deletes.
    foreach (var updateModel in models)
    {
        if (updateModel.Deleted == true)
        {
            DoDelete(updateModel, GetTarget(updateModel));
        }
    }

    return models;
}

Derived classes are responsible for implementing the details for how to perform the various operations, which include create a new entity, deleting an existing entity, and moving an entity (in the case of hierarchical entities).  Derived classes don’t necessarily have to implement all the operations.  Obviously you don’t need to worry about MoveToNewParent if your entities aren’t hierarchical.  If you aren’t allowing the users to add new rows, then you don’t need to worry about implementing the CreateAndUpdate method, either.  The same goes for DoDelete.  The BeforeUpdateModel method is optional.  You can use it to hook in and perform custom actions prior to applying updates (we use it to hook in validation).  In fact, the only operation you have to implement in a derived class is GetTarget.  This operation receives a view model and is responsible for locating the corresponding backend entity and returning it.  In our case, this involves looking the entity up using Castle ActiveRecord, but LiteGridUpdater is not coupled to any data access strategy.

Updates to existing entities are handled by the view model.  The ILiteGridUpdateModel defines a single method for performing the updates on an entity:

public interface ILiteGridUpdateModel<TTarget>
{
    /// <summary>
    /// True if the model was deleted. 
    /// </summary>
    bool? Deleted { get; }

    /// <summary>
    /// Maps the view model to the specified target.
    /// </summary>
    /// <param name="target"></param>
    void MapTo(TTarget target);
}

We use AutoMapper in our concrete liteGrid view models, but you are free to implement the update logic as you see fit.  Here’s a made up example for a Widget:

public class WidgetViewModel : ILiteGridUpdateModel<Widget>
{
    public int WidgetId { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public bool? Deleted { get; set; }

    /// <summary>
    /// Configures AutoMapper mappings.
    /// </summary>
    static WidgetViewModel()
    {
        Mapper.CreateMap<WidgetViewModel, Widget>();
    }

    /// <summary>
    /// Creates an uninitialized view model
    /// </summary>
    public WidgetViewModel()
    {
        
    }

    /// <summary>
    /// Maps the view model to the specified target.
    /// </summary>
    /// <param name="target"></param>
    public void MapTo(Widget target)
    {
        Mapper.Map(this, target);
    }
}

After LiteGridUpdater applies the updates, it returns the same view models that it received.  These should be pumped back to liteGrid so that it knows what changed and can update its state accordingly.

Prior to creating LiteGridUpdater, we had quite a bit of repeated, complex logic in our system for dealing with liteGrid updates.  Now that we have LiteGridUpdater, we have a cleaner, more robust solution, and a lot less duplicate logic. 

Again, I really need to find the time to move LiteGridUpdater as well as some of our other liteGrid infrastructure into the liteGrid project as I originally intended.  Maybe someday soon I’ll find that mythical block of “free time” that everyone else seems to be enjoying.

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Using liteGrid with ASP.NET, Part 1 – The LiteGridJsonResult

clock January 21, 2010 11:25 by author Matt

When I first started building liteGrid, one of my design goals was to build a grid library that worked easily with ASP.NET MVC.   I’m not sure I’ve delivered on that goal, at least not externally.  Internally, we’ve built quite a lot of MVC plumbing that makes working with liteGrid easier.  We have custom JSON result types, view models, helpers, etc.  Sadly time has not yet permitted me to migrate most of these improvements back into the (empty) Visual Studio .NET project that’s in liteGrid, but I plan to start doing that as soon as I have time to do some cleanup and refactoring.  In the meantime, I thought I would start showing off some of the plumbing that we’ve built, starting with the LiteGridJsonResult.

The LiteGridJsonResult is used to send data to an instance of liteGrid.  The intended use is something like this:

//Get your objects from wherever
var domainObjects = GetDomainObjects();

return new LiteGridJsonResult(
    domainObjects.Select(d => new MyCustomViewModel(d)).ToArray()
);

Note that we’re converting our domain objects to view models, then sending the view models to liteGrid through the result.  Client-side, this means that liteGrid is going to receive data that looks exactly like the view models we’re working with server-side.  This allows us to build our column definitions, validation rules, etc. from our view models in a strongly-typed way. 

The actual implementation looks like this:

/// <summary>
/// A custom JsonResult that returns data in a format that 
/// liteGrid expects.
/// </summary>
public class LiteGridJsonResult : StandardJsonResult
{
    /// <summary>
    /// The data items being sent to the grid.
    /// </summary>
    public Array DataItems { get; private set; }

    /// <summary>
    /// Creates a result with the specified data items. 
    /// </summary>
    /// <param name="dataItems"></param>
    public LiteGridJsonResult(Array dataItems)
    {
        DataItems = dataItems;
    }

    /// <summary>
    /// Copies the values into the Data anonymous object. 
    /// </summary>
    /// <param name="context"></param>
    public override void ExecuteResult(ControllerContext context)
    {
        //The base class serializes the DataItems to JSON
        //and assigns it to a 'dataItems' property in the result.
        Properties.Add("dataItems", DataItems);

        base.ExecuteResult(context);
    }
}

The base class, StandardJsonResult, is a specialization of MVC’s JsonResult that we’ve created.  It exposes a Boolean Status property that indicates success/failure of a JSON operation in a consistent way (poor choice of name in hindsight, but it serves the intended purpose).  It was originally created when we were using anonymous types instead of view models, and was intended to make it easier to test that objects were being projected correctly (yeah, I know, bad idea).  It’s on my TODO list to rework it.  For now, suffice to say that it takes care of projecting our view models into JSON that looks like this (the format that liteGrid expects):

{
 status: true,
 dataItems: [{ID: 1, Name: "Name", Title: "Title"}, {ID: 2, Name: "Name", Title: "Title"}]
}

LiteGridJsonResult is still a little rough around the edges (this blog post actually reminded me of how much work we still need to do), but it works.  In the next post, I’ll show you how we handle synchronizing changes from liteGrid back to the server-side object model.

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Work-around for jQuery UI Draggable refresh limitation

clock January 15, 2010 10:01 by author Matt

The jQuery UI draggable plug-in is used within liteGrid by the DraggableRowsModule.  It enables users to rearrange the order of rows as well as to place rows into a hierarchy (if the TreeGridModule is installed). 

Recently a request came through to make liteGrid scroll when you are dragging rows.  This becomes very important in large grids when you want to make a newly added row a child of the first row in the grid.  Without scrolling, you must resort to repeatedly drag-and-dropping your way up the list.  This feature sounded easy enough to implement, but like most things dealing with tables, HTML, and CSS, it wasn’t.

First there was the draggable’s ‘scroll’ option.  In the demo, using this option achieves exactly the result I was after, but it didn’t work for liteGrid.  As usual, I believe this to be a limitation of using the plug-in with a table element instead of with a standard block-level element.  So, until I find time to rewrite the liteGrid rendering to use div’s instead of a table, that solution was out of the question.

Adding the logic necessary to make liteGrid scroll was actually quite easy to do.  In the DraggableRowsModule, I added the following to the drag event handler:

//If we're dragging outside of the grid, scroll.  We can't
//use the built-in scroll capabilities of draggable because 
//its not the table that we need to scroll, but rather the parent. 
var body = base.liteGrid.bodyDiv;
var bodyOffset = body.offset();
var bodyHeight = body.height();
var currentScroll = body.attr("scrollTop");

var rowOffset = ui.helper.offset()

//If we're above the body div, scroll up.
if (rowOffset.top < bodyOffset.top) {
    body.attr("scrollTop", currentScroll - base.options.dragIncrement);
}
else if (rowOffset.top > (bodyOffset.top + bodyHeight)) {
    body.attr("scrollTop", currentScroll + base.options.dragIncrement);
}

This worked, except when the drag handle caused the window to resize.  When that happened, suddenly the drop targets no longer lined up with the correct elements.  You can see what I mean here:

I'm pretty sure that's not where my mouse is...

After some digging, I found the ‘refreshPositions’ option in the draggable plug-in, but the documentation states it can have major performance impacts.  Well, the documentation is right.  For a grid with a lot of rows, the performance was not acceptable.  What I really wanted was a way to tell draggable to update the positions on demand as opposed to every time; after all, unless the grid scrolls, there’s no need to refresh the positions.  There is a work item queued up to add this functionality to jQuery UI, but no activity has been performed on it to date. [sad faec]

I tried a few different means of hacking it but ran into failures every time before I finally settled on this solution:

//This is wired in by the module's init function
base.dragGhost = function(event, ui) {

    var dragHandle = $(event.target);

    //If dragging caused a scroll, the positions were refreshed already,
    //so we can turn thi sback off..
    if (dragHandle.draggable('option', 'refreshPositions')) {
        dragHandle.draggable('option', 'refreshPositions', false)
    }

    //--SNIP: Boring code to handle adding children to a row--

    //--SNIP: More boring code to grab offsets, see snippet above

    if (rowOffset.top < bodyOffset.top) {
        //Here's the interesting part
        dragHandle.draggable('option', 'refreshPositions', true);
        body.attr("scrollTop", currentScroll - base.options.dragIncrement);
    }
    else if (rowOffset.top > (bodyOffset.top + bodyHeight)) {
        //And again
        dragHandle.draggable('option', 'refreshPositions', true);
        body.attr("scrollTop", currentScroll + base.options.dragIncrement);
    }
}

When the grid scrolls, I temporarily enable the refreshPositions option.  The next time the drag handle moves, jQuery UI will refresh the drop target positions as desired, and my event handler disables the option again.  This achieves the desired effect: when dragging-and-dropping, the droppable positions are only re-calculated when the grid is scrolling, otherwise they are left alone.  This can still cause a slow down during grid scrolling, but it’s the only solution I’ve found so far.

This feature is available now on the liteGrid trunk.

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Recent liteGrid changes

clock January 15, 2010 04:09 by author Matt

Despite the lack of noise on the topic, liteGrid has received a host of updates recently thanks almost entirely to the efforts of James "poprhythm" Kolpack.  I’ve updated the online demo of liteGrid so you can play with some of the recent changes, which include validation support, checkbox columns, and a slew of other minor improvements.

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


The New Year – 2010 Edition

clock January 6, 2010 10:36 by author Matt

Wow, it’s actually been (a little over) a year since I posted my goals for 2009.  Going back and re-reading those goals, I’m a little surprised at my goals, and saddened that I made so little progress. I thought it might be a healthy exercise to look at how I did in meeting each of my 2009 goals.

Goal 1: Get the new layout integrated into this blog.
This one isn’t completely my fault, only mostly.  My friend actually decided that he didn’t like the layout he did and wanted to make another one, and I think he hasn’t had time to do that yet.  Sadly that was in like June, which means I failed to integrate the previous layout into this blog for a full 6 months.  :(

Goal 2: Learn Silverlight.
Ack, I really dropped the ball on this one.  I looked briefly at Silverlight, and I did learn some WPF and XAML, but I never actually sat down and did anything with Silverlight.  I have no excuse other than I had no pressing need and insufficient free time to tackle this.

Goal 3: Learn XNA.
… :(

Goal 4: Continue to make 3 blog posts per week, minimum.
I didn’t keep up a 3-per-week average, but I did ok.  The readership on my blog (according to Feedburner) grew from ~20 to over 100, so I’m actually fairly satisfied with my performance on this goal.  Yes, I did fall short of the 3-per-week I set out to maintain, but I think I made some useful contributions on a fairly consistent basis.

Goal 5: Write more.
I actually nailed this one, but not in the way I thought.  Aside from finishing my thesis (a 100+ page monster of technical writing), I also contributed to and authored numerous research publications.  Sadly only one has been accepted so far, but at least I’m getting lots of practice.  I still would like to do some CodeProject articles, but that’s taken a back seat to other things for now.

Goal 6: Maintain a more positive attitude towards work.
Again, I feel like I nailed this one.  I think I’ve stayed very positive despite a bumpy year.  Hiring a good friend and great dev in James helped, but I still tried not to let things here get to me too badly.

Overall, I’m disappointed that so many of my goals fell by the way-side, but I’m not surprised.  I failed to account for a several things that should have made my list, including finishing my thesis, graduating (in only 3 full semesters), and becoming a new dad. 

Goals for 2010

Time to set up my apologetic blog post for 2011!  I decided to set fewer goals this year than last year:

Goal 1: Move forward on ideas for new products. 
I have had several product ideas floating around in my head for many months now, and over the years I’ve had several great ideas that I procrastinated on only to see others implement them and become wildly successful (I’m looking at you, Facebook).  I don’t want to endure the pain of seeing another one of my ideas make someone else rich, so I’m focusing on maturing my ideas in 2010.  Already I’ve fleshed out a small handful of ideas, and I plan to move forward aggressively with one in the near future.

Goal 2: Read more technical material.
I feel like I’m falling behind a bit in terms of technical knowledge.  It takes constant vigilance and dedication to stay on top of what’s going on in the research world in my field (Information Retrieval), plus there’s always new things going on in software development in general.  In 2010, my goal is to read more technical books (already finished up Head First Design Patterns, now working through both Taming Text and ASP.NET MVC In Action) as well as to stay more current on what’s being done in the research world.

And that’s it.  I do have additional goals not related to development (sadly “relax more” didn’t make the cut), but I’m focusing on these two big weaknesses and hope to have a more positive review of 2010 one year from now.  See you then!

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Useful snippets

clock December 28, 2009 11:27 by author Matt

I had two small “breakthroughs” while coding today that saved me quite a bit of time.  The first dealt with mocking HtmlHelper<T> with Moq for unit testing purposes:

/// <summary>
/// A mocked-out <see cref="HtmlHelper{TModel}"/> that can be used for testing.
/// </summary>
/// <typeparam name="TModel">The view model type.</typeparam>
public class FakeHtmlHelper<TModel> : HtmlHelper<TModel> where TModel : class
{
    /// <summary>
    /// Creates the fake.
    /// </summary>
    public FakeHtmlHelper(TModel model) : base(new FakeViewContext(), GetMockContainer(model))
    {
        
    }

    /// <summary>
    /// Gets a mock view data container that returns view data for the specified model.
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    private static IViewDataContainer GetMockContainer(TModel model)
    {
        var dataContainer = new Mock<IViewDataContainer>();

        ViewDataDictionary<TModel> dataDictionary = new ViewDataDictionary<TModel>(model);

        dataContainer.Setup(c => c.ViewData).Returns(dataDictionary);

        return dataContainer.Object;
    }
}

(Note that FakeViewContext is a similarly-designed fake class, but it could also be a Mock object.)

With this fake helper, you can now unit test extension methods for HtmlHelper<T>. 

The second “snippet” I found useful today was aligning a group of divs.  The desired layout was something like the following:

inlineBlockGood

However, setting the divs to display to inline-block resulted in something like this instead, where the div with less content did not line up with the other divs even though their heights were all set to the same value

inlineBlockBad

A quick scan of the CSS spec got me pointed back in the right direction, and I used a vertical-align of top to achieve the desired layout.

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Exposing the View Model to JavaScript in ASP.NET MVC

clock December 22, 2009 17:24 by author Matt

The prevailing practice for moving data between the controller and the view in ASP.NET MVC applications is to utilize a view model.  While using a view model from within the view’s ASPX page is quite easy, utilizing it from JavaScript can be more complex.  While JavaScript blocks declared inline on the view page can easily consume values from the model, external script files cannot.  In order to take advantage of script batching and minimization, you should avoid the use of inline script blocks and instead use external JavaScript files (.js).  What happens when you need to reference a value from the view model in your JavaScript though?  Since the JavaScript files are not (by default) processed by the ASP.NET pipeline, it isn’t possible for them to leverage the Model; the Model exists server-side, while JavaScript is processed client-side. 

I’ve struggled with this limitation since the first preview release of ASP.NET MVC.  Here are a couple of the approaches that I tried (and hated):

Place scripts in partial views

Instead of following best-practices and placing JavaScript in an external script file, scripts can instead be placed in partial views.  This simplifies the main view by encapsulating the script, and it does allow the script to be re-used.  It also allows the script to easily reference values from the view model. 

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<AwesomeViewModel>" %>

<script type="text/javascript">
    
    alert('Hello from the view model: <%=Model.Hello%>');
    
</script>

The downside to this approach is that the script cannot be easily minimized or combined, and it can’t be cached by the browser since it is actually rendered inline in the final markup produced by the view. 

Pass view model properties through an initialization function

Another approach that I’ve used is to define an initialization function within my external JavaScript files.  Any values that are needed by the script can be extracted from the model within the main view, then passed to the external JavaScript through the initialization function.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AwesomeViewModel>" %>
...
<script type="text/javascript" src="ExternalScript.js"></script>
<script type="text/javascript">
    var name = "<%=Model.Name %>";
    ExternalScript_Init(name);
</script>
...

//Contents of ExternalScript.js
ExternalScript_Init(name) {
    alert("Hello from JavaScript: " + name);
}

This approach is also less than ideal.  Any values the script requires must be manually extracted from the view model, which makes maintenance more of a headache than it should be. 

The ideal solution

The previous two approaches “work”, but they each have drawbacks.  The ideal solution would allow the model to be easily consumed by external JavaScript files within a minimal amount of manual work.  Adding a new property to the view model should require zero JavaScript in order to expose the new property for use by scripts.  It turns out that this is actually quite easy to do….

The right way: serialize the model to JavaScript!

.NET 3.5 introduced the JavaScriptSerializer class for serializing objects to/from JSON. With it, most .NET types can be easily converted into a form that’s easily consumable by JavaScript.  Scott Gu introduced a simple ToJSON extension method on his blog which can be used to transform a view model into JSON.  When the output of this method is assigned to a JavaScript variable, the properties of the view model effectively become available to client-side script (note that methods defined on the view model, if any, are ignored by the JavaScriptSerializer). 

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AwesomeViewModel>" %>
...
    <script type="text/javascript">
        var Model = <%=Model.ToJson() %>
        //If needed, new properties can be added to the model, such as URLs for AJAX requests:
        Model.MyAjaxMethod = '<%=Html.BuildUrlFromExpression<MyController>(c => c.DoAjaxyThing()) %>';        
    </script>

The above code block should appear before any scripts that wish to access properties from the view model, which can reference view model properties easily:

<script type="text/javascript">
    
    alert("Hello from the JSON view model:" + Model.Hello);
    
</script>

This is a big improvement over the other two approaches I’ve tried (at least in my opinion), but it still requires me to perform this mundane serialization task on each view.  An easy improvement is to move it to the master page:

<script type="text/javascript">
    var Model = <%=Model != null ? Model.ToJson() : "{}" %>;
</script>

Now every view that has a view model will automatically have a Model object available.

Thoughts?  Suggestions?  Anyone found a better solution that I’ve just overlooked somehow?

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


About Matt

I am an overworked (and apparently overpaid) software developer with aspirations of acquiring a PhD in Computer Science. I started off coding in C over a decade ago.  Since then, I've migrated from C to C++ and branched out to C#, PHP, VB.NET, JavaScript, and worked with a wide assortment of other languages that I hope to never deal with again (I'm looking at you, COBOL). Oh, and yes, I've written some Java.  Does that make me a bad person?

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in  anyway.

© Copyright 2009

Sign in