5

I am trying to invoke a method from another .dll file . It is sending a message through the VPN then Return the RecievedMessage from another computer.

As you now it takes time to sending and receiving message and VpnObject just send message and I should wait for listener to invoke the RecievedMessage.

This method is like this!

    public string RecievedMessage()
    {
        string Recieved ;
        // Some VPN Code  and then return the result;
        return Recieved;
    }

    public string SendAndRecieveMessage(string MessageToSend)
    {
        string RecievedAnswer = string.Empty;

        // Now Sending Message through the VPN
        VpnObject.SendMessage(MessageToSend);

        //Then want to Recieve the answer and return the answer here .

        return RecievedAnswer;
    }

I'm just thinking how can wait for RecievedMessage to invoke then return the result .

You know it is simple to use a variable and assign it value and check for while but it reduced the performance dramatically .

Is there anyway to continue from SendAndRecieveMessage just when RecievedMessage invoked ? (I think it is something with async and await but don't know how!)

Edit :VpnObject is just a sender and receiver through the vpn . it contains a simple socket send and a listener that invoke a method(RecievedMessage) when new message received .

Mohammad Sina Karvandi
  • 1,064
  • 3
  • 25
  • 44
  • 1
    What is `VpnObject`? Does it provide any events to let you know when the request has completed? Also, if you poll at a reasonable time resolution you shouldn't see too much of a performance impact. – Asad Saeeduddin Jul 12 '15 at 16:43
  • @Asad pls see the edit . thank you – Mohammad Sina Karvandi Jul 12 '15 at 16:46
  • 1
    That still doesn't tell us enough. How is `VpnObject` aware of `ReceivedMessage`? Can you substitute the callback it invokes? – Asad Saeeduddin Jul 12 '15 at 16:47
  • @Asad you can imagine that it doesn't exist . It's just a listener that invoke a given method only. – Mohammad Sina Karvandi Jul 12 '15 at 16:49
  • I'm not sure I understand what you mean. I think the easiest way to clarify is to show us the exact methods you' calling on `VpnObject`, or to point us to the documentation for the lib you're using. – Asad Saeeduddin Jul 12 '15 at 16:56
  • You gave us two methods, but it doesn't show where those methods live. Clearly the aren't in VpnObject, since you have to call `VpnObject.SendMessage`. – Aron Jul 12 '15 at 17:21

2 Answers2

2

Whether or not you have an alternative to polling depends on whether the library you are using provides any events or callbacks that will tell you when the request has completed.

Either way, the standard approach to exposing the deferred result of an asynchronous operation is to use a Task. Your method signature would look like this:

public Task<string> SendAndRecieveMessage(string MessageToSend)

Now, how you actually implement the method depends on what API VpnObject exposes. TaskCompletionSource is very useful for this kind of thing.

If VpnObject has an event that fires when the request completes:

public Task<string> SendAndReceiveMessage(string messageToSend)
{
    var tcs = new TaskCompletionSource<string>();
    ...
    VpnObject.OnMessageReceived += (s, e) => tcs.SetResult(e.Message);
    ...
    return tcs.Task;
}

If VpnObject can accept a callback that it will invoke when the request completes:

public Task<string> SendAndReceiveMessage(string messageToSend)
{
    var tcs = new TaskCompletionSource<string>();
    ...
    VpnObject.OnMessageReceived(message => tcs.SetResult(message));
    ...
    return tcs.Task;
}

If VpnObject doesn't support any of this, you can fall back to polling:

public async Task<string> SendAndReceiveMessage(string messageToSend)
{
    var tcs = new TaskCompletionSource<string>();
    ...
    while(!VpnObject.IsMessageReceived)
        await Task.Delay(500); // Adjust to a reasonable polling interval
    ...
    return VpnObject.Message;
}
Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
  • @Aron It's worse than that. I actually have no idea how the class works. All of the code that interacts with `VpnObject` is pseudocode intended to give the OP an idea of what they need to do, since I have no idea what library `VpnObject` comes from or what methods it exposes. The primary value of the answer is to show how non-`Task`-based APIs can be wrapped into `Task`-based ones. – Asad Saeeduddin Jul 12 '15 at 17:20
  • @Asad yeah with some changes the second code is what I trying to do . – Mohammad Sina Karvandi Jul 12 '15 at 17:22
  • Actually, rereading the question now I see its pretty bad. I can't figure out where to place the TCS so both the Receive method and the Send method can access it. As it seems as though the `VpnObject` calls back to `Receive`, but how it does that isn't clear. If it is configurable I would suggest he has it call back to a lambda that calls the TCS. Also I would actually use a library like Rx for the wrapping as there are exception and EAP unsubscribes to handle. Overall there isn't enough to answer the question correctly... – Aron Jul 12 '15 at 17:24
0

You know it is simple to use a variable and assign it value and check for while but it reduced the performance dramatically .

A spin while loop is definitely not the way to implement this. Even with a sleep, it's clunky, and C# has multiple ways to solve this problem.

It's not entirely clear how your VPN Send and Receive method works, but the idea for solving this is to either use a callback approach, or as you noted, use C# async framework.

Without more details on the VPN Object, I'll just have to have some stub methods. The idea is to create a Task that returns the string, mark it as an async task, then await for it to complete. In your case, the task is receiving the VPN response string.

Something like this.

public Task<string> ReceivedMessage()
{
    //get the response from the VPN Object.
    string Received = VpnObject.GetResponse(); 
    var ts = new TaskCompletionSource<string>();
    ts.SetResult(Received);

    // Some VPN Code  and then return the result;
    return ts.Task;
}

public async Task<string> SendAndReceiveMessageAsync(string MessageToSend)
{
    string result = string.Empty;

    // Now Sending Message through the VPN
    VpnObject.SendMessage(MessageToSend);

    result = await ReceivedMessage();

    return result;
}
Alan
  • 45,915
  • 17
  • 113
  • 134
  • 2
    What is `await string Received` supposed to mean? – Asad Saeeduddin Jul 12 '15 at 16:45
  • Edited with a comment that indicates that it should be the code that waits for the VPN Response. – Alan Jul 12 '15 at 16:49
  • 2
    Your usage of `await` doesn't even compile. – Aron Jul 12 '15 at 17:15
  • @Alan This still doesn't make any sense. You have a declared but unassigned variable `Received`. You create a `TaskCompletionSource`, then try to set it's value to your still null variable `Received`. If this is pseudocode, it isn't clear where the actual async operation is supposed to go. – Asad Saeeduddin Jul 12 '15 at 18:08
  • @Asad There isn't information about the VpnObject class, so I have no idea how it works. – Alan Jul 12 '15 at 18:29
  • @Alan Right, that's why I'm assuming this is pseudocode. My point is that if `VpnObject` has a synchronous `GetResponse` method that waits for the request to complete and provides you with the result, you wouldn't want to call it on the same thread. Sitting at the first statement waiting for the entire request to complete, then wrapping the already materialized result in a `Task` just for kicks isn't useful. – Asad Saeeduddin Jul 12 '15 at 18:33
  • @Asad: Right the GetResponse() is just pseudocode, and isn't likely synchronous. The original question has a `ReceivedMessage()` method that has the VPNs Response (retrieved mostly likely via callback). That is the method that should be awaited. – Alan Jul 12 '15 at 18:43
  • @Alan How could `GetResponse` not be synchronous if it returns a `string`? – Asad Saeeduddin Jul 12 '15 at 18:44
  • Or, put another way, if the `GetResponse` isn't waiting for the entire response to complete (thereby rendering all the rest of the async and task based code useless), what string is it returning? – Asad Saeeduddin Jul 12 '15 at 18:48