Skip to content
This repository has been archived by the owner on Dec 20, 2019. It is now read-only.

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
dajuric authored Jan 3, 2018
1 parent 86a4d5d commit 17e338d
Showing 1 changed file with 79 additions and 120 deletions.
199 changes: 79 additions & 120 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,157 +34,116 @@ Implemented API, if used only for RPC, does not use anything from the library.

Check the samples by following the link above. The snippets below demonstrate the base functionality.

#### 1) .NET <-> .NET (raw messaging)
The sample demonstrates communication between server and client using raw messaging. The server relays client messages.
#### 1) .NET <-> .NET (RPC)
The server's *TaskAPI* has a function which during its execution updates progress and reports it only to clients which called the method.

**Server** (C#)
``` csharp
Server.ListenAsync("http://localhost:8000/", CancellationToken.None, (c, wc) =>
interface IProgressAPI
{
c.OnOpen += () => Task.Run(() => Console.WriteLine("Opened"));
c.OnClose += (status, description) => Task.Run(() => Console.WriteLine("Closed: " + description));
c.OnError += ex => Task.Run(() => Console.WriteLine("Error: " + ex.Message));

c.OnReceive += msg => await c.SendAsync("Received: " + msg); //relay message
})
.Wait(0);
```

**Client** (C#)
``` csharp
Client.ListenAsync("ws://localhost:8000/", CancellationToken.None, c =>
{
c.OnOpen += () => await c.SendAsync("Hello from a client");
},
reconnectOnError: true)
.Wait(0);
```

#### 2) .NET <-> .NET (RPC)
A data aggregator service is built. The server gets the multiple number sequences of each client and sums all the numbers.
The procedure is repeated for each new client connection.

**Server** (C#)
``` csharp
//client API contract
interface IClientAPI
{
int[] GetLocalNumbers();
void WriteProgress(float progress);
}

....
async Task WriteTotalSum()
{
//get all the clients (notice there is no 'this' (the sample above))
var clients = RPC.For<IClientAPI>();

//get the numbers sequences
var numberGroups = await clients.CallAsync(x => x.GetLocalNumbers());
//flatten the collection and sum all the elements
var sum = numberGroups.SelectMany(x => x).Sum();

Console.WriteLine("Client count: {0}; sum: {1}.", clients.Count(), sum);
class TaskAPI //:ITaskAPI
{
public async Task<int> LongRunningTask(int a, int b)
{
for (var p = 0; p <= 100; p += 5)
{
await Task.Delay(250);
//select only those connections which are associated with 'IProgressAPI' and with 'this' object.
await RPC.For<IProgressAPI>(this).CallAsync(x => x.WriteProgress((float)p / 100));
}

return a + b;
}
}

//run server
Server.ListenAsync("http://localhost:8000/", CancellationToken.None,
(c, wc) =>
{
c.Bind<IClientAPI>();
c.OnOpen += WriteTotalSum;
})
.Wait(0);

/*
Output:
Client count: 1; sum: 4.
Client count: 3; sum: 14.
...
*/
...
Server.ListenAsync(8000, CancellationToken.None,
(c, wc) => c.Bind<TaskAPI, IProgressAPI>(new TaskAPI()))
.Wait(0);
```

**Client** (C#)
``` csharp
//client API
class ClientAPI
class ProgressAPI //:IProgressAPI
{
int[] GetLocalNumbers()
{
var r = new Random();

var numbers = new int[10];
for(var i = 0; i < numbers.Length; i++)
numbers[i] = r.Next();
void WriteProgress(float progress) {
Console.Write("Completed: " + progress * 100 + "%\r");
}
}

return numbers;
}
interface ITaskAPI {
Task<int> LongRunningTask(int a, int b);
}

....
//run client
Client.ListenAsync("ws://localhost:8000/", CancellationToken.None,
c => c.Bind(new ClientAPI())).Wait(0);
...
Client.ConnectAsync("ws://localhost:8000/", CancellationToken.None,
(c, wc) => c.Bind<ProgressAPI, ITaskAPI>(new ProgressAPI()))
.Wait(0);
...
var r = await RPC.For<ITaskAPI>().First().CallAsync(x => LongRunningTask(5, 3));
Console.WriteLine("Result: " + r);

/*
Output:
Completed: 0%
Completed: 5%
...
Completed: 100%
Result: 8
*/
```

#### 3) .NET <-> Javascript (RPC)
Simple math service is built and invoked remotely. The math service has a single long running method which adds two numbers (server side).
Client calls the method and receives progress update until the result does not become available.
#### 2) .NET <-> Javascript (RPC)
Let us use the same server implementation as in the two-way binding sample, but this time the client will be written in JavaScript.

**Server** (C#)
``` csharp
//client API contract
interface IReportAPI
{
void WriteProgress(int progress);
}
//the server code is the same as in the previous sample
//server API
class MathAPI
{
public async Task<int> LongRunningTask(int a, int b)
{
for (var p = 0; p <= 100; p += 5)
{
await Task.Delay(250);
//update only the client which called this method (hence 'this')
await RPC.For<IReportAPI>(this).CallAsync(x => x.WriteProgress(p));
}

return a + b;
}
}

....
//generate js code with JsDoc documentation taken from XML comments (if any)
File.WriteAllText("MathAPI.js", RPCJs.GenerateCallerWithDoc<MathAPI>());
//run server
Server.ListenAsync("http://localhost:8000/", CancellationToken.None,
(c, wc) => c.Bind<MathAPI, IReportAPI>(new MathAPI())).Wait(0);
//generate JavaScript client (file)
var code = RPCJs.GenerateCallerWithDoc<TaskAPI>();
File.WriteAllText("TaskAPI.js", code);
```

**Client** (Javascript)
``` javascript
//init 'MathAPI'
var api = new MathAPI("ws://localhost:8000");
//implement the 'IReportAPI'
api.writeProgress = p => console.log("Progress: " + p + "%");
//init API
var api = new TaskAPI("ws://localhost:8001");

//implement the interface by extending the 'TaskAPI' object
api.writeProgress = function (p)
{
console.log("Completed: " + p * 100 + "%");
return true;
}

//connect to the server and call the remote function
//connect and excecute (when connection is opened)
api.connect(async () =>
{
var r = await api.longRunningTask(5, 3);
console.log("Result: " + r);
var r = await api.longRunningTask(5, 3);
console.log("Result: " + r);
});

/*
Output:
Progress: 0 %
Progress: 5 %
Progress: 10 %
...
Result: 8
*/
```

#### 3) ASP.NET Core
``` csharp
class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//the MVC initialization, etc.
//initialize web-sockets
app.UseWebSockets();
//define route for a new connection and bind the API
app.MapWebSocketRPC("/taskService",
(httpCtx, c) => c.Bind<TaskAPI, IProgressAPI>(new TaskAPI()));
}
}
```

## How to Engage, Contribute and Provide Feedback
Remember: Your opinion is important and will define the future roadmap.
Expand Down

0 comments on commit 17e338d

Please sign in to comment.