AdvancedRpcLib 1.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package AdvancedRpcLib --version 1.0.1
NuGet\Install-Package AdvancedRpcLib -Version 1.0.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AdvancedRpcLib" Version="1.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AdvancedRpcLib --version 1.0.1
#r "nuget: AdvancedRpcLib, 1.0.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install AdvancedRpcLib as a Cake Addin
#addin nuget:?package=AdvancedRpcLib&version=1.0.1

// Install AdvancedRpcLib as a Cake Tool
#tool nuget:?package=AdvancedRpcLib&version=1.0.1

AdvancedRPC

AdvancedRPC is a remote procedure call library for .NET. It differs from common solutions like REST, GRPC or WebSockets in that it supports an object hierarchy similar to .NET Remoting. I wrote the library mainly as a replacement for .NET Remoting to make our corporate application ready for .NET Core. It relies heavily on the ability to make remote procedure calls on objects.

Features

  • Communication via TCP and Named Pipes
  • Support for impersonation with Named Pipes
  • Deep object hierarchies
  • Events and callbacks
  • No need for serialization annotations, just publish an interface
  • Support for multiple clients with notification on connection and disconnection
  • .NET 4.8, .NET Standard 2.0 and .NET Standard 2.1
  • Very easy to setup: No need to start a web service or define proto files. Just define an interface that is shared between applications and you are ready.

Example

Common interface definition


public interface IRpcServer 
{
    IRpcObject CreateObject(string name);
}

public interface IRpcObject 
{
    string Name { get; }

    void ChangeName(string name);

    event NameChanged;
}

Server implementation


class RpcServer : IRpcServer 
{
    IRpcObject CreateObject(string name)
    {
        return RpcObjectImpl(name);
    }
}

class RpcObjectImpl : IRpcObject 
{
    public RpcObjectImpl(string name)
    {
        Name = name;
    }

    string Name { get; private set; }

    void ChangeName(string name)
    {
        Name = name;
        NameChanged?.Invoke(this, EventArgs.Empty);
    }

    event NameChanged;
}

class Program
{
    static async Task Main(string[] args)
    {
        var server = new NamedPipeRpcServerChannel(new BinaryRpcSerializer(), 
                            new RpcMessageFactory(), "myipcchannelname");
        server.ObjectRepository.RegisterSingleton<RpcServer>();
        await server.ListenAsync();

        Console.WriteLine("Press key to quit");
        Console.ReadKey();
    }
}

Client implementation


class Program
{
    static async Task Main(string[] args)
    {
        var client = new NamedPipeRpcClientChannel(new BinaryRpcSerializer(), 
                            new RpcMessageFactory(), "myipcchannelname");        
        await client.ConnectAsync(TimeSpan.FromSeconds(5));

        var rpcServerObj = await client.GetServerObjectAsync<IRpcServer>();
        var nameObj = rpcServerObj.CreateObject("Jon Doe")
        nameObj.NameChanged += (sender, e) => Console.WriteLine(((IRpcObject)sender).Name);

        // This calls the method on the server and invokes
        // the event NameChanged on the client.
        nameObj.ChangeName("Jane Doe"); 

        Console.WriteLine("Press key to quit");
        Console.ReadKey();
    }
}

See unit tests for more advanced scenarios.

Some Notes

  • If you return a plain static object that doesn't need to know about server changes, use the Serializable attribute on the implementation. In that case the object will be serialized and copied to the client or server without creating a proxy object. This can be more efficient for data objects if you have a lot of properties and deep hierarchies. This behaves like a REST call.
  • Do not return or pass IEnumerable, as this will result in a remote call for every MoveNext when iterating over it. Instead, use an array in those cases.
  • Watch out for memory leaks. AdvancedRPC handles a lot of scenarios for you but take care to remove your event listeners.
  • CAREFUL! Every remote call can throw an exception if the server goes down.

Restrictions

  • Method overloads with same parameter count are not supported (yet). Overloads with different parameter count are possible though.
  • Named Pipe impersonation limitations:
    • doesn't work with .NET Standard 2.0 (for now)
    • only works on Windows
  • IEnumerable doesn't work for .NET Core (the interfaces use ByRef Values). There might be a workaround to support this.
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 is compatible.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.8 511 6/2/2022
1.0.7 406 5/19/2022
1.0.6 421 5/3/2022
1.0.5 313 12/14/2021
1.0.4 517 9/20/2020
1.0.3 490 8/29/2020
1.0.2 400 8/28/2020
1.0.1 410 8/26/2020
1.0.0 403 8/25/2020

1.0.1 Fixed Serializable objects
1.0.0 Initial release