(Assuming a WCF method called \"MyFunction\")
Currently, to support canceling a WCF request, I\'m using the BeginMyFunction/EndMyFunction methods generated by svcuti
.Net 4.5
Something similar can be implemented in older .Net frameworks too where CancellationToken is not yet available.
Cancelling a request isn't really practical in the general sense simply due to the asynchronous nature of the request you're talking about. Specific workarounds can be performed. E.g., adding a new Cancel signal to your protocol that sets some shared state that your primary, long-running task periodically checks to verify that it should continue executing.
Either way, once again due to the asynchronous nature of the request, I believe that it's still the client's responsibility to know to ignore results from a request that has been cancelled. It isn't possible to guarantee that the client won't receive a response from a request that it's just cancelled simply because a race exists between the client and the server. It's possible to add an additional layer that monitors whether something has been cancelled and knows to throw away a request's response, but that's not preventing the result from being transmitted to the client.
If I understand you correctly you are trying to correctly abort a pending call to a WCF service. You want to use the MyFunctionCompleted
event because it is handled in the UI Thread.
What you probably should do is call the Abort
method on the WcfClient
(you need to keep a reference to it). This will cleanup resources on the client side. The server will stil finish the request, but the client will not wait on it any more. Shortly after the MyFunctionCompleted
event is triggered. By checking the client.State
you will know whether the call succeeded, failed or was aborted.
Here is a small test app having a Send button, a Abort button and a textbox for the results:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private SomeServiceClient m_client;
private void buttonSend_Click(object sender, EventArgs e)
{
m_client = new SomeServiceClient();
m_client.MyFunctionCompleted += new EventHandler<MyFunctionCompletedEventArgs>(client_MyFunctionCompleted);
m_client.MyFunctionAsync(4000, m_client);
}
private void buttonAbout_Click(object sender, EventArgs e)
{
if( m_client != null )
m_client.Abort();
}
void client_MyFunctionCompleted(object sender, MyFunctionCompletedEventArgs e)
{
var client = e.UserState as SomeServiceClient;
if (client != null)
{
if (client.State == System.ServiceModel.CommunicationState.Opened)
{
textBox.Text += string.Format("Result: {0}\r\n", e.Result);
client.Close();
return;
}
else if (client.State == System.ServiceModel.CommunicationState.Faulted)
{
textBox.Text += string.Format("Error: {0}\r\n", e.Error.Message);
}
client.Abort();
}
}
}
There is no exception handling and cleaning up... I don't know if it is the recommended way, but I think calling abort is the right way. You need to handle the different error situations any way.
Easiest way I know of to do this with a WCF Client and the Task based async pattern is to register an Abort action with the cancellation token
private async Task CallOrAbortMyServiceAsync(CancellationToken cancellation)
{
var client = new SomeServiceClient();
cancellation.Register(() => client.Abort());
try
{
await client.CallMyServiceAsync();
} catch (CommunicationObjectAbortedException) {
// This will be called when you are cancelled, or some other fault.
}
}
There is no way to cancel the asynchronous request unless you manually create the asynchronous functions. Considering that you are auto generating your WCF calls that would make it more of a chore. Even then like you said the call does not cancel it will still run it's course. If you still want to have a cancel you just have to make sure the client/UI ignores the results from the call.