Raw Caller

The callee proxy is the easiest way to consume WAMP caller capabilities, but it is limited to C# features. In some cases you might want to handle a RESULT message differently. For these cases, the Raw callback api exists.

In order to use raw callback api from a WampSharp client, create a class implementing IWampRawRpcOperationClientCallback. This class will be notified when a result arrives. Then create a new instance of your class, and access RpcCatalog property of WampChannel’s RealmProxy, then call Invoke of your desired method with desired parameters.

The IWampRawRpcOperationClientCallback methods receive a IWampFormatter so you can deserialize the message parameters yourself.

Client sample code:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using WampSharp.Core.Serialization;
using WampSharp.V2;
using WampSharp.V2.Client;
using WampSharp.V2.Core.Contracts;
using WampSharp.V2.Rpc;

namespace MyNamespace
{
    internal class Program
    {
        public static async Task Main(string[] args)
        {
            const string serverAddress = "ws://127.0.0.1:8080/ws";

            DefaultWampChannelFactory factory = new DefaultWampChannelFactory();
            IWampChannel channel = factory.CreateJsonChannel(serverAddress, "realm1");

            await channel.Open().ConfigureAwait(false);

            IWampRealmProxy realmProxy = channel.RealmProxy;

            realmProxy.RpcCatalog.Invoke
                (new MyCallback(),
                 new CallOptions(),
                 "com.myapp.add_complex",
                 new object[] {2, 3, 4, 5});

            // This line is required in order to release the WebSocket thread, otherwise it will be blocked by the following Console.ReadLine() line.
            await Task.Yield();
            
            Console.ReadLine();
        }
    }

    public class MyCallback : IWampRawRpcOperationClientCallback
    {
        public void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details)
        {
            throw new NotImplementedException();
        }

        public void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments)
        {
            throw new NotImplementedException();
        }

        public void Result<TMessage>(IWampFormatter<TMessage> formatter,
                                     ResultDetails details,
                                     TMessage[] arguments,
                                     IDictionary<string, TMessage> argumentsKeywords)
        {
            int c = formatter.Deserialize<int>(argumentsKeywords["c"]);
            int ci = formatter.Deserialize<int>(argumentsKeywords["ci"]);

            Console.WriteLine("Got result: " + new {c, ci});
        }

        public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error)
        {
            throw new NotImplementedException();
        }

        public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error, TMessage[] arguments)
        {
            throw new NotImplementedException();
        }

        public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error, TMessage[] arguments,
                                    TMessage argumentsKeywords)
        {
            throw new NotImplementedException();
        }
    }
}

Manual proxy samples

This sample demonstrates a manual implementation of Reflection-based caller.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WampSharp.Core.Serialization;
using WampSharp.V2;
using WampSharp.V2.Client;
using WampSharp.V2.Core.Contracts;
using WampSharp.V2.Rpc;

public interface IArgumentsService
{
    [WampProcedure("com.arguments.ping")]
    void Ping();

    [WampProcedure("com.arguments.add2")]
    int Add2(int a, int b);

    [WampProcedure("com.arguments.stars")]
    string Stars(string nick = "somebody", int stars = 0);

    [WampProcedure("com.arguments.orders")]
    string[] Orders(string product, int limit = 5);

    [WampProcedure("com.arguments.ping")]
    Task PingAsync();

    [WampProcedure("com.arguments.add2")]
    Task<int> Add2Async(int a, int b);

    [WampProcedure("com.arguments.stars")]
    Task<string> StarsAsync(string nick = "somebody", int stars = 0);

    [WampProcedure("com.arguments.orders")]
    Task<string[]> OrdersAsync(string product, int limit = 5);
}

public class ArgumentsServiceProxy : IArgumentsService
{
    private readonly IWampRpcOperationCatalogProxy mCatalogProxy;
    private readonly CallOptions mDummy = new CallOptions();

    public ArgumentsServiceProxy(IWampRpcOperationCatalogProxy catalogProxy)
    {
        mCatalogProxy = catalogProxy;
    }

    public Task PingAsync()
    {
        PingCallback callback = new PingCallback();
        mCatalogProxy.Invoke(callback, mDummy, "com.arguments.ping");
        return callback.Task;
    }

    public Task<int> Add2Async(int a, int b)
    {
        AddCallback callback = new AddCallback();
        mCatalogProxy.Invoke(callback, mDummy, "com.arguments.add2", new object[] { a, b });
        return callback.Task;
    }

    public Task<string> StarsAsync(string nick = "somebody", int stars = 0)
    {
        StarsCallback callback = new StarsCallback();

        mCatalogProxy.Invoke(callback, mDummy, "com.arguments.stars", new object[] { nick, stars });
        return callback.Task;
    }

    public Task<string[]> OrdersAsync(string product, int limit = 5)
    {
        OrdersCallback callback = new OrdersCallback();
        mCatalogProxy.Invoke(callback, mDummy, "com.arguments.orders", new object[] { product, limit });
        return callback.Task;
    }

    public void Ping()
    {
        try
        {
            this.PingAsync().Wait();
        }
        catch (AggregateException ex)
        {
            throw ex.InnerException;
        }
    }

    public int Add2(int a, int b)
    {
        try
        {
            return this.Add2Async(a, b).Result;
        }
        catch (AggregateException ex)
        {
            throw ex.InnerException;
        }
    }

    public string[] Orders(string product, int limit = 5)
    {
        try
        {
            return this.OrdersAsync(product, limit).Result;
        }
        catch (AggregateException ex)
        {
            throw ex.InnerException;
        }
    }

    public string Stars(string nick = "somebody", int stars = 0)
    {
        try
        {
            return this.StarsAsync(nick, stars).Result;
        }
        catch (AggregateException ex)
        {
            throw ex.InnerException;
        }
    }

    private abstract class Callback<T> : IWampRawRpcOperationClientCallback
    {
        protected readonly TaskCompletionSource<T> mTask = new TaskCompletionSource<T>();

        public Task<T> Task
        {
            get { return mTask.Task; }
        }

        public abstract void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details);

        public abstract void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments);

        public abstract void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments, IDictionary<string, TMessage> argumentsKeywords);

        public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error)
        {
            IDictionary<string, object> deserializedDetails =
                formatter.Deserialize<IDictionary<string, object>>(details);

            WampException exception = new WampException
                (deserializedDetails,
                 error);

            mTask.SetException(exception);
        }

        public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error,
                                    TMessage[] arguments)
        {
            IDictionary<string, object> deserializedDetails =
                formatter.Deserialize<IDictionary<string, object>>(details);

            object[] deserializedArguments = arguments.Cast<object>().ToArray();

            WampException exception = new WampException
                (deserializedDetails,
                 error,
                 deserializedArguments);

            mTask.SetException(exception);
        }

        public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error,
                                    TMessage[] arguments,
                                    TMessage argumentsKeywords)
        {
            IDictionary<string, object> deserializedDetails =
                formatter.Deserialize<IDictionary<string, object>>(details);

            object[] deserializedArguments = arguments.Cast<object>().ToArray();

            IDictionary<string, object> deserializedArgumentsKeywords =
                formatter.Deserialize<IDictionary<string, object>>(argumentsKeywords);

            WampException exception = new WampException
                (deserializedDetails,
                 error,
                 deserializedArguments,
                 deserializedArgumentsKeywords);

            mTask.SetException(exception);
        }
    }

    private class PingCallback : Callback<bool>
    {
        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details)
        {
            mTask.SetResult(true);
        }

        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments)
        {
            mTask.SetResult(true);
        }

        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments, IDictionary<string, TMessage> argumentsKeywords)
        {
            mTask.SetResult(true);
        }
    }

    private class AddCallback : Callback<int>
    {
        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details)
        {
            throw new NotImplementedException();
        }

        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments)
        {
            int result = formatter.Deserialize<int>(arguments[0]);
            mTask.SetResult(result);
        }

        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments, IDictionary<string, TMessage> argumentsKeywords)
        {
            int result = formatter.Deserialize<int>(arguments[0]);
            mTask.SetResult(result);
        }
    }

    private class StarsCallback : Callback<string>
    {
        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details)
        {
            throw new NotImplementedException();
        }

        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments)
        {
            string result = formatter.Deserialize<string>(arguments[0]);
            mTask.SetResult(result);
        }

        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments, IDictionary<string, TMessage> argumentsKeywords)
        {
            string result = formatter.Deserialize<string>(arguments[0]);
            mTask.SetResult(result);
        }
    }

    private class OrdersCallback : Callback<string[]>
    {
        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details)
        {
            throw new NotImplementedException();
        }

        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments)
        {
            string[] result =
                arguments.Select(x => formatter.Deserialize<string>(x))
                         .ToArray();

            mTask.SetResult(result);
        }

        public override void Result<TMessage>(IWampFormatter<TMessage> formatter, ResultDetails details, TMessage[] arguments, IDictionary<string, TMessage> argumentsKeywords)
        {
            string[] result =
                arguments.Select(x => formatter.Deserialize<string>(x))
                         .ToArray();

            mTask.SetResult(result);
        }
    }
}

Usage:

public async static Task Main()
{
    const string serverAddress = "ws://127.0.0.1:8080/ws";

    DefaultWampChannelFactory factory = new DefaultWampChannelFactory();

    IWampChannel channel =
        factory.CreateJsonChannel(serverAddress, "realm1");

    await channel.Open().ConfigureAwait(false);

    ArgumentsServiceProxy proxy =
        new ArgumentsServiceProxy(channel.RealmProxy.RpcCatalog);

    int nine = await proxy.Add2Async(4, 5).ConfigureAwait(false);
}