.NET Framework Developer Center > .NET Framework Forums > Windows Communication Foundation (WCF) > Provide Way to Detect Client Abort/Disconnect in WCF

Answered Provide Way to Detect Client Abort/Disconnect in WCF

  • Saturday, August 11, 2007 5:38 PM
     
     

    I wanted to post here to discuss an issue posted in the Microsoft Connect system (http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=286012)

     

    Microsoft has closed this issue by design, but I feel that support for this should be added to WCF.

     

    Here is an excerpt:

     

    Suppose a WCF web service receives a message to execute a lengthy operation (such as a mathematical calculation or a complex database query). I would like to be able to periodically check a property (and/or get an asynchronous notification) to see that the client aborted (i.e., the underlying connection to the IIS web server has abruptly closed.) .NET provides ClientBase.Abort() to abort the connection on the client side, but there seems to be no way to detect that this has happened on the server side. It is important to be able to reliably and quickly detect that the client has done this, so that server resources are not wasted letting a lenghty operation continue to execute needlessly.

     

    Please see the connect page URL and also the comment that was left in the Community Discussion at the bottom of that page.  MS does provide a workaround that makes sense, but the system should go further by providing a way to detect the network-layer disconnect whether it is through the client calling the Abort method or just the TCP/IP layer terminating the socket session.  (Obviously, not all transports will be able to support this on the server side, but most of the ones that cannot support it are async/queuing transports where it is not relevant.)

     

    I think not having this feature is a significant "regression" as other systems commonly provide this capability.

     

    Any thoughts?

     

    Thanks.

Answers

  • Friday, September 07, 2007 2:43 AM
     
     Answered

     

    > I would have thought a stateless design and killing the SQL transaction would be better.

     

    I agree, and I'd really want to implement both ways of detecting an abort (both an independent cancel, so an admin can cancel any session, and a socket disconnect detect so that the session ends if someone uses taskmgr to kill the client process).

     

    >> Taskmanager , will try to clean things up nicelly first  ,  Some work around IDisposable could give the same affect. And this only applies to error conditions which should be rare - running the request on a non UI thread on the client should be important in these scenarios. 

     

    > IsClientConnected is fairly meaningless

     

    I disagree.  I think this kind of solution is the only way to resolve the REST example I gave earlier.

     

    >> You are not using REST  but SOAP . It looks like REST but REST does not send HTTP 100 Received /Continued repplies.  Howver I was wrong in that even for SOAP ISClientConnected should be valid for the term of the  call as it is probably just looking to see if the socket is there and open.

     

    This is a very unusual case you may see it as a feature in a later verion but it is certainly not a bug.

     

     

    Regards,

     

    Ben

     

     

     

All Replies

  • Sunday, August 12, 2007 7:33 AM
     
     

    Hello,

     

    Im not sure i understand why does the client not just send an abort and a keep alive ?  Every time you get the keep alive you set a timer and if youve not heard from the client in x time you terminate the work ( or if the client cancels) .

     

    Regarding providing a network connect feature ; This is hard to do reliably , and doing it unreliably is worse then not doing it at all. In addition it almost needs to be done by the card driver and then you get into technolgy dependencies eg when is a wireless network or GPRS network down ?  In Some Wireless and GPRS networks sockets are kept alive even though there has been no ack. The only way in some enviroment is just to see how long till you last heard from the other end.  Even worse if your socket has droped due to a small interruption in the link , your socket is gone but the network is still up.

     

    Also most WAN network failures on links are of very short duration so keeping a socket open for a long time means you cant survive these drops  -  if you use HTTP the link can drop for a second  the server continues and at the end you get your result.

     

    Regards,

     

    Ben

  • Sunday, August 12, 2007 3:34 PM
     
     

    I believe that in the most common situations, TCP/IP and Winsock reliably detects this.

     

    1.  If the user reliably shuts down Windows, the socket connection will almost always be gracefully disconnected.

    2.  If the user terminates the client application, the socket connection will almost always be gracefully disconnected.

    3.  If the user calls Abort, the socket connection will almost always be gracefully disconnected.

     

    However, as you point out, if the network layer fails or power is abruptly lost, all bets are off.

     

    To understand this further, let me explain what I'm trying to accomplish.  End users can submit database queries through my application.  These database queries may take from a few seconds to five or more minutes before the results come back from SQL.  The user is presented with a Cancel button so that if they get tired of waiting, they can stop the query.  (One reason for pressing Cancel is that the user learns that they made an inefficient query, which really cannot be resolved with a fixed timeout because it is all relative to how complex the query is and how long the user is willing to wait.)

     

    In the IIS server, I want to spin up another thread that periodically checks for the disconnect (i.e., very 0.5 seconds).  If disconnected, I want to tell SqlCommand to terminate (terminating it is easy to do).  Now, the method call to terminate must be made on the same IIS server that is running the SqlCommand in a load balancing scenario.  This is really easy to do if one can just look using the background thread to see if the socket has been shut down by the client.  If I cannot check the socket, I must put flags in the database and poll these flags.  I don't want to do this every 0.5 seconds.

     

    I do agree that to cover the power failure case, the "ping and poll the database for the flag" solution would be necessary.  If desired for the app, this could be combined so that every 0.5 seconds it checks for the socket shutdown and every 30 seconds it checks for the database flag.

     

    What do you think?

  • Sunday, August 19, 2007 4:54 PM
     
     

    Consider also the case of implementing a REST service in .NET 3.5.  This service might return a multi-gigabyte file to the client.  The client might be nothing more than just a plain Internet Explorer browser.  It is useful to be able to detect if this connection has terminated (for example, the user presses Cancel on the file download dialog box).  There doesn't seem to be anyway to do that right now.

  • Saturday, August 25, 2007 11:39 PM
     
     

    If your transport of choice is TCP or Named Pipes, you can check the State property of the channel you are using. If the value is Faulted or Closed, you'll know the channel is no longer usable. Note that the state of the WCF channel will only change if WCF had a chance to discover that something went wrong with the underlying network resource. This will only happen if WCF is trying to send or receive on it (for example, the ConcurrencyMode of your service would have to be Multiple in order for WCF to have a pending receive on the resource).

     

    The last point in the previous paragraph also explains why this is not possible over HTTP. Once a datagram HTTP request is received, the network resource isn't touched until a response is ready. If you were coding against System.Net.HttpWeb*, you wouldn't know that the client disconnected until you tried to write the response, either.

  • Monday, August 27, 2007 2:53 AM
     
     

    Firstly are you using HTTP ? If so checking whether it is is open is meaningless , HTTP via netClient will open up connections when needed.

     

    The real issue hear is we are running with state but want a load balanced server farm. Server load balancing is IMHO overused  though it is needed in the larger scenarios. A lot of people use stickly load balancing to get around this problem.

     

    One option worth considering is returning the query id/spid with the sql and when you cancel send a termina query direct to the SQL server. This will give you a stateless design.  (KILL QUERY ? - im not an SQL expert)

     

    Are clients sending SQL directly to the middle tier ? This is really bad practice as a single client and lock out the entire system. Generally my appservers have fairly tightly crafted queries often via paging / limited resultsets.  For Reporting and addhoc  queries i tend to skip SOA/ WCF and go direct to a reporting DB ( same with maintenance) .

     

    Regards,

     

    Ben

  • Sunday, September 02, 2007 5:39 PM
     
     

    ISTM, you can't know if the client disconnected via System.Net.HttpWeb*, as there isn't any way to implement an HTTP server using this API.

     

    Maybe you meant System.Web.Http*?  Looking there, I see there is HttpResponse.IsClientDisconnected.  That would seems to fit the bill.  In MSDN for ISAPI, I also see IResponse::IsClientConnected.  In the IIS hosted case, possibly all that would be needed is for WCF to provide a property/method to wrap these APIs.  In non-IIS cases, WCF would need to check the Socket.  The .NET documentation for Socket.Connected says that you need to make a "zero byte Send call" and check for WAEWOULDBLOCK.

     

  • Monday, September 03, 2007 1:22 AM
     
     

    ISClientConnected is fairly meaningless as some clients will stay connected for extended periods others will disconnect quickly and reconnect when needed.  It is relevant for HTTP pages as the operations are atomic (GET Page) .

     

    This pattern is fairly well established now for may comm /proxy providers eg look at Close on an SqlConenction.

     

    The problem is more your orignal choice to link abort of the tranport to abort of the operation. In many cases protocols like HTTP SOAP will retry on a new connection (POST /GETSTATUS/GETSTATUS/GET) - this is good as it helps against the very short drops that you sometimes get on WANS and the internet.  For REST it may work , but i have not done much with REST WCF services,

     

    Also the comms transport is a shared resouce aborting it ( like with tcp) can affect other operations in multi threaded clients.

     

    What about protocols like Reliable connections , MSMQ and smtp what does aborting a communication channel mean for these ?

     

    For Tcp however you can check this  but is it it good practice to build higher level code refencing transport layers ( in contraction to the old OSI stack) .Will the maintenance programmers understand the dependency ?   I agree that many solutions build in heart beats but this is done at the session (eg reliable messaging) / service level and can only be dual direction for duplex style tranports eg the server still does not know.

     

    In your case what you really want is to abort a  session and you probably can do this ( by having the Cancel method and cancel the session) , all you need to then is have a list on the server of your worker threads for each session and kill them.

     

    I would have thought a stateless design and killing the SQL transaction would be better.

     

    Regards,

     

    Ben

  • Monday, September 03, 2007 9:52 PM
     
     

    > I would have thought a stateless design and killing the SQL transaction would be better.

     

    I agree, and I'd really want to implement both ways of detecting an abort (both an independent cancel, so an admin can cancel any session, and a socket disconnect detect so that the session ends if someone uses taskmgr to kill the client process).

     

    > IsClientConnected is fairly meaningless

     

    I disagree.  I think this kind of solution is the only way to resolve the REST example I gave earlier.

     

    Thanks.

     

  • Friday, September 07, 2007 2:43 AM
     
     Answered

     

    > I would have thought a stateless design and killing the SQL transaction would be better.

     

    I agree, and I'd really want to implement both ways of detecting an abort (both an independent cancel, so an admin can cancel any session, and a socket disconnect detect so that the session ends if someone uses taskmgr to kill the client process).

     

    >> Taskmanager , will try to clean things up nicelly first  ,  Some work around IDisposable could give the same affect. And this only applies to error conditions which should be rare - running the request on a non UI thread on the client should be important in these scenarios. 

     

    > IsClientConnected is fairly meaningless

     

    I disagree.  I think this kind of solution is the only way to resolve the REST example I gave earlier.

     

    >> You are not using REST  but SOAP . It looks like REST but REST does not send HTTP 100 Received /Continued repplies.  Howver I was wrong in that even for SOAP ISClientConnected should be valid for the term of the  call as it is probably just looking to see if the socket is there and open.

     

    This is a very unusual case you may see it as a feature in a later verion but it is certainly not a bug.

     

     

    Regards,

     

    Ben