Silverlight and synchronous calls to WCF
I already know that calls to WCF services via Silverlight are async. I also know that many people try to find ways to make them sync calls for a variety of silly reasons (blocking UI thread for example), and that such a thing should be avoided like the plague, generally.
I just want to be able to handle all of the threading stuff myself as I have found that having to hook / unhook all of the '*Completed' events is a lot of extra work, and a huge pain, especially when you don't know the order of the 开发者_运维技巧calls etc. Anybody know of a clever way to make the sync calls and do the threading yourself?
Given that you shouldn't make synchronous networking calls, you shouldn't make synchronous networking calls and you shouldn't make synchronous networking calls, if you really, really know what you're doing, then you actually can make synchronous (blocking) calls only if you are not in the UI thread.. Just realize that it is not an officially supported scenario (so it wasn't as tested as the other features), but I've tried it a few times and it just works.
All you need to do is to use the [ServiceContract]
interface (instead of the client class) - the one which exposes the Begin/End operations - and call EndXXX(BeginXXX(parameters, null, null))
as shown in the example below (this is a page with two controls, a Button
whose Click
event is bound to the Button_Click
handler, and a TextBox
named "txtDebug" where the code writes the results.
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.AddToDebug("In Button_Click");
ThreadPool.QueueUserWorkItem(delegate
{
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
ServiceReference1.Service1 asInterface = client;
this.AddToDebug("Calling server \"synchronously\"...");
int result = asInterface.EndAdd(asInterface.BeginAdd(45, 67, null, null));
this.AddToDebug("Result: {0}", result);
client.CloseAsync();
});
}
private void AddToDebug(string text, params object[] args)
{
if (args != null && args.Length > 0)
{
text = string.Format(text, args);
}
text = string.Format("[{0} - {1}] {2}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"), text);
this.Dispatcher.BeginInvoke(() => this.txtDebug.Text = this.txtDebug.Text + text + Environment.NewLine);
}
}
Now, if you want to do it from the UI thread, then really, there's no way to block and wait for the response (since the response is supposed to be returned on the UI thread as well). And if you're confortable with the Begin/End pattern, you can still do the asynchronous calls, but without worrying about event handlers being leaked.
Solutions that rely on blocking a thread (any thread not just the UI thread) are best avoided. Threads are expensive resources and ThreadPool threads are a limited resource. Thats why network APIs have callback semantics in first place.
I agree with Carlos the first thing to do is switch to the .NET Async Pattern interface provided by the service instead of the horrible event based one. (The event based approach is designed to make things simple for UI developers that "think in events"). If your service is called "Service1" your clientside class will be called "Service1Client". However that class will also support an interface called "Service1", which will have Begin/End versions of the OperationContracts.
"a clever way to make the sync calls"
Without blocking a thread this is impossible. However making a series of tasks synchronous isn't really the requirement. What we want is simply to ensure that a series of tasks occur in sequence. You can do this simply by calling the next task from the callback method of the previous task but nesting becomes a bit of a problem.
Have a look a this series of articles perhaps starting with the one on the .NET Asynchronous Pattern. Unfortunately a WCF article is still a work in progress but I really must get it posted soon, this stuff comes up here often.
What if you wrap the call in another function, and that function will sleep until the async call returns?
精彩评论