July 2010 - Posts

Links to Scott Guthrie's Using LINQ to SQL Tutorials
27 July 10 11:56 PM | Scott Mitchell | 5 comment(s)

Back when Visual Studio 2008 came out, Scott Guthrie wrote an excellent series of blog posts on using LINQ to SQL. Unfortunately, the various installments are not easy to follow when starting from Part 1 and going onward, so I've decided to gather and organize the links here for myself and for anyone else interested in his tutorial.

Using LINQ to SQL

Also, there was (at one time) a single PDF containing all of these tutorials, but the website where it was hosted appears to be offline. Does anyone have a copy of that PDF they'd care to send me to host?

UPDATE: Some time ago a developer by the name of Kadir Pekel compiled all nine tutorials into a single PDF and hosted them on his website, http://it-box.blogturk.net, but that website no longer is around. Helpful reader Milan had a copy of said PDF and sent it to me (thank you!), which you can download here, if interested: http://www.datawebcontrols.com/classes/LINQToSql.zip

Happy Programming!

A Review of Desktop / Screen Sharing Software
18 July 10 12:32 AM | Scott Mitchell | 15 comment(s)
I work as an independent consultant and trainer. Most of my business involves me meeting with clients (in person or online), discussing their needs, and then building a new application or enhancing an existing one from my own desktop. However, a growing part of my business has been what I call "online consulting and training," which involves me using screen sharing software to remote into the client's computer. The client is seated at his computer and we are on the phone and during these meetings we'll either practice pair programming, hash out a particularly difficult block of code, or use the time as a one-on-one tutoring session. Some clients I meet with regularly (like 3 hours every week, say), while for others we meet when something comes up and they need a helping hand.

If you're interested in such online consulting or training, please drop me a line at mitchell@4guysfromrolla.com. You can find out more about my experience and rates at http://www.4guysfromrolla.com/ScottMitchell.

In any event, I spend a fair amount of time - 5-15 hours a week, usually - sharing my desktop or working from the client's desktop. During these sessions there's the same sort of activities you perform when developing ASP.NET applications at your workstation: typing in code, switching between Visual Studio, the browser, running queries from SQL Server Management Studio, and so forth. I've evaluated four different screen sharing programs and thought I'd share what I liked best about each and what I liked least. Keep in mind that my rankings are based on my typical usage when sharing screens. If you are doing something different - showing a PowerPoint presentation, for instance - your mileage may vary.

Here they are, from worst to first:

#4.) FogCreek Copilot
Copilot has a couple of really nice selling points when compared to the other three competitors:

  • It's the most affordable - starting at $244/year, or $24/month, Copilot is about half of what the other competitors charge. Plus you can buy a one-day pass for $5 during the week - on the weekends, it's free!
  • It's especially easy to start the meeting - unlike some of the other options, which involve first time users to download and install software prior to joining the meeting, Copilot is run from an executable that doesn't require any installation steps. Just download the file, double-click it, and you're off and running. This can be helpful when assisting a computer "challenged" friend or when working with someone in a corporate environment that prohibits them from installing software on their machine.

The big problem with Copilot is that it is slooooow. Switching from one full screen window to another can take a could one to three seconds. What's more, if you're not a slow typer you'll find that there is a noticeable lag when viewing a remote user's screen and typing into it. Type - wait a half-second - the letter appears. Type - wait a half-second - the letter appears. Needless to say, it can be quite frustrating to speedily type out a long line of code. I don't have the patience to type one character at a time, continuing only when the letter shows up. My clients, who are paying by the hour, wouldn't be satisfied with this approach either. So I end up typing a line of code and don't see the whole line complete until a couple of seconds after I finished typing. And if you transposed two letters or forgot a parenthesis you have to carefully (and slowly) move the cursor back to the right spot and then fix the mistake.

Another problem with Copilot is that you can't seamlessly switch control from one desktop to another. Say that I am viewing the client's remote computer and want to show them a diagram on my computer. It would be nice to be able to just click a button and have them see my screen, but that's not possible with Copilot. Also, Copilot only allows one-on-one screen sharing. You can't have a meeting with three (or more) attendees.

Copilot's ease of setup and low price point may make it attractive to people doing limited screen sharing or for those giving presentations or assisting a family member with a computer problem, but it is not a viable option for online consulting and training due, primarily, to its speed issues.

#3.) Adobe Connect Pro
Of all the desktop sharing products I evaluated, Adobe Connect Pro is certainly the easiest to get a meeting started. Adobe Connect Pro meetings are powered by Flash, which means if the participants have Flash installed on their computers (and, honestly, who doesn't these days?) then they can join the meeting. There's no software to download, nothing to install.

It seems that Adobe Connect Pro is more targeted to online meetings and eLearning scenarios than desktop sharing. While Adobe Connect Pro certainly allows the host (or a participant) to share their desktop with everyone else, it also has features like online quizzes, registration forms, and other features that would be useful for teaching an online class, but not at all needed for doing the type of online consulting and training that I do. And while I'm sure their online quizzes and other eLearning features are all top notch, I regret to report that their screen sharing is not - it suffers from the same speed issues found in Copilot. In short, there is a perceptible delay when typing on the remote user's computer; likewise with switching between windows on the remote computer.

Adobe Connect Pro is also the most expensive option out of the bunch. An annual plan will run you $540. By the month it's $55. Adobe offers a pay-per-use option, but that's $0.32 per minute per user, which can add up fast. While the two share similar speed problems, I decided to rank Adobe Connect Pro ahead of Copilot because it does offer more screen sharing features, like the ability to toggle between the host and participant's screens, and the ability to choose which monitor to share (if you have multiple monitors), and audio conferencing options. But for some these extra features might not be worth the added cost.

#2.) GoToMeeting
After using Copilot and Adobe Connect Pro, the first thing you notice about GoToMeeting is that there is no longer a delay when typing. Sure, there may be a hiccup every now and then when the network gets congested, but for the most part every time you type a letter from your keyboard, wham, it appears on the remote computer instantly. Also, switching between windows on the remote computer is noticeably faster than with Copilot or Adobe Connect Pro.

Unlike the previous two products, GoToMeeting requires a bit more of an installation process to join (or host) a meeting. It's all very nicely automated - you only need to click a few "I Agree"s and "Next" buttons - but these extra steps might trip up a computer novice. And the need to install software may be a deal breaker in certain corporate environments.

My biggest gripe with GoToMeeting is that the client swallows (or outright disallows) certain keyboard shortcuts when typing from the host computer into a remote computer. And it's not just any keyboard shortcuts that are not permitted, but two of the most popular ones: Alt+Tab and Ctrl+C. Say you're writing code and want to copy some block of text and paste it elsewhere. If you're at all like me, you instinctively use the keyboard to highlight the selected text and then use Ctrl+C to copy it to the clipboard. However, this combination does not copy anything to the clipboard. Consequently, when you later hit Ctrl+V, what was previously in the clipboard gets emitted! In order to copy to the clipboard you need to select the text and then, using your mouse, right-click it and choose Copy from the context menu. Similarly, Alt+Tab doesn't work. Alt+Tab, when typed from the host computer, tabs out of the GoToMeeting window and to a different window on your desktop. If you want to switch between windows on the remote computer you have to use your mouse and click the appropriate window from the taskbar.

GoToMeeting has all of the screen sharing bells and whistles. You can have up to 15 participants. Sharing one participant's screen with the group or sharing the host's screen is quite simple, too. There's a phone number participants can optionally call to join an audio conference, or the conferencing can be done over the Internet using the computer's speakers and microphone.

Price-wise, GoToMeeting falls in between CoPilot and Adobe Connect Pro. You can sign up for an annual plan for $468 or go monthly for $49.

#1.) Webex
Webex is a lot like GoToMeeting. Both have a similar download and install story. Both cost the same. Both have comparable performance (although Webex does seem a tad bit faster to me). And both offer pretty much the same feature set.

The differences between the two are, by most accounts, minor ones, although as one who prefers using the keyboard over the mouse, these differences are important. Namely, the Webex client doesn't swallow keyboard shortcuts. Alt+C and Alt+Tab work as expected when typing from my keyboard to the remote client's computer. That's not to say the Webex client is not without its own annoyances. In fact, there are two that irk me. First, when the remote user is made the presenter and shares his screen with me, a little command window with various options appears on the remote computer's desktop in the lower right corner. These options are only displayed on the remote computer's screen and not on my screen. However, if I have control of the remote client's computer and move my mouse to the lower right corner and click it, my clicks are intercepted by that command window (even though I don't see it). The problem goes away if the remote client remembers to minimize that command window. It would be nice to have an option that would hide that command window right away (or not have it intercept my clicks or show it to me, as well).

The second issue is that when I have control of the remote client's computer a little bubble follows my mouse cursor that says to the remote client and me, "Scott has control of your computer. Click here to take control back." This bubble is supposed to be beneath the mouse cursor and offset to the right, but every now and then the mouse cursor gets positioned over it and, wouldn't you know, when that happens any mouse click is intercepted by that bubble. It doesn't revert control back to the remote client, but it does "swallow" my mouse click. I have to "jiggle the mouse" to get it off that bubble so that I can click what I meant to click in the first place.


In Conclusion...
So there you have it, Webex is the winner. You don't have to take my word for it, though - each of these products offers a free trial so you can experiment with each and find which one best fits your workload.

For background, when I first started offering online consulting and training I used Copilot for several months, suffering through the speed issues. I incorrectly had presumed that all screen sharing products were going to have a little bit of lag. After one particularly frustrating day I decided to try GoToMeeting for giggles as they had a free 30 day trial. I was blown away by the difference in speed and immediately switched. The $25 extra each month was definitely worth it. Earlier this year, GoToMeeting updated their software to a new version where the Ctrl+C shortcut no longer worked. Their telephone support was helpful and was able to roll me back to the previous version so that I could continue to use the keyboard to copy and paste. A month ago (or so), they stopped supporting the old version of the software and upgraded me to the new version (which still did not support Ctrl+C). At that point I evaluated Adobe Connect Pro and then Webex, which is what I use today.

Happy (Remote) Programming!

In addition to evaluating these four products, I also tried Microsoft Live Meeting. Unfortunately, the client I attempted to evaluate this product with received error messages when attempting to download the software used by the meeting. This happened on two separate occasions, so I threw in the towel.

Filed under:
HOWTO: Update Records in a Database Table With Data From Another Table (MS SQL Server)
13 July 10 08:01 AM | Scott Mitchell | 6 comment(s)

SQL's UPDATE statement makes it easy to update one or more records in a database table. The most common UPDATE statement pattern assigns static or parameterized values to one or more columns:

UPDATE MyTable SET
    Column1 = Value1,
    Column2 = Value2,
    ...
WHERE PrimaryKeyColumn = SomeValue

But what if you need to update values in one database table from values in another database table? There are a couple ways this can be done. One way is to use a subquery:

UPDATE MyTable SET
    Column1 = (SELECT SomeColumn FROM SomeOtherTable WHERE SuchAndSuch = ThisAndThat),
    Column2 = (SELECT SomeOtherColumn FROM SomeOtherTable WHERE SuchAndSuch = ThisAndThat),
    ...
WHERE PrimaryKeyColumn = SomeValue

Alternatively, you can use a JOIN statement in your UPDATE clause. The precise syntax seems to vary a bit based on the database system. For Microsoft SQL Server, use the following syntax:

UPDATE MyTable SET
    Column1 = SomeOtherTable.SomeColumn,   
    Column2 = SomeOtherTable.SomeOtherColumn,
    ...
FROM MyTable
    INNER JOIN SomeOtherTable ON
        MyTable.SuchAndSuch = SomeOtherTable.ThisAndThat
WHERE PrimaryKeyColumn = SomeValue

Bear in mind that updating data in one table with data from another table may be a sign of bad database design. I've seen developers use these approaches to duplicate data across multiple tables so that it's "easier" or "quicker" to write a query to read the data, but such actions are (usually) folly. Data duplication may make your SELECT queries easier to write, but you can very easily end up with data integrity issues.

So when might you need to copy data from one table to another? Consider a help desk application that allows support staff to create support tickets, where each ticket in the system exists as a record in the Tickets table. A ticket may have dozens of data points. To ease data entry, let's say that administrative users can create "ticket templates," which pre-define the values for a number of ticket data points that are stored in a table named TicketTemplates. Applying a template to an existing ticket would require that the existing record in the Tickets table have its non-set data points assigned to the corresponding default values of the selected template. Presume that the Tickets table has a TicketTemplateId field that indicates what template is to be applied to the ticket. Once this value has been assigned, the following UPDATE statement could be executed to copy the template's pre-defined values to the non-assigned data points in the Tickets table:

UPDATE Tickets SET
    PriorityId = ISNULL(Tickets.PriorityId, TicketTemplates.PriorityId),
    CategoryId = ISNULL(Tickets.CategoryId, TicketTemplates.CategoryId),
    IsPublic = ISNULL(Tickets.IsPublic, TicketTemplates.IsPublic),
    ...
FROM Tickets
    INNER JOIN TicketTemplates ON
        Tickets.TicketTemplateId = TicketTemplates.TicketTemplateId
WHERE Tickets.TicketId = @TicketId

Happy Programming!

Filed under:
Determining an ASP.NET Page's View State Footprint
06 July 10 11:35 PM | Scott Mitchell | 6 comment(s)

ASP.NET view state is the technique used by an ASP.NET Web page to persist changes to the state of a Web Form across postbacks. The view state of a page is, by default, placed in a hidden form field named __VIEWSTATE, and can easily get very large. Not only does the __VIEWSTATE form field cause slower downloads, but, whenever the user posts back the Web page, the contents of this hidden form field must be posted back in the HTTP request, thereby lengthening the request time, as well. Because view state is buried in a hidden form field and because as developer we typically test locally, the affect of view state bloat on the user experience requires preemptive action. Steps must be taken to measure view state's size and to take steps in trimming down view state if it begins to negatively affect the user experience.

There are a variety of techniques for measuring the view state size on a given page. Perhaps the simplest is to turn on page tracing. With page tracing enabled you can see the estimated view state of each control in the control hierarchy. For instance, the screen show below shows that two Labels on my page consume (roughly) 120 bytes of view state each.

There's also a free add-on for Firefox that reports view state size directly in your browser window: Viewstate Size. When installed, this add-on will show a little icon in your browser's lower right corner reporting the view state size for a given page.

 

It's also possible to determine the view state size programmatically. Today I was working on a demo for an article and wanted to have the view state size displayed on every page. After reading an article I wrote back in 2004 - Understanding ASP.NET View State - I came up with the following code snippet to compute and display the view state size for a given page. This technique uses the "old school" way of doing it, relying on objects that have been around since ASP.NET's inception. Consequently, the below code will work in any ASP.NET application.

Visual Basic Version:

Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
    MyBase.SavePageStateToPersistenceMedium(state)

    Dim formatter As New LosFormatter()
    Dim viewStateLength = -1

    Using writer As New StringWriter()
        formatter.Serialize(writer, state)
        viewStateLength = writer.ToString().Length
    End Using

    Response.Write(String.Format("<h1 class="" viewstate-summary="">Total ViewState Size For This Page: {0:N0} bytes</h1>", viewStateLength))
End Sub

C# Version:

protected override void SavePageStateToPersistenceMedium(object state)
{
    base.SavePageStateToPersistenceMedium(state);

    var formatter = new LosFormatter();
    var viewStateLength = -1;

    using (var writer = new StringWriter())
    {
        formatter.Serialize(writer, state);
        viewStateLength = writer.ToString().Length;
    }

    Response.Write(String.Format(@"<h1 class="" viewstate-summary="">Total ViewState Size For This Page: {0:N0} bytes</h1>", viewStateLength));
}

The approach overrides the SavePageStateToPersistenceMedium method, which is what is invoked when the page is ready to persist its view state. In ASP.NET 1.x you would override this method to store view state to an alternative store, such as to a file on the web server, rather than in a hidden input field on the form. Starting with ASP.NET 2.0 you could use the PageStatePersister class. However, here I just want to compute the size of the serialized view state string. Consequently, I start by calling the base class's SavePageStateToPersistenceMedium method. Next, I replicate the default logic that the ASP.NET Page class uses to serialize view state - namely, I create a LosFormatter object and serialize the content to a StringWriter. Once I've done this I can determine the size of the persisted view state by getting the StringWriter's contents and determining how many characters are included. The above code can be placed directly in a code-behind class or, better yet, in a custom base Page class.

The above programmatic approach is relatively easy to implement and works in all versions of ASP.NET. However, it won't produce the precise view state size for ASP.NET 2.0 applications and beyond. This is because the LosFormatter class was replaced with a new formatting type, ObjectStateFormatter, starting in ASP.NET 2.0. (You can certainly use the LosFormatter code above in ASP.NET 2.0 and beyond applications, as the class remains in the framework for backwards compatibility. Granted, the reported view state size and actual size will differ slightly, but in analyzing whether a page contains too much view state or not, precise numbers aren't required - a close estimate will usually suffice.)

To get precise measurements we can use the ASP.NET 2.0+ by doing the following:

  1. Create a class that extends the HiddenFieldPageStatePersister class. This is the class that is used by ASP.NET (by default) to persist view state and other information to hidden form fields. We want to extend this class to include a property that reports the size of the persisted state, and
  2. Override the Page class's PageStatePersister property and return the custom persister class created in step 1.
  3. Override the Page class's SavePageStateToPersistenceMedium method and read the value of the view state size from the class created in step 1.

Here's the code for the class that extends HiddenFieldPageStatePersister, which I've named MyHiddenFieldPageStatePersister (please don't mock me for my lack of naming creativity). This class is pretty simple: it defines a property named StateSize, overrides the Save method, and then sets the StateSize property from this method using the same code/logic as used internally by the HiddenFieldPageStatePersister class. The code snippet below takes advantage of some language features that you might not have at your disposal if you're using an older version of C# or VB (for example, the use of automatic properties). But the concept is sound and should work (with a little tweaking) in earlier versions of VB/C#. (I tested this using ASP.NET 4. You can download the complete source code here.)

Visual Basic Version:

Public Class MyHiddenFieldPageStatePersister
    Inherits HiddenFieldPageStatePersister

    Public Sub New(ByVal page As Page)
        MyBase.New(page)
    End Sub

    Public Overrides Sub Save()
        If MyBase.ViewState IsNot Nothing OrElse MyBase.ControlState IsNot Nothing Then
            Me.StateSize = MyBase.StateFormatter.Serialize(New Pair(MyBase.ViewState, MyBase.ControlState)).Length
        End If
        
        MyBase.Save()
    End Sub

    Public Property StateSize As Integer
End Class

C# Version:

public class MyHiddenFieldPageStatePersisterCS : HiddenFieldPageStatePersister
{
    public MyHiddenFieldPageStatePersisterCS(Page page) : base(page) { }

    public override void Save()
    {
        if (base.ViewState != null || base.ControlState != null)
            this.StateSize = base.StateFormatter.Serialize(new Pair(base.ViewState, base.ControlState)).Length;

        base.Save();
    }

    public int StateSize
    {
        get;
        private set;
    }
}

The last step, then, is to override the Page class's PageStatePersister property and return an instance of our persister class, MyHiddenFieldPageStatePersister. Again, this can be done in the code-behind class of an ASP.NET page, but I recommend putting it in a custom base Page class.

Visual Basic Version:

Private _PageStatePersister As PageStatePersister = Nothing

Protected Overrides ReadOnly Property PageStatePersister As System.Web.UI.PageStatePersister
    Get
        If _PageStatePersister Is Nothing Then
            _PageStatePersister = New MyHiddenFieldPageStatePersister(Me)
        End If

        Return _PageStatePersister
    End Get
End Property

C# Version:

private PageStatePersister _PageStatePersister = null;

protected override PageStatePersister PageStatePersister
{
    get
    {
        if (_PageStatePersister == null)
            _PageStatePersister = new MyHiddenFieldPageStatePersisterCS(this);

        return _PageStatePersister;
    }
}

EDIT [2010-07-07]: I forget an important final piece of the puzzle for using the MyHiddenFieldPageStatePersister class! In addition to overriding the PageStatePersister property you also need to override the SavePageStateToPersistenceMedium method like in the LosFormatter example, but instead of using LosFormatter you need to read the value of the StateSize property from the MyHiddenFieldPageStatePersister class. The code for this overridden method follows:

Visual Basic Version:

Protected Overrides Sub SavePageStateToPersistenceMedium(ByVal state As Object)
    MyBase.SavePageStateToPersistenceMedium(state)

    Dim myPersister As MyHiddenFieldPageStatePersister = CType(Me.PageStatePersister, MyHiddenFieldPageStatePersister)

    Response.Write(String.Format("

Total ViewState Size For This Page: {0:N0} bytes

", myPersister.StateSize)) End Sub

C# Version:

protected override void SavePageStateToPersistenceMedium(object state)
{
    base.SavePageStateToPersistenceMedium(state);

    var myPersister = this.PageStatePersister as MyHiddenFieldPageStatePersisterCS;

    if (myPersister != null)
        Response.Write(String.Format(@"

Total ViewState Size For This Page: {0:N0} bytes

", myPersister.StateSize)); }

Happy Programming!

More Posts

Archives

My Books

  • Teach Yourself ASP.NET 4 in 24 Hours
  • Teach Yourself ASP.NET 3.5 in 24 Hours
  • Teach Yourself ASP.NET 2.0 in 24 Hours
  • ASP.NET Data Web Controls Kick Start
  • ASP.NET: Tips, Tutorials, and Code
  • Designing Active Server Pages
  • Teach Yourself Active Server Pages 3.0 in 21 Days

I am a Microsoft MVP for ASP.NET.

I am an ASPInsider.