"a place for my stuff..." -- a blog by John Nelson

 

 
 

Frankly, I’m surprised that it took until page 12 of the jQuery Cookbook to mention putting JavaScript at the bottom of the page before the closing </body> tag.  Pages load faster with the JavaScript at the bottom, and it removes the need to use the ready() function.  This is great advice.  Using a ContentPlaceHolder helps keep the scripts in their optimal location.

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>
    <asp:ContentPlaceHolder ID="TitleContent" runat="server" />
  </title>
</head>
<body>
  <div>
    <asp:ContentPlaceHolder ID="MainContent" runat="server" />
  </div>
  <script type="text/javascript"
    src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script>
  <!-- ScriptContent for putting JavaScript at the bottom of every page -->
  <asp:ContentPlaceHolder ID="ScriptContent" runat="server" />
</body>
</html>

Then, I’m able to include an <asp:Content> element inside of my View and use it freely.  Notice that I was able to include jquery.min.js above the ContentPlaceHolder, which means jQuery will already be warm for any JavaScript in my ScriptContent.

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
  About
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  <h2>About</h2>
  <div class="about-message"></div>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ScriptContent" runat="server">
  <script type="text/javascript">
    $('.about-message').text("This is the About Page!");
  </script>
</asp:Content>


Another added perk to this ContentPlaceHolder approach is that it lets me include other JavaScript libraries that individual Views might depend on.  Pretty simple, but I hope you enjoy it!

Thursday, January 21, 2010 10:00:41 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] -
ASP.NET MVC | JavaScript | jQuery

Last Saturday, Steve and I attended Philly.NET Code Camp 2009.2. There were about 475 attendees and 12 separate tracks, each with 5 sessions. Here is the list of tracks that I attended:

8:30 AM – Len Smith, “Test Driven Development and Dependency Injection”

10:00 AM – Jess Chadwick, “What’s New and Hot in .NET 4.0”

12:30 PM – Al Katawazi, “Enterprise ASP.NET MVC Application Development”

2:00 PM – Steve Bohlen, “Refactoring to a S.O.L.I.D. Foundation”

3:30 PM – Sara Chipps, “Making Your Personal Projects a Reality”

Overall, the tracks were great. I felt like I was able to get something out of each one. My interests were split, attending two new and upcoming topics and two craftsmanship* topics.

On the topic of all things new and exciting, here are some .NET 4.0 points of interest:

  • DLR (Dynamic Language Runtime)
  • Lazy (lazy instantiation of the generic type)
  • Code Contracts, with Runtime and Compile time checking
  • Covariance and Contravariance
    • IEnumerable b = new IEnumerable();
    • DoSomething(Action func); DoSomething(Base b => b.Value);
  • Named & Optional Parameters
    • A(B b, int i = 0); A(i: 5, b: new B());
  • PLINQ
    • Parallel.ForEach, parallelizes a task across a collection
  • MEF (Managed Extensibility Framework)
    • Provides Extensibility, and Dependency Management
    • Similar to IoC, but not quite there.

Enterprise ASP.NET MVC was interesting because it demonstrated true reuse of components in an MVC application. I was particularly interested in how he set up the MVC application, separating it into several projects. Each project had an extremely specific task:

  • Demo
  • Communication
  • QA
  • Security
  • Static Content

The presenter, Al Katawazi also mentioned referencing a separate project for all Static Content. He referenced a post by Nick Berardi about the Google App Engine that I found very interesting.

More bloggy goodness to come…

Monday, October 19, 2009 11:22:06 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
.NET 4.0 | ASP.NET MVC | Code Camp | Philly.NET

I must say that being able to use the Routing engine in ASP.NET MVC is liberating.  In the traditional web model, your browser is making a request for a file on some remote web server.  The server looks for that file, processes it, and makes a response.  This model works great, but what if you don’t want “.aspx” on the end of your Url?  Beyond that, relative paths on the server can take away from any readability your Urls may have had.  Ever tried explaining query string parameters to the average user?  Painful.

Routing isn’t a new thing by any means, but has recently become a reality in the world of .NET.  There’s a whole namespace dedicated to it in System.Web.Routing.  It allows you to create cognitive, user friendly, and meaningful Urls.  Time for an example.

Sam is on a project, and his program manager instructs him to create a user profile page for their application.  With some special permission, Sam is able to try out ASP.NET MVC.  Does he start coding at the drop of a hat?  Never.  Ever.  Requirements first!  One of the general requirements says “The average user knows what page the Url represents.”  Sam is a good programmer, so his gut reaction is a question: “How would the user know that a Url points to their own profile?”  He writes out on his whiteboard (because all good programmers write things out on a whiteboard):

Traditional ASP.NET Web Forms Way:

http://localhost:1234/Users/UserProfile.aspx?UserID=1&Username=johncoder
http://localhost:1234/Users/UserProfile.aspx?UserID=1

Ideal Ways in ASP.NET MVC:

http://localhost:1234/Users/1/johncoder
http://localhost:1234/Users/1
http://localhost:1234/Users/johncoder <- Possible naming conflicts, but previous two work fine.

Now that Sam knows how he wants to accomplish his goal.  He fires up Visual Studio and creates a new ASP.NET MVC Web Application.  He uses his company’s existing data access layer, which uses LINQ to SQL classes.  Routes point to Action Methods on Controllers, which means that Sam needs a UsersController:

public class UsersController : Controller
{
    public ActionResult Details(int id)
    {
        UserRepository repository = new UserRepository();
        User user = repository.FindUserById(id);
        return View(user);
    }
}


The Details Action Method finds the target User, and a View for the user model.  By default, it will use “Views\Users\Details.aspx”.  There’s more!

public class MyMvcApplication : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = "" }
        );
    }

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }
}


The above code appears in the Global.asax.cs file an MVC application by default.  “Default” is the name being assigned to this given route, and “{controller}/{action}/{id}” is the Url.  The anonymous object in the next line serves as the default values for this route.  Using this route, the Url to a user would look like this:

http://localhost:1234/Users/Details/1

This isn’t quite what he had in mind.  Sam needs to create a new route to facilitate his need.  Here’s what he came up with:

routes.MapRoute(
    "UserProfile",
    "Users/{id}/{username}",
    new { controller = "Users", action = "Details", username = "" }
);


There's a little trickery going on here. Notice that he made no mention of a controller, or even an action method in the Url. Instead, he is taking advantage of the default parameter values by using an anonymous type. Since he didn’t include “{controller}” in his Url, the anonymous object needs to specify which controller to use.  MVC is built to look for "controller" and "action" keywords, and allows you to add your own. In this case, he added "id" and "username" parameters. If the user does not specify an "id" value, the request will not match against this route, and continue searching the RouteCollection until it finds a match.  Since he specified a default “username” as an empty string, the user is not required to enter a username.  The Url in this route has “Users” hard coded into it.  That literally means that the Url has to have “Users” in it.

Another feature of the Routing engine is that it can be used to generate Urls, too.  Sam can change any View in his application to use an HtmlHelper method like so:

<%= Html.RouteLink(user.FullName, "UserProfile", new { id = user.Id, username = user.Username } ) %>


The first parameter is the anchor text. The second is the name of the Route that the engine should use. The properties of the anonymous object are the parameters in the Url.

Don’t you agree that this is much more flexible than relying on the file system to create Urls?  It is my honest opinion that attention to usability details (even as transparent as a Url) produces a professional, high quality product.  By taking advantage of newer features, like the Routing engine, we can escalate our standards to the next level.

Thursday, October 08, 2009 12:11:37 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] -
ASP.NET MVC | C# | Routing | Usability

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

© Copyright 2010
John Nelson
Sign In
Statistics
Total Posts: 24
This Year: 2
This Month: 0
This Week: 0
Comments: 1
 
  All Content © 2010, John Nelson