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