Scott Hanselman

Hanselminutes Podcast 194 - Hello World: Computer Programmer for Kids and Other Beginners

January 15, '10 Comments [11] Posted in Podcast | Programming
Sponsored By

51dJNsAaLuL._SL500_AA240_ My one-hundred-and-ninety-fourth podcast is up. Scott chats with Warren Sande and his 10 year old son, Carter, about their new book "Hello World: Computer Programming for Kids and Other Beginners." Listeners can get 40% off Hello World! from Manning.com with the code "hanselm40". The offer is valid until Jan 31, 2010

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

Download: MP3 Full Show

Links from the Show

Links from the Show

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 our sponsor for this show.

Check out their UI Suite of controls for ASP.NET. It's very hardcore stuff. One of the things I appreciate aboutTelerik is their commitment tocompleteness. For example, they have a page about their Right-to-Left support while some vendors have zero support, or don't bother testing. They also are committed to XHTML compliance and publish their roadmap. It's nice when your controls vendor is very transparent.

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

2010 Survey Results: What .NET Framework features do you use?

January 14, '10 Comments [37] Posted in ASP.NET | ASP.NET Ajax | ASP.NET Dynamic Data | ASP.NET MVC | Learning .NET | Programming | Web Services | Windows Client | WPF
Sponsored By

In October of 2008 I took an informal survey on Twitter. I wanted to get an idea of what features of the .NET Framework people were using.

Also, here's the disclaimer. I did this on a whim, it's not scientific, so the margin of error is +/-101%. That said, the results feel intuitively right to me, personally.

I put the poll out again last week, adding only Silverlight to the end as an option. I realize I could have added many other subsystems and choices, but I felt it would have made this new poll too different from the original. There's certainly many ways that it could be improved as a survey, but it's best to think of it more as a "which direction is the wind blowing" question, than a survey per se.

I also didn't push/promote this survey very hard, so it got only about 1250 responses, vs. the nearly 5000 from last year, but I've kept the same color and attempted to keep the scale so one could extrapolate trends visually.

Hanselman Blog Informal .NET Subsystem Survey CHART - Updated 2010 

Here's the original survey:

Hanselman Blog Informal .NET Subsystem Survey CHART - 2008

It's also worth noting that 'NHibernate' was written into the "other" option 24 times. The poll was taken with TwtPoll.

Here's my conclusions.

  • WinForms remains popular but WPF is closing the gap.
  • ASP.NET MVC is nearly as popular as ASP.NET WebForms. Remember, however, that my readership 'skews Alpha' so might be more likely to be using MVC.
  • ADO.NET Data Services is starting to get some of the appreciation it deserves, but the existence of ADO Datasets persists.
  • Lots of folks use Silverlight, in this example set, even more than WPF.

What are your conclusions and analysis?

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

Favor - Help Us Test .NET 4 Beta 2 on Windows Update (WU)

January 14, '10 Comments [37] Posted in ASP.NET | Microsoft | Programming | VS2010 | Win7 | Windows Client | WPF
Sponsored By

The folks in the .NET Framework Setup team have a favor to ask, and it's pretty cool info so I offered to help. Here's the deal. When .NET 4 releases, the .NET 4 Client Profile will be released as a recommended update on Windows Update (WU) for Vista and Windows 7. It'll be listed as optional on Windows XP. They need help testing the WU parts.

You may have heard, but the .NET 4 Client Profile size is WAY smaller than before. There's been lots of cool improvements since the .NET 3.5 Client Profile. For example, on Window XP the download for .NET 4 Client is just ~28Mb for machines with no framework.

.NET Framework 3.5 SP1 Client Profile

.NET Framework 4 Client Profile

Web install only Local package and Web install.
Only Windows XP SP2 or SP3 and x86 architecture. All platforms and CPU architectures supported by the full .NET Framework 4 Beta 2 except IA64.
Separate from the framework. Part of the full .NET Framework. The .NET Framework is made up of the Client Profile and Extended components that exist separately in Add or Remove Programs.
Windows Update will upgrade it to the full .NET Framework. Independent component.
  • Can be serviced separated.

  • Does not need the full framework.

You may have noticed on Soma's blog that .NET Framework 4 launch was moved back a few weeks. About 6-8 weeks after the .NET Framework 4 launches, the .NET 4 Client Profile will show up on Windows Update (WU) and Windows Server Update Service (WSUS) as it's considered part of the serviceable operating system. It'll start deploying the .NET 4 Client Profile as either optional or recommended, depending on some rules. More technical details are here on Rabi Satter's blog post on .NET Framework 4 Beta 2 on WU. Of course, corporate customers can block or delay updates also.

Before all this happens though, we'd like to test the Windows Update part of things even more.

Read Carefully - Here's the Favor.

The .NET Framework 4 Beta 2 is up on Windows Update for a while for testing, IF you set this special registry key to "opt-in" for the test. Otherwise it won't get offered to you.

If you have a machine that doesn't have any .NET 4 bits on it, make a text file on your system with a name like "NETFX4.reg" and put this text in it:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4B2WU]
"OptIn"=dword:00000001

Then double-click this new registry file to create the key. Then check Windows Update and install the .NET 4 Beta 2 Client Profile. You can also do this key manually if you like.

Alternatively, you can open an Administrator Command Prompt and paste this command in. It'll have the same effect:

reg.exe add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4B2WU" /v OptIn /t REG_DWORD /d 1 /f

Don't worry, later in the year when .NET 4 is released, it'll install over the top of your installation and upgrade it. We'd like to get several thousand more WU-based installations in the next few days, so please try this out on any machines, VMs, or other machines you have lying around.

It's a very safe install. Remember it's a small download. It can be uninstalled, and it's installed side-by-side and it will NOT break any existing .NET 1.1, 2.0 or 3.5 installations. It will NOT make any of your existing .NET apps run under .NET 4.

Here's a screenshot of the package being offered on Windows 7 in Windows Update. I put in a Registry screenshot also.

The .NET Framework 4 Client Profile Beta 2 being offered in Windows Update

And here's the same package being offered on Windows XP in Windows Update.

 The .NET Framework 4 Client Profile Beta 2 being offered in Windows Update

If you do run into any rare problems then visit the .NET Framework 4 Setup & Deployment Support Forum as they really want to hear from you. They are actively manning the forum every day. I've installed this on all my VMs and six machines around the house with no problems.

Do me a favor and spread the word (blog, tweet, etc) about this test to your Alpha Geek friends. ;)

Related Links

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

Fixing Quiet or Low Audio output on the PDC Tablet PC - Acer 1420P Convertible

January 13, '10 Comments [17] Posted in Tools
Sponsored By

I finally got my hands (via eBay) on one of the Tablet PCs that were given away at PDC this year (effectively a custom Acer 1420P Convertible). It's fabulous. I easily upgraded the memory to 4GB for about $40 and that makes little netbook a nice portable developer rig.

One serious point of frustration that I understand may be common on Acer laptops is that the audio output is extremely low. Like really low. Think of quiet, and imagine it quieter than that. It effectively made the regular speakers totally useless for things like movies, etc.

I poked around in the audio settings and came up with these changes to make the audio tolerable.

First, right click on the little speaker near the clock and select Playback Devices:

image

Double click on the Speakers item:

image

Then click on the Enhancements Tab. Make sure that "Loudness Equalization" is checked and nothing else.

image 

Also, go to the Custom tab and make sure "Limited Output" is NOT checked.

These changes nearly doubled my speaker output and at least make it possible to watch a web video.

Enjoy!

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

The Weekly Source Code 47 - ASP.NET 3.5 Dynamic Data: FilterRepeaters and Dynamic Linq Query Generation

January 13, '10 Comments [5] Posted in ASP.NET | ASP.NET Ajax | ASP.NET Dynamic Data | ASP.NET MVC | Source Code
Sponsored By

First, let me start this post by thanking Tatham Oddie. He helped my buddy John Batdorf and I debug our issue remotely from Australia. He's patient, kind, opinionated and Tatham's got a darn fine blog that you should subscribe to now. I also found great inspiration from Stephen Naughton's excellent blog. He's continually pushing ASP.NET and Dynamic Data to do fun things and I was able to use 95% of his auto-complete code as I found it. And finally Marcin Dobosz's blog is where I started, taking his Dynamic Data sample Filter Repeaters and ending up at the Dynamic Data Futures samples.

Technical Disclaimer: This is me just messing about with the .NET 3.5 SP1 Dynamic Data samples as this non-profit wanted .NET 3.5. The Filters I'm messing with here are from the VS2008 SP1 Dynamic Data Futures from May of 2009 but are included out of the box and are much cooler in .NET 4 in Visual Studio 2010 Beta 2. Some method names and base classes have changed, but the idea is effectively the same. If you're using .NET 4 you'll notice you'll get the ~/DynamicData/Filters folder when you do File | New Project and a new QueryableFilterRepeater rather than an AdvancedFilterRepeater, and like that. In my 3.5 project I included the DynamicDataExtensions Project in my solution, while in .NET 4 all this functionality is in System.Web.DynamicData itself. I'll update this project and blog a sample when .NET 4 is closer to release.

Ok, the story is that John and I are doing some volunteer work and updating a local non-profit's website on the side in our copious spare time. They have simple needs, on the front end they want a nice simple autocomplete textbox and maybe a filter drop down or two. This'll send the user to a results page with a non-editable paged grid and a dynamically generated image for printing. On the backend, they want a few more dropdowns for admins and then a nice editable grid for searching, paging, etc.

We each thought this would be a fun opportunity to see if could put it together in a night and learn more about ASP.NET Web Forms and Dynamic Data at the same time. It's all very meta, so we decided we'd be meta also. (Remember, that means effectively "solution non-specific." We'd like to be able to use whatever things we create for ASP.NET Dynamic Data in other projects.)

Meta Meta

When creating a site with ASP.NET Dynamic Data, the pages you create are templates - they are kinds of pages - rather than instances of pages themselves. So, I create a List.aspx, and it's not specific to (in my case) Brick objects. It's for listing any kind of object I want to in my solution.

Here's a simplified example of my list.aspx in my Dynamic Data solution. The things we care about are that it has a:

  • LinqDataSource
  • GridView
  • AdvancedFilterRepeater - Again, this was the name it had in the 3.5 Dynamic Data Futures. It's an extension of the standard Filter Repeater that comes with ASP.NET. It has a DelegatingFilter in its ItemTemplate.

And that's it.

<ContentTemplate>
<asp:ValidationSummary ID="ValidationSummary1" runat="server" EnableClientScript="true"
HeaderText="List of validation errors" />
<asp:DynamicValidator runat="server" ID="GridViewValidator" ControlToValidate="GridView1" Display="None" />

<asp:AdvancedFilterRepeater id="AdvancedFilterRepeater" runat="server">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td valign="top"><%# Eval("DisplayName") %>:</td>
<td><asp:DelegatingFilter runat="server" ID="DynamicFilter" OnSelectionChanged="OnFilterSelectedIndexChanged" />
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:AdvancedFilterRepeater>

<asp:GridView ID="GridView1" runat="server" DataSourceID="GridDataSource"
AllowPaging="True" AllowSorting="True" CssClass="gridview">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="DetailsHyperLink" runat="server"
NavigateUrl='<%# table.GetActionPath(PageAction.Details, GetDataItem()) %>'
Text="Details" />
</ItemTemplate>
</asp:TemplateField>
</Columns>

<PagerStyle CssClass="footer"/>
<PagerTemplate>
<asp:GridViewPager runat="server" />
</PagerTemplate>
<EmptyDataTemplate>
There are currently no items in this table.
</EmptyDataTemplate>
</asp:GridView>

<asp:LinqDataSource ID="GridDataSource" runat="server" EnableDelete="false" EnableInsert="false" EnableUpdate="false">
<WhereParameters>
<asp:DynamicControlParameter ControlID="AdvancedFilterRepeater" />
</WhereParameters>
</asp:LinqDataSource>

<br />
</ContentTemplate>

The AdvancedFilter repeater is what's cool and it's what Marcin blogged about and that ended up in the samples. Stephen Naughton has since extended the FilterRepeater even more with his wonderful "Dynamic Data Futures" series.

The FilterRepeater is a special Repeater control that binds to a collection of columns (properties) in an table (list<object>) and make dynamically make controls that will allow filtering.

For example, here's my Brick object model (actually the "buddy metadata class" of my Brick object. It's a mirror of what's in the database:

[MetadataType(typeof(Brick_MD))]
public partial class Brick
{
public class Brick_MD
{
[Filter(FilterControl = "AutoComplete")]
public object Name { get; set; }

[Filter(FilterControl = "Integer", AuthenticatedOnly = true)]
public object Square { get; set; }

[Filter(FilterControl = "Integer")]
public object Year { get; set; }

public object Side { get; set; }

public object Row { get; set; }

public object BrickNum { get; set; }

public object Order { get; set; }
}

}

imageNotice the Filter attributes. I've extended it with a property called AuthenticatedOnly for properties that only authenticated users (non-anonymous) can see filters for. I've also said that one property/column needs an AutoComplete style filter (without being specific about the implementation) and two others need Integer style (again, implementation non-specific metadata. Could be combo, slider, whatever.)

ASP.NET Dynamic Data uses a special folder by convention called DynamicData with sub-folder like FieldTemplates for specific kinds of fields (Integer, DateTime, Person, etc) and PageTemplate for specific pages (List, Edit, Details, etc.)

The FilterRepeater sample extends this concept with a ~/DynamicData/Filters folder. This is set in the GetFilterControl method inside the FilterFactor if you want to see where the actual mention of the 'Filters' directory exists in the code. The point is that there's a string on my meta-model that says "AutoComplete" and that maps by convention to the ~/DynamicData/Filters/AutoComplete.ascx control, just as "Integer" maps to Integer.ascx, etc.

This is all Integer.ascx is, for example:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Integer.ascx.cs" Inherits="AdvancedFilterRepeaterSite.Integer_Filter" %>

<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true" EnableViewState="false">
<asp:ListItem Text="All" Value="" />
</asp:DropDownList>

It's just a dropdown list. When the FilterRepeater is checking out the columns/properties on the Brick_MD object, it's saying, "oh, I to put a Integer.ascx here" and it'll feed it the data it needs. All these controls like the Integer one derive from FilterUserControlBase and just have to override the properties or methods for the behavior they want to change.

All this is pretty straight forward, and you can do really cool stuff with it.

Dynamically Generating Generically Specific LINQ Queries

However, things got hairy when we noticed that the DropDownList being created didn't have the values sorted ahead of time. This made weird dropdowns with the integers in whatever order they were in the database already.

You would think you'd want some code like this behind your Integer Filter Control:

protected void Page_Init(object sender, EventArgs e) {
var items = Column.Table.GetQuery();

//magic psuedo code here
var result = items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue)

foreach (var item in result) {
if (item != null) DropDownList1.Items.Add(item.ToString());
}
}

Notice the "magic" part. That's the LINQ query we wish we could call, but remember that I don't want to make a query against a specific table and a specific column. If I did, this wouldn't be the Integer Filter Control, it'd be the Year Filter Control or the Month Filter Control. It'd be specific, not generic.

We need to dynamically create a LINQ query. But just like you don't want to just make dynamic SQL by concatenating strings, the same applies for LINQ. Instead we will use the System.Linq.Expressions.Expression base class to creating a tree that represents our LINQ query. Another metaphor/example would be using XmlDocuments and the DOM to make XML rather than making it with a bunch of strings.

We want effectively, this query, made specific. Each time this Integer Filter Control is run it'll be specific to the column (and even the type, arguably, could be something other than integer) we're currently making a control for.

Items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue)

We need the building blocks for this query, starting with whatever "row" is.

// row
var entityParam = Expression.Parameter(Column.Table.EntityType, "row");

Because we are a FilterUserControlBase, we can ask Dynamic Data for the typeof(row) which is in Column.Table.EntityType. We'll be using the types and info that DynamicData provides to create this query.

Next we get the Property of row by passing in (building on) the entityParam we just made. Now "columnLambda" is of type LambdaExpression.

// row => row.Property
var columnLambda = Expression.Lambda(Expression.Property(entityParam, Column.EntityTypeProperty), entityParam);

Next the Select. Here we are dynamically generating a LINQ function call. This is LINQ's idea of Reflection, effectively. The Type[] are the params. Remember what the Select call looks like: Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) and we're giving it just those things it wants.

// Items.Select(row => row.Property)
var selectCall = Expression.Call(typeof(Queryable), "Select", new Type[] { items.ElementType, columnLambda.Body.Type }, items.Expression, columnLambda);

Now we add just Distinct to the previous call. Look at the comment. See how we are building on the previous selectCall expression?

// Items.Select(row => row.Property).Distinct
var distinctCall = Expression.Call(typeof(Queryable), "Distinct", new Type[] { Column.EntityTypeProperty.PropertyType }, selectCall);

Here's what Tatham saved our bacon. I got turned around and he broke up my crazy one-liner into clearer code. Eilon Lipton helped me get this straight as well.

In the first expression, the "sortValue" string doesn't matter. It just has to be something so we can make a lambda that is x=>x.

In the second, we call the standard LINQ OrderBy and give it the (x=>x), or in this example the year=>year, so really,
Items.Select(brick => brick.Property).Distinct.OrderBy(year => year)

// colvalue => colvalue
var sortParam = Expression.Parameter(Column.EntityTypeProperty.PropertyType, "sortValue");
var columnResultLambda = Expression.Lambda(sortParam, sortParam);
// Items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue)
var ordercall = Expression.Call(typeof(Queryable), "OrderBy",
new Type[] { Column.EntityTypeProperty.PropertyType, columnResultLambda.Body.Type },
distinctCall, columnResultLambda);

Then we actually CALL the query and fill the dropdown list so here's the whole thing:

protected void Page_Init(object sender, EventArgs e) {
var items = Column.Table.GetQuery();
var entityParam = Expression.Parameter(Column.Table.EntityType, "row");

// row => row.Property
var columnLambda = Expression.Lambda(Expression.Property(entityParam, Column.EntityTypeProperty), entityParam);

// Items.Select(row => row.Property)
var selectCall = Expression.Call(typeof(Queryable), "Select", new Type[] { items.ElementType, columnLambda.Body.Type }, items.Expression, columnLambda);

// Items.Select(row => row.Property).Distinct
var distinctCall = Expression.Call(typeof(Queryable), "Distinct", new Type[] { Column.EntityTypeProperty.PropertyType }, selectCall);


// colvalue => colvalue
var sortParam = Expression.Parameter(Column.EntityTypeProperty.PropertyType, "sortValue");
var columnResultLambda = Expression.Lambda(sortParam, sortParam);

// Items.Select(row => row.Property).Distinct.OrderBy(colvalue => colvalue)
var ordercall = Expression.Call(typeof(Queryable), "OrderBy",
new Type[] { Column.EntityTypeProperty.PropertyType, columnResultLambda.Body.Type },
distinctCall, columnResultLambda);

var result = items.Provider.CreateQuery(ordercall);

foreach (var item in result) {
if (item != null) DropDownList1.Items.Add(item.ToString());
}
}

So what?

Conclusion

image Now I can add [Filter(FilterControl = "Integer")] to any meta-model in any of my ASP.NET Dynamic Data sites and automatically get a nice simple set of Filters, driven completely by attribute with their implementation both separate from my logic and completely generic to my tables.

For a complete working sample, go check out the VS2008 SP1 Dynamic Data Futures from May of 2009. I modified (barely) the Integer.acsx.cs to add the OrderBy which was flummoxing me. I needed to break it all down to figure out those few lines.

I also modified the FilterAttribute to add the AuthenticatedOnly attribute like [Filter(FilterControl = "Integer", AuthenticatedOnly = true)] :

using System;

namespace Microsoft.Web.DynamicData.Extensions {
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple=false)]
public sealed class FilterAttribute : Attribute {

public FilterAttribute() {
Order = Int32.MaxValue;
Enabled = true;
}

public string FilterControl { get; set; }

// Lower values take precedence before greater values
public int Order { get; set; }

public bool Enabled { get; set; }

public bool AuthenticatedOnly { get; set; }
}
}

...and the AdvancedFilterRepeater to act on that new property:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.DynamicData;
using System.Web.UI.WebControls;
using System.Web;

namespace Microsoft.Web.DynamicData.Extensions {
public class AdvancedFilterRepeater : FilterRepeater {

protected override IEnumerable<MetaColumn> GetFilteredColumns() {
// sort the filters by their filter order as specified in FilterAttribute.
return Table.Columns.Where(c => IsFilterableColumn(c)).OrderBy(column => column, new FilterOrderComparer());
}

protected bool IsFilterableColumn(MetaColumn column) {
if (column.IsCustomProperty) return false;

var filterAttribute = column.Attributes.OfType<FilterAttribute>().FirstOrDefault();
if (filterAttribute != null)
{
if (filterAttribute.AuthenticatedOnly == true && (HttpContext.Current.User == null || HttpContext.Current.User.Identity.IsAuthenticated == false)) return false;

return filterAttribute.Enabled;
}

if (column is MetaForeignKeyColumn) return true;

if (column.ColumnType == typeof(bool)) return true;

return false;
}

private class FilterOrderComparer : IComparer<MetaColumn> {
public int Compare(MetaColumn x, MetaColumn y) {
return GetWeight(x) - GetWeight(y);
}

private int GetWeight(MetaColumn column) {
var filterAttribute = column.Attributes.OfType<FilterAttribute>().FirstOrDefault();
return filterAttribute != null ? filterAttribute.Order : Int32.MaxValue;
}
}

}
}

Disclaimer: I did this in .NET 3.5 SP1. I'm still learning this deeper stuff myself, and I'd say that while this meta-LINQ stuff is powerful, it's too complex to generate dynamic LINQ. Remember also that this post is on the outer outer edge of what you'd want to do. It's not representative of a typical ASP.NET Dynamic Data experience, or a typical LINQ experience. However, it is nice to know that the whole thing is incredibly extensible just that if I want to go this deep, I can. I'll go talk to that team and see what they've got planned for the future! If we've missed something, leave it in the comments or email me and I'll update this post. I'll find out both what has been improved for ASP.NET Dynamic Data 4 and for C# 4.

Related Links

Good ASP.NET WebForms Resources and Blogs

Webforms Q&A

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.