Tuesday, July 1, 2008

Big Silverlight Troubles! No synchronous server calls

We have been tearing our hair out around here because we can’t find a way in Silverlight 2.0 Beta to write a method that blocks the UI thread while it fetches data.

In case you are not aware of this problem, permit me to illustrate.

Suppose in the bowels of your business logic you have a validation rule that says: “total of order not to exceed the customer’s maximum cost for a single order”.

You’re using a domain model with objects that have dotted navigation. You write your rule along the lines of:

… TotalCost(myOrder.Details) < myOrder.Customer.SingleOrderLimit …

Unfortunately, both myOrder.Details and myOrder.Customer.SingleOrderLimit could involve lazy loads of the Details and the Customer.

The UI that enabled the user to create a new detail item for the order is not aware of this rule and didn’t pre-fetch Details and/or SingleOrderLimit.

No problem in regular .NET. You just wait while you lazy load the SingleOrderLimit from the database.

Big problem in Silverlight.

All server calls have to be asynchronous. Your fetch of the SingleOrderLimit is going to have to return immediately; the value will be accessible later during the asynch callback.

Ok, you try to rewrite SingleOrderLimit to stall the UI thread until you get the callback. But there’s no way to do it. If you sleep the thread, you never hear the callback. You make the server call on a worker thread and sleep the UI thread; you never hear the callback. Sit and spin on the UI thread? You never hear the callback. What’s with that?

I understand that I can write synchronous code on the background thread. The problem is that I can't make the UI thread wait for the result.

So you try to live within this crazy world. You decide that you will somehow detect this particular problem and you stash the validation object somewhere, postponing its execution until all the dependent server trips have completed; in my example, the validator can’t run until Details and Customer have been retrieved and how I knew to stack these dependencies is anyone's guess. Good thing they're mutually independent requests because if one query depended on the outcome of another query, the logic would get really twisted.

Meanwhile your original validation call - the one that got us into this mess - must return with some indication like “I don’t know”.

It can't report “everything is ok” or “it’s invalid”. So you have to be sure that the ancestor caller somewhere way up the stack postpones whatever it was doing (like trying to save the order) until you have a definitive answer. And, of course, when it becomes possible to render an answer, you have to remember to renew your originating operation (e.g., the save). You weren't just going to tell the user "Sorry, I can't save yet, not enough information ... try again soon" were you?

Let's say you got that all figured out. But watch out. Maybe your WPF-ish UI is binding to objects in your unit-of-work container. Over on your worker thread you're doing some synchronous magic that fetches Customer and Detail objects. You better not put them into that container on the UI thread ... because it's not thread-safe and if WPF is looking for 'em there's going to be trouble! You better be ready to fetch Customer and Detail into a separate container and then martial them back across the thread boundary in the callback. Oh joy.

You see where I’m going with this. Application programming just became immensely difficult. You can’t write a real program if every data fetch is async. Your UI controller shouldn't have to anticipate every bit of data you might possibly need upfront either. This is a disaster.

Do you know what to do about this? Do you know anyone who does? We’re beating every bush and so far, nada.

51 comments:

  1. We solved this by adding an IsValidating property to our objects performing the validation. You can then bind controls on your UI to the IsValidating property, such as an IsEnabled property of an Ok button or the Visibility property of a processing animation (with a converter of course).

    Frankly, this is much better in my honest opinion. It is a little harder for the developer to start to think async but it's much better from a user experience perspective. Synchronous validation is a very bad user experience.

    ReplyDelete
  2. Oh by the way, I think the reason why making a service call waits forever if you block the UI thread to return is because WCF is trying to dispatch the call to the server on the UI thread... This is my theory only but it certainly seems to behave this way even if it's not entirely true.

    Interestingly enough this seems to be compounded if you have multiple silverlight applications in the same browser, they seem to all share a UI thread. If you make a call to the server and the server holds onto your thread then all other service calls from that process (i.e. other tabs or child windows) will also be blocked until that call returns.

    The threading model in silverlight is extremely limited. In it's defense though I think it's just calling into IE's threading model and is probably limited for security reasons.

    Good luck!

    btw: http://www.justnbusiness.com

    ReplyDelete
  3. @justin - Thanks for the comments. I'm glad you "solved" it with an "IsValidating" property. Solutions along this line have occurred to us ... and to others.

    It is difficult for me to agree that this is "much better". It is intrinsically awful if the developer must disrupt the logical flow to accommodate an implementation artifact.

    When I choose to validate at the point of data entry it is because I think the user should be held in place until I can pronounce on the validity of the data entered. That is my choice of user experience. If I know that the validation cannot complete in "reasonable time" then I may choose an async approach and suffer the added burden of figuring out what it means for my UI to "hold" while I get the data. How to make it hold and how I display that it is "waiting for data" will undoubtedly burden my user experience with all kinds of unwanted behavior. If that's what I need, I'll deal with it.

    But the choice should be mine, not dictated to me because Microsoft thinks it may take too long to get an answer from the server.

    HAVING to think in async terms violently breaks encapsulation by coupling my user experience to the peculiarities of data retrieval.

    It gets much worse if my scenario is unpredictable as when it has nothing to do with Validation.

    Suppose I want to display the TotalCost of an invoice. Why should my UI be made aware of the possibility that TotalCost cannot be calculated directly? Why do I have to write explicitly for that possibility?

    How does Microsoft know that my user will be unwilling to wait while I retrieve the elements of cost? MS has no business telling me what is or is not a good user experience. It's an unwarranted and paternalistic intrusion on my perogatives as developer.

    ReplyDelete
  4. This seems mostly true except that I think that they didn't choose to deprive you of a synchronous data access method intentionally, I believe it is more a limitation of living withing a browser. I believe it is piggy backing on the same mechanism that ajax uses and suffers from the same limitations.

    That being said, I believe that asyncrhonous network connectivity is actually superior in every way and does not have to disrupt your logical flow at all. Lambda expressions, for example, are a very powerful way to allow synchronous logical flow despite actually asynchronous execution. This is going to be a more and more common scenario as we find that processors do not become much more powerful but instead we have to utilize multiple cores. Something like this might look like:

    Customer.Fetch( 10, c => list.DataSource = c );

    Here, your logical flow is synchronous but the actual execution is not. I guess what I'm trying to say is that passing methods as parameters can allow you to chain asynchronous behavior in a logically synchronous manner.

    I don't really see how this breaks encapsulation to be honest. It seems fair to have a UI be aware of network activity and such. Users want loading screens and progress indicators, this is the perfect way to do it.

    ReplyDelete
  5. I have to agree with Ward on this. Here is my scenario. I am building dynamic class loading into my Silverlight application. If ClassA requests ClassB from a ClassFactory, and the ClassFactory discovers that ClassB is not in the AppDomain on the client, the ClassFactory calls to the server to retrieve ClassB. Because of async the ClassFactory returns nothing back to ClassA, so the whole operation fails.

    I also have to agree with Ward that async breaks encapsulation. You do not want your UI code to know about anything except UI. The fact that there is a network should be abstracted from the UI.

    ReplyDelete
  6. I still don't think it breaks encapsulation, you just have to encapsulate something different. For example, use closures instead.

    For your scenario suppose you had a method:
    CreateType(Type t)

    What you would want to do to make it async friendly is to use a closure so change it to: CreateType(Type t, Action<object> complete)

    Calling it might have looked like this the old way:
    object obj = CreatType(t);
    DoSomething(obj);

    But now it looks like this:
    CreateType(t, o =>
    DoSomething(o));

    Any nested calls to CreateType would go through the same process and the final complete lambda would only be called when it was actually complete. You just have to pass method pointers (aka delegates) as variables instead of values.

    It's tricky and affects your design considerably but it is a quite powerful technique for asynchronous code. The C# lambda syntax is very friendly also (sorry if you're trying to use VB). But this is totally doable and quite elegant when taken to its logical conclusion.

    ReplyDelete
  7. What if there are a few service function calls in a row, with ifs and elses.
    It's not always Func() and then DoSomething(). Pretty often it's Func1(); Func2(); Func3(); etc..

    This is not a matter of design change but having broken functionality in a base function.
    Having OnFuncEnd handlers all over.

    And I'm not even talking about combinations of function calls,
    func1() { f1();f2();f3() }
    func2() { f3();f1();f2() }

    makes the owner class look horrible.

    ReplyDelete
  8. func1(Action completed)
    {
    f1(() => f2(f3));
    completed();
    }
    func2(Action completed)
    {
    f3(() => f1(f2);
    completed()
    }

    func1(() =>
    func2(() => {});

    ReplyDelete
  9. Yes, that's just what i meant, not nice at all, isn't it :-)

    ReplyDelete
  10. Beauty is in the eye of the beholder I guess :)

    ReplyDelete
  11. Hard to argue with that :-)

    ReplyDelete
  12. Async ruined my life

    ReplyDelete
  13. http://www.codeproject.com/KB/silverlight/SynchronousSilverlight.aspx

    This article discusses about synchronous programming within Silverlight.

    ReplyDelete
  14. @Rajeesh - that article does a nice job of explaining how Silverlight gets us into this predicament.

    If I read it correctly, it does not address the synchronous programming problem we're covering here ... which is how to stall the UI while waiting for a remote process to finish.

    @Justin's resort to functional programming style is wonderful at explaining how to respond to the inherent async nature of SL ... and I applaud him for it.

    But I also think he dramatizes my very point ... which is that I must be aware of side-effects in my business logic (e.g., validations) at the UI level ... and must code accordingly with functional programming. That's a burden, as he acknowledges. It means I have to be aware of concerns (trip to server) where I do not want such awareness.

    Now there may be good perf reasons for such concerns to leak into my UI thinking; if I could block the UI, I might freeze the UI unacceptably. But that should be my decision; I shouldn't have the async patterns forced upon me.

    Regarding function chaining (@Justin and Anonymous), it may be worth noting that DevForce provides a facility for parallel and serial chaining of tasks ... especially those that involve async trips to the server.

    Moreover, you can write these so that the decision to move from task 'A' to 'B' is contingent on outcome from 'A'. And there are provisions for exception handling. Pretty robust. Check it out.

    Thanks everyone for your contributions; it's a worthy exchange.

    ReplyDelete
  15. @Ward
    You are right, there is absolutely no way you can block the UI thread. I guess what you can do however is disable it, i.e. setting the controls that need to be blocked to isEnabed=false or something similar.
    In the completed handler set re-enable the UI.

    ReplyDelete
  16. Hello all
    [url=http://www.replicaonnet.com/]ativan without prescription[/url]
    The noted side effects of Lorazepam are: • Dizziness • Dose-dependent respiratory depression • Sedation • Fatigue • Amnesia, and • Unsteadiness Remember that consulting your doctor on the onset of such side effects will do you good.
    cheap ativan

    Following are the doses given to certain group of patients: • An initial dose of 2 – 3 mg is the normal prescription given to patients and to be taken twice or three times in a day.
    http://www.replicaonnet.com/ - ativan pharmacy
    Sedation, lack of recall, relief of anxiety and sedation are just some of Ativan’s pharmacological effects and normally last for eight hours.

    ReplyDelete
  17. Hi,
    http://www.hhservices.net/ - generic finasteride
    Having missing patches of hair can cause a variety of problems in relationships, or in single men who are looking for a partner.
    [url=http://www.hhservices.net/]buy cheap propecia[/url]

    Propecia's main ingredient is finasteride which takes action against hair loss.
    propecia pills
    If you are suffering from hair loss, don't let this condition hinder your relationships any longer.

    ReplyDelete
  18. gay and lesbian singles hawaii hot college lesbian girl webcams extreme black lesbian freaks androgynous lesbian dating in europe lesbian beauties 3 asian beauties lesbian choose action allison fisher a lesbian

    ReplyDelete
  19. Intercontinental mankind and stupefying facts [url=http://onlineviagrapill.com]buy viagra[/url]. Our commission secretly online anaesthetic chemist's [url=http://ambiendrug.com]buy ambien[/url].

    ReplyDelete
  20. If you bed the way that [url=http://www.andysonet.com/eshop/forum/viewtopic.php?p=123898&Twesid=f595a42bbfc88c4b63c3bd4239874995#123898]design[/url] [url=http://forum.senatorinfo.com/index.php?showtopic=161001]style shoes sale[/url] blackamoor suede bootee attend on you, so blame up these awful options today! These black-market suede cloth bootee will appear unbelievable on you with everything in your closet. The timeless fashion lines and beautiful features of these boots volition be your favorites to article of clothing when you are brainsick of your pumps, and demand a change! Hit the assailable touring in comfortableness and flair with a avid distich of racing shoes. A brace of racing place bequeath bring up you to the future(a) level, disregarding of skill, expertise or experience. You can ease assured knowing that you'll aspect avid when you are road fast. consolation and reliableness are the most important expression of retention your feet happy and prophylactic during a race. So put on one of these bang-up pairs and appearance the creation that you are all business. For major dash that volition ne'er let you down, beak up a brace of blackamoor suede boots. This indispensable conduct to black-market suede boots are specifically for those fashionistas seeking a bully distich that bequeath act for mundane with casual attract and beauty. blame up your deary and pass on! Cowboy boots for women are aphrodisiac and fun! once you deficiency to rattling clout off a very voguish look, you ask to try on a distich of cattleman boots. equitable cogitate all but it, how cute would that footling tartan attire you bought appear with just about fun boots of this nature? Dresses aren't the exclusively bit of vesture that leave await adorable with these boots, you can break but all but anything such as scrawny jeans, leggings and fifty-fifty a precious distich of jean cutoffs. Who wouldn't wan to assume these looks? What a man of necessity in dictate to brand a affirmation with his apparel are the allow place to check with what he is wearing. Ferragamo place for men are devilishly hot and rattling in good taste(p) whether you are look for a couplet of accidental walk shoes to something a bit to a greater extent dressy and dependable for the office. You testament be able-bodied to breakthrough any genial of flair that you are looking for for when it comes to Ferragamo place because they bear so a good deal to bid a man and even More to extend a wardrobe. Clogs are a capital expressive style of place because they are comfortable, comfortable to berth on and are ordinarily really stylish. No subject what case of gal you are, you leave be capable to do good from eating away a brace of clogs. These are such bully place to article of clothing for a effortless day with jeans and a perspirer or in a Sir Thomas More professional person and posh personal manner with a glossy dame or an A-line dress. No affair what your elan is, you will be capable to assume a distich of these place and genuinely rep the benefits.

    ReplyDelete
  21. dmrSDACvc Casino News MQpBatU7N6 Casino 8yUGOzRpTc Free Casino Game ASamWdync3 Casino Templates RIZG1QDus3 Casino On uik3Rmwbd Casino Gambling GEYkl7czQr Casino 2 7scYpGLv0 Casino Management

    ReplyDelete
  22. http://akudeye.freehostia.com/ adult web page
    http://ebecuji.freehostia.com/ adult xxx ecards
    http://hicuxahi.freehostia.com/ real adult amateur pics
    http://hofavut.freehostia.com/ free cam adult amateur chat
    http://jahafero.freehostia.com/ is nick cannon dating christina milian
    http://nidomuf.freehostia.com/ adult stores shreveport la
    http://nifuqes.freehostia.com/ professional dating uk
    http://sozenag.freehostia.com/ sex adult you tube
    http://viruhoko.freehostia.com/ parenting advice young adult
    http://zijijika.freehostia.com/ calabasis adult entertainment

    ReplyDelete
  23. valium american pharmacyambien discount online pharmacy
    [url=http://www.bebo.com/buyvicodinnow] buy vicodin [/url]

    ReplyDelete
  24. I keep getting spam emails from this blog post so I have been thinking about it some recently.

    I recently came across this video, which you may find interesting (if you're able to get over the poor presentation skills of the presenter):
    http://jsconf.eu/2009/video_nodejs_by_ryan_dahl.html

    Which is about a relatively new project called node.js. It's a javascript platform for the server. Which sounds a little crazy at first since js usually exists in browsers currently but there are specific reasons why they adopted js as the language. One of which is the primary thesis of the project "we are doing IO wrong" (my summary). Where they basically claim that doing synchronous IO (including network calls) is very bad in general. And due to the nature of js it's naturally adaptable to an asynchronous way of writing code.

    I'm curious to know, since some time has passed, how your opinions have changed or not on this subject? Have you managed to find acceptable styles of working with or around the lack of synchronous API's for doing networking in Silverlight?

    ReplyDelete
  25. exelent info, thank, is very usesfu for my job

    ReplyDelete