Scott Hanselman

ASP 4 - Whirlwind Tour around .NET 4 (and Visual Studio 2010) Beta 1

May 19, '09 Comments [14] Posted in ASP.NET | ASP.NET Dynamic Data | ASP.NET MVC | TechEd
Sponsored By

Hey, we released Visual Studio 2010 Beta 1. JasonZ has a great post with piles of details and a metric crapload of screenshots. Definitely take a moment (or eight) and check out his very detailed post. You can get it NOW if you're an MSDN Subscriber, or after the general announcement on Weds if you're not.

UPDATE: My bad, of course it's called ASP.NET 4 and not ASP 4. Sorry, typo.

Should You Freak Out?

I don't think so. There's a lot of stuff that's new and added in .NET 4, but not in that "overwhelming-I-need-to-relearn-everything" way. More in that, "oh, this is way easier/simpler now" way. Like, moving data around with ADO.NET DataServices is easy, binding with client templates is easy, there's F# if you need it, the "dynamic" keyword if you need it, Silverlight's already installed, oh, and the parallel stuff will freak you out, but in a good way.

I'll do a series of posts on what I think is cool with lots of details. I'll put code samples up also as I can. I will also point out where you can already do much of this with 3.5 SP1, as well.

Here's a general outline of a small part of the goodness:

  • New Shell, new File|New, new Extensions Manager
  • Lots of focus on "Code First" (TDD-friendly, etc)
  • Office and COM Interop that is actually fun to do.
  • Automatic Properties for VB, no more "_" for multi-line, inline subs, collection initializers
  • C# gets the dynamic keyword
  • F# is included out of the box
  • WPF Databinding in the Designer
  • Silverlight included out of the box
  • Piles of HTML Snippets for non-designer people
  • Better JavaScript Intellisense
  • MSBuild for C++
  • UML for VS Team Architecture
  • TFS Branch and Changeset visualizers
  • Parallel computing
  • Workflow speedup, new designer
  • SharePoint tooling

Rather than try to top Jason with a laundry list of what's new and what not, here's some details on a few things that I find particularly interesting. They may be obscure to you, and perhaps not deeply interesting, but they were interesting enough to me that I used them for demos at TechEd last week (with a hat tip to Jonathan Carter and Jason Olson).

This is just a smattering of the features (hence: "Whirlwind" although "totally random cool stuff" would have also worked) coming in .NET 4. These are features I'm interested in because they've solved problems I've had in the past.

I'm realizing I'll definitely do these as separate posts because they're going to get long. First, ASP.NET and Ajax.

ASP.NET 4

There is an excellent whitepaper at http://www.asp.net/learn/whitepapers/aspnet40/ with a lot of detail on the changes in ASP.NET 4.

There's lots new in ASP.NET 4, but at TechEd09 I showed two. First was control over my controls' client ids. Rather than getting a generated ID like ctl09_list45_whatever99, I can make my control ids more predictable.

More Control over ClientIDs in WebForms

For example, here's a ListView (ol/li) of Television shows. It uses jQuery to be sortable. Notice the new attributes in asp:ListView, specifically ClientIDRowSuffix and ClientIDMode.

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Television Series Picker</title>
<link href="Default.css" rel="stylesheet" type="text/css" />
<script src="jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="ui.core.js" type="text/javascript"></script>
<script src="ui.sortable.js" type="text/javascript"></script>
<script type="text/javascript">

$(document).ready(function() {
$("#televisionList li").append("<div><span>Click</span></div>");
$("#televisionList").sortable({ handle: $("#televisionList li div") });
});
</script>
</head>
<body>
<form runat="server">
<h1>Television Series Picker</h1>
<p>Order the following television series' based on which you think is most awesome:</p>
<asp:ListView
DataSourceID="televisionDataSource"
ClientIDRowSuffix="ID"
ClientIDMode="Predictable"
runat="server">
<LayoutTemplate>
<ol id="televisionList">
<asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
</ol>
</LayoutTemplate>
<ItemTemplate>
<li id="televisionItem" runat="server">
<%# Eval("Name") %>
</li>
</ItemTemplate>
</asp:ListView>
<asp:ObjectDataSource
ID="televisionDataSource"
TypeName="_01_ClientId.TelevisionDataProvider"
SelectMethod="GetTelevisionSeries"
runat="server" />
</form>
</body>
</html>

The list is populated using an ObjectDataSource and I want the client id's to be created with a suffix using the ID property from the Television object.

Routing and WebForms

You probably know that System.Web.Routing is a big part of ASP.NET MVC, and you may know it's in .NET 3.5 SP1 as well. In .NET 4 it'll be even more easy to use with better support for WebForms. For example:

public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add("Product",
new Route("Products/{category}",
new PageRouteHandler("~/Products.aspx")));
}
}

Here I'm setting update a route such that /Products/SomeCategory routes to the /Products.aspx WebForms Page. The Category parameter is a RouteParameter and can be retrieved (of course) and used. System.Web.UI.Page has a RouteData parameter now, or you can refer to RouteValues in your ASPX markup. For example:

<p>The following are all the products within this category:</p>
<h2><asp:Literal Text="<%$ RouteValue:Category %>" runat="server" /></h2>

or into a Data Source via <RouteParameter>:

<asp:EntityDataSource
ID="productsDataSource"
ContextTypeName="AdventureWorksLTEntities"
EntitySetName="Products"
OrderBy="it.Name"
Where="it.Category.Name = @Category"
runat="server">
<WhereParameters>
<asp:RouteParameter
Name="Category"
RouteKey="Category"
Type="String" />
</WhereParameters>
</asp:EntityDataSource>

There will also be Routing Extension Methods like GetUrlForRoute or the like, in Beta 2, as well as IgnoreRoute. Basically anything that makes it simple, simple, simple to use Routes with WebForms. This'll be nice for hybrid WebForms/MVC apps as well.

Ajax 4

The Client Templates stuff in Ajax 4 is pretty sweet. This allows for 2-way data-binding using only JavaScript. For example, this template pulls from a JSON DataService at customers.svc. The JavaScript is below. We create a DataContext pointing to that endpoint, two DataViews that take the "customers-template" and "customer-template" HTML elements and creates a binding between them.

Sys.Application.add_init(function()
{
var dataContext = $create(Sys.Data.AdoNetDataContext,
{
serviceUri: "Customers.svc"
});

var customersTemplate = $create(Sys.UI.DataView,
{
dataProvider: dataContext,
fetchOperation: "Customers",
fetchParameters: { $top: 20, $orderby: "FirstName", $expand: "Orders" },
initialSelectedIndex: 0,
selectedItemClass: "selected"
},
null, null,
$get("customers-template"));

var customerTemplate = $create(Sys.UI.DataView,
null, null, null,
$get("customer-template"));

// This imperatively creates the binding
// between the customer grid and the customer
// detail form. When you select a record in
// the grid, it will automatically re-bind
// the detail view as well.
$create(Sys.Binding,
{
defaultValue: null,
source: customersTemplate,
path: "selectedData",
target: customerTemplate,
targetProperty: "data"
});

// This uses jQuery live event bindings to hook up
// the click event for the update button that will be
// "generated" when the customer detail form is bound.
$("#update-button").live("click", function()
{
dataContext.saveChanges();
});
});

Then we use jQuery live events, and then save the changes back to the dataContext. The changes that are made on the client side are tracked automatically, and those changes are sent back via JSON and commited. Note the source: and target: in the $create() call above that sets the master/detail relationship between customers and customer (singular.)

The client-side templates are similar to the server-side templates you probably already know how to use. You can even use expressions like to conditionally apply CSS.

image

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>AdventureWorks AJAX</title>
<link href="Content/Styles/reset-min.css" rel="stylesheet" type="text/css" />
<link href="Content/Styles/Default.css" rel="stylesheet" type="text/css" />

<script src="Content/Scripts/MicrosoftAjax.debug.js" type="text/javascript"></script>
<script src="Content/Scripts/MicrosoftAjaxTemplates.debug.js" type="text/javascript"></script>
<script src="Content/Scripts/MicrosoftAjaxAdoNet.debug.js" type="text/javascript"></script>
<script src="Content/Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>

<script src="Content/Scripts/Default.js" type="text/javascript"></script>
</head>
<body
xmlns:sys="javascript:Sys"
xmlns:class="http://schemas.microsoft.com/aspnet/class">
<h1>Customer Directory</h1>
<table cellspacing="0">
<thead>
<tr>
<th>Title</th>
<th>First Name</th>
<th>Middle Name</th>
<th>Last Name</th>
<th>Suffix</th>
</tr>
</thead>
<tbody id="customers-template" class="sys-template">
<tr sys:command="select" class:odd="{{ $index % 2 != 0 }}">
<td>{binding Title, defaultValue=}</td>
<td>{binding FirstName}</td>
<td>{binding MiddleName, defaultValue=}</td>
<td>{binding LastName}</td>
<td>{binding Suffix, defaultValue=}</td>
</tr>
</tbody>
</table>
<fieldset id="customer-template" class="sys-template">
<legend>{{ FirstName + " " + LastName }}</legend>
<label for="first-name">
<span>First Name:</span>
<input type="text" id="first-name" value="{binding FirstName}" />
</label>
<label for="middle-name">
<span>Middle Name:</span>
<input type="text" id="middle-name" value="{binding MiddleName, defaultValue=}" />
</label>
<label for="last-name">
<span>Last Name:</span>
<input type="text" id="last-name" value="{binding LastName}" />
</label>
<input id="update-button" type="button" value="Update" />
</fieldset>
</body>
</html>

This exact scenario can also be done declaratively with you having to write ANY JavaScript at all. The "declarations" from the JavaScript file above are replaced with declarative namespace statements like:

<fieldset
class="sys-template"
sys:attach="dataview"
dataview:data="{binding selectedData, source={{customersTemplate}}}"
dataview:sys-key="customerTemplate">
<legend>{{ FirstName + " " + LastName }}</legend>
...

And the result is the same as above:

image

It's important to point out that while you can go get the VS 2010 Beta 1, you can also play with this stuff TODAY running on .NET 3.5 SP1. Go over to the ASP.NET 4 Ajax Preview site on CodePlex.

Also, don't freak out that ASP.NET MVC isn't baked into VS2010 Beta 1. Phil explains here.

Related Links

Have fun!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Hanselminutes Podcast 162 - PowerShell 2.0

May 19, '09 Comments [0] Posted in Podcast | PowerShell | TechEd
Sponsored By

Windows_PowerShell_iconMy one-hundred-and-sixty-second podcast is up. Scott's at TechEd and bumps into Hal Rottenberg and Kirk Munro. Hal's a PowerShell IT guy and Kirk's a Powershell-focused Dev. What's new in PowerShell 2.0 and what's in it for the .NET developer or Windows power user?

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

Telerik is a sponsor for this show!

Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET and Windows Forms. Enjoy the versatility of our new-generation Reporting Tool. Dive into our online community. Visit www.telerik.com.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Hanselminutes Podcast 161 - BBSs and Wildcat! from Mustang Software

May 13, '09 Comments [12] Posted in Podcast
Sponsored By

SmallWc4logo My one-hundred-and-sixty-first podcast is up. Scott chats with founders of Mustang Software (creators of Wildcat! BBS) Jim Harrer and Scott Hunter about the BBS era. We start at 300 baud and work our way up. Remember Hayes modems, v.32bis, Fidonet, Compuserve? This is the show for you.

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

Telerik is a sponsor for this show!

Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET and Windows Forms. Enjoy the versatility of our new-generation Reporting Tool. Dive into our online community. Visit www.telerik.com.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Switching my Windows 7 Boot Disk from D to C with BCDBoot rather than BCDEdit

May 7, '09 Comments [22] Posted in Musings
Sponsored By

Disclaimer: It's very likely that I have NO idea what I'm talking about. This is a blog, not a technical article or official anything. Listening to me may well kill your pet kitten and render both your computer and you personally unbootable. Run away in fear as this is all completely useless information.

I paved (reformatted and started over) my main machine, formerly named QUADPOWER, now QUADPOWER7 to use the new Windows 7 RC a few days ago. I went through the process, but wasn't really paying attention. I have a tendency to just Next>Next>Next>Finish my way through most wizards. This will likely be the death of me at some point.

Anyway, my system is a little non-standard and I had at some point a year ago switched hard drives around to make the faster one be my boot drive. I did this by changing the boot order in the BIOs.

Fast forward a bit, and today I wanted to format my DATA drive - my D: drive - and the format applet said "not so fast."

I opened up Disk Management and it showed me this...

clip_image001

Yikes! See how my D: drive is Disk 0 and is marked as System, but my C: drive is Disk 1 and marked as Boot? That means that the Boot Configuration Data (BCD) is on my D: drive. I checked my BIOs, and it turned out, in fact, that I had told it to boot of that drive. However, I'd installed Windows to the other drive and got myself into this situation:

  • Disk 0 - D: Drive with BCD
  • Disk 1 - C: Drive with C:\windows and other booty

I couldn't format D: because it was what I booted off of. Poop.

I searched around and found all sorts of hard and scary descriptions of how to fix this. Basically it boiled down to:

Approach 1: Nuclear Option. Wipe and Start Over.

Approach 2: Copy the Hidden/System Boot Manager and Boot Folder over to the C: drive and run a tool called BCDEdit to move things around in 12 short steps. ;)

This was a scary prospect for me, because from my point of view, while this was a fairly advanced operation, I just wanted to switch where the boot info comes from.

Turns out there is a new (profoundly advanced, you have been warned) command line tool called BCDBoot.

C:\windows\system32>bcdboot /?

Bcdboot - Bcd boot file creation and repair tool.

The bcdboot.exe command-line tool is used to copy critical boot files to the
system partition and to create a new system BCD store.

bcdboot <source> [/l <locale>] [/s <volume-letter>] [/v]
[/m [{OS Loader ID}]]

source Specifies the location of the windows system root.

/l Specifies an optional locale parameter to use when
initializing the BCD store. The default is US English.

/s Specifies an optional volume letter parameter to designate
the target system partition where boot environment files are

copied. The default is the system partition identified by
the firmware.

/v Enables verbose mode.

/m If an OS loader GUID is provided, this option merges the
given loader object with the system template to produce a
bootable entry. Otherwise, only global objects are merged.


Examples: bcdboot c:\windows /l en-us
bcdboot c:\windows /s h:
bcdboot c:\windows /m {d58d10c6-df53-11dc-878f-00064f4f4e08}

This means that I could type this from an Administrator Command Prompt:

bcdboot c:\windows /s c:

And BCDBoot would basically re-gen the BCD stuff I needed on the C: drive given what it knows about the C:\Windows install.

I ran it, and rebooted. I immediately went into the BIOS and changed the Boot Order so that my 300 GIG C: faster drive (the one I thought I was booting off of all the time) was my startup drive.

Now, Disk Management shows that C:\ is both System and Boot and all is right with the world.

image

More subtle awesomeness from Windows 7.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

ELMAH and Exception Driven Development FTW

May 5, '09 Comments [53] Posted in ASP.NET | ASP.NET MVC
Sponsored By

Jeff blogged last month about Exception-Driven Development. I've been using ELMAH for years and you should too. Having great instrumentation in your app is such a joy. I added ELMAH to NerdDinner and have learned all sorts of things. It's amazing that someone would care to hack a site about Nerds eating dinner, but they try.

This wasn't a hack, but a great bug found in my Nerd Dinner Mobile code that I wouldn't have thought to look for. Here I'm getting a NullReference Exception...why?

image

Well, here's the code:

private bool UserAgentIs(ControllerContext controllerContext, string userAgentToTest)
{
return (controllerContext.HttpContext.Request.UserAgent.IndexOf(userAgentToTest,
StringComparison.OrdinalIgnoreCase) > 0);
}

Of course, I'm breaking the "Law Suggestion of Demeter" with all that digging, but what's the real issue? I'm assuming that the request has a UserAgent string at all! Exactly as the YSOD that ELMAH "tivo'ed" for me above.

So I changed it to this. Yes, I know that this could all be on one line and really baroque, but I find a few more lines to be easier to read.

public bool UserAgentIs(ControllerContext controllerContext, string userAgentToTest)
{
string UA = controllerContext.HttpContext.Request.UserAgent;
if (string.IsNullOrEmpty(UA) == true)
return false;
return (UA.IndexOf(userAgentToTest, StringComparison.OrdinalIgnoreCase) > 0);
}

I likely would have never thought of this bug had I not had logs and instrumentation. A smart user could have told me, or I could have used a Unit Test Generator like Pex, OR I could have just used my head and thought of it first. ;) Assert your assumptions. I didn't, and I assumed, wrongy, UserAgent would be non-null.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

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