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

Sunday, April 19, 2009

Cleaner Validation with ASP.NET MVC Model Binders & the Enterprise Library Validation Application Block

I accidentally stumbled across an awesome combination the other day:  using the Enterprise Library Validation Block with ASP.NET MVC.  Though I’ve played around with them a few times in the past, this is the first time I’ve really started to apply the Validation block in a serious application, and it just so happened to have an ASP.NET MVC website as its client.  My jaw dropped more and more as I started to realize the awesomeness that was unfolding before me…  hopefully this blog post will do the same (or as close as possible) to you!

Using the Enterprise Library Validation Block

It all started with an innocent enough Model requiring a wee bit of validation that I didn’t feel like hand-writing, so (as usual) I turned to the EntLib library to do it for me.  Applying the Enterprise Library Validation Block was surprisingly simple. 

It all started with a simple enough class (the names have been changed to protect the innocent):

public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public int Quantity { get; set; }
}



This is basically just a DTO (data transfer object), but this ain’t the Wild West – there are rules, and they need to be followed!  After a few minutes, I’d come up with something like this:

using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

public class Product
{
[RangeValidator(
1, RangeBoundaryType.Inclusive,             /* Lower Bound */
int.MaxValue, RangeBoundaryType.Inclusive   /* Upper Bound */
)]
public int ID { get; set; }

// Let's assume that we've got a field length limitation in
// our database of 500 characters, which we'll check for here
[StringLengthValidator(
1, RangeBoundaryType.Inclusive,             /* Lower Bound */
500, RangeBoundaryType.Inclusive            /* Upper Bound */
)]
public string Name { get; set; }

// No rules for the description - anything goes!
public string Description { get; set; }

// The Price can be whatever we want, as long as it's positive
[RangeValidator(0, RangeBoundaryType.Inclusive, double.MaxValue, RangeBoundaryType.Inclusive)]
public double Price { get; set; }

// Same deal with the Quantity - we can never have a negative quantity
[RangeValidator(0, RangeBoundaryType.Inclusive, int.MaxValue, RangeBoundaryType.Inclusive)]
public int Quantity { get; set; }


public bool IsValid()
{
return Validate().IsValid;
}

public ValidationResults Validate()
{
return Validation.Validate<Product>(this);
}
}



There are a couple of cool things I like about this setup:



  1. Declarative validation rules:  These rules are very explicit expression of business logic - there is no “if-else-then”, mumbo-jumbo.  In other words, there isn’t any code to worry about… and no code means no bugs (well, less bugs at least :).  Moreover, if any of these business rules change, it’s very easy to update these attributes without hunting around for that stray line of “if-else” code somewhere.  Lastly, I’ve heard talk of these mystical “business people” who are also able to read and understand simple code; and, if you run into one of these guys/gals they’ll easily be able to verify that you have the rules set properly as well.
  2. All of the validation logic is in one place:  all consumers of this class need to do is set its properties and ask the object whether or not it is valid.  There are no stray “if(string.IsNullOrEmpty(product.Name)” scattered through your code, just “if(product.IsValid())”.  I feel like this approach has a decent amount of cohesion.  Granted, it could be a bit more cohesive if we had, say, a separate “ProductValidator”, but this seems like overkill.  Regardless, it was bugging me enough that I actually created a super-class to encapsulate this logic further of the chain of inheritance and that made me feel a bit more comfortable:
  3. public class SelfValidatingBase
    {
    public bool IsValid()
    {
    return Validate().IsValid;
    }
    
    public ValidationResults Validate()
    {
    return ValidationFactory.CreateValidator(this.GetType())
    .Validate(this);
    }
    }
    
    public class Product : SelfValidatingBase
    {
    // ...
    }


As with pretty much anything, there is at least one glaring drawback to this approach:  there is no “real-time” checking.  That is, this approach allows consumers to set invalid values on these validated properties at any time – possibly overwriting valid values without any checks prior to the update.  I think that as long as your application (i.e. developers) know about this limitation, it’s not so much of an issue, at least not for the scenarios I’ve used it in, so this drawback doesn’t really bother me.



Now, let’s see how this applies to ASP.NET MVC…



The Awesomeness that is ASP.NET MVC’s Model Binders



When it comes to me and ASP.NET MVC’s Model Binders it was love at first site – and I haven’t stopped using them since.  In case you’re not sure what I’m talking about, here’s an example.  Instead of an Action with individual parameters and populating a new instance ourselves like this:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(string username, string message, string userUrl)
{
var comment = new Comment
{
Message = message,
Username = username,
UserUrl = userUrl,
PostedDate = DateTime.Now
};
commentsRepository.Add(comment);
return RedirectToAction("Index");
}



We let the MVC framework populate a new instance for us, like this:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Comment comment)
{
commentsRepository.Add(comment);
return RedirectToAction("Index");
}



I just think that’s beautiful, and so I’ve come to (over?)use Model Binders on my Controller Actions almost exclusively. 



ASP.NET MVC Model Binders + Enterprise Library Validation Block = BFF



The magic that I refer to at the beginning of this post first exposed itself when I inadvertently used one of my Model objects like the one I showed earlier as an Action parameter (which was really only a matter of time given the fact that I’d taken to using them so much!) using MVC’s Model Binding, and then created some validation logic for it (if you’re not sure what I’m referring to in regards to “creating validation logic”, you’ll want to check out this article on MSDN before continuing).  As I started writing my validation logic in my Action and populating the ModelState with my validation errors like so:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Product product)
{
if (!product.IsValid())
{
if(string.IsNullOrEmpty(product.Name))
this.ModelState.AddModelError("name", "Please enter a product name");
if(product.Price < 0)
this.ModelState.AddModelError("price", "Price must be greater than 0");
if(product.Quantity < 0)
this.ModelState.AddModelError("quantity", "Quantity must be greater than 0");

return View(product);
}

productRepository.Add(product);
return View("Index");
}



Now, even if I moved this code outside of my Action, I’d still be pretty embarrassed of it…  but after looking at it for a while I realized that I don’t have to do this after all – the EntLib ValidationResult (usually) maps perfectly to MVC’s Model Binding…  and ModelState errors!  Check out the same code, taking advantage of the EntLib validation results:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Product product)
{
var validationResult = product.Validate();
if (!validationResult.IsValid)
{
foreach (var result in validationResult)
this.ModelState.AddModelError(result.Key, result.Message);

return View(product);
}

productRepository.Add(product);
return View("Index");
}



I added this and awesomeness ensued.  The magic comes from the fact that the Key field of the EntLib ValidationResult is the name of the property which is causing the validation error.  This leads to what I can do in line 8 above, which is just iterate through all of the validation errors and add their message to the ModelState using their Key property, which corresponds to the form id’s that we’re using to populate the model.  Just so you don’t think I’m lying, here’s what the form would look like:

<%= Html.ValidationSummary(
"Create was unsuccessful. 
Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Add New Product</legend>
<p>
<label for="Name">Name:</label>
<%= Html.TextBox("Name") %>
<%= Html.ValidationMessage("Name", "*") %>
</p>
<p>
<label for="Description">Description:</label>
<%= Html.TextBox("Description") %>
<%= Html.ValidationMessage("Description", "*") %>
</p>
<p>
<label for="Price">Price:</label>
<%= Html.TextBox("Price") %>
<%= Html.ValidationMessage("Price", "*") %>
</p>
<p>
<label for="Quantity">Quantity:</label>
<%= Html.TextBox("Quantity") %>
<%= Html.ValidationMessage("Quantity", "*") %>
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>



I Think We Can Do Just a Bit Better…



So, there you have it – easy validation using ASP.NET MVC Model Binders, MVC’s Validation components, and Enterprise Library’s Validation block.  The preceeding should work like a charm, but me being the perpetual perfectionist and idealist saw one more piece of duplication that I wanted to remove.  Namely, the foreach loop used to map the ValidationResults to the ModelState.  Using an extension method to extend the ValidationResults class, this duplication can easily be removed like so:

using System.Web.Mvc;
using Microsoft.Practices.EnterpriseLibrary.Validation;

public static class EntLibValidationExtensions
{
public static void CopyToModelState(this ValidationResults results, ModelStateDictionary modelState)
{
foreach (var result in results)
modelState.AddModelError(result.Key ?? "_FORM", result.Message);
}
}



Now the previous Action looks just a bit cleaner:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Product product)
{
var validationResult = product.Validate();
if (!validationResult.IsValid)
{
validationResult.CopyToModelState(this.ModelState);
return View(product);
}

productRepository.Add(product);
return View("Index");
}



And with that, I’m happy…  What do you think??

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.