Friday, September 25, 2009

Silverlight duplex client limitation

I ran into an interesting (and largely irrelevant) limitation today on Silverlight's implementation of duplex web services.

I'd been using Jeff Wilcox's handy Silverlight Unit Test Framework to test the data access piece of my current Silverlight project. However, I was running into a nasty problem that was driving me nuts. Part way through every test run, my unit tests would start failing. I could usually get through something like 10 or so tests before every new WCF call would return "Not Found" (which is not really the most helpful error message Microsoft ever came up with). It didn't have anything to do with the individual tests themselves, because the error would show up after 10 tests, no matter which 10 tests they were.  I'd been working through this error for some time before I realized that the "10" number was undoubtedly significant, since that seems to be the default number of connections that WCF allows, unless you go in and bump it higher. (Now of course, IMO, that's a pretty dumb default: the obvious purpose for leaving it that low is to prevent DOS attacks -- but the net result is that instead of needing some 10,000 connections to DOS your server, you only need 10. Sigh.)

This made me think that I might be leaking a connection somewhere. In theory, I was closing all my connections in one test before moving on to another, but we all know how well that works :-).  Since I was opening and closing all my connections through the same static class, I wrote up some quick instrumentation, and saw that yeah, one connection was staying open after every test.  Some additional poking around, and I found a method that was opening a new connection and failing to close it.  Easily fixed.  Instead of this final line in my method:

EnqueueTestComplete();

I just made it do this:

EnqueueCallback(() => DataConnectionManager.TryClientClose(client,
            error => EnqueueTestComplete()));

And TryClientClose() looks something like this:
        public static void TryClientClose(RoomServiceClient client, OperationCallback callback)
        {
            if (client != null && client.State == CommunicationState.Opened)
            {
                client.CloseCompleted += (sender, e) =>
                {
                    ClientsClosed++;
                    ClientsOpen--;
                    if (e.Error != null)
                    {
                        client.Abort();
                    }
                    if (callback != null)
                    {
                        callback(e.Error);
                    }
                };
                client.CloseAsync();
            }
            else
            {
                if (callback != null)
                {
                    callback(null);
                }
            }
        }

Close enough. But why was I running into this error in the first place?  Truth be told, I don't completely know.  But my best guess is that the Silverlight client (or maybe the browser that's hosting it) has a limitation on how many duplex callback sessions it can support.  And so far as I'm aware, there's no way to increase this number.  At least, I've poked around in all the relevant blogs, and looked through the appropriate docs, and can't find anything obvious.  But the net result is that you don't want to have more than 10 duplex clients open at the same time on any given Silverlight application.

Saturday, September 19, 2009

And Three More Silverlight Complaints

Unhelpful error messages rank high on my list of complaints about Silverlight and WPF. Take this particular error message: AG_E_PARSER_BAD_TYPE. I get it pretty regularly, but this particular instance started showing up about 15 minutes ago. The location that it points to (presumably in App.xaml? – it doesn't actually say) has nothing to do with the error in question.

The error is presumably triggered by some XAML I screwed up somewhere in one of the 50+ different XAML files in my solution. I have no idea which file (I just did a big search-and-replace as part of a codebase-wide refactor). So first of all: AG_E_PARSER_BAD_TYPE? Since when does that qualify as an error message? We're not doing sockets programming here, folks. The CLR allows for an incredibly rich set of exceptions. So why the incomprehensible error message? But more to the point, why am I being pointed to the wrong location? One of the things that makes the Silverlight tools for Visual Studio feel so frustrating is that they know which file is problematic, and they know precisely what the problem is, and they refuse to tell me. Yes, I know my reaction makes Silverlight a little more anthropomorphic than necessary. But it sure as heck feels like the Microsoft tools are out to get me sometimes. (For what it's worth, after an hour of troubleshooting, I opened the solution in Blend, and for once, Blend gave me what I needed to know, and immediately highlighted the problematic file.)

My second complaint is bogus error messages, i.e., error messages when there's no error. Again, to take one example of many, in one particular form in my project, Visual Studio lists 27 different errors, all having to do with certain local controls not being found.

The assembly in question (SlideLinc.Client.dll) and the associated namespace (SlideLinc.Client) are registered correctly in the form, and indeed, the form loads and executes correctly at runtime. For once, Blend recognizes this, and doesn't raise any errors. In other words, there's no problem. But I've tried six ways from Sunday to make those errors go away in Visual Studio, and nothing has been successful. In this particular case, it's generally not that problematic – except when it comes time to track down a real error, and you have to fight your way through dozens of bogus error messages to find the right one. (It's at least a tad ironic that these bogus error messages at least show up at the right time, i.e., when the app is compiling, and are able to point me to exactly the place where they – incorrectly – think the error is occurring. In contrast, the quite real AG_E_PARSER_BAD_TYPE error that I ran into above showed up way too late, at runtime, and wouldn't even tell me which file it was occurring in. It's this kind of stuff that makes you pull your hair out – and which has cost me at least a month of troubleshooting on my current project.)

My third complaint is more specific, and has to do with the Add Service Reference feature in Visual Studio. Specifically, I run into two reoccurring, distinct, but possibly related bugs when I try to update my service references. Neither of these occurred with the March 2009 SL3 CTP, and both started showing up immediately after I upgraded to SL3 RTW.

  1. Periodically (about a third of the time), when I pull open the "Configure Service Reference" dialog box, the "ObservableCollection" option for collection types isn't available; instead, there's something listed called "(Custom)", which is apparently interpreted as "Array[]". So when it generates your proxy references, it generates any list of values as an array, rather than an ObservableCollection. This breaks all your existing code, which of course was written to expect an ObservableCollection in those instances. What usually fixes it for me is simply restarting Visual Studio. Nothing else seems to work.
  2. The second problem is that periodically the Reference.cs file fails to generate – which of course also breaks all your existing code. I ran into a tip from someone, somewhere, who recommended deselecting the option "Reuse types in specified referenced assemblies", and then select only "System.Core". When I do this, and then I update my service reference, it seems to fix this pretty reliably. Sometimes it happens anyway, at which point in time I simply change which referenced assemblies it should try to reuse, and then immediately everything works again.

On this last point, I should note that lots of other folks besides me have been running into these issues. Indeed, I don't know anybody who regularly works with Silverlight and WCF who hasn't run into them. It's also been quite well-documented on the forums. I've tried to report these bugs on the MS Connect website, but I can't figure out how: I don't seem to have that option.

I should note that the Silverlight runtime itself seems to be pretty darned stable, all things considered. I've beat the thing to death with stress tests, and haven't run across any bugs worth mentioning that weren't my own damned fault. All the real problems seem to show up in the various tools you use to build Silverlight applications.

It seems to me that there are going to be some massive improvements to the .NET platform coming with the impending .NET 4.0 / Visual Studio 2010 release. I keep hoping that the reason these bugs haven't been fixed out in the wild is that MS is working so hard to improve the quality of that upcoming release.

I can hope, can't I?

Friday, September 18, 2009

Mixed Feelings about Silverlight

I spent all day yesterday at the Microsoft Silverlight FireStarter event. (You can see the decks here, and the recordings will be up shortly.) It was an appropriate place for me to be hanging out, since Alanta, my current startup, is working to build a web conferencing system on Silverlight. I came away from the day with a variety of mixed feelings.

First, I realized that not only do I have a lot to learn, but what I don't know is hurting me. If I knew the tools and frameworks better, I could make a lot faster progress on our product, and the resulting code would be better architected and more maintainable. The demo that Adam Kinney did on Blend made me realize just how crappy my own Blend skills are, and how I could be a ton more productive if I knew Blend better. Similarly, the stuff that Marco Matos did with the Silverlight Toolkit, and Karl Shifflet's demo of his XAML PowerToys.

I also felt grateful to Microsoft (in general) and to the people who put on the event (very specifically). They've pretty much dedicated their lives to creating tools and frameworks and platforms for the rest of us to use, to make our lives easier or better in some way. And when, like me, you spend more than half your waking hours working with those particular tools and frameworks and platforms, that's not something you can just take for granted. It's something to be thankful for.

At the same time, I think I spent more time at the event feeling frustrated than anything else. I've said before that you know a product is succeeding when people start complaining about it; and by that standard, Silverlight is a very successful product. Here are my top three complaints about the current state of Silverlight and its tools:

  1. Silverlight databinding is a mess. This is partly due to the fact that it is missing many of the features of its more powerful cousin, WPF databinding. But databinding in both Silverlight and WPF suffer from the same underlying problem: it's incredibly difficult to get right, very easy to get wrong, and MS provides provides no troubleshooting help at all. As I've said elsewhere (here and here), I think the biggest underlying problem with the current databinding implementation is that it's untyped, i.e., you never specify the type of the DataContext your XAML is expecting. As a result, there's no Intellisense to help you when you define your bindings, and no design-time or compile-time checking to make sure you got them right. I could probably live with this limitation if Microsoft provided better tools and frameworks for runtime troubleshooting. But at runtime, any binding errors get swallowed entirely and completely. A very few of them will show up in the Visual Studio debug window, but you have absolutely no insight into the vast majority of things that might go wrong. Even if MS thought that it was too big of a switch to move to a strongly-typed DataContext, they should at the very least, for the sake of all that is holy, have their controls raise an event when something goes wrong, so that you have some opportunity to see and respond to what might be happening. I can't express strongly enough how absolutely insane it is that we're about to see version 4 of Silverlight, and Microsoft still hasn't fixed this basic, fundamental problem. I spend enormous amounts of time troubleshooting databindings, and it's the primary reason why we've only partially adopted an MVVM architecture for Alanta. I spend enough of my time troubleshooting WCF, which is complicated and annoying, but at least it provides real errors. There's not enough time in the day to guess (and guess and guess and guess again) what might be going wrong with my databindings.

    I should note that Tim Heuer, frequently the face of Silverlight to the world, was able to sympathize with these problems yesterday. He pointed me Glimpse, a recent tool from Karl Shifflett, that provides some insight into what's happening under the hood with databinding errors. I haven't had the chance to try it out yet, but it seems like a step in the right direction. Still, "not sucking quite so horribly" doesn't equal "sufficient", least of all "good".

    Microsoft and the rest of the community is making a huge push towards MVVM as the standard development model for Silverlight and WPF. That makes sense: but its adoption by average, everyday developers will remain limited until MS is able to fix their databinding experience.

  2. Blend is a mess. Yes, it's incredibly powerful. And yes, V3 is much, much better than V2. And it goes without saying that it's better than Visual Studio for UI design. But as the premiere MS tool for designing great user experiences, it shows an astonishing lack of appreciation of what makes for a great user experience. To take just a couple examples:
    1. In the picture below, try to guess which of the two tabs ("FileRowControl" or "FileManagerControl") is selected. Is it the one on the left whose bold, dark color seems to flow uninterrupted into the workspace? Or is it the one on the right whose light gray color, everywhere else in the Windows UI, indicates "disabled"? Astonishingly, it's the tab on the right that's selected. I've been working with Blend for months now, and every time I have to look at the open file tabs, I have to stop and think which one is actually selected. That's inexcusable for a company with as many design resources as Microsoft.
       
    2. Here's a fairly standard property panel in Blend:
       
      Now, somewhere in this panel is a way to set these properties in an advanced fashion, i.e., through databinding or other similar techniques. Care to hazard a guess as to how you do that? Might one, perhaps, right-click and see some options for doing so? Nope, no right-click menu is available. Give up? Well, I'm astonished that you missed the tiny little two-pixel squares to the right of every property. It turns out that if you navigate your mouse over one, and after two or three tries manage to click on it successfully, it pops up this context menu:
       
      This is such a non-standard user experience that there isn't even a name for it. (Adam Kinney has suggested calling it a Property Peg.) But there's a darned good reason there isn't a name for it. It's because it's a bad idea! It's a horrible UX design. How more completely unintuitive and non-discoverable is it possible to get? (That's apart from the fact that because the, umm, peg is so small, even once you figure out what it's there for, it's still hard to use.)

    3. In every other Windows application, scrolling your mouse wheel moves the selected document up or down. In Blend, scrolling your mouse wheel sets the zoom level on your current workspace. That wouldn't be so bad if it made a better guess about where you were aiming. For instance, here's what my screen looks like after I open up a specific user control I've been working on lately:
       
      And here's my screen after four "zoom in" mouse-wheel movements:

       
      Rather than zooming in on anything that I might be interested in (say, the selected object), Blend has helpfully chosen to move my control entirely off the screen. And what's worse, it seems bloody well determined to be random about the direction it moves it. Sometimes it moves it off my screen up and to the right, sometimes down and to the left, and occasionally, very occasionally, it decides to actually zoom in on the thing I'm interested in. Taken all together, though, it's as if Blend is determined to take my mouse wheel, one of the very best usability inventions ever, and make it entirely useless.

      I could go on for quite a while about Blend's failings: these are only a couple of random examples. But they should be sufficient to demonstrate that Blend desperately needs some UX TLC.

  3. Silverlight is still missing some very basic features. The one that's usually brought up is the lack of printing support, which is laughable, if you think about it very long at all. Given the project I'm currently working on (web conferencing), the feature that I miss the most is obviously web camera and microphone support. Flash has supported web cameras and microphones for years, so it was very disappointing to me that this feature got cut from Silverlight 3. From the knowing and slightly embarrassed looks that I see on Microsoft faces whenever the subject gets brought up, I'm pretty sure that it'll make it into Silverlight 4. But still. Of the six months that I've spent working on Alanta, at least a month out of that time has gone to troubleshooting the clever but ultimately painful Flash hack that we're currently using.

I feel the need to repeat what I said earlier: you know a product is being successful when people start complaining about it. They complain – I complain – because I can see the potential for the product, and get frustrated because it's not there yet. I'm also a developer, and know how hard it is to get these things right. The folks at MS are only human. But I also hope that they're listening.