My Resume

  • My Resume (MS Word) My Resume (PDF)


Affiliations

  • Microsoft Most Valuable Professional
  • INETA Community Champion
  • Leader, NJDOTNET: Central New Jersey .NET User Group

Tuesday, March 10, 2009

Come Learn Silverlight 2 From a Master!

Hey all - if you're in the Princeton, NJ area this coming Thursday (March 12th, 2009), be sure to stop by our monthly NJDOTNET User Group meeting because this month we will be hosting Jason Beres - international conference speaker, Microsoft MVP, and an author of the two Silverlight Programmers References from WROX Press!  Jason is an incredible speaker and I strongly encourage you to do everything you can to attend this meeting!  Here are the details:

What:  NJDOTNET March Meeting – Understanding RIA’s with Silverlight 2

When: THIS Thursday, March 10, 2009  6:15 PM – 8:30 PM

Where:  Infragistics Corporate HQ  (Click here for directions)

Who:
Jason Beres is the Director of Product Management for Infragistics, the world’s leading publisher of presentation layer tools.  Jason is one of the founders of Florida .NET User Groups, he is the founder of the Central New Jersey .NET User Group, he is a Visual Basic .NET MVP, and he is on the INETA Speakers Bureau.  Jason is the author of several books on .NET development, including the recently published Silverlight 2 Programmers Reference from Wrox Press.  Jason is a national and international conference speaker; he is a frequent columnist for several .NET publications, and keeps very active in the .NET community.

Abstract:
Understanding RIA’s with Silverlight 2
In this code-focused talk, we’ll look at the features in Silverlight 2 and how they can help you build better RIA (Rich Internet Application) experiences.  We’ll look at the Silverlight development experience, how to build a Silverlight application with the new Silverlight 3 features, and how this will help you build rich line-of-business experiences using data binding, animations and media.

Tuesday, February 17, 2009

Tag Mappings to the Rescue!

Our recent project at work lately (and the main reason for my previous two months of blog silence) has been upgrading and re-theming our installation of Community Server.  I’ve written a few posts in the past on the couple of modules and customizations I’ve done for our current site, and this upgrade is no different.  In fact, I’ve had to do more!  The most recent one I did just a few minutes ago just happens to be not Community Server-specific at all, but a regular ol’ ASP.NET trick, so I wanted to write about it first.  You’ll see more about the Community Server-specific customizations I’ve had to do following this post.

Community Server sites are really just the “Community Server Platform” (which encompasses a whole lotta stuff!), and a customizable theme on top of that platform.  Like any well-made site, CS themes are plain ol’ ASPX pages with a mixture of user and server controls.  This leaves us with themes that have got somewhere between a dozen and a million pages with the following mark-up:

<CSForum:BreadCrumb runat="server" Tag="Div" />

… but I don’t like what it’s outputting and I want to override some of its behavior.  Overriding the control’s behavior is easy enough, of course – you just extend the class and throw in an override here and there and you’re all good.  Now we’ve got our new control – Infragistics.CommunityServer.Controls.ForumsBreadCrumb – and the trick is getting this nice shiny control in place.  Your first thought might be that we’re up for a massive global search n’ replace, right?  Wrong!


I know I kinda ruined the surprise in the title of this post, but for those of you who skipped over that part, forget the global replace – it’s tag mappings to the rescue!  Tag mappings allow you to substitute (or map if you want to get technical) one control for another using a simple web.config change!  In our case, we’ll do this:


<pages>
<tagMapping>
<add
tagType="CommunityServer.Discussions.Controls.BreadCrumb"
mappedTagType="Infragistics.CommunityServer.Controls.ForumsBreadCrumb"/>
</tagMapping>
</pages>

It’s pretty straight-forward – you’re telling ASP.NET that everywhere you’ve used a tag in your markup (tagType) you want to use another type instead (mappedTagType).  This makes it really easy to override and/or extend the functionality of a control and use your custom version instead of the original, without changing any of your code


This tactic can really help you reduce the risk of such a major change, since - I don’t know about you - but my history with global replacements in markup pages have more often than not cost me more problems (and time spent fixing those problems) than if I had just manually made all the replacements to begin with.  Next time you’re tempted to do a global replace on a control, take a couple of seconds to think about whether or not this tactic will work for you.  It might end up saving you quite a bit of time!


And, as always, happy coding!

Friday, December 19, 2008

ASP.NET MVC Release: So close you can FEEL it!

I had a great time reading ScottGu's blog post today discussing all of the cool new features coming in the RC. Some of them (like the View page template not including a code-behind file) really got me excited, but I nearly freaked out when I got to the end and read this:

We'll be releasing the ASP.NET MVC Release Candidate in January. Our plan is to have that build be ASP.NET MVC V1 API and feature-complete and have zero known bugs. We'll give people a short period to upgrade to it, give it a good tire-kicking, and report any last minute issues they find. We'll then ship the official V1 release shortly after that (so not far off now).

ASP.NET MVC v1 is SOOO close! I really feel like this framework has come a long way in its relatively short development lifetime and with all of the recent candy that's been added in the past few releases, I can just tell that it will be a wonderful platform to develop on for years to come.

Microsoft... ScottGu (and the rest of the MVC team)... You ROCK. I can not wait to be working in this framework on a daily basis.

Tuesday, December 9, 2008

Princeton, NJ -- Community Events This Week

If you're in the Princeton, NJ area - or can somehow manage to get here - this week, boy do we have some events for you!  Infragistics has teamed up with our local .NET User Group (NJDOTNET) and our local Microsoft Developer Evangelists out of New York City to bring you the following awesome events:

  1. Thursday, December 11th, 1PM - 5PM:  MSDN Roadshow
    Presenters:  Peter Laudati and Bill Zack
    Session 1: Cloud Computing

    Hear about key problems that cloud computing is solving and how these services fit into the Microsoft cloud computing initiatives. Learn about the pillars of the platform, its service lifecycle, and see how they fit with both Microsoft and non-Microsoft technologies.

    Session 2: Silverlight 2 Application Development

    Now it’s time for you to get ready to build next generation rich Internet applications with Silverlight!  In this session, we’ll quickly review what the Silverlight 2 platform is, and then move into the bits and bytes.

    If you're interested, register using this link:

    http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032395688&culture=en-US

     

  2. Thursday, December 11th, 6:15-8:30 PM:  NJDOTNET User Group monthly meeting
    Topic:  The ASP.NET MVC Framework
    Presenter:  Jess Chadwick

    The Model-View-Controller (MVC) architectural pattern is one that many developers are familiar with which separates an application into three main components: the model, the view, and the controller. The ASP.NET MVC framework provides an alternative to the ASP.NET Web Forms pattern for creating MVC-based Web applications. It is a lightweight, highly testable framework that allows you to easily incorporate this pattern into your applications, helping to separate the different aspects  (input logic, business logic, and UI logic) into loosely-coupled and pluggable elements.

  3. Saturday, December 13th,  9:30 AM - 5:00 PM:  NJDOTNET ASP.NET MVC Firestarter
    Join us at the Infragistics HQ to participate in an all-day, deep-dive into one of Microsoft's latest (and greatest!) technologies: ASP.NET MVC.

    At the ASP.NET MVC Firestarter, we’ll give you a quick tour of the framework, then peel back the layers and dive deeper into how it works.   As part of that, we’ll spend time discussing the design and development practices that lead to the creation of the MVC framework.  By the time you leave, you’ll have enough knowledge to get fired up and start building web applications with it.

    Detailed Agenda:

    • ASP.NET MVC Introduction
      • The MVC Design Pattern
      • Hello World Demo – Walking through routing, controllers, and views
    • Framework Fundamentals & Practices
      • C# 3.0 Primer
      • Anonymous Classes
      • Lambda Expressions
      • Extention Methods
      • LINQ
      • Dependency Injection
    • Routing & Controllers
      • Routing 101
      • Controllers – Actions & ActionResults
      • Controllers & TDD
    • Rendering Markup
      • Views (using WebForm tools)
      • Extensibility with View Engines
    • Working with Data
      • Creating & Submitting Forms
      • UI Helpers
    • Building Rich Web Interfaces
      • Applying AJAX Helper extensions
      • Walkthrough of ASP.NET AJAX + MVC Extensions
      • Enhancing MVC with jQuery
      • Action Filters & applying to AJAX

    If you are interested in attending this session, please register using the following link:
    http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032397108&culture=en-US

 

I look forward to seeing you at these great events!

Sunday, November 16, 2008

Easier Automated Database Testing with SQL Express

Scenario

I've got a project in which I actually have full create scripts for my database such that I can build a whole new instance from the bottom up.  I've also got some automated unit/integration tests that I want to run against this database, complete with a bunch of scripts that can build some test data for me (unrealistic, I know...  but bear with me :).  Also, I really don't want to have to worry about configuring connection strings just for my tests - I just want some database available to me when I need it that I can wail on with requests and gets cleaned up for me when I'm done.  Finally, I want to keep my tests as isolated as possible, which to me means a file-based SQL Express database; that way, I can attach, detach, and delete as much as I want with as little exposure and impact to the rest of my build system as possible.

Solution

My solution to the above scenario I found myself in was to create a helper class called TestDatabase whose job is to give me a database when I need one, provide me with a clean version of my test data before each test I run, and clean up after me when I'm done.  To this end, I started searching for how to create a file-based SQL Express database using code, and came up with Louis DeJardin's great blog post that walked me right though it.  After I had that, it was a simple matter of whipping up the class, shown below (Note: this is only a partial listing.  You can get the full listing from my code repository):

TestDatabase.cs (partial listing)
public class TestDatabase : IDisposable
{
private readonly string connectionString;
private readonly string databaseFilename;

public string ConnectionString { get { return connectionString; } }
public string Schema { get; set; }
public string TestDataScript { get; set; }

public TestDatabase(string databaseFilename, string schema, string testData)
{
this.databaseFilename = databaseFilename;
connectionString = string.Format(
@"Server=.\SQLEXPRESS; Integrated Security=true;AttachDbFileName={0};",
Path.GetFullPath(databaseFilename));
Schema = schema;
TestDataScript = testData;
}

public void Dispose()
{
DeleteDatabaseFiles();
}

public void RecreateTestData()
{
EnsureDatabaseCreated();

if (!string.IsNullOrEmpty(TestDataScript))
ExecuteQuery(TestDataScript);
}

// Create a new file-based SQLEXPRESS database
// (Credit to Louis DeJardin - thanks! http://snurl.com/5nbrc)
protected void CreateDatabase()
{
var databaseName = Path.GetFileNameWithoutExtension(databaseFilename);

using (var connection = new SqlConnection(
"Data Source=.\\sqlexpress;Initial Catalog=tempdb;" +
"Integrated Security=true;User Instance=True;"))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText =
"CREATE DATABASE " + databaseName +
" ON PRIMARY (NAME=" + databaseName +
", FILENAME='" + databaseFilename + "')";
command.ExecuteNonQuery();

command.CommandText =
"EXEC sp_detach_db '" + databaseName + "', 'true'";
command.ExecuteNonQuery();
}
}

// After we've created the database, initialize it with any
// schema we've been given
if (!string.IsNullOrEmpty(Schema))
ExecuteQuery(Schema);
}
}


Let's analyze the things we've got going on here:


  1. First, we've got the CreateDatabase() method (lines 34-61) - basically ripped right from Louis's blog post linked above - which does the magic of creating a file-based SQL Express database.  It all boils down to a "CREATE DATABASE" and "EXEC sp_detach_db" call on the local SQL Express instance's tempdb database, which everyone has access to.  Then when that's all done, I execute the schema script that the tester passed in to build the database schema and finish the initial setup.
  2. Now that the database has been created and initialized with its schema, we can run some tests against it!  Problem is, at this point it's just an empty database...  Fortunately for us, we've got the RecreateTestData() method, which just executes the TestDataScript against the current database, allowing us to easily populate whatever test data we want!  This script should include everything it needs to clean out the database and rebuild it from scratch with a new set of clean data.
  3. Built-in connection string management.  As you can see, our constructor takes in a database filename, builds a connection string out of it, and then exposes that connection string to our testers via a read-only property.  That is one less connection string that our test project has to worry about managing in its app.config (or whatever), which is pretty nice and clean, IMHO!
  4. Finally, our big finale:  cleaning up after ourselves!  You can see that TestDatabase implements IDisposable, allowing us to create a Dispose() method which cleans up after everything we've done - namely, deleting the database files we've created along the way.  This means that after everything is said and done, we've left not one footprint of our presence on the build system.

Now, after we've got our TestDatabase class available, our unit tests become as easy as this:


public void SomeCoolDatabaseDrivenServiceTest()
{
var mySchema = System.IO.File.ReadAllText("mySchema.sql");
var testData = System.IO.File.ReadAllText("testData.sql");
using (var db = new TestDatabase("TestDatabase.mdf", mySchema, testData))
{
db.Initialize();
var service = new MyService(db.ConnectionString);
service.DoSomething();
}
}

Of course, individual tests can have even less code if you manage the test database outside of the test by using your test framework's setup and teardown methods.  For example, if I had a whole slew of tests against the same database (which is usually always the case), the test class would start out like this:


TestDatabase database;

public void ClassInitialize()
{
var mySchema = System.IO.File.ReadAllText("mySchema.sql");
var testData = System.IO.File.ReadAllText("testData.sql");
database = new TestDatabase("TestDatabase.mdf", mySchema, testData);
database.Initialize(true);
}

public void TestInitialize()
{
// Rebuild the test data from scratch before EVERY test
database.RecreateTestData();
}

public void ClassCleanup()
{
database.Dispose();
}

Now that we have all of that setup and teardown logic out of the way, we can focus on what we're actually testing, so then that test I showed you before becomes a simple one-liner (as it would have been if we were just passing in a connection string from a configuration file):


public void SomeCoolDatabaseDrivenServiceTest()
{
// No TestDatabase setup - just use its connection string!
var service = new MyService(database.ConnectionString);
service.DoSomething();
}

What's cool about this is that not only do we not have to worry about where to get our connection string from, our entire suite of test data is also being rebuilt for us before every test is run!

Try It Out For Yourself!


If you like what you've seen in this post and want to try it out for yourself, you can grab the full source file (complete with in-line comments and unit tests) from my repository: TestDatabase.cs.  Just drop it in your project and start using it!
Note: The full source file has unit tests included. If you don't want them, you can simply delete them without affecting the main class.


As always, I'd love to hear your comments and feedback on all this.  If you've found this useful or - better yet - if you have a better way of doing it, please let me know!

Monday, October 27, 2008

Live from PDC: Getting settled in and thoughts on the Keynote

Greetings from PDC!

After a long and uncomfortable (for those who don't know me - 6'3", 220lbs...) flight, I'm finally here in beautiful and smoggy Los Angeles, ready for some PDC action!  First up - this morning's keynote in which Ray Ozzie announced Windows Azure, their new offering.  Sounds much like Amazon's service offerings (EC2, S3, etc)... only .NET and a whole slew of other MS offerings.  Sounds pretty darn cool, if you ask me.  So far, I haven't really been interested in utilizing Amazon's services, mostly due to cost, and I wonder how Azure will compare.  Ozzie says their CTP will be free due to changes that may possibly break anything and everything that you make with it at this point (my words, not his), and says that the final pricing will be "competitive with the market" (dunno if that's an exact quote or not, but it's about right).  One has to ask - what's "the market"?  As far as I can tell, that means Amazon's services and - as I just got done saying - their pricing was a deal-breaker for me.  Along these same lines, I noticed that one of the bullet points said "hobbyist-friendly" - with any luck that is referring to their pricing structure.

I also found it interesting that they referred to "new patterns and best practices such as loosely-coupled services and applications" numerous times...  It really is news to me that loosely-coupled designs are "new patterns and best practices"!   But, I'm not complaining - if developers are now more or less forced to use loosely coupled architectures to take the most advantage of cloud services, that's a good thing, right?

My next session (A Lap Around Windows Azure) is starting, so I should wrap this one up...  but, more to come for sure.

Wednesday, October 8, 2008

Wow - Thanks, Microsoft!

It's taken me quite a few days to get around to writing this post (been busy preparing and delivering a new ASP.NET MVC presentation at the Richmond Code Camp last Saturday), but I received a great email last Wednesday welcoming me to a great community of Microsoft professionals, and beginning with this header:

I'm now a Microsoft MVP in ASP.NET!  Needless to say, as soon as I found out, I got crazy excited and began thinking of everyone who was so helpful in achieving this great award. 

The first two guys I needed to thank were Aaron Marisi and Todd Snyder.   These two have been - and continue to be - crucial in helping me run the NJDOTNET User Group.  With their help (and it was only possible with their help!) we have been able to expand this monthly meeting to a meeting every week, providing exponentially more value to the members of the group.  I am going to make it my mission from here on out to make sure these two guys get all the credit they deserve!

In a separate class altogether are Ambrose Little and Jason Beres.  It is these two guys that had the greatest impact on my professional and community life because it was the leadership, knowledge, and obvious passion that these two MVPs (and I mean that in every sense of the acronym) exhibit on a daily basis that inspired me to become so involved with the development community in the first place.  Were it not for them, I probably would still be sitting in the back of the monthly user group meetings, barely saying a word.  But, after working with them for only a short time, their selfless guidance and inspirational example were too much to ignore and I just had to join in and attempt to contribute even half as much as they do.  In fact, I attribute so much of my recent success to them that if I could (and if they didn't already have one!) I would give my award directly to them.

I can't even imagine how much more vibrant and exciting our community would be if there were more Aarons, Ambroses, Jasons, and Todds out there pushing things along.  I eternally grateful to be able to work with all of them and even call them my friends.

So, thank you everyone for all of your support and I am really looking forward to all of the great community participation in the coming year!

Wednesday, September 10, 2008

S-E-Ooooh, That's How You Do It!

My boss, Kevin, and I headed out to Seattle last month (coincidentally during the time that some of our Infragistics buddies were heading up the speaker list at DevScovery) to attend an expert-level SEO seminar given by the bright folks over at SEOmoz.  And, boy was it enlightening!

Now, before I go any further, I'm going to have to state right up front that (until late last month) I have been wandering through my professional web career knowing only a bare minimum about SEO.  I thought I understood basic concepts like linking and keyword placement - the more times you link to a page and repeat a word, the higher your search rank, right?  Unsurprisingly, it turns out to be a bit more involved that that. :)

There's no way I'm going to duplicate in a blog post or even a series of blog posts what I learned at that awesome seminar - if you're truly that interested, I would suggest signing up for the training or at the very least checking out the articles on SEOmoz.  However, I wanted to 'jot down' a few of my largest takeaways, because they really made me reevaluate my view on the way SEO works.  Since I have a knack for oversimplifying things (verging on naivety), I figured a bulleted list would do just the trick.  So, below you'll find my ridiculously simplified...

List of Things You Probably Already Knew About SEO But Didn't Realize How Important They Were (or at least I didn't...):

  1. Backlinks.  I'm sure it comes as no surprise that having other sites (especially the big/important ones) link to yours is beneficial, but I'd have to say the most unexpected thing I took away from this seminar was just how important they are!  From what I understand, these account for the vast majority of your PageRank-ings - I'm talking well over half.  That means you need to beg, borrow, cheat, and steal (wait, no... not those last two) to get everyone and their dog to link back to you (assuming their dog's site has a lot of traffic, of course!).  As always, the better their PageRank, the better your Link Juice.

  2. Oh, yeah - Link Juice and nofollow!   To be honest, I'd never heard the term 'link juice' before.  But after hearing it explained, it was just so incredibly appropriate I really became endeared with it.  Put simply, think of the traffic to any one of your pages as water flowing into a pipe.  You start out with 10 gallons of water coming into one pipe (this landing page) from which it is split up and diverted to various other pipes (pages you're linking to from the landing page).  Each of these splits divides and cuts down the volume of the initial 10 gal., such that if you have, say, 10 links on your page each of them gets 1 gal. of that initial 10.  Now, if you play that concept all the way through each page, constantly splitting up the water on every page, you can imagine how quickly that 10 gallon deluge can become just a trickle...  Obviously, we'd like to see some pages on our site get more traffic than others, so how do we  keep our existing links so people can still navigate our site, yet "divert the water" to the pages that we think are the most important?  Fortunately, the answer is pretty simple - the "rel='nofollow'" tag!  Placing this tag on any of your links basically tells search engines "this page really isn't important to me and I really don't want to waste my influence on it."  It's kind of like disavowing all knowledge of your pages... even if it quite obvious that they're worth something to you (since they still exist, after all).

  3. Then there's plain ol' good, properly-formatted, and relevant content...  Really, from what I could tell, those first two bullets are the major players in terms of tips & tricks.  The search engines are getting better at filtering out spammers every day through various techniques, so your ultimate defense is to create interesting content, and make use of standard best practices like putting your important keywords in your <title> and <hx> tags, concentrating on creating relevant content, and trying to keep your markup light and semantically correct.  Simple... right?  "Easier said than done" is more like it!

I had intended from the start for this to be a quick overview of what I took away from my recent training and nowhere near a "deep dive" into SEO.  But, to help you on your way, I've collected a few resources that might help you learn some more if I've happened to pique your interest... which I certainly hope I have!

Additional Resources:

Hope this all helps!  Oh, and please leave me a comment and let me know if it does - I'd love to hear about it!

Saturday, August 2, 2008

The NJDOTNET Dojo is Born!

If you're a developer in the Princeton, NJ area, you'll be pleased to know that the NJDOTNET organizers have decided to create yet another group for your .NET learning pleasure!  Just this past Thursday, we had our first NJDOTNET Dojo meeting, at which I gave a presentation on the Web Development Productivity Tools I use to get things done. 

This new group will continue to meet on an on-going basis every Thursday night that there isn't another meeting (the main User Group or Agile discussion) going on.  Basically, if you're looking to learn about .NET, come on down to the Infragistics HQ on any given Thursday and you're bound to be satisfied!

See this forum thread for more details.

Tuesday, July 1, 2008

Use ASP.NET MVC ActionFilters to Render AJAX Responses!

In my previous blog post on ASP.NET MVC, I walked through an example based on the MVC Preview 2 bits which showed how to make your own custom view engines and ActionFilters.  I also proved (or at least hope I proved) just how powerful these parts of the framework can be, especially when used in conjunction with each other.  The truth is that - while I thought they made great examples on how to extend the base parts of the framework - the whole thing seemed kind of kludgie to me.  What I mean is that it felt kind of awkward having to use the ActionFilter to change which ViewEngine is being used on the fly.  I don't know, maybe I just feel like view engines should be more closely tied to the controller and shouldn't just be chosen willy-nilly like that!

This was all before the introduction of the ActionResult in MVC Preview 3.  Oh man, was this a great addition!  Expanding the notion of being "loosely coupled", the controller action's job is no longer to execute logic and chose which view to display-- ok, well, it is...  only now its main responsibility is returning an ActionResult, which is basically a command object that tells the framework what to do instead the controller taking that action itself.  This not only helps us to decouple the controller (allowing for easier testing, etc.), it also lets us know what the controller wants the framework to do before it happens.  When you think of it, this is pretty powerful stuff, and gives us access to a whole new part of the process in which can inject additional logic.  And inject it we shall...

The SerializableViewDataAttribute Revisited

In my previous post, the attribute that I adorned my Actions with was pretty stupid.  It just said, "Is this an AJAX request? If so, set our custom view engine."  Pretty much all of the meaningful (and interesting) logic happened in our custom view engine.  Now, with the introduction of the ActionResult we no longer have to wait until the view engine phase to get access to (and override) the way our data is returned to the client - we can hijack it in the attribute, and manipulate the Action's result!  Before I confuse you any more, here's the code:

SerializableViewDataAttribute: Preview 3 style
public class SerializableViewDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Get the (lowercase) render mode from the querystring
var method = filterContext.HttpContext.Request.QueryString["renderMode"] ?? string.Empty;
method = method.ToLowerInvariant();

// Get the view data from the context (using a custom extension method defined elsewhere)
var viewData = filterContext.GetViewData();

// If this isn't a serializable request or it has no data, just return
if (string.IsNullOrEmpty(method) || viewData == null) return;

// Decide which method to use
switch (method)
{
case ("xml"):
filterContext.Result = getXmlResult(viewData);
break;
case ("json"):
filterContext.Result = getJsonResult(viewData);
break;
case ("partial"):
// If this is supposed to be a partial request, just change the view name.
// Obviously, this implies that this view exists (in addition to your
// original view that the controller was pointing to to begin with.
var viewResult = ((ViewResult)filterContext.Result);
viewResult.ViewName = "Partial" + viewResult.ViewName;
break;
}
}

private static ActionResult getJsonResult(object viewData)
{
// Since there's a JsonResult Action,
// all we have to do is pass in the data
return new JsonResult { Data = viewData };
}

private static ActionResult getXmlResult(object viewData)
{
// There's no "XmlResult" so we have to serialize it ourselves
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
new XmlSerializer(viewData.GetType()).Serialize(writer, viewData);
}

// ...then pass it into a ContentResult
return new ContentResult
{
ContentType = "text/xml", // Be sure to set the ContentType!
Content = sb.ToString()
};
}

}


As you can see, it is a lot like the logic that was used to create my custom view engine in the last post.  In fact, I essentially copied and pasted it (and added support for partial rendering)!  Also, now that all of this logic lives in the ActionFilter we have no more need for that pesky custom view engine.  So long, cruft!


For the benefit of those who may not have read the explanation of this logic in my previous blog post, I'll go ahead and repeat (as well as expand on) it here.  This version should actually be a lot easier to understand since the logic is now contained in one place instead of spread out between the ActionFilter and the ViewEngine.  Here's a basic run-down of what's going on:


  1. The first thing to note is that we're overriding the OnActionExecuted method of the ActionFilter.  What this implies is that the controller action to which this attribute is applied has already completed, so we now have access to everything it's done: ViewData, TempData, ViewName, etc.  We could also have overridden the OnResultExecuting method as well; this would be somewhat similar to the difference between the PreRender and Render events when using Web Forms.
  2. Once the "event" has been triggered, the first thing we want to do is figure out what, exactly, is expected of us - AKA, which serialization mode (if any) we should be using.  In this implementation, I have decided to glean this information from the querystring, but you can just as easily use any other environment variable you'd like (such as the Route Data, cookies... whatever!).
  3. Next, I get the ViewData from the context, if any, using the filterContext.GetViewData() extension method.  Though this method is defined elsewhere and you can't see it in this snippet, it's not really all that interesting - it's just a convenience method that drills down into filterContext.Controller.ViewData (or ViewData.Model, if available) and returns it.
  4. Check the render method that we got in Step #2 and if that or the ViewData is invalid, there's nothing for us to do, so we're done and we just return.
  5. Assuming we didn't bail out in Step #4, we then go on to overwrite the existing ActionResult (or its properties), depending on what the user has asked for.  This particular version supports:
    1. JSON:  Along with the introduction of the ActionResult came the JsonResult, which is a super-cool implementation of ActionResult that serializes whatever data you give to it into JSON to be rendered down to the browser.  As you can see in this example, this makes handling requests for JSON data really simple and easy.
    2. XML:  Though there is no "XmlResult" as there is for JSON, the MVC framework still provides a ContentResult which is a lot like the JsonResult in spirit.  Both of them allow us to send data in some form back to the browser without requiring a View to render it with.  Going back to our example - you can see that it takes a bit of work, but the end result is a raw batch of just XML sent back to the client for processing.
    3. Partial Rendering:  I included this render mode as a bit of a teaser - I should have a follow-up post going in-depth about using partial rendering in ASP.NET MVC.  For now, I'll just say that you can think of it a lot like the ASP.NET AJAX UpdatePanel server control...

  6. That's it!  If we've gotten to this step and not hit any of the three types above, this particular filter will just let the request continue on and have no effects what-so-ever.  That probably means it'll just end up rendering out a fully-rendered page like any other normal (non-AJAX) request.  The important part to note here is that this filter only injects behavior when it is appropriate.  Otherwise, things proceed as normal and noone even needs to know that these actions are AJAX-ified unless you want them to.


I don't know about you, but the power that this kind of stuff gives us just makes my head spin!  Hopefully you find the above useful; if you do, please feel free to contact me and let me know, especially if you end up using it in one of your apps!



As always, you can check out all of the source code in my repository: http://code.jesschadwick.com/


This particular piece of code can most easily be found at this direct link.