So I'm working on a client that consumes a web service. I used the WSDL and XSD files from the service to generate the proxy class, and all of the synchronous functions work fine. However, given their synchronous nature, making any of the calls causes the UI to stop responding until the call is finished. Classic reason for using async methods, right?
Problem is, I'm still in school for my degree and know little about asynchronous programming. I've tried to read up on it online (my employer even has a Books 24x7 subscription) but I'm having a hard time grasping how I should make the calls and how to handle the response. Here's what I have:
/// <remarks/>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://localhost:8080/getRecords", RequestNamespace="http://www.<redacted>.com/ws/schemas", ResponseNamespace="http://www.<redacted>.com/ws/schemas", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlArrayAttribute("records", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=true)]
[return: System.Xml.Serialization.XmlArrayItemAttribute("list", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
public record[] getRecords([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=true)] string username, [System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=true)] [System.Xml.Serialization.XmlArrayItemAttribute("list", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="integer", IsNullable=false)] string[] ids) {
object[] results = this.Invoke("getRecords", new object[] {
username,
ids});
return ((record[])(results[0]));
}
/// <remarks/>
public void getRecordsAsync(string username, string[] ids) {
this.getRecordsAsync(username, ids, null);
}
/// <remarks/>
public void getRecordsAsync(string username, string[] ids, object userState) {
if ((this.getRecordsOperationCompleted == null)) {
this.getRecordsOperationCompleted = new System.Threading.SendOrPostCallback(this.OngetRecordsOperationCompleted);
}
this.InvokeAsync("getRecords", new object[] {
username,
ids}, this.getRecordsOperationCompleted, userState);
}
private void OngetRecordsOperationCompleted(object arg) {
if ((this.getRecordsCompleted != null)) {
System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
this.getRecordsCompleted(this, new getRecordsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
}
}
There's also this:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public partial class getRecordsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
private object[] results;
internal getRecordsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
base(exception, cancelled, userState) {
this.results = results;
}
/// <remarks/>
public record[] Result {
get {
this.RaiseExceptionIfNecessary();
return ((record[])(this.results[0]));
}
}
}
and this:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.1")]
public delegate void getRecordsCompletedEventHandler(object sender, getRecordsCompletedEventArgs e);
I chose this example because the synchronous call has a return type and the async does not--at least not in the function call itself. I understand that the getRecordsCompletedEventArgs class has the proper return type, and that that is how I will get the data back from the call. What I can't seem to figure out is how to actually do that.
Let's say that I replace my current call to getRecords with getRecordsAsync:
How do I set up the client to respond when the async call completes? I need to drop the XML into a file using a LINQ procedure I've already written, I need to log the operation's success or failure, and I need to notify the user that the operation completed.
How can I ensure that making the call actually happens asynchronously? I remember reading at one point that simply invoking an asynchronous SOAP method doesn't actually happen asynchronously with regard to the current thread unless you do something else first. Any tips?
Are there any other major considerations that I'm missing? (Such as: "If you forget to do this, it'll blow up your program!")
These are all questions that I haven't been able to find convincingly firm answers to so far. Thank you in advance for any help you all can offer.