BusinessRx Community

Dedicated to the advancement of software, technology and the people who devote their lives to it.

Welcome to BusinessRx Community Sign in | Join | Help
in Search

BusinessRx Reading List

These blog entries are written by industry experts and leaders. We consider this content to be a good read for any software developer or web technologist.

January 2007 - Posts

  • Watch Out for Folder Names with Parentheses!

    I created a new web site project earlier this week using Visual Studio 2005 SP 1. Everything worked great except for building - when there was an error, no line numbers showed up in the Errors window! While this annoyance is sufferable when there are only a few pages, classes, and so forth in the project, as the number of pages and classes grew, the lack of line numbers made debugging increasingly difficult. There'd be some error message and then I'd have to track down where the error might reside out of the dozens of classes and pages that may have been modified since my last build. Urp.

    After needlessly putting up with this nuisance for a couple days, I decided to get to the bottom of this. I found the following newsgroup post to microsoft.public.vsnet.debugging from an obvious Simpsons fan, someone going by the name of Rainier Wolfcastle:

    “It turns out that there is some really helpful bug in Visual Studio 2005 whereby you don't get file names or line numbers in the Error List if your solution lives in a directory with parentheses in the path.”

    Sure enough, the parent folder of the root of the web site application had a parenthesis in it. Once that was removed, line numbers returned to the Errors window. I wonder why this wasn't fixed in SP 1...

  • ASP.NET AJAX 1.0 Source Code Released

    As I mentioned last week when ASP.NET AJAX 1.0 shipped, we are publishing the full source code to the ASP.NET AJAX product.  This includes the source to the server-side ASP.NET integration (including the UpdatePanel, UpdateProgress, and ScriptManager controls, as well as the source to the Network Serialization code).

    The client-side ASP.NET AJAX JavaScript library (which we also call the "Microsoft AJAX Library") is being released under the Microsoft Permissive License (Ms-PL).  This grants developers the right to freely customize/modify the library, as well as to redistribute the derivative versions of the JavaScript library for both commercial and non-commercial purposes. 

    The code for the server-side ASP.NET AJAX 1.0 implementation was released this morning.  You can download it here.  It is being released under the Microsoft Reference License (Ms-RL).  Included with the source code are debugger symbols for the shipped binary, which will allow you to step from your own code into the ASP. NET AJAX library while debugging, with line number and symbol data preserved.  Note that the setup installs the source code locally on your machine within the "\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\Source" directory.

    You can also obviously download (and modify) the source code for the ASP.NET AJAX Control Toolkit.  It is built as a collaborative CodePlex Project that both Microsoft and non-Microsoft developers contribute code and work on together.

    Thanks,

    Scott 

    P.S. I'm hoping on a plane to Europe in an hour for my presentations in Belgium and the UK, and will be out the rest of this week (it only took me 3 frantic hours to find my passport last night -- sheesh).  As a result there will be some delays with blog comments (and my responses to them) while I'm away. 

     

  • Passing Information Between Master Pages and Content Pages

    I teach two ASP.NET classes through the Extension program at the University of California - San Diego, and one of the most common questions I am asked regarding Master Pages is, “How do I pass information from my Master Page to its content page (or vice-a-versa)?”

    For example, in the ASP.NET Programming II class, students create a custom site map provider whose structure is based upon the data in the database. The Master Page contains navigation controls (a TreeView, perhaps, or a Menu) that uses this custom site map provider. The challenge is on administrative pages, where an admin might add, update, or delete the corresponding database data, the Master Page's navigation is rendered before the content page executes its database command to modify the site map structure. Consequently, the page's navigation is not up-to-date immediately after modifying the site map structure (although it picks up the changes on the next postback). This can be remedied by having the content page tell the Master Page, “Hey, you there! I just updated the site map data, so go ahead and rebind the site map data to your TreeView.“

    This begs the question, How do you get the content page and Master Page talking? To address this question, I wrote up an article discussing different techniques: Passing Information Between Content and Master Pages.

  • 500

    I've averaged 13.5 posts per month over the last 37 months to arrive at today's post #500.I'm not sure if I'll make another 500 posts, but I have pages of notes for posts covering ASP.NET, AJAX, Windows Workflow, WCSF, and more. I also have enough material for at least 15 more "What's Wrong with This Code" posts, which several people have told me are fun and educational. One day, I might even finish my "Design Patterns - A Love Story" post. Then again, maybe that story should be purged from the Internet forever. 

    Thanks for reading!

  • Video: Using LINQ with ASP.NET in VS "Orcas" (Part 1)

    One of my goals this year is to use video more with my blog.  My theory is that video is often a better medium than text to walkthrough how something works, and can also help you avoid the tedium of reading though some of my really long blog posts... :-)

    Over the next few months I'm going to try and create a new video every other week or so on various topics.  Many of these videos are going to involve first looks at some of the new features coming with Visual Studio "Orcas", which is our new release that will ship later this year.  For today's video I decided to focus on introducing LINQ - which I think is one of the most exciting features coming with "Orcas". 

    At a high-level, LINQ makes the concept of query a first class programming concept within .NET.  Using LINQ you can easily query relational databases, XML files, as well as any plain-old .NET object.  You can also easily use your own data source abstractions with LINQ to provide rich domain models for various data providers (for a great example of this check out Fabrice's LINQ to Amazon implementation that supports LINQ queries against Amazon data exposed via web-services).  Both VB and C# include rich language integration with LINQ as part of the "Orcas" release, including full intellisense, compile-time checking, and debugging support.

    Watch or Download the Video

    This first video starts with a new project, and then demonstrates the basics of using LINQ against a SQL Database to build a simple data reporting page (including support for aggregate values computed from multiple tables, and efficient server-side paging within the database). 

    You can watch the video online here (it is 24 minutes in length).  Or you can download a .zip version of it here if you want to save and watch it locally.  Note that it might take 30-60 seconds to buffer (since it is a large video).  In the event that my server is swamped with requests, I'll update the location and post it on one of the Microsoft video servers later this week.

    For more information on LINQ (including the slide deck for a "Building ASP.NET Data Driven Application Using LINQ" talk of mine), please check out my previous post here.  For other ASP.NET 2.0 Tips, Tricks and Tutorials please check out my ASP.NET Tips and Tricks summary listing page.

    Specifics Topics Covered in this Video

    My walkthrough in this video illustrates a number of new features:

    1) A brief demonstration of some of the new WYSIWYG HTML designer capabilities (including split-view and a brief look at the new CSS manager - both of which I'll cover in more detail in the future in a separate video):

    2) How to create classes that model data using the new VS "Orcas" ORM designer for LINQ to SQL:

    3) How to use the new LINQ intellisense support within the VS "Orcas" code editor to get full intellisense and compilation support for queries:

    4) How to use LINQ to SQL to create a data report that combines Product entity data with aggregate unit and revenue values computed from OrderDetail entities associated with the Product entities.  This data report uses server side database paging to efficiently retrieve only 10 rows of data at a time (so that with a 100,000 row products table you only ever retrieve 10 rows of data from the database regardless of which page index you are on within a report):

    Future Videos

    I'll be drilling into LINQ some more with future videos (I barely scratched the surface with this one).  Additional segments will include content on:

    • Type inference and the "var" keyword (and why that is so cool)
    • Supporting Insert, Update and Deletes scenarios using LINQ to SQL
    • Using SPROCs with LINQ to SQL
    • Richer JOIN support with LINQ to SQL
    • LINQ to XML and LINQ to Objects
    • Using the new LINQDataSource controls and other ASP.NET Data Controls to easily create Web UI with LINQ

    I'll also obviously have many more ASP.NET and web-related video topics to cover including:

    • The new HTML WYSIWYG Designer and CSS support
    • Client-JavaScript Intellisense
    • JavaScript Debugging
    • ASP.NET AJAX Extender Support
    • Database Dump and Upload Integration
    • Unit Testing
    • Multi-targeting support (showing how you can use VS "Orcas" to build ASP.NET 2.0 projects - without having to upgrade your framework/server)

    Hope this helps,

    Scott

    P.S. If you have other topics and/or subjects you'd like me to drill in on with videos, please post them in the comments section of this post.

  • Great Response to Windows Developer Power Tools Day

    Check out some of the great posts we got in response to our “unilaterally declaring Friday, January 19th to be Windows Developer Tools Day.”

    Tools for powering Windows and Web Development – Anand Narayanaswamy

    Windows Developer Power Tools – Ben Carey

    Editor’s Pick – David  Dossot

    Windows Developer Tools Day – Avonelle Lovhaug

    Resharper – Developer Tool of the Day – Jason Lautzenheiser

    My Favorite Tool – Jay Flowers

    Windows Developer Power Tools Day Today! – Jeff Blankenburg

    PureText – Joe Wirtley

    2006 Microsoft Developer Out of Box Releases – Josh Ledgard

    Three Reasons to Use FitNesse – Micah Martin

    Windows Developer Tools Day — My Favorite Tools – Michael Eaton

    Power tools: ReSharper, definitely the most intelligent add-in to VS – Patrick Riva

    Windows Developer Tools Day – Paul Bartlett

    Windows Developer Tools Day – Phil Haack

    Windows Developer Tools Day – Rhys Jeremiah

    In Conjunction with Windows Developer Tools Day 2007 – Salocin.TEN

    Windows Developer Tools Day – Shawn Weisfeld

    Windows Developer Tools Day – Steve Pietrek

    Windows Developer Power Tools Book – Dan Fernandez

    Windows Developer Tools Day – Donald Belcham

    If you posted and I missed you drop a comment or send me an email and I will get you added!

    -James

  • The Confusing "Cannot implicitly convert type 'string' to 'System.Web.UI.WebControls.TextBox'" Compilation Error

    When building an ASP.NET 2.0 application in Visual Studio 2005, I received the following error: “Cannot implicitly convert type 'string' to 'System.Web.UI.WebControls.TextBox'”. No line number, no source page informing me where to begin my search. And it had been a while since my last build so there was a lot of code and markup that could be the source of the problem.

    A quick Google search turned up this entry by Sam Judson:

    Strange ASP.NET 2.0 Error

    While developing a new web site using ASP.Net 2.0 recently I came across this strange error on compilation.

        Cannot implicitly convert type 'string' to 'System.Web.UI.WebControls.TextBox'
    

    It took my ages to work out what the hell was the problem, which string was it trying to convert?

    The problem occurred because of the new Page.Title property. I had a TextBox whose ID was also set to Title. It was therefore trying to convert the string in the Page declaration into a textbox - not gonna work! This Title property is new for ASP.Net 2.0 so you might want to watch that one in your apps.

    And that was the cause of my problem, a TextBox with an ID of Title. Once the ID was changed to something else, the project compiled without error. For more on the Page.Title property new to ASP.NET 2.0, see Dynamically Setting the Page's Title in ASP.NET 2.0.

  • .NET Masters Lecture Series :: Los Angeles, CA :: Saturday, February 10th

    In a couple of weeks I'll be presenting a full-day, hands-on conference/lecture/class/lab at the Robert Half Technology offices in Los Angeles. Together we will build a complete, functional, real-world blog engine that highlights recommended practices and ASP.NET 2.0-specific features. Topics discussed and implemented will include: using base page classes for encapsulating common functionality; logging and gracefully handling errors; building data access and business object layers; working with data through the ObjectDataSource; displaying and customizing data using the data Web controls; efficiently paging and sorting data; and employing caching to boost performance.

    There is only room for 50 attendees and, at the time of this writing, close to half the spots are already taken. There are no computer workstations, so attendees are encouraged to bring their own laptops loaded with Visual Studio 2005 and SQL Server 2005 to follow along. (The free versions - Visual Web Developer and SQL Server 2005 Express Edition - will suffice.)

    Here are the details:

    • Cost: $45 (includes lunch; parking nearby for an additional $6-7 for the day)
    • When: Saturday, Feburary 10, 2007, 9:00 AM - 5:00 PM (with a one hour lunch break)
    • Where: Robert Half Technology, 10877 Wilshire Blvd, 4th floor (Suite 400), Los Angeles, CA 90024-4341, Phone: 310.209.6838 [map]
    • Signup: To sign up, use the PayPal link at http://www.ladotnet.org/EventDescription.asp?133

    Hope to see you there!

  • Links to ASP.NET AJAX 1.0 resources, and answers to some common questions

    Below are a few links to some ASP.NET AJAX 1.0 resources, and answers to a few common questions I've seen with the ASP.NET AJAX 1.0 release:

    Great Free Resource: ASP.NET AJAX PDF Cheat Sheets

    Milan has updated his great ASP.NET AJAX PDF Cheat Sheets for the ASP.NET AJAX 1.0 final release. 

    You can download his updated versions here.  Make sure to subscribe to his blog to receive updates as new ones come out.

    Common Gotcha: Restart IIS and Flush your Browser Cache after Install

    I've seen a few cases where people are seeing older versions of the ASP.NET AJAX scripts being used even after upgrading to the ASP.NET AJAX 1.0 release.  Often this manifests itself with a client-side JavaScript error about Sys.Debug not being found.  Two things to check if you encounter this:

    1) Make sure you restart IIS after you install ASP.NET AJAX (you can type "iisreset" on the command-line to-do this).  If IIS already has an older version of the ASP.NET AJAX assembly loaded when the new one is installed, it will continue to use the already loaded older version until the next time the worker process is restarted.  Restarting the worker process will cause it to pick up the new one.

    2) Make sure you clear your browser cache if your browser is setup to store cached files forever.  This will avoid you running into issues where your browser still has old versions of the .js files in its cache, and uses these instead of fetching the newer versions from the server.

    Common Gotcha: PageMethods now require the EnablePageMethods property to be set on the <asp:scriptmanager> control

    I've seen a few people run into an issue where their static AJAX Page Methods no longer seem to work when upgrading an ASP.NET AJAX RC application to the final V1 release.  The reason for this is that ASP.NET AJAX Page Methods are no longer exposed by default on a page except if you set the "EnablePageMethods" property to true on the <asp:scriptmanager> control.  For example:

    <asp:scriptmanager id="s1" EnablePageMethods="true" runat="server"/>

    Once you set this attribute to true, everything else will work the same.  You can learn more about how to use PageMethods in the ASP.NET AJAX 1.0 documentation here.

    Common Gotcha: Validation Controls used within the <asp:updatepanel> control

    I've seen several people run into an issue where their validation controls no longer work inside an <asp:updatepanel> when upgrading to the RTM release. 

    In the Beta1, Beta2 and the RC versions ASP.NET AJAX provided a set of "compatibility" controls that used the <tagMapping> web.config feature within ASP.NET to replace the built-in ASP.NET validation controls with AJAX aware controls that could be used within the <asp:updatepanel> control.  This made it appear like you were using the standard ASP.NET validation controls within your site - when in reality you were using a new set of controls that added AJAX hooks.

    For the final release of ASP.NET AJAX, we decided to instead release a patch for ASP.NET 2.0 that adds the AJAX-awareness features directly into the real ASP.NET 2.0 validation controls.  This ensures that the controls work in all scenarios, and is a much cleaner and more reliable solution.  Unfortunately, though, this patch slipped a few weeks - and so wasn't pushed out via Windows Update in time for the ASP.NET AJAX 1.0 launch.

    As a temporary workaround until the patch is available, you can download the same compatibility validation controls we provided with the release candidate, and map the built-in ASP.NET validation controls to them using the <tagMapping> feature in your web.config file (just like in the RC release):

    <tagMapping>

       
    <add tagType="System.Web.UI.WebControls.CompareValidator" 
            mappedTagType
    ="Sample.Web.UI.Compatibility.CompareValidator, Validators, Version=1.0.0.0"/>

       <
    add tagType="System.Web.UI.WebControls.CustomValidator" 
            mappedTagType
    ="Sample.Web.UI.Compatibility.CustomValidator, Validators, Version=1.0.0.0"/>

       <
    add tagType="System.Web.UI.WebControls.RangeValidator" 
            mappedTagType
    ="Sample.Web.UI.Compatibility.RangeValidator, Validators, Version=1.0.0.0"/>

       <
    add tagType="System.Web.UI.WebControls.RegularExpressionValidator" 
            mappedTagType
    ="Sample.Web.UI.Compatibility.RegularExpressionValidator, Validators, Version=1.0.0.0"/>
       
       <
    add tagType="System.Web.UI.WebControls.RequiredFieldValidator" 
            mappedTagType
    ="Sample.Web.UI.Compatibility.RequiredFieldValidator, Validators, Version=1.0.0.0"/>
       
       <
    add tagType="System.Web.UI.WebControls.ValidationSummary"
            mappedTagType
    ="Sample.Web.UI.Compatibility.ValidationSummary, Validators, Version=1.0.0.0"/>

    </
    tagMapping>

    The validation controls will then work fine within <asp:updatepanel> controls, and behave exactly the same as with the release candidate version.  You can download these compatibility controls here.

    Hope this helps,

    Scott

  • My Upcoming Presentations in Belgium, London, and Orlando

    I just wanted to give a quick update on a few presentations I'm giving in the weeks ahead:

    Brussels, Belgium: I'll be presenting two talks ("First Look at Visual Studio and ASP.NET 'Orcas' and "ASP.NET 2.0 and ASP.NET AJAX Tips and Tricks") in Belgium on February 1st (next Thursday).  You can attend the event for free.  More details can be found here.

    Reading, England: I'll be presenting four talks ("First Look at Visual Studio and ASP.NET 'Orcas', Building an end-to-end application using IIS7, ASP.NET 2.0, ASP.NET AJAX and VS 2005 Part 1 and 2, and "First Look at WPF/E") at the WebDD event at the Microsoft campus in Reading on Saturday February 3rd.

    Orlando, Florida: I'll be presenting the keynote and several breakout sessions at the ASP.NET Connections conference in Orlando from March 25th->28.  If you haven't attended ASP.NET Connections yet, I highly recommend it.  It will have 40+ great talks done by excellent speakers in a great location.  You can learn more about it here.

    Hope to see some of you at the upcoming events!

    Scott

  • More on Managing Windows Workflow Events in ASP.NET

    In the last post I pointed out problems you can experience trying to handle workflow events in an ASP.NET page. Before we get to a working solution, let's take a look at another pitfall.

    We know the default WF scheduling service will select a thread from the CLR thread pool to execute workflows asynchronously. Generally speaking, this isn't a good approach for server side applications because we can tie up too many threads. Instead, we use the ManualWorkflowSchedulerService. The manual scheduler lets us run workflows on the same thread that is processing the HTTP request. We just need to call RunWorkflow on the service whenever we need a workflow to execute.

    It's tempting to think the manual scheduler can make life easier since we don't have to worry about threads. For instance, let's suppose we want any unhandled faults originating from inside a workflow to bring the current request to a screeching halt. We want unhandled exceptions! When a workflow faults and throws an exception, WF will catch the exception and raise a WorkflowTerminated event. This event will fire on the same thread as the request that ran the faulty workflow.

    Knowing that we want to end requests with an error, we could try to use global.asax like the following. After all, if we throw an exception on the current request thread, we should create the yellow screen of death (assuming the Page doesn't have an exception handler). Note: I'm using global.asax just to make this simple.

    void Application_Start(object sender, EventArgs e)
    {
        _workflowRuntime =
    new WorkflowRuntime("wfConfiguration");

        _workflowRuntime.WorkflowTerminated +=
            
    new EventHandler<WorkflowTerminatedEventArgs>
                (_workflowRuntime_WorkflowTerminated);

        _workflowRuntime.StartRuntime();

    }
      
    void _workflowRuntime_WorkflowTerminated
            (
    object sender, WorkflowTerminatedEventArgs e)
    {
        
    throw e.Exception;        
    }
            
    private static WorkflowRuntime _workflowRuntime;

    The problem is that the WorkflowRuntime is dedicated to its job. The runtime is tasked with telling all the event subscribers that a workflow terminated, and it is not going to let some unhandled exception prevent the rest of the subscribers from missing events. The WF runtime swallows our exception. See Ken Getz's article for how to use GetInvocationList to achieve this behavior.

    How can we communicate the exception back to the Page? Consider the following code.

    void _workflowRuntime_WorkflowTerminated
            (
    object sender, WorkflowTerminatedEventArgs e)
    {
        
    HttpContext.Current.Items["WorkflowResult"] = e.Exception;
    }

    Now the web form can pull the exception out of the HTTP request context. Problem solved!

    Oh, but wait - we are spiraling out of control. Now the ASP.NET developer has to remember to start workflows with the manual scheduler, and check the request context for exceptions, and use such and such a communication service to raise events to the workflow.

    If you are going to the trouble to use Windows Workflow in an ASP.NET application, then you have an architectural responsibility to abstract away these problematic and sometimes dangerous scenarios to the point that the ASP.NET developer doesn't even know there is a workflow driving the process. Bring a mediator to the party.

  • ASP.NET AJAX 1.0 Released

    I am really excited to announce that the final release of ASP.NET AJAX 1.0 (aka "Atlas") shipped this morning.  You can download it here.

    ASP.NET AJAX 1.0

    ASP.NET AJAX 1.0 delivers a rich client-side AJAX library that provides cross platform, cross browser support for a core JavaScript type-system, JSON-based network serialization stack, JavaScript component/control model, as well as common client JavaScript helper classes.  ASP.NET AJAX also delivers a rich server-side library that integrates AJAX functionality within ASP.NET, and enables developers to easily AJAX-enable existing ASP.NET 2.0 sites with minimal effort. 

    ASP.NET AJAX is available for free, and can be used with ASP.NET 2.0 and VS 2005.  It is a fully supported Microsoft product, and is backed by a standard 10 year Microsoft support license (with Microsoft Product Support available via phone 24 hours a day x 7 days a week). 

    ASP.NET AJAX Control Toolkit

    In addition to the fully-supported ASP.NET AJAX 1.0 release, you can use the more than 30 free ASP.NET AJAX enabled controls available within the ASP.NET AJAX Control Toolkit.  The control toolkit is a shared-source collaborative project built together by a team containing both Microsoft and non-Microsoft developers (visit the CodePlex Project to learn more, or volunteer to contribute).  All source for the controls is provided completely for free (with full re-use and modification rights). 

    The majority of controls within the ASP.NET AJAX Control Toolkit leverage the "Control Extender" pattern that the core ASP.NET AJAX library introduces, and which delivers a super powerful way to easily enable specific AJAX scenarios on a site with minimal effort.

    For example, consider the scenario where you want to add a cool AJAX calendar picker to a page (note that the browser below is Opera):

    To enable this with the ASP.NET AJAX Control Toolkit you can simply add a <ajaxToolkit:CalendarExtender> control to a page and point it at a textbox to store the date (no additional code required):

      <asp:TextBox ID="DateTextBox" runat="server" />
      
      <
    ajaxToolkit:CalendarExtender ID="Calendar1" runat="server" TargetControlID="DateTextBox" />

    The ASP.NET AJAX Control Toolkit will continue to grow and expand in the months ahead - with more controls, features (and bug-fixes) being added every month.  The new version of the AJAX Control Toolkit that ships today adds support for 4 new controls to the Toolkit: <ajaxToolkit:CalendarExtender>, <ajaxToolkit:MaskedEditExtender>, <ajaxToolkit:TabContainer>, and <ajaxToolkit:AutoCompleteExtender>.  You can try samples of them all out online here

    (Special thanks to Ron and Fernando for implementing the new Calendar, Tab, and MaskedEdit controls added this month). 

    ASP.NET AJAX 1.0 Source Release

    In addition to shipping the source code for the ASP.NET AJAX Control Toolkit controls, we are also releasing all of the source code for the fully supported ASP.NET AJAX 1.0 release.  Specifically:

    We are releasing the client-side ASP.NET AJAX JavaScript library (which we also call the "Microsoft AJAX Library") under the Microsoft Permissive License (Ms-PL).  This grants developers the right to freely customize/modify the library, as well as to redistribute the derivative versions of the JavaScript library for both commercial and non-commercial purposes. 

    To help with debugging and development, we are also releasing all of the source code for the server-side ASP.NET AJAX 1.0 implementation (including the UpdatePanel, UpdateProgress, ScriptManager, and Network Serialization code) under the Microsoft Reference License (Ms-RL).

    Changes between the ASP.NET AJAX Release Candidate and RTM Build

    We made a number of improvements and bug fixes between the ASP.NET AJAX Release Candidate and RTM builds.  These included:

    • Performance and scalability improvements for shared hosting scenarios.
    • Globalization fixes to ScriptManager and ScriptResource handler to support date & number parsing and UI culture fallback.
    • Updated ScriptResource handler to support automatic enabling/disabling JavaScript compression based on browser type.
    • Support for substitution caching to enable more fragment caching scenarios.
    • Additional bug fixes and overall robustness improvements.

    More complete documentation covering all changes can be found on the http://ajax.asp.net website. 

    If you have installed previous versions of ASP.NET AJAX on your system, I recommend that you delete the cached VS schema files for control markup that VS maintains to provide HTML view intellisense.  This will ensure that your HTML source editor Intellisense for the ASP.NET AJAX controls is correct and doesn't get lost (otherwise it might incorrectly use the old values from the Beta2 release and generate errors).     

    • With Windows XP you do this by deleting all files in this directory: c:\Document and Settings\[YourUserName]\Application Data\Microsoft\VisualStudio\8.0\ReflectedSchemas
    • With Windows Vista you do this by deleting all files in this directory: c:\Users\[YourUserName]\AppData\Roaming\Microsoft\VisualStudio\8.0\ReflectedSchemas

    Future Plans

    While the core ASP.NET AJAX 1.0 release is now officially shipped, we are definitely not slowing down. :-) 

    All of the ASP.NET AJAX 1.0 features will be integrated directly into the next release of ASP.NET (codename: "Orcas").  Visual Studio "Orcas" will also provide client-side JavaScript intellisense, JavaScript compilation checking, and rich JavaScript debugging support for ASP.NET AJAX scenarios. 

    We are also already at work on the next ASP.NET AJAX release, and will continue to add new features and improvements to the supported ASP.NET AJAX core.  You can already start using many of these new features with the ASP.NET AJAX Futures CTP (available for download now on the ASP.NET AJAX site - it also supports a "go live" license).

    Summary

    We are really excited about having the ASP.NET AJAX 1.0 release finally out.  It will dramatically simplify adding rich AJAX functionality to ASP.NET 2.0 applications, and is going to significantly improve user experience for customers. We are really looking forward to seeing all the great applications you build with it!

    Thanks,

    Scott

  • Hummingbird DM AEM: Automated Email Management

    I've had the opportunity lately to work with Hummingbird's Document Management (DM) system on one of my projects at Mimsware.  In particular I was tasked to install, configure, and learn about their Automated Email Management (AEM) system in a test environment.  What is AEM?  It is basically a plugin for MS Exchange that makes it possible for all emails in an organization to be automatically archived into the Hummingbird DM system according to flexible rules that you define.  The goal for some organizations will be to make legal compliance of email retention automatic, and any necessary legal discovery very easy, especially important in a government organization with open record laws.  Other organizations may also be interested in simply making email work like all other documents, so that one document management system can be used to store and search all types of documents in the organization.

    I was able to get AEM working effectively, but there were also several aspects of the installation and configuration that were not documented well, or which required a lot of trial and error, so I want to share some of the lessons learned.  We are using DM version 5.1.0.5 SR6, so that is what I installed for AEM to begin with, but at least on my system it would not start up successfully after an apparent successful install, so I had to use patch SR6 MR2.  I suppose some will say that you should always use the latest version, but a Hummingbird installation is a very complex beast, so once you have something in place that works for you, its a big deal to update everything.  Luckily in this case I was able to only install the new version for just AEM and leave the rest of the DM system on the current version, but even that was something that had to be thoroughly tested, and there may still be some unknowns.

    Once I had it installed it quickly became a very long and involved process to configure things correctly, but most of this was documented and in most other cases the log was sufficient.  I think the biggest problem is that everything is too configurable and that there are no smart defaults, and yet for this type of system there are a lot of defaults that just seem to be obvious.  For instance, they provide a default email profile, with fields to store the from, to, cc, bcc, received date, and send date, but none of these are configured for you so you have to specify both the profile and every one of these fields.  We also had some other custom fields that had to be set, and of course I would expect that to be my task, but I just don't see why they can't have the standard email fields defaulted to begin with.  But ignoring my custom fields for now, which were very easy to figure out with their log's help, here is what I determined to be the optimal set of profile values for the standard email fields:

    PROFILE=(DEF_MPROF), TYPE_ID=(EMAIL), ABSTRACT=(%s), EMAIL_FROM=(%f), EMAIL_TO=(%t), EMAIL_CC=(%h"cc"), EMAIL_BCC=(%h"bcc"), EMAIL_RECEIVED=(%h"datereceived"), EMAIL_SENT=(%h"date")

    The Type Id might be something else for someone else, since this was a custom type that I created myself, but I also think it just makes good sense to define an Email type to best differentiate email documents.  The Abstract value, which is used for the document description, and wasn't documented anywhere that I could find, may also be something that you may want to set differently -- I've simply set it to the subject.  On the other hand, all of the other values seem non-debateable to me since of course you want the from value set to the from address, and so one for the to, cc, bcc, received date, and sent date.  I should point out though that they do not document the dates anywhere, which seems to be an important oversight since these are pretty standard email fields, but I was able to figure out the sent date myself since it is a normal email header.  The received date on the other hand is very simple once you know what to do, but it took support a while to get this one found for me, and the received email header is quite involved so it was not something I could figure out myself.

    At this point I had it all installed and configured so that I could successfully send and receive emails and see them captured and stored in Hummingbird DM according to the rules that I had setup.  But there were still a few other problems that became apparent in testing -- the first being that email attachments were not getting profiled separately, which was an option that I had specified I wanted enabled during the installation.  It turns out that the installation program did not set a registry value correctly, and support was able to identify this pretty quickly, but I'm still not sure why this wasn't set correctly by the installation program.  I should also point out that this registry setting, and many others, are well documented, including some that have to be manually set since they do not have options in the installation, like full-text search.

    And that left me with everything working correctly with the exception of one advertised feature that was unable to work in my case, although its also a feature that we can probably do without for the time being.  The advertised feature is that you can specify folder names that don't yet exist and AEM will automatically create them on the fly, which I can see some shops wanting to better organize emails by sender or receiver or some other dynamic criteria.  My understanding on this issue, after many discussions with support, is that this feature does work in environments that do not have custom fields of their own added to the default profile form, but its our customizations that are causing it not to work.  Of course it does beg the question of how they never accounted for this situation before, since I would bet just about every Hummingbird setup involves some customizations, which they also strongly encourage by the way.  Oh well, its now on their list to fix, and its probably something we can live without for now, but hopefully by documenting here, along with my other lessons learned, I can save someone else out there some time.
  • REVIEW: HP LaserJet 3050 All-In-One

    For years I've had a very low-end Lexmark InkJet printer, the kind that sells for $39.95, which is just a shade more than what they charge per ink cartridge. In retrospect, I really should have ditched it earlier. It was painfully slow in printing and I was unable to share it on the network, meaning that if my wife wanted to print something she'd have to copy the file(s) to my computer and I'd print them. And did I mention it was slow? But if you don't work in an office where they have sleak, ultra-fast, network-shared printers, you don't know what you're missing. So I was content with my little Lexmark and my wife, after coming home from an office full of high-end laser printers had to copy anything she needed to print to my machine and then wait several minutes as the printer caughed them out.

    Finally we decided enough was enough and went looking for an All-In-One option to replace our printer and fax machine and to add scanning and copying capabilities. We ended up settling on the HP LaserJet 3050 All-In-One (shown on the right), which retails for $299.

    Not counting furniture moving, installation and setup was a breeze. Just plugged in the various cords, plugged in the printer to my machine via the USB cable, and we were off and running. Faxing, copying, scanning, and printing are all very straightforward, simple, and FAST. In the time it would take the ol' Lexmark to churn out a single page, this puppy can put out reems of paper. It just sucks in the paper and spits it out, taking a second or two. Yeah, yeah, this is probably no big deal to those of you who haven't been living with outdated technology, but for yours truly, this alone has made the purchase more than worthwhile.

    There are a couple of things that are less than ideal regarding the 3050:

    • No USB-to-printer cable included. I don't know if any printer manufacturer includes this anymore. I used my old one from the Lexmark printer (which I had to buy separately back in the day). In any event, I think most people would rather HP (or Lexmark or whomever) would charge $5 or $10 more and just include the damn cable rather than having you get home, get to setting it up, and then realizing, “Cripes, it's back to the store for me.“
    • No direct connection to network. The only way to hook up the 3050 model is through a USB cable, which is no biggie since it's hooked up to my always-on computer. But in a more traditional network setting, it's obviously ideal to have the printer hooked up to the network rather than a computer. To get the network hookup, you have to upgrade to the 3052 model, which is $100 more. $100 more also buys you a flatbed scanner/copier, which is nicer than the sheet feed option on the 3050. And I was just about ready to pony up the extra $100 for the 3052 and then found out that the 3052 doesn't include fax capabilities! If you want to fax and have a network jack and a flatbed scanner then you need the 3055, which is yet another $100. A 66% increase in the base price for a network jack and a flatbed scanner seemed a little too steep for this ol' cheapskate.

    In any event, I really have liked the 3050 and am sure the 3052 and 3055 are just as good models. Highly recommended!

  • Visual Studio "Orcas" Web Designer Integrated into Main

    This weekend was a really exciting one for the VS Web Tools team.  On Saturday they checked in their new HTML and ASP.NET WYSIWYG designer into Visual Studio.  This designer is a major, major improvement over previous HTML designers within Visual Studio, and will be a shared component used by both Visual Studio and Expression Web Designer going forward. 

    Among other things, the new HTML designer provides:

    • Split View Support (the ability to have both HTML Source and WYSIWYG design open simultaneously)
    • Extremely rich CSS support (CSS property window, CSS inheritance viewer, CSS preview, and CSS manager)
    • Dramatically improved view switching performance (moving from source->html design mode is now nearly instantaneous)
    • Support for control designers within source view (property builders, event wire-up and wizards now work in source view)
    • Richer ruler and layout support (better yet, values can be automatically stored in external CSS files)
    • Designer support for nested master pages

    Below is a screen-shot with a lot of the new features in action:

    We actually began working on the new designer in November 2004 - almost a year before VS 2005 shipped (there was a lot of work todo!).  Mikhail Arkhipov was the dev manager who led and architected the work.  You can learn more about the project and see some initial screen-shots of the new designer in his blog post here.

    I'm planning to record some videos over the next few weeks that show off the new HTML designer as well as other cool new "Orcas" features.  The next "Orcas" CTP will also contain the new designer (and a ton of other new features) to try out yourself.

    Hope you enjoy it,

    Scott

  • ASP.NET Tips and Tricks and LINQ Slides/Demos from CodeMash

    Below are the slides + demos for the two breakout talks I presented this past Friday at the CodeMash conference:

    ASP.NET 2.0 Tips and Tricks

    This talk covered ASP.NET UI, AJAX, Caching and Deployment Tips and Tricks, and Visual Studio 2005 tips/tricks.  Click here to download the slides+demos for this talk.

    You can learn more about the Visual Studio build performance optimization suggestions by reading this past post of mine on improving build performance.  You can also find several dozen more ASP.NET and Visual Studio Tips/Tricks of mine on my Tips and Tricks summary page.

    Building Data Driven Web Applications using LINQ

    This talk provided a drill down of LINQ (which will ship later this year), and demonstrated some of the dramatic productivity improvements it will bring for ASP.NET.  Click here to download the slides+demos for this talk.

    You can learn more about LINQ and how to use it with ASP.NET by reviewing some of my past LINQ posts.  Here are a few in particular worth reviewing:

    Thanks again to everyone who attended my talks - I really had a great time and hope you did too! 

    Scott

    P.S. I will also be posting the slides + demos from my LINQ keynote at the CodeMash event shortly.

  • Managing Windows Workflow Events on a Web Server

    Once you have the WorkflowRuntime up and running in an ASP.NET application or web service, you'll want handle key life cycle events like WorkflowTerminated and WorkflowCompleted. I want to warn you about some common pitfalls I've seen.

    There are two subtle but extremely dangerous problems in the following code.

    protected void Page_Load(object sender, EventArgs e)
    {
        
    // get a reference to our WorkflowRuntime singleton
        WorkflowRuntime runtime = ApplicationInstance.WorkflowRuntime;
        
        
    // wire up an event handler
        runtime.WorkflowCompleted +=
            
    new EventHandler<WorkflowCompletedEventArgs>
                  (runtime_WorkflowCompleted);

        
    // create and start a new workflow
        WorkflowInstance workflow;
        workflow = runtime.CreateWorkflow(
    typeof(SomeWorkflow));
        workflow.Start();

        
    // ask the manual scheduling service to execute the
        // workflow on this very thread
        ManualWorkflowSchedulerService scheduler;
        scheduler = runtime.GetService<
    ManualWorkflowSchedulerService>();
        scheduler.RunWorkflow(workflow.InstanceId);
    }

    void runtime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
    {
        
    // depending on what the workflow did for us, this is where we would
        // tell the user the final price, or approve their document, or whatever
        // workflowy thing that might have happened
    }

    Think: Singletons and event handling. The WorkflowRuntime will typically be a singleton in an ASP.NET app. In the WF RTM version, you can have multiple WF runtimes executing inside the same AppDomain (this wasn’t true in the betas), but chances are you don't want to pay the performance overhead of spinning up a new WF runtime for each request. Thus, we have a single and globally accessible WF runtime. For questions about the ManualWorkflowSchedulerService, see my article on hosting Windows Workflow. This scheduler allows us to run the workflow instance synchronously - on the same thread as the request.

    Problem #1: Someone Just Expensed a Ferrari

    The WorkflowCompleted event will fire for any workflow that completes, not just the workflow we are executing inside this page (or web request).

    Let's say the workflow is running some business rules to automatically approve or reject expense reports. This usually requires a human bean counter to get involved, but stick with me for a second and pretend it's all done in silicon. Let's say the workflow indicates approval or rejection with the OutputParameters property of the WorkflowCompletedEventArgs.

    User Joe submits an expense report for his new red stapler. At the same time, I submit an expense report for a red Ferrari Enzo. There are two pages executing on the server, and both subscribed to the WorkflowCompleted event. If things work out just right, Joe's workflow will complete first and approve his expense report. The runtime will raise the completed event, which both pages handle. Since Joe's workflow indicated approval, Joe will soon be stapling papers while I get to go 0-60 in less than 3.5 seconds.

    Problem #2: We Need More Power, Scotty!

    To fire the completed event, the WorkflowRuntime maintains a reference to the Page object. We should assume the WorkflowRuntime, as a singleton, will live for the duration of the AppDomain. Assuming the Page object never un-subscribes from the completed event, it will be in memory for the duration of the AppDomain, too. The garbage collector can't take the Page out of memory while it's being referenced by the WF runtime. RAM will start to disappear over time.

    Even worse, with each request another instance of this Page class will wire itself to the WorkflowRuntime, and each time a workflow completes the WF runtime will need to raise the event to all these zombie page objects. This will keep the CPU busy, too.

    It won't be long before the server is sucking mud, and the company is out of money.

  • LINQ to SQL "Real" Example App Available

    The Atlanta Code Camp was today, so I finally got to give my LINQ and O/R Mapping talk that I've been preparing.

    I tried to have minimal slides so that I could do a deep dive into real code, but I still went a little too long.  The slides look great on my own PC, and in fact they're mostly some I stole straight from other LINQ presentions.  But the overhead I was using made the text nearly unreadable for some reason, which made me take longer on the slides.  It also made some of the standard VS color syntax unreadable, with the work-around being to select that code.  I small the same problem with another speaker in the same room, so I guess it was the projector, but very frustrating.

    In the end I still got to hopefully show a fair amount of LINQ to SQL, but I had really hoped to show more.  I also made sure I gave a glimpse at SqlMetal and LINQ to Entities, but both of those were meant to be just glimpses.  Finally, I briefly demoed my new "real" example application written with LINQ to SQL which is included in my download.  This example shows off my own POCO objects with an external XML Mapping file, instead of the ugly code gen with attributes.  Its also a "real" app that consumes the LINQ to SQL with WinForms grids, drop-down filtering, and create, update, and delete.

    Note that it assumes the May 2006 CTP, but I'll update it to the next one when it comes out, hopefully next month.  Its also nearly identical to my existing "real" example app downloads that I have for my own ORMapper and NHibernate.
  • Books: Flags of our Fathers by James Bradley

    One of my goals is to read more history books, I have a ton of them sitting on my bookshelf and I just need to get better about grabbing one of them when I go looking for the next book to read. I have had Flags of our Fathers sitting on the book shelf for quite sometime, but when I saw the movie was coming out I wanted to make sure I read it before I saw the movie. (I finished the book a couple months ago and still haven’t seen the movie yet)

    James Bradley was in a unique position to write this book since his father was one of the flag raisers captured in the photo on the cover of the book. This book is more about the people in this photo than about the actual battle of Iwo Jima, although there is a great deal about the battle as well.

    Most of the books I have read about World War II have focused on the European theater so it was refreshing to read a book about the Pacific theater. The book starts out detailing the lives of the six men in this photo before the war. It goes on to talk about their path into the military, their role in the invasion, and then the circumstances that took them to the top of that mountain on Iwo Jima. The book then goes on to detail what happens to each of the different men in the photo, and most of the stories don’t end very well. I am sure there are plenty of books out there that do a much better job of covering the battle of Iwo Jima itself, but this book is unique in that it looks at the battle (and all of WWII) through the eyes of a number of individual men who were brought together for a press photo that changed their lives and inspired America.

    Now I just need to see the movie.

    -James

  • Books: Heart of Darkness by Joseph Conrad

    I have been alternating between reading a current novel and a classic the last couple of months, Heart of Darkness is one of the recent classics I read for the first time. Penguin has a series of books called the “Great Books of the 20th Century” and I am working my way through all of the books in that series.

    Heart of Darkness is a haunting tale about a trader trying to make his way into the jungle and reaching not only his limits, but the very limits of society. I know some people who found this book hard to read, but I thoroughly enjoyed it. I particularly enjoyed how well the writing style of the book worked to enhance the feeling of lawlessness and chaos in the Belgian congo. The book is first and foremost about the ill effects of colonialism on both the natives and the colonizers, which in 1902 when this was published was a fairly controversial view.

    The story and writing remind me of H.P. Lovecraft in some ways, although much less supernatural the nightmarish quality is very similar.

    -James

  • Books: Haunted by Chuck Palahniuk

    I have six books sitting next to me that I haven’t blogged about yet, so it’s time for a marathon blog session to clear out the queue. The book I most recently finished was Haunted by Chuck Palahnuik. Chuck is one of my favorite authors. I have read all of his stuff but I had been putting off reading this one for some time. Mostly because I hadn’t heard great things about it.

    Haunted is a novel that includes a mix of poems and short stories about each of the characters in the novel. My theory is that Chuck planned on doing a book of short stories, but someone talked him into trying to write a novel around it. I am sure the publisher was getting tired of his non-novel books like Stranger Than Fiction: True Stories and Fugitives and Refugees which usually don’t achieve the commercial success a proper novel does.

    The short stories are classic Palahnuik, they are strange, off-beat, filled with odd facts and events, and remind me of much of his earlier work. There is even one short story that I blogged about years ago because the story was that people were fainting while he read it on the book tour.The poems are decent, but nothing special. The novel itself is OK, but hardly up to the Palahnuik’s normal work.

    The novel section is about a group of people who go to a writer’s retreat that takes a turn for the worse, the problems are agitated by the fact that everyone sees this as their passage to pop culture stardom. They start to make the situation worse on purpose to make their story more sensational, meaning better book deals, talk shows, and movies. While it is obviously a statement on “reality TV” culture, it just doesn’t have the same qualities as most Palahnuik stories. The characters are definitely strange, but you don’t relate to them the way you do with his other characters. The writing style even seems different, many of his other stories are incredible strange but always sound like they could be true. This story doesn’t feel real at all. So if you are a Palahniuk fan I would read the book, but don’t expect much from the novel or poems and just enjoy the short stories.

    P.S. If you are wondering his name is pronounced Paula-Nick. (he wrote about how his parents taught him to pronounce it using his grandparents names)

    -James

  • TreeViews and Usability

    treeview

    One of the commercial applications I've worked on over the last few years has received consistent feedback from uses who dislike tree view controls. Many of these users are working with terminal emulators on a daily basis, so I first suspected that switching to a GUI came as a shock.

    I did some research on tree controls and usability, but didn't uncover much information. Actually, many articles I found herald the tree view as the ideal solution for categorizing and drilling into large amounts of hierarchical information. Only Alan Cooper's book "About Face" turned up a caveat:

    "Programmers tend to like this presentation [speaking of Tree controls]. It is often used as a file system navigator, and some find the format of the display to be effective – certainly more effective than scattering icons around in multiple windows on the desktop. Unfortunately, it is problematic for users because of the difficulty many nonprogrammer users with understanding hierarchical data structures. In general, it makes sense to use a treeview, no matter how tempting it may be, only in the case where what is being represented is "naturally" thought of as a hierarchy (such as a family tree). Using a treeview to represent arbitrary objects organized in an arbitrary fashion at the whim of a programmer is asking for big trouble when it comes to usability."

    I've changed my initial suspicion. Now I suspect users don't have a problem with the mechanics of the tree view, but rather with the content of the tree view. It's not a case of how to work with the control, but where to start to get to the right node in the tree.

    The more I think about the problem, the more I realize I face the same difficulty on an almost daily basis. When I call my cell phone company, I have to fit my specific problem into one of the three broad categories provided by the soothing sounds of an automated voice response system. If I initially choose the wrong category, I'm pretty well screwed and need to start over. This is frustrating.

    A software alternative to the tree view is a search feature. Allow the user to get to the lowest level of detail without navigating a hierarchy of unfamiliar categories. This often works in the real world, too. If I can't find something in the categorized aisles of a hardware store, I ask someone who works there.

    Interesting and somewhat related post: Luke Wroblewski has a look at the history of Amazon's Tab Navigation. I don't remember the last time I went to Amazon to browse categories, I always search for a specific item. It's well that they do away with tabs. 

    Searching capability is vital these days. I wonder, will System.SearchEngine will ever appear as a namespace in the .NET library?

  • David Douglass's favorite tools

    David is the first person I saw to participate in Windows Developer Power Tools Day with a great list of tools. Reflector, Fiddler, and WinMerge are definitely in my list of favorite tools.

    -James

  • Windows Developer Tools Day

    Today is the official “launch day” of Windows Developer Power Tools! We are asking bloggers to post about their favorite tool or tools and then shoot off a quick email to (powertools AT oreilly DOT com) and they will link to your blog from oreilly.com. (I am not sure where on the site yet)

    For the official announcement check out John Osborn’s (our editor) post over on O’Reilly.

    I look forward to seeing what tools people blog about. I was hoping to launch the website today as well but it looks like it will most likely be this weekend instead.

    -James

  • Some JavaScript Links To Chew On

    I've flagged a few links to noteworthy JavaScript posts over the last month.

    Yahoo! Video: Advanced JavaScript Part I, Part II, Part III. A lecture by Douglas Crockford.

    IEBlog: Jscript Inefficiencies Part I, Part II, Part III.

    Rick Strahl: "FireBug 1.0 Beta Rocks". FireBug is a JavaScript debugger with some remarkable features.

    Rick again: "HREF links and javascript : Navigation".

    Jason Diamond: "Not Delegates".

    Jim Ley: "JavaScript Closures".

    Sergio Pereira: Quick Guide To Somewhat Advanced JavaScript.

    Pathfinder: JsUnit – Agile AJAX Development

    Mike West: Scope In JavaScript

  • February's Toolbox Column Now Online

    My 14th Toolbox column in the February 2007 issue of MSDN Magazine is now avaiable online. The February issue examines three products:

    This month's issue reviewed .NET Test Automation Recipes, by Dr. James D. McCaffrey. From the review:

    All programs, regardless of their size, scope, or complexity, should be thoroughly tested to ensure correct results and behavior for both expected and unexpected inputs. Many developers employ commercial or open source testing frameworks to aid and automate the testing process. While testing frameworks have their place, in his book .NET Test Automation Recipes: A Problem-Solution Approach (Apress, 2006), fellow MSDN® Magazine columnist Dr. James D. McCaffrey proposes that these testing frameworks be complemented with lightweight test harnesses. A lightweight test harness is a short (four "pages" of source code or less), simple, standalone program written to perform a test or set of tests against the target app. ... Lightweight test harnesses are, by definition, simple and should not take significant time to develop. This time can be lessened by having the recipes discussed in Dr. McCaffrey's book at your fingertips.

    As always, if you have any suggestions for products or books to review for the Toolbox column, please send them into toolsmm@microsoft.com.

  • You Can't Touch My Windows Experience Index

    Leave it to Microsoft to quantify everything.

    The experience used to be emotional. There was the gentle purr of a power supply fan with the scent of plastics in the air. The caress of a firm, rubberized nipple would make pixels dance in front of my eyes. Those days are over.

    My Windows Experience is now a cold, calculated number.

    Windows Experience Index

    Top that!

    What's that you say? A low score is bad? Oh.

    Well, this desktop was a top of the line computer…

    … back in the year 2000.

  • Error When Installing Visual Studio 2005 SP1: "The installation source for this product is not available."

    I installed Visual Studio 2005 Service Pack 1 today on my main development box (Windows 2003 Server) and ran into the following error: “The installation source for this product is not available. Verify that the source exists and that you can access it.” In particular, I received the following error dialog box:

    Some Googling turned up a fix for a very common error message when installing SP1 - “Error 1718. File FileName was rejected by digital signature policy” - but it took a bit more searching before I found this bug report in which user rlasker provided the following helpful comment:

    I had this issue. When I looked in the event log I found this:

    Event Type:    Error
    Event Source:    MsiInstaller
    Event Category:    None
    Event ID:    1008
    Date:        12/18/2006
    Time:        12:18:31 PM

    Description:
    The installation of C:\DOCUME~1\...\LOCALS~1\Temp\ZNWA0\VS80sp1-KB926601-X86-ENU.msp is not permitted due to an error in software restriction policy processing. The object cannot be trusted.

    I followed the instructions at this link:
    http://support.microsoft.com/default.aspx/kb/925336

    And it no longer gave me the error descibed above.

    Looking in my Event Log I found the same details and dutifully applied the workaround described at the KB (http://support.microsoft.com/default.aspx/kb/925336). These steps remedied the problem, and after rebooting I was able to successfully install SP1. Hopefully this post makes it to the first page of Google's results so future developers running into the same problem who are Googling the error message can more quickly find a fix.

    For more VS 2005 SP1 info, see:

  • User Group Talk: Handling Errors in an ASP.NET Web Application

    Tomorrow night, Tuesday January 16th, I'll be speaking at the ASP.NET Specicial Interest Group here in San Diego. The meeting, held at Microsoft's office in UTC on La Jolla Village Drive east of Genese, starts at 6:30 PM with announcements and free pizza and soft drinks!!! I'll start blathering around 7:00.

    My talk examines techniques for handling errors in an ASP.NET web application and includes looking at:

    • Using custom, human-friendly error pages (avoid the Yellow Screen of Death!)
    • Techniques for automatically logging unhandled exceptions
    • Ways to automatically notify developers in the face of an unhandled exception
    • How to handle exceptions that arise from the depths of ASP.NET 2.0's data source controls. That is, we'll see how to handle exceptions that occur when you are working with data in an ASP.NET 2.0 page using the SqlDataSource control and a GridView and an exception is raised from the database layer.

    If you can't make the talk, you can download the PowerPoint slides and code demos here. Hope to see you tomorrow!

  • Managing the WorkflowRuntime In ASP.NET

    If you want to use Windows Workflow in ASP.NET, you'll need create and maintain a WorkflowRuntime instance. What's the easiest approach to use?

    The easiest approach (not necessarily the best), is to use global.asax.

    <%@ Application Language="C#" %>
    <%
    @ Import Namespace="System.Workflow.Runtime" %>

    <script runat="server">    
        
        
    void Application_Start(object sender, EventArgs e)
        {
            InitializeWorkflowRuntime();

        }
        
        
    void Application_End(object sender, EventArgs e)
        {
            
    if (_workflowRuntime != null)
            {
                _workflowRuntime.Dispose();
            }

        }      

        
    void InitializeWorkflowRuntime()
        {
            _workflowRuntime =
    new WorkflowRuntime();
            
            
    // ... additional configuration ...
            
        }
        
        
    public WorkflowRuntime WorkflowRuntime
        {
            
    get { return _workflowRuntime; }
        }
            
        
    private WorkflowRuntime _workflowRuntime;
          
    </script>

    This approach gives us a WorkflowRuntime we can reach from any page. Remember, in an ASP.NET Web Site project, the runtime code-generates a strongly-typed ApplicationInstance property from global.asax for each web form. We can access the WorkflowRuntime property defined in global.asax with ease:

    protected void Page_Load(object sender, EventArgs e)
    {
        
    // ...

        ApplicationInstance.WorkflowRuntime.CreateWorkflow( /* ... */ );

        
    // ...
    }

    This approach is simple, straightforward, and easy, but let's think about the disadvantages.

    First, global.asax makes the WF runtime readily available to the web application, but it's not so easy to obtain this reference from a data, business, or service layer. It's possible - but not pretty.

    Secondly, global.asax can cause headaches. I tend to avoid adding global.asax to a project, as once the file comes into play it tends to become a dumping ground for global "stuff" that an application needs.

    Generally speaking, a better approach is to manage the WF runtime from a lower layer in the application architecture. Using a Registry or Service Locator type pattern makes the runtime available through all layers of the application. Error reporting, logging, and tracking of workflows and their runtime can live inside one or more dedicated components. This approach requires a little more work, but provides the flexibility required for larger applications. More details to come.

  • Breaking News: Future Version of .NET Framework to Run on the Mac

     

    Breaking News: Microsoft is working on having a version of the framework that will run on the Mac!  That's right -- Rory broke this story just the other day in his interview with Scott Guthrie.

    First, a little bit of background, which although not secret has largely went unnoticed so far.  Hopefully you've heard of WPF/E, which is a subset of WPF that runs in the brower, even Firefox and Safari.  So far the first CTP is largely focused on the cool graphics capabilities and supporting media.  But even in this first CTP the XAML can be programmed against on the client-side using JavaScript, even with Ajax.  But its also already been discretely said that in the future WPF/E will also contain a small cross platform subset of the CLR.  That will mean that we will also be able to use C# or VB on the client-side to program against WPF/E!  And that will be true even in Firefox and Safari on the Mac -- and this is old news that simply hasn't been widely talked about.

    Mike Harsh as early as March 23, 2006 said:

    So what is WPF/E?  It is a cross-platform, cross-browser web technology that supports a subset of WPF XAML.  WPF/E also has a friction-free install model and the download size we’re targeting is very small.  WPF/E supports programmability through javascript for tight browser integration.  The WPF/E package also contains a small, cross platform subset of the CLR and .NET Framework that can run C# or VB.NET code.  Yes, we are bringing C# programming to the Mac.

    And Joe Stegman said this just last month:

    To be clear, "WPF/E" is independent of the .NET Framework.  In a future version, we'll support a small cross platform CLR based execution engine that will run on both Windows and Apple OS X (everything we do from a runtime perspective works on both Windows and Apple OS X).  In general, our tools are dependent on Windows but with the current version of "WPF/E", you can develop using a text editor and deploy on any web server.  When we support the small CLR, compiling/debugging will require Windows (and so will our designer tools) but running/deployment will still work cross platform.

    And then Scott said this in the interview at the 9 minute mark:

    Scott: And overtime we'll also support a managed programming language, uh framework, against WPF/E as well.  So in addition to using JavaScript, you'll be able to use C#, uh
    Rory: You mean, even for the other?
    Scott: Yeah even for the Safari and Mac.

    But what Scott said in this interview with Rory went beyond the small CLR for WPF/E in the browser.  Instead Scott said that they were also looking at a version of this that would run outside of the browser, even on the Mac!  Listen to this interview and its pretty clear that Scott was probably not intending to announce this until Mix.  Rory was also quite suprised and wondered if he needed to remove this from the video.  But Scott said he could keep it and acknowledged that this was probably the first time this was publicly talked about.  Rory was of course very excited to be the one to get this scoop out of Scott.  :)

    So here's what Scott said in the interview at the 23:45 mark:

    Rory: Is there any possibility of eventually having a framework that runs outside the browser?
    Scott: Yea, yea, that's definitely something we're looking at is, uh, kind of what we call the in-browser experience and kind of the out-of-browser experience.  And so that's something we'll talk more about at mix, uh
    Rory: And that stuff's secret now? Cause I don't mean to bring up something that's secret.
    Scott: No, no, well that's something, uh, that we haven't talked about publicly yet. But that's certainly a scenario we're thinking about.
    Rory: Do I have to get that out of the video?
    Scott: No, you can keep that.
    Rory: I can keep that? Is this like the first time anyone's heard it?
    Scott: Probably, yeah.

    Just having the ability to use our favorite .NET language and a subset of the CLR inside the browser to target an incredibly rich graphics platform like WPF/E is huge to me, but if we're not even restricted to the browser -- wow!  For instance, Keith Elder already has a post on his blog where he considers some of the possibilities, and that's just one person thinking out loud.  Of course right now the first CTP is still very much cool graphics and media, but this is a very strategic start.  Why?  Because this is focusing on what isn't easily possible any other way, and its getting the big media players involved.  And if the big media players use it then you can bet that everyone will be downloading the plugin just like they do now for Flash.  Most users aren't going to care about the .NET part, but once its ubiquitous, then we will also be able to take advantage of it.

    So there you go -- its just a matter of time before there will be a small CLR version of the .NET framework everywhere, with your favorite .NET language of course!

  • Video Interview of Me Talking about WPF/E, Orcas, IIS7 and MIX

    Yesterday Channel9 posted a video interview of me with Rory Blyth that was filmed earlier this week. 

    During the interview I talk about WPF/E, VS Orcas, IIS 7 and the upcoming Microsoft MIX conference on April 30th - where Ray Ozzie and I are the keynote speakers.  I also talk about having my car towed by Microsoft campus security.

    Click here to watch it.

    - Scott

     

     

     

     

     

     

     

     

     

  • Windows Developer Power Tools

    I know I haven’t blogged it yet, but Windows Developer Power Tools is now shipping from Amazon (and other book sellers). I realized the other day that I have hardly blogged about the book in general, well it’s time to make up for lost time.

    This book started as an idea by John Osborn at O’Reilly to come up with a format that would be similar to Visual Studio Hacks but on a wider scale. The book that started the power tools series, Unix Power Tools, is one of the first O’Reilly books and was the model for this book.

    Finding the right tools for the job is always a constant challenge for developers. If you are starting a new project today and want to do test-driven development you are faced with a number of different options.

    And this is just the testing chapter (which clocks in at over 120 pages).

    In each tool section we cover a couple of different important things:

    1) A quick summary of the tool and the problem it solves.

    2) A table listing the name of the tool, version covered, home page, summary, license, related tools, and some additional tool related information.

    3) A guide to getting started with the tool. This is usually anywhere from 2–10 pages on how to best get up and running using the tool.

    4) A quick section about the best way to get support on this tool, useful sites, books, etc.

    5) Finally we have a section called “in a Nutshell” for each tool where we sum up any pros and cons on the tool and compare it to any of it’s competitors.

    Since we cover over 170 tools it’s easy to see how this book came in at over 1300 pages.

    One of the best parts of the book is that we got a huge number of contributors to write for us, many of them writing about the tools they wrote themselves. Here are just a few of the contributors we have:

    Dan Fernandez (lead product manager for Visual Studio Express)

    Justin Greenwood the co-creator of MyGeneration

    Sara Ford the program manager for the Power Toys for Visual Studio

    Phil Haack who wrote Subtext (of course!)

    Rob Howard the CEO of Telligent Systems, Inc.

    And this is just the beginning! We also have Adam Nathan, Roy Osherove, Shaun Walker, and many many more. I am working on getting the complete list up over on the book site.

    On top of all these great contributors we were lucky to have both Scott Hanselman and Mike Gunderloy write forwards.

    As you can probably tell I am pretty excited about this book. I am working non-stop this weekend on getting the site finished and hope to launch it before the end of next week. 

    -James

     

     

     

  • Tip/Trick: How to upload a .SQL file to a Hoster and Execute it to Deploy a SQL Database

    Last month I posted about the new (free) Database Publishing Wizard that is designed to make it much, much easier to upload and deploy SQL Express and SQL Server databases in a web hoster environment.

    In my first Database Publishing post, I walked through how you can use the Database Publishing Wizard to automatically generate a .SQL installation file that contains the script necessary to recreate your database schema (tables, views, sprocs, triggers, full-text catalogs, etc) and also populate your database with the same table row contents as your original database.  This provides a super easy way to put together a .SQL script that entirely automates replicating your database on another server:

    In my previous post I mentioned how hosters often provide an online SQL management tool that you can then use to open and run your newly generate .SQL file, or provide a SQL query tool that allows you to copy/paste the .SQL file's contents into a query execution window to run.  Unfortunately, though, not all hosters support tools like this.  And even with hosters that do support it you might run into cases where your generated .SQL file is so big that copying/pasting it into a text box isn't really viable (doing a form post of 200MB of content will typically time out!). 

    This blog post walks through an alternative way to deploy your .SQL files in a remote hosting environment, and which does not require your hoster to configure or install anything on the backend.

    Steps to Deploy a SQL Database to a Remote SQL Server without using an Admin Tool

    Below are the steps to take to deploy a local database to a remote hoster without requiring or using any admin tool:

    Step 1: Generate a .SQL File Containing your Schema and Data

    The first step to remotely deploy your database in a hosted environment is to generate a .SQL file that dumps the schema and content of your database.  Follow the steps in my first Database Publishing blog post to learn exactly how to generate a .SQL file for either a SQL Express or SQL Server database.

    Step 2: FTP up the .SQL File to your Remote Hoster

    Once you've generated your .SQL file, upload it to your remote hoster using FTP or some other file transfer mechanism.  Ideally you should copy this into a protected location where remote users can't easily get access to it (one suggestion: give it a random name and upload it into the /app_data folder which is typically protected by default).

    The benefit of uploading this file over FTP is that it won't force you to limit the size of the .SQL file.  It can be 100s of megabytes in size if necessary.

    Step 3: Download the RunSQL.aspx Utility Page

    Visit this page and download the RunSQL.aspx file linked on it. 

    The RunSQL.aspx file is an ASP.NET page that the SQL Server team put together that supports two arguments: 1) The name of a .SQL file, and 2) The connection string of a database.  When run the RunSQL.aspx page will open the .SQL file and iterate over each of its statements and execute them against the database (indicated via the connection string).  This will provision the database defined within the .SQL file to the remote database target.

    Step 4: Edit the RunSQL.aspx Utility Page

    Open and locally edit the RunSQL.aspx file and and configure the name of your .SQL file, as well as provide the connection-string your hoster gave you for the SQL database:

    Replace the <<YOUR_SCRIPTFILE>> marker and associated connection-string markers with the correct values for your hosted configuration.  Note that unless you know the fully qualified path of the .SQL file, you'll probably want to use ASP.NET's Server.MapPath(fileName) method to calculate the absolute path of the relative .SQL file path in your web application.  For example:

        // Filename of the T-SQL file you want to run
        
    string fileName Server.MapPath("personal.SQL");    
        
        
    // Connection string to the server you want to execute against
        
    string connectionString @"Server=server123;User ID=user123;Password=password123;Initial Catalog=MyDBName123";  
        
        
    // Timeout of batches (in seconds)
        
    int timeout 600;

    Step 5: Upload the RunSQL.aspx Utility Page to Your Remote Hoster

    Once you have finished updating the fileName and connectionString values above, upload the RunSQL.aspx file to your remote hoster (for example: using FTP). 

    For security reasons I recommend giving the file a random file-name when you upload it so that other users can't easily find and run it.

    Step 6: Hit the RunSQL.aspx Utility Page with a Browser

    Once uploaded, hit the remote RunSQL.aspx page via your browser.  This will cause the page on your remote server to parse the .SQL file, and execute all of its statements.  Since the .SQL file contains all of the database schema creation and population statements necessary to recreate your database, once the page finishes running you'll have an identical database deployed at your hoster:

    Step 7: Delete the RunSQL.aspx and .SQL Files

    Once you've finished running your .SQL script, delete both the RunSQL.aspx page and the .SQL file from your remote hoster server. 

    For security reasons you do not want anyone else to be able to remotely hit the RunSQL.aspx page (since it might recreate your database causing you to lose data).

    Step 9: Update the Web.Config file of your application to point to the hoster database

    The only final step remaining then is to update your web.config file's <connectionStrings> section to also point at your remote hoster's database connectionstring value.  Once you do this your app should work fine remotely.

    Hope this helps,

    Scott

    P.S. For more of my ASP.NET Tips, Tricks and Recipes, please visit this page.

  • Laptop Suggestions, Advice, or Recommendations?

    It's about time for me to upgrade my laptop and am soliciting any recommendations/advice you, my faithful blog reading audience of six, care to share. I use the laptop for User Group talks, conferences, and as the presentation/demo machine for my classes and training. In total, it gets used maybe once or twice a week for a total average of maybe four hours/week. That's the only time the laptop is on. I do all my "real" work/development on a desktop.

    Currently I have an older Dell I bought four years ago with 512 MB of RAM. It can crawl at times with a couple Visual Studio 2005 instances running, SQL Server Management Studio up, a couple browsers going, and so on.

    I'd like to strike a nice balance between performance and portability, but there's no need to pay a premium for an "ultra-light." Moreover, since I only upgrade my laptop once every four or five years, I'd like something that's still capable (albeit slower, for sure) of handling Visual Studio 2010.

    It's been so long since I've been in the market for a laptop and I've yet to start researching prices/specs, but thought I'd put out a request for comments and feedback. My budget is in the $1,500-$2,000 range.

    Any comments, advice, or suggestions are most welcome.

  • Allchin's Email

    Apparently Jim Allchin sent this email to Ballmer and Gates back in 2004. Most people focus on the “I would buy a Mac” part, but I think this part is much more interest:

    “I know this doesn't show anything for businesses, but my point is about the philosophy that Apple uses. They think scenario. They think simple. They think fast. I know there is nothing hugely deep in this.”

    This email does a great job of summing up what companies like Apple, 37 signals, and others are doing to write great software. Jim later blogged to say he believes the problems have been resolved, but that sounds like damage control to me.

    -James

  • Download ASP.NET AJAX PDF Cheat Sheets

    Milan Negovan from the http://aspnetresources.com/ site has been working on putting together some really nice PDF "cheat sheets" for the client-JavaScript libraries in ASP.NET AJAX:

    These are super handy pages to print out and keep around to quickly find information and code-snippets to use. 

    Milan is making these available completely for free - so definitely download them and send him feedback (he is going through and adding them for all the core classes in the client-side AJAX library).

    Hope this helps,

    Scott

  • BUG: Off-By-One Error in the Paging/Sorting with the DataList or Repeater Tutorials

    Alert Working with Data in ASP.NET 2.0 tutorial reader Nathan P. wrote in to let me know that there is a small bug in the code for the paging and sorting with the DataList and Repeater tutorials. It's a silly off-by-one error that I should have caught long before turning in the tutorials.

    In any event, the problem in the default paging examples is in computing the PageCount. I use:

        1 private int PageCount

        2 {

        3     get

        4     {

        5         return (TotalRowCount / PageSize) + 1;

        6     }

        7 }

    Which works well unless TotalRowCount and PageSize are evenly divisible. For example, let TotalRowCount = 79 and PageSize = 10, then this formula works as desired since 79/10 = 7, and 7+1 = 8, indicating that there are, indeed, 8 pages. But if there are 80 records in total, then 80/10 = 8, and 8+1 = 9, even though there are just 8 pages of data.

    I fixed this by changing this to the following:

        1 private int PageCount

        2 {

        3     get

        4     {

        5         if (TotalRowCount <= 0 || PageSize <= 0)

        6             return 1;

        7         else

        8             return ((TotalRowCount + PageSize) - 1) / PageSize;

        9     }

       10 }

    Alternatively, you could just return ((TotalCount - 1) / PageSize) + 1, which is equivalent to the formula in on line 8 in the above snippet.

    Similarly, in the custom paging example I have the same off-by-one error, but it's in computing the starting index of the last page. In the ProductsDataSource's Selecting event handler there is:

    int

    LastPageStartRowIndex = (TotalRowCount  / MaximumRows) * MaximumRows;

    Change this to:

    int

    LastPageStartRowIndex = ((TotalRowCount - 1) / MaximumRows) * MaximumRows;

    Also update this formula in the LastPage Button's Click event handler.

    I've submitted the code/article updates for the affected tutorials. It should be updated on the live site within a few days, hopefully.

  • What's Wrong With This Code (#10)

    This time, Joe Developer thinks he found a bug in the .NET framework. Joe read that the volatile modifier is "usually used for a field that is accessed by multiple threads without using the lock Statement". Joe wants to try this out, and writes the following class.

    class Worker
    {
        
    public void Start()
        {
            queue =
    new Queue<string>();

            
    Thread[] threads = new Thread[maxThreads];
            
    for (int i = 0; i < threads.Length; i++)
                threadsIdea =
    new Thread(PopulateQueue);

            
    Array.ForEach(threads, delegate(Thread t) { t.Start(); });
            
    Array.ForEach(threads, delegate(Thread t) { t.Join(); });
            
            
    Debug.Assert(queue.Count == maxThreads * maxIterations);
        }

        
    void PopulateQueue()
        {
            
    for (int i = 0; i < maxIterations; i++)
            {
                queue.Enqueue(
    "foo");
            }
        }

        
    volatile Queue<string> queue;

        
    const int maxThreads = 5;
        
    const int maxIterations = 1000000;
    }

    This code ran successfully at least a dozen times, then suddenly blew up with the following exception:

    System.ArgumentException was unhandled
    Message="Destination array was not long enough.
    Check destIndex and length, and the array's lower bounds."
    Source="mscorlib"
    ParamName=""
    StackTrace:
    at System.Array.Copy ...
    at System.Collections.Generic.Queue`1.SetCapacity ...
    at System.Collections.Generic.Queue`1.Enqueue ...
    at Worker.PopulateQueue ...
    ...

    Joe thinks something has gone terribly wrong in the CLR, and for once, Joe would like to show his boss a problem in someone else's software. What should his boss think?

  • Next Generation Yahoo Messenger built with WPF and .NET

    At the Consumer Electronics Show this week, Yahoo showed off some cool demos with their next generation messenger client (you can watch a video of it in action at http://messenger.yahoo.com/vista).  One of the really cool things about the new messenger client is that it was built using Windows Presentation Foundation (WPF) and the .NET Framework.

    One of the most powerful aspects of WPF is its ability to create really immersive user experiences that go far beyond what we typically expect today from either a client or web application.  Developers can style and templatize UI in a way not possible with most other UI frameworks, and use its built-in UI/Code separation model to enable both designers and developers to collaborate on projects together.

    Over the next few months I'll be posting a number of blog posts that walkthrough how you can start learning WPF to build great applications (note: WPF is now a built-in library of the .NET Framework redist).  If you are interested in learning more about WPF I'd also highly recommend subscribing to "theWPFBlog" - which posts some great articles on both WPF and WPF/E (the above screenshot came from this recent post).

    Fun stuff,

    Scott

  • JavaScript and Threading

    Someone asked me if the "asynchronous" in AJAX means we should be worried about thread safety and global variables in client-side script. This is an interesting question to ponder.

    A search of the ECMAScript language specification returns zero hits for the word "thread". JavaScript, like C++, appears to leave threads as an implementation detail. There are no keywords or intrinsic ECMAScript objects available to manage threads, or to provide for thread synchronization.

    I find it strange that there are articles like "Implementing Mutual Exclusion For AJAX" claiming to control threads. Some of these articles assert that integer assignment in JavaScript is an atomic operation. I've yet to see documentation that proves this assertion and I'm wary of this claim given the number of software layers between the scripting runtime and the hardware.

    I don't think we are in a position to even worry about concurrent threads in script. With no mechanism to control threads, we have to trust our browsers to "do the right thing". IE7 appears to use a single thread for executing script code in a page. Based on experiments with the native debugger and Winspector, the thread appears to be a message-pumping UI thread. I'd have to assume that other browsers (at least on Windows) also follow a single threaded model for simplicity. I have no proof, so any insight readers can provide would be appreciated.

    In trying to confirm this behavior, I came across a 2003 post by Eric Lippert: "What are "threading models", and what threading model do the script engines use?". Here is a juicy excerpt:

    * When the script engine is in a state where it cannot possibly call an ActiveX object -- for instance, if it has just been created and has not started running code, or if it is just about to be shut down -- then the script engine really is free threaded, but who cares? It can't do much in this state.
    * When the script engine is initialized -- when the script engine host has started the process of passing code and object model state to the engine -- the script engine morphs into an apartment threaded object. All calls to the script engine must be on the initializing thread until the script engine is shut down again.

    Eric then muddies the water in a later comment:

    It's very difficult to do true multi-threading inside IE. However, there are clever things you can do with the setTimeout method. I've also been thinking that it might be interesting to describe setTimeout from a continuation-passing-style perspective.

    It doesn't appear that Eric ever followed up on this comment, unfortunately.

    But what about the A in AJAX? Assuming xmlHttp is a native object it is free to use any number of background threads to free up the browser's UI. When xmlHttp raises an event, however, that call must marshal to the thread responsible for executing script.

    I do wonder what this single threaded model means for the future. As the amount of script code for AJAX and WPF/E grows, this model has the potential of being a bottleneck.

  • Personal Blog about Paul Wilson and My Family

    Sorry for this post, but my personal blog which tells all about Paul Wilson and my family needs some google juice.
  • Mimsware Website Updated due to Blog Comment

    You may remember me posting about joining Mimsware as a software consultant here in Atlanta a couple of months ago.  Well first let me say that things are going well and that I really enjoy working with Mimsware, and of course I highly recommend them if you're in the Atlanta area.  But it was pointed out by Wim in the comments that Mimsware's website looked like Microsoft's website back in the year 2000.  Well I'm happy to report that Dave Mims took that comment to heart and made updating the Mimsware site a priority -- so take a look now.  Its also worth noting that Dave did already know that it really needed updating, but it had just never been a priority until Wim's comment.

  • Doug Reilly

    I was sad to see Doug recently passed after a long fight with cancer. I had the pleasure of meeting and hanging out with Doug in Redmond for the MVP Summit and will always remember him as an easy and fun to talk to guy. He will definitely be missed.

    -James

  • Five Things

    Well, this meme must have gotten far enough down the blog hole to reach me through a number of different people (Jim, Jay, Dan).

    So here are five things you probably don’t know about me (but depending on who you are you might know, considering I don’t really know who you are)

    • My junior year in high school (1996) I scored a job at the local comic shop by promising I could figure out how to build them a web site. I learned HTML from a manual that came with my modem and cranked out their site. The site never really took off, but I started doing web sites for companies my dad worked with and eventually started my first company (New Release Web Design) before getting out of high school.
    • I don’t have a degree. This seems to be a pretty frequent item to show up in this meme. I went to Middle Tennessee State University for a semester and did pretty good before taking a job at Dell when they opened up a facility in Nashville. I would love to go back but I think I would focus more on English than Comp Sci or Business.
    • When I was growing up in Maryland my Dad worked for the federal government in drug prevention. This meant when they needed someone to present “Just Say No” pledges to Nancy Reagan I was selected. It was cool to go to the White House, get a tour, and then hang out in the Rose Garden. I also got invited back to welcome Mrs. Reagan back to the White House after her surgery (where I saw the president but didn’t get to meet him)
    • Three years ago this May I married my wife at Dalhousie Castle in Scotland. Dalhousie is a 14th century castle that has been turned into an incredible hotel. We then took our honeymoon traveling around Scotland including the Highlands and Skye.
    • I recently lost over 50 pounds through diet, exercise, and some friendly competition. I bet my brother-in-law that I could lose more weight than he could before Christmas (the one before last). The deal was that whoever lost had to buy the other an Xbox 360 for Christmas. I won, but because I am a softy, I bought him an Xbox 360 too.

    I tag Dave Donaldson, Nino, Michael Wood, Ben Carey, and Brad

    -James

     

  • Atlanta Code Camp 2007 Registration is Open

    Registration for Atlanta Code Camp 2007 on January 20th is now open.  Space is limited and fills up fast, so do NOT delay registering -- it's free.  Thanks to Jim Wooley for putting this together this year.

    I'll be presenting a session titled "Linq and O/R Mapping" that will be lots of real code and very little powerpoint.  If you've seen the standard Linq sessions already, or even if not, but you've been wanting more then this is for you.  I'm not going to waste any time on Linq to Objects or Xml, although those are cool in their right -- I will focus purely on Linq to Sql, and to a lesser extend Linq to Entities or Datasets.  Do you want to see a real application built using Linq to Sql?  That's what I plan to do, and I'll do it several ways so you can experience the possibilities.  For instance, should we use SqlMetal, the GUI Designer, or do our own thing with xml mappings instead of attributes?  What if you want to include some relationships, use some stored procs, and even some inheritance?  We shall cover all of those possibilities and more -- you will NOT be disappointed since this will not be just another slide deck or sample series based on what's already available.  In fact, I would actually challenge you to find any other "real" sample that includes all of these with xml mappings, but you won't find it since it doesn't exist.  I hope you get that I'm excited about this, as these technologies have definitely matured past my initial criticisms.  And even if you can't make it for some reason, I'll post at least some version of my sample app after the event is over for all to see.

  • A WPF Wonderland

    A couple months ago, I shared a ride to the Dallas airport with my friend Walt Ritscher. I remember Walt was excited about WPF and WPF/E - so excited it seems he now has a blog dedicated to the topic: WPF Wonderland.

    Walt added some west coast flair to my WPF/E Game Of Life code and hosted the sample. You can give it a whirl if you have the December 2006 WPF/E CTP installed.

  • The T-SQL Emitted by the aspnet_regsql.exe Command Line Program when Adding the Infrastructure for SQL Cache Dependencies

    In order to use SQL cache dependencies in ASP.NET 2.0 on the Express Edition of SQL Server 2005 or on SQL Server 7.0 or 2000, ASP.NET needs to continuously poll the database to determine if there's been any change to the monitored tables. For this to work, the database needs some infrastructure installed on it - namely a “maintenance” table named AspNet_SqlCacheTablesForChangeNotification that keeps track of each monitored table and its latest changeId, stored procedures for reading and writing to this table, and triggers on the monitored tables.

    This infrastructure is created using the aspnet_regsql.exe command line program, pointing it to the appropriate database and specifying that the polling infrastructure should be created on the database (which adds the maintenance table and sprocs) as well as what tables need to be monitored (which adds the triggers). aspnet_regsql.exe contains a switch called -sqlexportonly that will output the SQL syntax to a specified file, but sadly this option does not work with the polling infrastructure option. I was curious as to the output so I used SQL Profiler to examine the incoming T-SQL from aspnet_regsql.exe. I figured others might be interested as well, so I post it here to save others the three minutes it took me to get it from SQL Profiler:

    Running the database-related command, aspnet_regsql.exe -S server -d database -E -ed, results in the following T-SQL sent to the database:

    /* Create notification table */ IF NOT EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = 'AspNet_SqlCacheTablesForChangeNotification' AND type = 'U') IF NOT EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = 'AspNet_SqlCacheTablesForChangeNotification' AND type = 'U') CREATE TABLE dbo.AspNet_SqlCacheTablesForChangeNotification ( tableName NVARCHAR(450) NOT NULL PRIMARY KEY, notificationCreated DATETIME NOT NULL DEFAULT(GETDATE()), changeId INT NOT NULL DEFAULT(0) ) /* Create polling SP */ IF NOT EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = 'AspNet_SqlCachePollingStoredProcedure' AND type = 'P') IF NOT EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = 'AspNet_SqlCachePollingStoredProcedure' AND type = 'P') EXEC('CREATE PROCEDURE dbo.AspNet_SqlCachePollingStoredProcedure AS SELECT tableName, changeId FROM dbo.AspNet_SqlCacheTablesForChangeNotification RETURN 0') /* Create SP for registering a table. */ IF NOT EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = 'AspNet_SqlCacheRegisterTableStoredProcedure' AND type = 'P') IF NOT EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = 'AspNet_SqlCacheRegisterTableStoredProcedure' AND type = 'P') EXEC('CREATE PROCEDURE dbo.AspNet_SqlCacheRegisterTableStoredProcedure @tableName NVARCHAR(450) AS BEGIN DECLARE @triggerName AS NVARCHAR(3000) DECLARE @fullTriggerName AS NVARCHAR(3000) DECLARE @canonTableName NVARCHAR(3000) DECLARE @quotedTableName NVARCHAR(3000) /* Create the trigger name */ SET @triggerName = REPLACE(@tableName, ''['', ''__o__'') SET @triggerName = REPLACE(@triggerName, '']'', ''__c__'') SET @triggerName = @triggerName + ''_AspNet_SqlCacheNotification_Trigger'' SET @fullTriggerName = ''dbo.['' + @triggerName + '']'' /* Create the cannonicalized table name for trigger creation */ /* Do not touch it if the name contains other delimiters */ IF (CHARINDEX(''.'', @tableName) <> 0 OR CHARINDEX(''['', @tableName) <> 0 OR CHARINDEX('']'', @tableName) <> 0) SET @canonTableName = @tableName ELSE SET @canonTableName = ''['' + @tableName + '']'' /* First make sure the table exists */ IF (SELECT OBJECT_ID(@tableName, ''U'')) IS NULL BEGIN RAISERROR (''00000001'', 16, 1) RETURN END BEGIN TRAN /* Insert the value into the notification table */ IF NOT EXISTS (SELECT tableName FROM dbo.AspNet_SqlCacheTablesForChangeNotification WITH (NOLOCK) WHERE tableName = @tableName) IF NOT EXISTS (SELECT tableName FROM dbo.AspNet_SqlCacheTablesForChangeNotification WITH (TABLOCKX) WHERE tableName = @tableName) INSERT dbo.AspNet_SqlCacheTablesForChangeNotification VALUES (@tableName, GETDATE(), 0) /* Create the trigger */ SET @quotedTableName = QUOTENAME(@tableName, '''''''') IF NOT EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = @triggerName AND type = ''TR'') IF NOT EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = @triggerName AND type = ''TR'') EXEC(''CREATE TRIGGER '' + @fullTriggerName + '' ON '' + @canonTableName +'' FOR INSERT, UPDATE, DELETE AS BEGIN SET NOCOUNT ON EXEC dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure N'' + @quotedTableName + '' END '') COMMIT TRAN END ') /* Create SP for updating the change Id of a table. */ IF NOT EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = 'AspNet_SqlCacheUpdateChangeIdStoredProcedure' AND type = 'P') IF NOT EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = 'AspNet_SqlCacheUpdateChangeIdStoredProcedure' AND type = 'P') EXEC('CREATE PROCEDURE dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure @tableName NVARCHAR(450) AS BEGIN UPDATE dbo.AspNet_SqlCacheTablesForChangeNotification WITH (ROWLOCK) SET changeId = changeId + 1 WHERE tableName = @tableName END ') /* Create SP for unregistering a table. */ IF NOT EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = 'AspNet_SqlCacheUnRegisterTableStoredProcedure' AND type = 'P') IF NOT EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = 'AspNet_SqlCacheUnRegisterTableStoredProcedure' AND type = 'P') EXEC('CREATE PROCEDURE dbo.AspNet_SqlCacheUnRegisterTableStoredProcedure @tableName NVARCHAR(450) AS BEGIN BEGIN TRAN DECLARE @triggerName AS NVARCHAR(3000) DECLARE @fullTriggerName AS NVARCHAR(3000) SET @triggerName = REPLACE(@tableName, ''['', ''__o__'') SET @triggerName = REPLACE(@triggerName, '']'', ''__c__'') SET @triggerName = @triggerName + ''_AspNet_SqlCacheNotification_Trigger'' SET @fullTriggerName = ''dbo.['' + @triggerName + '']'' /* Remove the table-row from the notification table */ IF EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = ''AspNet_SqlCacheTablesForChangeNotification'' AND type = ''U'') IF EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = ''AspNet_SqlCacheTablesForChangeNotification'' AND type = ''U'') DELETE FROM dbo.AspNet_SqlCacheTablesForChangeNotification WHERE tableName = @tableName /* Remove the trigger */ IF EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = @triggerName AND type = ''TR'') IF EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = @triggerName AND type = ''TR'') EXEC(''DROP TRIGGER '' + @fullTriggerName) COMMIT TRAN END ') /* Create SP for querying all registered table */ IF NOT EXISTS (SELECT name FROM sysobjects WITH (NOLOCK) WHERE name = 'AspNet_SqlCacheQueryRegisteredTablesStoredProcedure' AND type = 'P') IF NOT EXISTS (SELECT name FROM sysobjects WITH (TABLOCKX) WHERE name = 'AspNet_SqlCacheQueryRegisteredTablesStoredProcedure' AND type = 'P') EXEC('CREATE PROCEDURE dbo.AspNet_SqlCacheQueryRegisteredTablesStoredProcedure AS SELECT tableName FROM dbo.AspNet_SqlCacheTablesForChangeNotification ') /* Create roles and grant them access to SP */ IF NOT EXISTS (SELECT name FROM sysusers WHERE issqlrole = 1 AND name = N'aspnet_ChangeNotification_ReceiveNotificationsOnlyAccess') EXEC sp_addrole N'aspnet_ChangeNotification_ReceiveNotificationsOnlyAccess' GRANT EXECUTE ON dbo.AspNet_SqlCachePollingStoredProcedure to aspnet_ChangeNotification_ReceiveNotificationsOnlyAccess

    Running the table-related command, aspnet_regsql.exe -S server -d database -E -t tableName -et, simply calls the AspNet_SqlCacheRegisterTableStoredProcedure sproc passing in the name of the specified table:

    exec dbo.AspNet_SqlCacheRegisterTableStoredProcedure @tableName=N'tableName'

    This stored procedure - added when registering the infrastructure eith the -ed switch - creates an insert/update/delete trigger on the specified table that invokes the AspNet_SqlCacheUpdateChangeIdStoredProcedure stored procedure, passing in the table's name. AspNet_SqlCacheUpdateChangeIdStoredProcedure simply updates the changeId value in the appropriate row in AspNet_SqlCacheTablesForChangeNotification.

    For more on using SQL cache dependencies in an ASP.NET 2.0 web application, see Caching in ASP.NET with the SqlCacheDependency Class, Overview of SqlCacheDependency, or wait for my upcoming Working with Data in ASP.NET 2.0 tutorial on the topic.

  • AJAX UpdatePanels and ContentPlaceHolders

    I've seen the following model popup frequently:

    <asp:ScriptManager ID="ScriptManager1" runat="server" />

    <
    asp:Menu ID="Menu1" runat="server" Orientation="Horizontal">
        <Items>
            <asp:MenuItem
                
    NavigateUrl="~/Default.aspx" Text="Default.aspx" />
            <asp:MenuItem
                
    NavigateUrl="~/Default2.aspx" Text="Default2.aspx"  />
        </Items>
    </
    asp:Menu>

    <
    asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server"/>
        </ContentTemplate>
    </
    asp:UpdatePanel>

    This is an ASP.NET MasterPage with a content placeholder wrapped inside an UpdatePanel. A menu control provides links to default.aspx and default2.aspx - both content pages that use this master page.

    The misconception is that the update panel will magically reload only the area inside the ContentPlaceHolder control when the user clicks on a navigation link in the menu. This example uses a menu, but we could substitute any type of control that generates hyperlinks to a new page. Since both pages use the same master page, this behavior seems plausible.

    The behavior described above isn't how AJAX and MasterPages work, however.

    First, the hyperlink forces the browser to navigate to an entirely new page. There is no opportunity for the partial page rendering magic of AJAX to work. When the user clicks a navigational link, the browser will load 100% of the new page. If you want to update just the content area then you need the browser to stay on the same content page.

    Secondly, ASP.NET always mashes the MasterPage and ContentPage into a single piece of output. From the client browser's perspective, it's all coming from the same resource. Each new page request will require ASP.NET to recreate both the master page and content page (assuming there is no caching). If you want to embed the contents of a new page into an existing page, then HTML IFRAME element still wants to be your friend.

  • A Message For You

    Some might say it's a day late, but nevertheless, it is a message. And it's for you.

    Of course, you'll have to figure out what the message is by reading the source code. This year's code isn't quite as ugly as last year's code, but if you can figure this one out without a compiler - three cheers! If you do figure it out, you might still want to run the code as a console application to see the full effect...

    using System;
    using System.Collections;

    class _2007_
    {
        
    static void Main()
        {
            
    int x, y; x = y = 0;
            
    Console.SetWindowSize(84, 7);
            
    do
            {
                
    foreach (string i in Order)
                {
                    
    foreach (int n in numbers[Int32.Parse(i)])
                    {
                        
    Console.SetCursorPosition(x + n % 5,
                                                  y + n / 5);
                        
    Console.ForegroundColor = SomeColor;
                        
    Console.Write("@");
                    }
                    x += 6;
                }
            }
    while (!Console.KeyAvailable && (x = y = 0) < 1);
        }

        
    static IEnumerable Order
        {
            
    get
            {
                
    yield return 4.ToString(); yield return 6.ToString();
                
    yield return 2.ToString(); yield return 2.ToString();
                
    yield return 1.ToString(); yield return 0.ToString();
                
    yield return 3.ToString(); yield return 8.ToString();
                
    yield return 5.ToString(); yield return 0.ToString();
                
    yield return 1.ToString(); yield return 8.ToString();
                
    yield return 6.ToString(); yield return 7.ToString();
            }
        }

        
    static int[][] numbers =
        {            
            
    new int[] { },
            
    new int[] {0,4,5,9,11,12,13,17,22},
            
    new int[] {0,1,2,3,5,9,10,11,12,13,15,20},
            
    new int[] {0,4,5,6,9,10,12,14,15,18,19,20,24},
            
    new int[] {0,4,5,9,10,11,12,13,14,15,19,20,24},
            
    new int[] {0,4,5,9,10,14,15,17,19,20,21,23,24},
            
    new int[] {1,2,3,5,9,10,11,12,13,14,15,19,20,24},
            
    new int[] {0,1,2,3,4,5,9,10,11,12,13,15,18,20,24},
            
    new int[] {0,1,2,3,4,5,10,11,12,13,14,15,20,21,22,23,24}
        };

        
    static ConsoleColor SomeColor
        {
            
    get
            {
                
    return (ConsoleColor)colors.GetValue(
                        rand.Next(colors.Length)
                    );
            }
        }

        
    static Array colors = Enum.GetValues(typeof(ConsoleColor));
        
    static Random rand = new Random();
    }


  • Sidebar Gadget Article

    A new year deserves a new OdeToCode article: "Developing Gadgets for the Windows Vista Sidebar".

    Feedback is always appreciated.
  • A few VS 2005 SP1 Links and Information Nuggets

    In  you were out the second half of December, you might have missed some of the VS 2005 Service Pack 1 posts that I've previously made:

    Below are a few more recent links and blurbs of information about VS 2005 SP1 that you might also find useful:

    1) Details on some of the specific bug-fixes and changes for web app support in VS 2005 SP1

    The VS servicing team is putting together a page that you'll be able to visit to obtain a more complete list of changes/fixes within VS 2005 SP1 as a whole.  Until then, you can check out this blog post: Visual Studio 2005 SP1 Released - details about changes for web tools.  This summarizes a lot of the changes specifically made in VS 2005 SP1 by the VS Web Tools team that builds the designer and project system that targets ASP.NET.

    2) How to determine if you have VS 2005 SP1 Installed

    A few people have asked me how they can tell if VS 2005 SP1 installed successfully.  Two ways you can quickly check if VS 2005 SP1 is installed:

    a) Select the "Help->About Visual Studio 2005" menu item within the IDE and check to make sure that SP1 is listed as one of the installed items:

    and

    b) Select the "File->New Project" menu item within the IDE and check to make sure that the VS 2005 Web Application Project model option (which is now built-in with SP1) is installed and works:

    Heath Stewart also has a good post on how to programmatically detect if VS 2005 SP1 is installed (by checking a registry entry) if you want a more programmatic way to detect if it is installed.

    Important: VS 2005 SP1 needs to be installed for each instance of Visual Studio that is installed on your machine - so if you have Visual Web Developer Express, Visual Basic Express and Visual Studio Professional installed it will need to install SP1 three times (once for each instance).  If you cancel out of the install part-way through you might find that SP1 installed for some of the instances but not for all of them.  Using the above steps will enable you to check to make sure that the instance of Visual Studio that you are using had it applied successfully.  If not, then re-run the SP1 setup to install it on the remaining VS instances on your machine.

    3) What happens when you install VS 2005 SP1?

    A lot of people have asked "what is it doing that takes so long to install VS 2005 SP1?" 

    Heath Stewart from the VS Setup team has put together an awesome post that details the steps that occur during the VS 2005 SP1 Install Experience.  It also details a number of ways to improve the performance of the install (as well as why these steps improves the performance).  I'd definitely recommend reviewing this if you want to understand exactly what is going on during the install experience.

    4) Improve Performance and Disk Space when installing VS 2005 SP1

    One very important setup performance tip is to make sure you disable anti-virus software before launching the VS 2005 SP1 install.  Because anti-virus software typically scans all files before they are read, and the VS 2005 SP1 patch is both large *and* read multiple times, having anti-virus software enabled can significantly impact your setup performance.  Turn this off before running install, and then re-enable it once it is complete.

    For further tips to improve SP1 install performance read Heath's detailed SP1 install post here.  In particular, look for his suggestions on disabling the SAFER check, as well as with how to use the /quiet flag.  Both of these should improve setup performance of VS 2005 SP1 significantly.

    5) How to work around a "Error 1718. filename.msp was rejected by digital signature policy" error message when installing on Windows Server 2003

    Several people commented on my first SP1 blog post about running into an error message when installing VS 2005 SP1 on Windows Server 2003 about a "digital signature policy" failing to be validated.

    This KB Article describes how to work around this problem. 

    6) Slipstreaming the VS 2005 SP1 Patch onto a VS 2005 Setup (to avoid having to install it again on a new machine)

    Heath has another great post here on how you can automatically slip-stream the SP1 patch into your own modified VS 2005 setup program so that you can create an already patched VS 2005 Install for yourself (or better yet for your team).  This avoids you in the future having to install VS 2005 and then run the SP1 patch when doing a clean install on another machine.

    Future VS 2005 downloads from MSDN will have SP1 automatically applied.  Until then you can use this article if you want to learn how to create your own slipstreamed setup in the meantime.

    Hope this helps,

    Scott

    P.S. Where possible, please post SP1 install questions on Heath's blog posts above - since he is the real expert of how the VS 2005 SP1 install process works.  I'm also still on vacation still this week (posting from a hotel room right now), and so will be slow to respond to blog comments and questions (so his blog might be faster to get a response).

This Blog

Syndication

Powered by Community Server, by Telligent Systems
'