8
\$\begingroup\$

I'm attempting to implement a simple long-polling/comet/reverse AJAX solution, and came across the concept of delegates, specifically with the BeginInvoke and EndInvoke methods. I've built a Web Service that uses these concepts, but, having never used these, they make me a little nervous, and I have my doubts as to whether they are actually what I want.

The goal, of course, is to offload the actual processing from IIS processes onto other framework processes, for a reduction in server load when waiting on a long-poll request for data. I can't have gotten this right, but I want to know why and at least get some direction in how it might be better accomplished (not necessarily a solution, but maybe an article or some documentation).

The Web Service code:

Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Threading
Imports System.Runtime.InteropServices

<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class WebService
    Inherits System.Web.Services.WebService

    <WebMethod()> _
    Public Function HelloWorld() As String
        Dim threadId As Integer
        Dim thing As New Things
        Dim caller As New AsyncDoStuff(AddressOf thing.doStuff)
        Dim result As IAsyncResult = caller.BeginInvoke(3000, threadId, Nothing, Nothing)

        result.AsyncWaitHandle.WaitOne()

        Dim returnValue As String = caller.EndInvoke(threadId, result)

        result.AsyncWaitHandle.Close()

        Return returnValue
    End Function
End Class

Public Class Things
    Public Function doStuff(ByVal callDuration As Integer, <Out()> ByRef threadId As Integer) As String
        ' Imagine this method was accessing a database, looking for new information, and returning when it found some
        Thread.Sleep(callDuration)
        threadId = Thread.CurrentThread.ManagedThreadId()
        Return String.Format("My call time was {0}.", callDuration.ToString())
    End Function
End Class

Public Delegate Function AsyncDoStuff(ByVal callDuration As Integer, <Out()> ByRef threadID As Integer) As String
\$\endgroup\$
  • 1
    \$\begingroup\$ You've never used an event handler? EventHandler is just a delegate with a (Object, EventArgs) signature and no return value. You know delegates more than you think you do. \$\endgroup\$ – Mathieu Guindon Nov 22 '13 at 2:48
  • \$\begingroup\$ Wow. Blast from the past. I never actually got this implemented, opting instead for simple polling with increased intervals when no data was returned. I guess I never trusted myself with off-processes. \$\endgroup\$ – Ryan Kinal Nov 22 '13 at 16:36
3
+100
\$\begingroup\$

This Stack Overflow answer to the question "Is there a VB.NET equivalent of C# out parameters" is pretty clear:

No, there is no equivalent construct that allows a non-initialised variable to be passed to a method without a warning [...]

However specifying the <Out()> attribute, despite being ignored by VB (ByRef is all you need, really), does allow a C# client to use it as an out parameter - so good call then!


Declaring the delegate at the bottom of the module, after it's being used, makes it uselessly confusing and prompts for unnecessary scrolling; I would have put it at the top... actually, I would have made the delegate a public member of the WebService class:

Public Class WebService
    Inherits System.Web.Services.WebService

    Public Delegate Function AsyncDoStuff(ByVal callDuration As Integer, <Out()> ByRef threadID As Integer) As String

    '...

I very, very seldom declare my own delegate types, if at all. I don't like ref ByRef and out <Out()> parameters either - I think they should be avoided.

In this case I would have gone with a Func<int,AsyncStuffResult> (please excuse the C# notation), where the int parameter is the callDuration, and the AsyncStuffResult is a class that encapsulates everything you want to return from the function call - whatever that is.

This way if/when you need to return more things, your signature doesn't need to change, you only add new members to your result class - note that the EventArgs class fulfills the same goal.

Public Class AsyncStuffResult
    '- expose ThreadId as a get-only property
    '- expose your String result as a get-only property, too
    '- expose a constructor to assign the members
End Class
\$\endgroup\$
  • \$\begingroup\$ Death to delegates!!! \$\endgroup\$ – IEatBagels Sep 26 '14 at 18:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.