Skip to content

Commit

Permalink
Merge pull request #138 from jacqueskang/develop
Browse files Browse the repository at this point in the history
v3.0.0
  • Loading branch information
jacqueskang authored Jun 12, 2020
2 parents 2a046a5 + ac98e5f commit ebb2488
Show file tree
Hide file tree
Showing 146 changed files with 3,118 additions and 2,876 deletions.
12 changes: 12 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# These are supported funding model platforms

github: jacqueskang
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
11 changes: 0 additions & 11 deletions .travis.yml

This file was deleted.

195 changes: 69 additions & 126 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,163 +1,106 @@
[![Build Status](https://travis-ci.org/jacqueskang/IpcServiceFramework.svg?branch=develop)](https://travis-ci.org/jacqueskang/IpcServiceFramework)
| CI build | Stable build |
|----------|--------------|
|[![Build Status](https://dev.azure.com/jacques-kang/IpcServiceFramework/_apis/build/status/IpcServiceFramework%20CI?branchName=develop)](https://dev.azure.com/jacques-kang/IpcServiceFramework/_build/latest?definitionId=9&branchName=develop)|[![Build Status](https://dev.azure.com/jacques-kang/IpcServiceFramework/_apis/build/status/IpcServiceFramework?branchName=master)](https://dev.azure.com/jacques-kang/IpcServiceFramework/_build/latest?definitionId=14&branchName=master)|

# IpcServiceFramework

A .NET Core lightweight inter-process communication framework allowing invoking a service via named pipeline and/or TCP (in a similar way as WCF, which is currently unavailable for .NET Core). Secure communication over SSL is also supported.

Support using primitive or complex types in service contract.

Support multi-threading on server side with configurable number of threads (named pipeline endpoint only).

[ASP.NET Core Dependency Injection framework](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) friendly.
A .NET Core 3.1 based lightweight framework for efficient inter-process communication.
Named pipeline and TCP support out-of-the-box, extensible with other protocols.

## Usage
1. Create an interface as service contract and package it in an assembly to be shared between server and client.
2. Implement the service and host it in an console or web applciation.
3. Invoke the service with framework provided proxy client.

## Downloads

IpcServiceFramework is available via NuGet:
1. Create an interface as service contract and package it in an assembly to be referenced by server and client applications, for example:

- [JKang.IpcServiceFramework.Server](https://www.nuget.org/packages/JKang.IpcServiceFramework.Server/)
- [JKang.IpcServiceFramework.Client](https://www.nuget.org/packages/JKang.IpcServiceFramework.Client/)

## Quick Start:

### Step 1: Create service contract
```csharp
public interface IComputingService
```csharp
public interface IInterProcessService
{
float AddFloat(float x, float y);
string ReverseString(string input);
}
```
_Note: This interface is ideally to be placed in a library assembly to be shared between server and client._

### Step 2: Implement the server

1. Create a console application with the following 2 NuGet packages installed:
```

```
> Install-Package Microsoft.Extensions.DependencyInjection
> Install-Package JKang.IpcServiceFramework.Server
```

2. Add an class that implements the service contract

```csharp
class ComputingService : IComputingService
1. Implement the service in server application, for example:

```csharp
class InterProcessService : IInterProcessService
{
public float AddFloat(float x, float y)
public string ReverseString(string input)
{
return x + y;
char[] charArray = input.ToCharArray();
Array.Reverse(input.ToCharArray());
return new string(charArray);
}
}
```
```

1. Install the following NuGet packages in server application:

3. Configure and run the server
```powershell
> Install-Package Microsoft.Extensions.Hosting
> Install-Package JKang.IpcServiceFramework.Hosting.NamedPipe
```

```csharp
1. Register the service implementation and configure IPC endpoint(s):

```csharp
class Program
{
static void Main(string[] args)
public static void Main(string[] args)
{
// configure DI
IServiceCollection services = ConfigureServices(new ServiceCollection());

// build and run service host
new IpcServiceHostBuilder(services.BuildServiceProvider())
.AddNamedPipeEndpoint<IComputingService>(name: "endpoint1", pipeName: "pipeName")
.AddTcpEndpoint<IComputingService>(name: "endpoint2", ipEndpoint: IPAddress.Loopback, port: 45684)
.Build()
.Run();
CreateHostBuilder(args).Build().Run();
}

private static IServiceCollection ConfigureServices(IServiceCollection services)
{
return services
.AddIpc(builder =>
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
builder
.AddNamedPipe(options =>
{
options.ThreadCount = 2;
})
.AddService<IComputingService, ComputingService>();
services.AddScoped<IInterProcessService, InterProcessService>();
})
.ConfigureIpcHost(builder =>
{
// configure IPC endpoints
builder.AddNamedPipeEndpoint<IInterProcessService>(pipeName: "my-pipe");
})
.ConfigureLogging(builder =>
{
// optionally configure logging
builder.SetMinimumLevel(LogLevel.Information);
});
}
}
```
_Note: It's possible to host IPC service in web application, please check out the sample project *IpcServiceSample.WebServer*_

### Step 3: Invoke the service from client process
```

1. Install the following package in client application:
```bash
$ dotnet add package JKang.IpcServiceFramework.Client
```
1. Install the following NuGet package in client application:

2. Add reference to the assembly created in step 1 which contains `IComputingService` interface.
```powershell
> Install-Package JKang.IpcServiceFramework.Client.NamedPipe
```

3. Invoke the server
1. Invoke the server

```csharp
IpcServiceClient<IComputingService> client = new IpcServiceClientBuilder<IComputingService>()
.UseNamedPipe("pipeName") // or .UseTcp(IPAddress.Loopback, 45684) to invoke using TCP
.Build();
```csharp
// register IPC clients
ServiceProvider serviceProvider = new ServiceCollection()
.AddNamedPipeIpcClient<IInterProcessService>("client1", pipeName: "pipeinternal")
.BuildServiceProvider();

float result = await client.InvokeAsync(x => x.AddFloat(1.23f, 4.56f));
```
// resolve IPC client factory
IIpcClientFactory<IInterProcessService> clientFactory = serviceProvider
.GetRequiredService<IIpcClientFactory<IInterProcessService>>();

__Welcome to raise any issue or even provide any suggestion/PR to participate this project!__
// create client
IIpcClient<IInterProcessService> client = clientFactory.CreateClient("client1");

## Security
string output = await client.InvokeAsync(x => x.ReverseString(input));
```

If you are running IPC channels over TCP on an untrusted network, you should consider using SSL. IpcServiceFramework supports SSL on TCP clients and hosts.

### Generate certificates for testing

**Do not use the provided certificates in the project folder.** These are used for example purposes only.

For testing, you can generate a self-signed certificate using the following openssl command:

openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.cer -days 365

This generates a key and a certificate that can be used for testing.

### Setting up the SSL endpoint

The endpoint requires a PKCS12 file containing both the certificate and a corresponding private key.

A certificate and key can be combined to a PKCS12 file for use with the server using the following command:

openssl pkcs12 -export -in cert.cer -inkey key.pem -out server.pfx

You will be asked for a password.

You can import the certificate and provide it to the server endpoint using code similar to the following:

var certificate = new X509Certificate2(@"path\to\server.pfx", "password");
serviceHostBuilder.AddTcpEndpoint<ISomeServiceContract>("someEndpoint", ip, port, certificate);

See the ConsoleServer and WebServer projects for more complete examples.

Note: for security and maintenance reasons, we do not recommend that you hard-code the certificate password. It should instead be stored in the application configuration file so that it can be easily changed.

### Safe usage

SSL/TLS is only secure if you use it properly. Here are some tips:

* For production purposes, use a proper server certificate, signed by a real certificate authority (CA) or your organisation's internal CA. Do not use self-signed certificates in production.
* Do not use custom certificate validation callbacks on the client. They are hard to implement correctly and tend to result in security issues.
* Unconditionally returning true in a validation callback provides no security whatsoever against an attacker who can perform man-in-the-middle attacks.
* The callback used in the ConsoleServer project example is not secure. It checks for the correct certificate by hash but does not check its validity, expiry date, revocation status, or other important security properties.
## Downloads

### Client certificates
IpcServiceFramework is available via NuGet packages:

Client certificates are not currently supported.
- [JKang.IpcServiceFramework.Hosting.NamedPipe](https://www.nuget.org/packages/JKang.IpcServiceFramework.Hosting.NamedPipe/)
- [JKang.IpcServiceFramework.Client.NamedPipe](https://www.nuget.org/packages/JKang.IpcServiceFramework.Client.NamedPipe/)
- [JKang.IpcServiceFramework.Hosting.Tcp](https://www.nuget.org/packages/JKang.IpcServiceFramework.Hosting.Tcp/)
- [JKang.IpcServiceFramework.Client.Tcp](https://www.nuget.org/packages/JKang.IpcServiceFramework.Client.Tcp/)
## Stream translators
## FAQs

If you want to process the binary data after serialisation or before deserialisation, for example to add a custom handshake when the connection begins, you can do so using a stream translator. Host and client classes allow you to pass a `Func<Stream, Stream>` stream translation callback in their constructors, which can be used to "wrap" a custom stream around the network stream. This is supported on TCP communications both with and without SSL enabled. See the `XorStream` class in the IpcServiceSample.ServiceContracts project for an example of a stream translator.

Stream translators are also useful for logging packets for debugging. See the `LoggingStream` class in the IpcServiceSample.ServiceContracts project for an example of using a stream translator to log traffic.
21 changes: 21 additions & 0 deletions build/azure-pipelines-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
variables:
- template: version.yml

name: $(version)-ci-$(Date:yyyyMMdd)$(Rev:.r)

trigger:
branches:
include:
- develop

pr: none

pool:
vmImage: 'ubuntu-16.04'

steps:
- template: templates/build-test.yml
parameters:
buildConfiguration: Release

- template: templates/pack-publish.yml
19 changes: 19 additions & 0 deletions build/azure-pipelines-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
variables:
- template: version.yml

name: $(version)-pr-$(Date:yyyyMMdd)$(Rev:.r)

trigger: none

pr:
branches:
include:
- '*'

pool:
vmImage: 'ubuntu-16.04'

steps:
- template: templates/build-test.yml
parameters:
buildConfiguration: Debug
31 changes: 31 additions & 0 deletions build/azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
variables:
- template: version.yml

name: $(version)

trigger:
branches:
include:
- master

pr: none

pool:
vmImage: 'ubuntu-16.04'

steps:
- checkout: self
persistCredentials: true

- template: templates/build-test.yml
parameters:
buildConfiguration: Release

- template: templates/pack-publish.yml

- script: |
git config --global user.name "Azure DevOps"
git config --global user.email "fake@dev.azure.com"
git tag -a "v$(Build.BuildNumber)" -m "v$(Build.BuildNumber)"
git push origin "v$(Build.BuildNumber)"
displayName: Tag source
19 changes: 19 additions & 0 deletions build/templates/build-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
parameters:
- name: buildConfiguration
type: string
default: Release

steps:
- task: DotNetCoreCLI@2
displayName: Build
inputs:
command: 'build'
projects: 'src/*.sln'
arguments: '--configuration ${{parameters.buildConfiguration}}'

- task: DotNetCoreCLI@2
displayName: Test
inputs:
command: 'test'
projects: 'src/*Tests/*.csproj'
arguments: '--configuration ${{parameters.buildConfiguration}}'
18 changes: 18 additions & 0 deletions build/templates/pack-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
steps:
- task: DotNetCoreCLI@2
displayName: Pack
inputs:
command: 'pack'
packagesToPack: 'src/**/*.csproj'
configuration: Release
nobuild: true
versioningScheme: 'byEnvVar'
versionEnvVar: 'Build.BuildNumber'

- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
displayName: Publish artifacts

2 changes: 2 additions & 0 deletions build/version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
variables:
version: '3.0.0'
5 changes: 5 additions & 0 deletions doc/stream-translator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Stream translators

If you want to process the binary data after serialisation or before deserialisation, for example to add a custom handshake when the connection begins, you can do so using a stream translator. Host and client classes allow you to pass a `Func<Stream, Stream>` stream translation callback in their constructors, which can be used to "wrap" a custom stream around the network stream. This is supported on TCP communications both with and without SSL enabled. See the `XorStream` class in the IpcServiceSample.ServiceContracts project for an example of a stream translator.

Stream translators are also useful for logging packets for debugging. See the `LoggingStream` class in the IpcServiceSample.ServiceContracts project for an example of using a stream translator to log traffic.
Loading

0 comments on commit ebb2488

Please sign in to comment.