Asynchronous method calls on the server side

Questions regarding the use of the .NET SDK 2.0 for Server or Client development or integration into customer products ...

Moderator: uasdknet

Post Reply
tearvisus
Jr. Member
Jr. Member
Posts: 1
Joined: 14 Jul 2014, 11:32

Asynchronous method calls on the server side

Post by tearvisus »

Hi!
I'm trying to implement a server with objects whose methods are time consuming. Hence I wish that the methods would run asynchronously on the server.

Right now I have a class generated by UaModeler with methods:

Code: Select all

StatusCode AMethodName(RequestContext context, MyModel model)
{
   //do work
   return StatusCodes.Good;
}
When a client calls those methods via BeginCall they run synchronously. What should I change to make two such methods run simultaneously?

User avatar
Support Team
Hero Member
Hero Member
Posts: 3070
Joined: 18 Mar 2011, 15:09

Re: Asynchronous method calls on the server side

Post by Support Team »

Hello,

The NodeManager calls UA Methods synchronously be default.

To process UA Methods asynchronously you have to override FinishCallTransaction and add the method call to the ThreadPool. You need some helper methods and a helper class to implement this. There is an example in the DemoServer project. Please search for the method DoSomethingAfter10s.

The following source code is an additional example that uses the MethodDispatcher to select the method. In this example only one method call is added to the ThreadPool.

Code: Select all

private class CallMethodAsyncData

{

    public RequestContext Context;

    public IList<Variant> InputArguments;

    public MethodOperationHandle OperationHandle;

    public CallCompleteEventHandler Callback;

    public object CallbackData;

}

private void OnAsyncMethodCompletes(object state)

{

    CallMethodAsyncData data = (CallMethodAsyncData)state;

    ((CallCompleteEventHandler)data.Callback)(data.OperationHandle, data.CallbackData, CallMethodAsync(data), false);

}

private CallMethodResult CallMethodAsync(CallMethodAsyncData data)

{

    CallMethodResult result = new CallMethodResult();

 

    Argument[] arguments = Server.InternalClient.ReadValue<Argument[]>(

        data.Context,

        data.OperationHandle.MethodHandle.MethodId,

        UnifiedAutomation.UaBase.BrowseNames.OutputArguments,

        null);

    VariantCollection outputArguments = null;

    if (arguments.Length > 0)

    {

        outputArguments = new VariantCollection(arguments.Length);

        for (int ii = 0; ii < arguments.Length; ii++)

        {

            outputArguments.Add(new Variant());

        }

    }

    StatusCode status = data.OperationHandle.MethodHandle.Dispatcher(

        data.Context,

        data.OperationHandle.MethodHandle,

        data.InputArguments,

        result.InputArgumentResults,

        outputArguments);

    if (status.IsGood())

    {

        result.OutputArguments = outputArguments;

    }

    result.StatusCode = status;

    return result;

}

public override void FinishCallTransaction(TransactionHandle transaction)

{

    CallTransactionHandle transaction2 =

        transaction as CallTransactionHandle;

 

    for (int ii = 0; ii < transaction2.MethodHandles.Count; ii++)

    {

        MethodOperationHandle methodHandle

            = transaction2.MethodHandles[ii];

 

        // check for long running methods which are processed

        // asychnonously.

        if (methodHandle.MethodHandle.MethodDeclarationId.Equals(

            MethodIds.MyType_LongRunning.ToNodeId(Server.NamespaceUris)))

        {

            ThreadPool.QueueUserWorkItem(

                OnAsyncMethodCompletes, new CallMethodAsyncData()

            {

                Context = transaction.Context,

                InputArguments = transaction2.InputArguments[ii],

                Callback = (CallCompleteEventHandler)transaction.Callback,

                CallbackData = transaction.CallbackData,

                OperationHandle = transaction2.MethodHandles[ii],

            });

 

            continue;

        }

 

        // call normal methods synchronously.

        CallMethodResult result = CallMethod(

            transaction.Context,

            transaction2.MethodHandles[ii].MethodHandle,

            transaction2.InputArguments[ii]);

 

        ((CallCompleteEventHandler)transaction.Callback)(

            transaction2.MethodHandles[ii],

            transaction.CallbackData, result, false);

    }

}
The follwing source code shows an example how to add all methods to the ThreadPool:

Code: Select all

public override void FinishCallTransaction(TransactionHandle transaction)
{
    CallTransactionHandle transaction2 = transaction as CallTransactionHandle;

    for (int ii = 0; ii < transaction2.MethodHandles.Count; ii++)
    {
        MethodOperationHandle methodHandle
            = transaction2.MethodHandles[ii];

        ThreadPool.QueueUserWorkItem(
            OnAsyncMethodCompletes, new CallMethodAsyncData()
        {
            Context = transaction.Context,
            InputArguments = transaction2.InputArguments[ii],
            Callback = (CallCompleteEventHandler)transaction.Callback,
            CallbackData = transaction.CallbackData,
            OperationHandle = transaction2.MethodHandles[ii],
        });
    }
}

private class CallMethodAsyncData
{
    public RequestContext Context;
    public IList<Variant> InputArguments;
    public MethodOperationHandle OperationHandle;
    public CallCompleteEventHandler Callback;
    public object CallbackData;
}

private void OnAsyncMethodCompletes(object state)
{
    CallMethodAsyncData data = (CallMethodAsyncData)state;
    CallMethodResult result = CallMethod(data.Context, data.OperationHandle.MethodHandle, data.InputArguments);
    ((CallCompleteEventHandler)data.Callback)(data.OperationHandle, data.CallbackData, result, false);
}
Best regards
Support Team

Post Reply