What's the best way to cancel an asynchronous WCF request?

前端 未结 5 505
孤城傲影
孤城傲影 2020-12-31 13:57

(Assuming a WCF method called \"MyFunction\")

Currently, to support canceling a WCF request, I\'m using the BeginMyFunction/EndMyFunction methods generated by svcuti

相关标签:
5条回答
  • 2020-12-31 14:23

    .Net 4.5

    1. Every WCF call implementation creates a CancellationTokenSource and stores it in a location accessible to all WCF services. I.e. in single server environments can be in an in memory cache.
    2. CancellationTokenSource.Token is passed to all method calls initiated by WCF method, including calls to databases and network calls where applicable.
    3. The WCF method can have a unique identifier as parameter or can return a unique identifier what is associated with CancellationTokenSource.
    4. When client needs to cancel the operation calls a WCF method and passes in the unique identifier of previous call.
    5. CancellationTokenSource is retrieved using the unique identifier and its Cancel method is invoked. If cancellation token is properly handled the operation started by previous call will soon be cancelled and can either return OperationCanceledException or a CancelFault or some other fault what signals client that call was cancelled.
    6. When client calls cancel at step 4 at the same time can abort the original WCF call. However if clients properly handle OperationCanceledException or CancelFault this isn't needed. OperationCanceledException can even bubble up to an ajax call if original call was started from a web page.

    Something similar can be implemented in older .Net frameworks too where CancellationToken is not yet available.

    0 讨论(0)
  • 2020-12-31 14:40

    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.

    0 讨论(0)
  • 2020-12-31 14:41

    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.

    0 讨论(0)
  • 2020-12-31 14:44

    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.
        }
    }
    
    0 讨论(0)
  • 2020-12-31 14:45

    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.

    0 讨论(0)
提交回复
热议问题