tag:blogger.com,1999:blog-5430866.post1158247093819380670..comments2024-01-02T08:54:14.406-05:00Comments on Peter Bromberg's UnBlog: OMG, Silverlight! Asynchronous is Evil! (or, Call me back when you got it)peterbromberghttp://www.blogger.com/profile/18173639411723574123noreply@blogger.comBlogger52125tag:blogger.com,1999:blog-5430866.post-40201556365174700332010-09-11T18:23:59.637-05:002010-09-11T18:23:59.637-05:00Might I recommend an approach to this thread where...Might I recommend an approach to this thread where one might provide an example of when they feel they need sync call, then Peter can offer a recommendation to solve the same problem via async?<br /><br />Let me start... <br /><br />It is very typical pattern in LOB applications to cache results from a web service to memory. This allows us to prevent additional web service calls for the same data over and over again. For example, a list of states. <br /><br />It would be nice to <br />1. Test if the states are cached in an application level variable.<br />2. If not, then make a call to the web service to get the list of states.<br />3. Upon return, save this list to the global variable for use by other LOB forms as needed. <br /><br />Of course, the above pattern can be accomplished using async.<br /><br />Now, imagine you have a LOB form. This form grabs data from a web service via async (say a list of customer addresses). The data only contains a list of stateID's which are used in the data. The data is bound to a gridview. <br /><br />The form allows the user to change the state for the customer via a combobox in the state column of the gridview. Now here is were the issue lays...<br /><br />In order to populate the state combobox with the complete list of states, the state web service routing above MUST complete before the form web service returns. If the states web service never returns, the combobox will not be populated. <br /><br /><br />Now if this was not a LOB application, this might be OK; however, LOB users might have a UI which is not locked up, but they also have a non-functional form for them. This results in calls to tech support, and general unhappiness from the users. In this case, the users would rather have the UI stay inactive until it is ready to actually use. <br /><br />Peter, in this use case, what would the acceptable async approach to solve this problem.<br /><br />Thanks in advanced for your input. <br /><br />(p.s. another possible use case for sync might be user login process)Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-48037136607972357572010-09-11T18:21:39.509-05:002010-09-11T18:21:39.509-05:00Might I recommend an approach to this thread where...Might I recommend an approach to this thread where one might provide an example of when they feel they need sync call, then Peter can offer a recommendation to solve the same problem via async?<br /><br />Let me start... <br /><br />It is very typical pattern in LOB applications to cache results from a web service to memory. This allows us to prevent additional web service calls for the same data over and over again. For example, a list of states. <br /><br />It would be nice to <br />1. Test if the states are cached in an application level variable.<br />2. If not, then make a call to the web service to get the list of states.<br />3. Upon return, save this list to the global variable for use by other LOB forms as needed. <br /><br />Of course, the above pattern can be accomplished using async.<br /><br />Now, imagine you have a LOB form. This form grabs data from a web service via async (say a list of customer addresses). The data only contains a list of stateID's which are used in the data. The data is bound to a gridview. <br /><br />The form allows the user to change the state for the customer via a combobox in the state column of the gridview. Now here is were the issue lays...<br /><br />In order to populate the state combobox with the complete list of states, the state web service routing above MUST complete before the form web service returns. If the states web service never returns, the combobox will not be populated. <br /><br /><br />Now if this was not a LOB application, this might be OK; however, LOB users might have a UI which is not locked up, but they also have a non-functional form for them. This results in calls to tech support, and general unhappiness from the users. In this case, the users would rather have the UI stay inactive until it is ready to actually use. <br /><br />Peter, in this use case, what would the acceptable async approach to solve this problem.<br /><br />Thanks in advanced for your input.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-27703252734105434582010-06-04T14:50:38.339-05:002010-06-04T14:50:38.339-05:00Unlike the other posters here, I will say that I p...Unlike the other posters here, I will say that I prefer to learn to work within the given framework than trying to find workarounds. Kind of like a WCF developer trying to implement an old remoting design that normally isn't allowed in WCF. <br /><br />I find the async work a little bit harder to do: especially when in old days I would then want a user verification after a call. Now the security model requires I ask if they want it, then I do it, then I see if it works. <br /><br />On the other hand, the busy indicator is a great and simple way of making sure that the user does not do something while I'm out getting stuff. The only issue I've found so far is when initialization is loading 4 tables and I've no idea when all four are done. I've resorted to assigned bits in a byte with each one doing a lock, set, see if I'm done, release logic.<br /><br />The only issue I've encountered outside of the multi-get is that management cannot understand why coding takes so long when I've got to write at least two event handlers for each request.Michaelnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-89702211458870085362010-02-25T11:18:57.423-05:002010-02-25T11:18:57.423-05:00http://ittyurl.net/kQHA.ashx That's a link to...http://ittyurl.net/kQHA.ashx That's a link to a solution article I just published, with a downloadable sample solution. Again, I don't recommend doing this, but what the heck.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-70941023057398005372010-02-25T11:17:35.164-05:002010-02-25T11:17:35.164-05:00This comment has been removed by the author.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-32502632652961094542010-02-25T07:19:18.774-05:002010-02-25T07:19:18.774-05:00Would you guys mind posting the project / dll when...Would you guys mind posting the project / dll when you are ready?<br />I think it adds some clicks.. I mean value.Ghdjdhttps://www.blogger.com/profile/01561493199090171968noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-84269953548156444262010-02-23T21:27:48.643-05:002010-02-23T21:27:48.643-05:00Well that depends on what you are doing. I don'...Well that depends on what you are doing. I don't have anything I can show here at the moment, but I think this demonstrates the advantages pretty clearly:<br /><br />In the encryption handshake exchange within my library, you have:<br /><br />-DNS Lookup of host<br />-Connect<br />-Get list of supported encryption methods<br />-Specify desired encryption method<br />-Get the public key<br />-Send verification code<br />...etc etc<br /><br />That requires:<br /><br />ConnectAsync, ConnectCompleted, ReceiveEncryptionMethodsAsync, ReceiveEncryptionMethodsCompleted, SendEncryptionMethodAsync, SendEncryptionMethodCompleted, ReceivePublicKey, ReceivePublicKeyCompleted, ....<br /><br />All those need error checking and complicated flow control, and it becomes a crazy mingled uber-chain that is impossible to maintain.<br /><br />Instead, it is much easier to create an asyncronous method called "ConnectAsync" which makes a background thread, performs all the above tasks synchronously on that thread, and then fires the completed delegate.<br /><br />The developer using my library can never tell the difference, but as I'm the one writing the library, internally chaining all those calls is a nighmare to maintain and comprehend. The application with the UI still only sees asynchronous calls, so from the updating UI perspective, nothing changes really.<br /><br />Perhaps I'll write up a complete example if I find some time, but I think the advantage is pretty clear in this case.MikeMnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-45589704800920650262010-02-23T21:17:33.675-05:002010-02-23T21:17:33.675-05:00@MikeM
For example you could do something like thi...@MikeM<br />For example you could do something like this to simulate a sync WebClient call:<br /><br />public partial class Page : UserControl<br /> {<br /> public Page()<br /> {<br /> InitializeComponent();<br /> Thread thd = new Thread(new ParameterizedThreadStart(GetPage));<br /> thd.Start("Http://ittyurl.net/rss.aspx");<br /> }<br /> private void GetPage(object url)<br /> {<br /> string s= SyncWc.GetData((string)url);<br /> Dispatcher.BeginInvoke(() => text1.Text = s);<br /> } <br /> }<br /><br /><br /> namespace SyncWebClient<br />{<br /> public static class SyncWc<br /> {<br /><br /> private static ManualResetEvent mre = new ManualResetEvent(false);<br /> public static string GetData(string url)<br /> {<br /> string s = "";<br /> WebClient wc = new WebClient();<br /> wc.DownloadStringCompleted += (sender, e) =><br /> {<br /> s = e.Result;<br /> mre.Set();<br /> };<br /> wc.DownloadStringAsync(new Uri(url));<br /> mre.WaitOne(1000);<br /> return s;<br /> }<br /> }<br />}peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-49845116782490561252010-02-23T21:06:48.247-05:002010-02-23T21:06:48.247-05:00Er, sorry, minor correction regarding where the er...Er, sorry, minor correction regarding where the error is thrown:<br /><br />public void Connect(EndPoint endPoint)<br />{<br /> SocketAsyncEventArgs args = new SocketAsyncEventArgs { RemoteEndPoint = endPoint };<br /> SocketError error = SocketError.Success;<br /><br /> args.Completed += (s, e) =><br /> {<br /> error = e.SocketError;<br /> syncEvent.Set();<br /> };<br /><br /> asyncSocket.ConnectAsync(args);<br /> syncEvent.WaitOne();<br /> syncEvent.Reset();<br /><br /> if (error != SocketError.Success)<br /> {<br /> throw new Exception("Connect Error: " + error.ToString());<br /> }<br />}<br /><br />---<br /><br />That way the error is thrown on your original calling thread.MikeMnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-73045643980601025672010-02-23T21:06:13.592-05:002010-02-23T21:06:13.592-05:00@MikeM,
that is great but I don't see any real...@MikeM,<br />that is great but I don't see any real implementation code, e.g. let's send something / receive something and then update the UI.<br />Better yet, how about a sample that uses either WebClient or HttpWebRequest/Response as sockets are rarely used by Silverlight programmers? I mean, a complete working sample.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-57576986794381787992010-02-23T21:00:50.270-05:002010-02-23T21:00:50.270-05:00I just quickly adapted this to the normal Silverli...I just quickly adapted this to the normal Silverlight socket, but our actual implementation is way different because we use our own platform-abstracted sockets to facilitate code sharing between Silverlight, .NET and CF. We have an abstraction layer that eliminates any platform differences which lets us code our library once and it just works on any of the .NET platforms.<br /><br />The Code (formatting is gonna be screwed I'm sure):<br /><br />public class SyncSocket<br />{<br /> Socket asyncSocket;<br /> ManualResetEvent syncEvent = new ManualResetEvent(false);<br /><br /> public SyncSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)<br /> {<br /> asyncSocket = new Socket(addressFamily, socketType, protocolType);<br /> }<br /><br /> public void Connect(EndPoint endPoint)<br /> {<br /> SocketAsyncEventArgs args = new SocketAsyncEventArgs { RemoteEndPoint = endPoint };<br /><br /> args.Completed += (s, e) =><br /> {<br /> if (e.SocketError != SocketError.Success)<br /> {<br /> throw new Exception("Connect Error: " + e.SocketError.ToString());<br /> }<br /><br /> syncEvent.Set();<br /> };<br /><br /> asyncSocket.ConnectAsync(args);<br /> syncEvent.WaitOne();<br /> syncEvent.Reset();<br /> }<br />}<br /><br />You would just repeat this for Send and Receive.MikeMnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-39251114368110725082010-02-23T20:42:26.055-05:002010-02-23T20:42:26.055-05:00@MikeM,
Do you have a working sample of this code ...@MikeM,<br />Do you have a working sample of this code for Silverlight 3.0?<br />You make it sound so simple, man!peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-23792557215406110422010-02-23T20:26:36.154-05:002010-02-23T20:26:36.154-05:00@Peter:
I don't have to know you very well to...@Peter:<br /><br />I don't have to know you very well to be frustrated by the attitude you are portraying in your comments. You are effectively stiffling a good debate and annoying people by saying "your points don't matter, because MS isn't adding it." People are trying to debate the merits of the sync model and you are dismissing their points by countering with "too bad."<br /><br />And I beg to differ on "ugly and non-productive" remark. Wrapping the socket connection class for sync calls is 10 line long:<br /><br />-Create ManualResetEvent<br />-Call SendAsync (or ReceiveAsync)<br />-ManualResetEvent.WaitOne()<br />-Check state, fire exception if error<br /><br />-EndSend/EndReceive delegate: store error state and set ManualResetEvent<br /><br />---<br /><br />Simple, easy, clean. Of course doing this for every single method in a web service would be painful and annoying, but that's what code generators are for. Generated code doesn't have to be pretty (and usually isn't). If MS just threw that into their web service code generator, it wouldn't need to be messy at all. It could even be optional - have a property on the service reference called "GenerateSyncMethods."<br /><br />In the case of the socket, you only have to do it once.<br /><br />If you have ever tried to chain 5+ asynchronous calls, you will no doubt know the benefits of doing it synchronously on a background thread. A good example of this is an encryption handshake exchange for sockets (which I recently had to implement) which had almost 10 potential back-and-forth chained calls with different branches and error checking in each one. The 10 line synchronous wrapper was a HUGE productivity boost, simplifying the exchange considerably, and allowed you to wrap the whole process in a single try-catch block.<br /><br />There are countless other useful scenarios, but I'm sure you know that, you are just being difficult and stubborn :)MikeMnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-18833578452967926622010-02-23T20:02:51.894-05:002010-02-23T20:02:51.894-05:00@MikeM, I guess you don't know me very well; I...@MikeM, I guess you don't know me very well; I love controversy.<br /><br /> Many developers have successfully "worked around" the asynchronous model, and almost universally, it is extremly ugly and non-productive to do so. Again, Microsoft is not going to give you native sync web calls in Silverlight.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-20418609048766672542010-02-23T20:01:29.984-05:002010-02-23T20:01:29.984-05:00This comment has been removed by the author.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-77412493684935525902010-02-23T19:28:16.894-05:002010-02-23T19:28:16.894-05:00The main reason I was prompted to post was how utt...The main reason I was prompted to post was how utterly frustrating your attitude is (Peter). People aren't debating whether MS is adding synchronous methods or not. They are debating whether MS SHOULD add them. Your "last resort" retort of "yeah, well, too bad, you aren't getting them, get over it" is arrogant and irrelevant, and makes you sound like you have some sort of superiority complex talking to us like we are your 7 year old children. If that's all you have left, then a simple "yeah, they do have useful and legitimate uses but unfortunately it doesn't look like they be added" would be a more appropriate response.<br /><br />While I no-doubt agree that things like web service calls should be done asynchronously, as others have already pointed out it is extremely useful to have syncronous calls on a background thread. Dumb programmers can mess up an application in 10,000 ways. Sacrificing the utility of syncronous calls in appropriate situations to remove one of those ways is silly at best. For multi-stage processes, synchronous calls on a background thread are an order of magnitude easier to manage and understand.<br /><br />Your NPAPI argument has no grounds because it is very easy to wrap the async calls in a sync wrapper, as I've done many times. MS could do the same without changing their current implementation at all.MikeMnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-55989362756334455672010-02-23T18:49:42.024-05:002010-02-23T18:49:42.024-05:00@Anonymous,
Thanks for the sage advice, but the bo...@Anonymous,<br />Thanks for the sage advice, but the bottom line still remains: You're not going to get synchronous HTTP in Silverlight. In Silverlight 4.0, with elevated privileges and out of browser, you now will have basically a desktop app, and so different things can be done.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-7933021372466646092010-02-23T18:48:33.021-05:002010-02-23T18:48:33.021-05:00This comment has been removed by the author.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-43233651067603347902010-02-23T18:11:30.613-05:002010-02-23T18:11:30.613-05:00I am not the previous anonymous. But I would like ...I am not the previous anonymous. But I would like to say that not having sync calls and delegate.BeginInvoke is bad for developers doing large real-time apps...<br /><br />and yes Peter. Denying the obvious and trying to diverge the conversation from your mistake to something like MS team will not add bla-bla-bla..<br /><br />There are 3 separate issues:<br /><br />1. lot of idiots from html/flash/php world will screw browser with sync calls and create large negative feedback. this is why sync calls were banned.<br /><br />2. not having precise control over async model in general is a problem for real developers working with async on large scale.<br /><br />3. you made mistake as the old Anon pointed - you deliberately removed the healthy argument and substituted the whole subject and painted it in circus-red. and then you deny you did it...<br /><br />CheersAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-39421370170230177602009-10-03T08:48:47.986-05:002009-10-03T08:48:47.986-05:00@Bo,
The Silverlight documentation and forums have...@Bo,<br />The Silverlight documentation and forums have many examples of the use of asynchronous methods. You can also look at http://www.eggheadcafe.com for some Silverlight articles I've written that have example downloadable source code.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-73729839620202289202009-10-03T08:43:11.207-05:002009-10-03T08:43:11.207-05:00Thats all very sweet. But you couldn't possibl...Thats all very sweet. But you couldn't possibly find the time to tell people HOW you use this async theory in practice?<br /><br />I rest my case..Bonoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-86785768296311914362009-07-22T09:14:10.502-05:002009-07-22T09:14:10.502-05:00@anonymous, I think it is highly unlikely that syn...@anonymous, I think it is highly unlikely that sync Http calls will be added. There is too much risk that dumb developers will cause a very bad user experience, and of course Microsoft will be blamed.peterbromberghttps://www.blogger.com/profile/18173639411723574123noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-6722664878688099902009-07-22T09:07:19.280-05:002009-07-22T09:07:19.280-05:00I hope that sync web calls will be supported in th...I hope that sync web calls will be supported in the future. This is a much needed feature, at least from the background threads.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-5430866.post-29812707360040538302009-06-19T10:38:15.056-05:002009-06-19T10:38:15.056-05:00"it’s the Zen of the sound of a single hand c..."it’s the Zen of the sound of a single hand clapping"<br /><br />HEHE!<br /><br />I agree with Pete, async is a good thing.Artur Carvalhohttps://www.blogger.com/profile/09128067596192412067noreply@blogger.comtag:blogger.com,1999:blog-5430866.post-79827654866417212462009-05-30T19:20:47.356-05:002009-05-30T19:20:47.356-05:00Wow, this thread got heated!! :) Come on guys, we'...Wow, this thread got heated!! :) Come on guys, we're all on the same side here, save the battles for those PHP pricks.. ;) Anway, I can see why some would want synchronous methods (for example, for doing some really quick validation and then saving) but I love the fact that they didn't allow it because you can still work with it and your end-users will love you for it. It feels to me like async ajax without all the pain and suffering debugging in javascript..Justinhttps://www.blogger.com/profile/00225001014663833227noreply@blogger.com