Git Product home page Git Product logo

servicewire's Introduction

.NET

ServiceWire

A Lightweight Services Library for .NET.

ServiceWire is a very fast and light weight services host and dynamic client library that simplifies the development and use of high performance remote procedure call (RPC) communication between .NET processes over Named Pipes or TCP/IP.

Find "how to use" examples in the tests code. ServiceWire documentation is available on the wiki.

Important

ServiceWire's dynamically generated proxy will NOT run as x86 on an x64 system. This ususally occurs when you use Visual Studio to create a console application with the default "prefer x86" in project properties selected. Just be sure to choose AnyCPU or the specific target (x86 or x64) so that you do not run 32bit in WOW on an x64 machine.

Get It on Nuget

Get the NuGet package here.

Using the library is easy.

  1. Code your interface

  2. Code your implementation

  3. Host the implementation

  4. Use dynamic proxy of your interface on the client side

This unique library supports:

  • TCP and NamedPipes protocols

  • ByRef (out and ref) parameters (except for non-primitive value types)

  • Dynamic client proxy generation from service interface

  • Very fast serialization of most native types and arrays of those types

  • Multiple service interface hosting on the same endpoint

  • Aspect oriented interception with pre-, post- and exception handling cross cutting

  • Hosting of single service implementation singleton on multiple endpoints and protocols

  • Protocol, serialization and execution strategy extension

Portions of this library are a derivative of RemotingLite.

History

Support for Enum by Ref 5.5.4

  1. Contributed support for proper async exceptions.

Support for Enum by Ref 5.5.3

  1. Contributed support for Enum by ref parameters.

Bug Fix for Important Edge Case 5.5.2

  1. Contributed fix to case service on a host with same interface was called previously on a different host.

Replaces BinaryFormatter with System.Text.Json 5.5.0

  1. Replaces BinaryFormatter in DefaultSerializer with System.Text.Json. Improves performance and reduces allocations in serializing small object graphs which is the most common use case in any RPC library.
  2. Fixes null value in string array bug #50.
  3. See source for former DefaultSerializer in ServiceWire.Serializers in BinaryFormatterSerializer. Use that code as a custom injected serializer if this version breaks your serialization.
  4. Using ServiceWire in an ASP.NET app no longer requires the use of the EnableUnsafeBinaryFormatterSerialization flag in your project file.

Capture serialization error bug fix in 5.4.2

  1. Single target of NetStandard 2.0 for a smaller NuGet package.
  2. Fix to a NamedPipes performance issue.
  3. Elimination of NET462 code differences.

Capture serialization error bug fix in 5.4.1

  1. In .NET 5+, the BinaryFormatter is marked obsolete and prohibited in ASP.NET apps.
  2. This bug caused an end of stream error rather than capturing it properly. This version fixes that bug and exposes the limitation introduced in .NET 5+ on ASP.NET apps.
  3. Using ServiceWire in an ASP.NET app is still possible but requires the use of the EnableUnsafeBinaryFormatterSerialization flag in your project file. Use this carefully and be sure you understand the risks.

ICompression added for injecting compression strategy in 5.4.0

  1. Added ICompression for injecting custom compression into usage.
  2. Added .NET 5.0 as target back in.

AssemblyQualified names from user defined types in 5.3.6

  1. Fix for AssemblyQualified names from user defined types.

Multiple Framework Targets and void Return Types 5.3.5

  1. Updated all projects to target .net462, .net48, netcoreapp3.1, and net6.0 only.
  2. Corrected multiple targets for multiple OS in projects for those using Linux.
  3. Updated NuGet package version.

BugFix + Test cases + 48

  1. Throwing the original error through an Intercept would fail for interface methods that have a void return type
  2. Updated framework references from .net462 to .net48

.NET Framework to .NET Core and Serializer Bug Fixes 5.3.4

  1. Support for .NET Framework to .NET Core core parameter types to eliminate exceptions when a Framework client is talking to a Core host or vice versa.
  2. Serializer injection bug fixed.

.NET 4.62 added back in version 5.3.3

  1. Added .NET Framework 4.62 build in package to prevent permissions issue in named pipes.
  2. Fixed custom serializer issue.
  3. .NET Standard 2.0 and 2.1 builds remain.
  4. Resolved parallel Zk test issues.

Note: Use of async/await and Task not recommended. Use of Task return type not supported. While the syntax of Task return type is supported, apparently it is not marked as Serializable. In fact async/await is not really supported. Under the covers the task type is stripped away over the wire and the method is executed on a worker thread on the server synchronously. If you think about it, you will understand that it's two separate processes, so the Task Parallel Library is not going to be able to manage the thread context across the processes. RPC is inherently synchronous but the handling of each request on the host is done on thread pools.

.NET Standard 2.0 and 2.1 in version 5.3.2

  1. Changed library build to only .NET Standard 2.0 and 2.1.
  2. This breaks users of named pipes in .NET 4.6.2 -- DO NOT UPGRADE until we resolve that issue.

Bug Fixes in version 5.3.1

  1. Fixed bug related to complex type serialization that occurred when using output parameters.

BREAKING CHANGES in version 5.3.0

  1. Injectable serialization (see project library tests for examples).

  2. Removes dependency on Newtonsoft.Json and uses BinaryFormatter for default serialization which means wire data classes must be marked [Serializable].

  3. Internal classes are attributed to support protobuf-net serialization as well.

Changes in version 5.2.0

  1. Adds support for return types of Task and Task to support async / await across the wire.

Changes including some breaking changes in version 5.1.0

  1. Dropped strong named assembly.

  2. Support for NetCoreApp 2.0, 2.2 and .NET Framework 4.62. Dropped support for .NET 3.5.

  3. Modified projects and NuGet package generation from Visual Studio 2017.

  4. Dropped separate projects used to build different targets.

  5. Converted test projects to XUnit with multiple targets to allow "dotnet test" run of all targets.

Breaking Changes in version 4.0.1

  1. Switched ServiceWire (and ServiceMq) to Newtonsoft.Json for serialization. Eliminates use of BinaryFormatter and its required Serializable attribute. Also eliminates ServiceStack.Text 3 dependency which has problems serializing structs.

  2. Relaxed assembly version matching to allow additive changes without breaking the client or requiring an immediate client update.

  3. Strong name added to allow the library to be used by strong named applications and libraries.

  4. Added .NET 3.5 support to allow legacy applications to use the library. This adds a Framework specific dependency on TaskParallelLibrary 1.0.2856.0.

  5. For the .NET 4.0 and 3.5 versions, changed to "Client Profile" for the target framework.

  6. Removed dependency on System.Numerics in order to support .NET 3.5 and introduced ZkBigInt class taken from Scott Garland's BigInteger class. See license text for full attribution.

ConnBenchmarks (6/6/2022)

No real change from previous benchmarks. Making a connection is still expensive. About 15ms.

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
Intel Core i7-10750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=6.0.300
  [Host]     : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
  Job-OBEYHZ : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
  Job-REVQDN : .NET Framework 4.8 (4.8.4510.0), X64 RyuJIT

InvocationCount=64  MaxIterationCount=16  MinIterationCount=4
UnrollFactor=1

|  Method |        Job |            Runtime |        Mean |     Error |    StdDev | Ratio | RatioSD |   Gen 0 | Allocated |
|-------- |----------- |------------------- |------------:|----------:|----------:|------:|--------:|--------:|----------:|
| TcpConn | Job-OBEYHZ |           .NET 6.0 | 15,225.3 us | 314.91 us | 294.56 us |  1.00 |    0.00 |       - |     52 KB |
| TcpConn | Job-REVQDN | .NET Framework 4.8 |    736.5 us |  62.61 us |  55.50 us |  0.05 |    0.00 | 15.6250 |     96 KB |
|         |            |                    |             |           |           |       |         |         |           |
|  NpConn | Job-OBEYHZ |           .NET 6.0 |    265.1 us |   8.23 us |   8.08 us |  1.00 |    0.00 |       - |     63 KB |
|  NpConn | Job-REVQDN | .NET Framework 4.8 |    307.5 us |  16.52 us |  16.23 us |  1.16 |    0.07 | 15.6250 |    107 KB |

AllBenchmarks (6/6/2022)

These benchmarks so the improvements in switching to System.Text.Json in the CxOut tests. Faster and fewer allocations that previous benchmarks. Performance improvement is 17% on average on those specific benchmarks.

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.22000
Intel Core i7-10750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=6.0.300
  [Host]     : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
  Job-NJJOJB : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
  Job-VIKKWS : .NET Framework 4.8 (4.8.4510.0), X64 RyuJIT

InvocationCount=1024  MaxIterationCount=64  MinIterationCount=8
UnrollFactor=1

|       Method |        Job |            Runtime |      Mean |    Error |   StdDev | Ratio | RatioSD |  Gen 0 | Allocated |
|------------- |----------- |------------------- |----------:|---------:|---------:|------:|--------:|-------:|----------:|
|       TcpSim | Job-NJJOJB |           .NET 6.0 |  32.93 us | 0.626 us | 0.696 us |  1.00 |    0.00 |      - |     569 B |
|       TcpSim | Job-VIKKWS | .NET Framework 4.8 |  34.36 us | 0.661 us | 0.904 us |  1.04 |    0.04 |      - |     776 B |
|              |            |                    |           |          |          |       |         |        |           |
|   TcpSimJson | Job-NJJOJB |           .NET 6.0 |  31.79 us | 0.635 us | 0.680 us |  1.00 |    0.00 |      - |     569 B |
|   TcpSimJson | Job-VIKKWS | .NET Framework 4.8 |  32.46 us | 0.641 us | 0.536 us |  1.02 |    0.03 |      - |     784 B |
|              |            |                    |           |          |          |       |         |        |           |
|        TcpRg | Job-NJJOJB |           .NET 6.0 |  88.75 us | 1.625 us | 1.269 us |  1.00 |    0.00 | 1.9531 |  15,298 B |
|        TcpRg | Job-VIKKWS | .NET Framework 4.8 | 123.68 us | 2.293 us | 1.199 us |  1.39 |    0.03 | 3.9063 |  24,682 B |
|              |            |                    |           |          |          |       |         |        |           |
|    TcpRgJson | Job-NJJOJB |           .NET 6.0 |  90.42 us | 1.683 us | 1.217 us |  1.00 |    0.00 | 1.9531 |  15,298 B |
|    TcpRgJson | Job-VIKKWS | .NET Framework 4.8 | 138.37 us | 3.860 us | 8.791 us |  1.50 |    0.13 | 3.9063 |  24,671 B |
|              |            |                    |           |          |          |       |         |        |           |
|     TcpCxOut | Job-NJJOJB |           .NET 6.0 |  68.30 us | 1.305 us | 1.019 us |  1.00 |    0.00 | 0.9766 |   6,810 B |
|     TcpCxOut | Job-VIKKWS | .NET Framework 4.8 |  92.20 us | 2.251 us | 5.081 us |  1.28 |    0.04 | 1.9531 |  13,910 B |
|              |            |                    |           |          |          |       |         |        |           |
| TcpCxOutJson | Job-NJJOJB |           .NET 6.0 |  69.14 us | 1.319 us | 1.234 us |  1.00 |    0.00 | 0.9766 |   6,810 B |
| TcpCxOutJson | Job-VIKKWS | .NET Framework 4.8 |  86.90 us | 1.424 us | 1.949 us |  1.27 |    0.04 | 1.9531 |  13,908 B |
|              |            |                    |           |          |          |       |         |        |           |
|        NpSim | Job-NJJOJB |           .NET 6.0 |  23.71 us | 0.469 us | 0.716 us |  1.00 |    0.00 |      - |     569 B |
|        NpSim | Job-VIKKWS | .NET Framework 4.8 |  25.19 us | 0.485 us | 0.519 us |  1.06 |    0.04 |      - |     936 B |
|              |            |                    |           |          |          |       |         |        |           |
|    NpSimJson | Job-NJJOJB |           .NET 6.0 |  24.02 us | 0.477 us | 0.783 us |  1.00 |    0.00 |      - |     569 B |
|    NpSimJson | Job-VIKKWS | .NET Framework 4.8 |  27.08 us | 0.540 us | 0.887 us |  1.13 |    0.05 |      - |     936 B |
|              |            |                    |           |          |          |       |         |        |           |
|         NpRg | Job-NJJOJB |           .NET 6.0 |  76.97 us | 1.453 us | 0.961 us |  1.00 |    0.00 | 1.9531 |  15,298 B |
|         NpRg | Job-VIKKWS | .NET Framework 4.8 | 107.98 us | 2.029 us | 1.342 us |  1.40 |    0.03 | 3.9063 |  24,698 B |
|              |            |                    |           |          |          |       |         |        |           |
|     NpRgJson | Job-NJJOJB |           .NET 6.0 |  86.54 us | 1.679 us | 0.999 us |  1.00 |    0.00 | 3.9063 |  27,139 B |
|     NpRgJson | Job-VIKKWS | .NET Framework 4.8 | 116.80 us | 2.208 us | 4.846 us |  1.35 |    0.06 | 4.8828 |  36,338 B |
|              |            |                    |           |          |          |       |         |        |           |
|      NpCxOut | Job-NJJOJB |           .NET 6.0 |  60.93 us | 1.180 us | 1.312 us |  1.00 |    0.00 | 0.9766 |   6,810 B |
|      NpCxOut | Job-VIKKWS | .NET Framework 4.8 |  82.04 us | 1.506 us | 2.715 us |  1.36 |    0.05 | 1.9531 |  14,211 B |
|              |            |                    |           |          |          |       |         |        |           |
|  NpCxOutJson | Job-NJJOJB |           .NET 6.0 |  66.24 us | 1.223 us | 0.955 us |  1.00 |    0.00 | 0.9766 |  10,858 B |
|  NpCxOutJson | Job-VIKKWS | .NET Framework 4.8 |  82.45 us | 1.641 us | 2.133 us |  1.27 |    0.04 | 2.9297 |  18,729 B |

servicewire's People

Contributors

berk-csi avatar dependabot[bot] avatar gregmulvihill avatar ivotops avatar jbrookssmokeball avatar sergiibratus avatar tylerje avatar vbondaryuk avatar xen2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

servicewire's Issues

Closing a named pipe results in an error message

To reproduce, add the following lines to the Program class in DemoHost (just a place to quickly add this in the current codebase)

var myLogger = new Logger(logLevel: LogLevel.Debug, logDirectory: "C:/", messageBufferSize: 0);
const string pipeName = "myPipe";
var host = new NpHost(pipeName, myLogger);
host.AddService<IIPCBridge>(bridge);
host.Open();
host.Close();

The logfile will show the following error lines:

2023-09-27T15:22:10.003	Error	Error in ProcessRequest: System.IO.EndOfStreamException: Unable to read beyond the end of the stream.::   at System.IO.BinaryReader.InternalRead(Int32 numBytes)::   at System.IO.BinaryReader.ReadInt32()::   at ServiceWire.Host.ProcessRequest(Stream readStream, Stream writeStream) in *\src\ServiceWire\Host.cs:line 277
2023-09-27T15:22:10.048	Error	ProcessClientThread error: System.IO.IOException: Pipe is broken.::   at System.IO.Pipes.PipeStream.CheckWriteOperations()::   at System.IO.Pipes.PipeStream.Flush()::   at System.IO.BufferedStream.Flush()::   at System.IO.BufferedStream.Dispose(Boolean disposing)::   at System.IO.Stream.Close()::   at System.IO.BinaryReader.Dispose(Boolean disposing)::   at System.IO.BinaryReader.Close()::   at ServiceWire.Host.ProcessRequest(Stream readStream, Stream writeStream) in *\src\ServiceWire\Host.cs:line 317::   at ServiceWire.Host.ProcessRequest(Stream stream) in *\src\ServiceWire\Host.cs:line 252::   at ServiceWire.NamedPipes.NpHost.ClientConnectionMade(Object sender, PipeClientConnectionEventArgs args) in *\src\ServiceWire\NamedPipes\NpHost.cs:line 69::   at ServiceWire.NamedPipes.NpListener.ProcessClientThread(NamedPipeServerStream pipeStream) in *\src\ServiceWire\NamedPipes\NpListener.cs:line 85

When stopping the NpListener it makes a client.Connect call. See NpListener.cs, line 47

//make fake connection to terminate the waiting stream
try
{
         using (var client = new NamedPipeClientStream(PipeName))
         {
              client.Connect(50);
         }
}

Which in turn raises the ClientConnectionMade event in NpHost, which then tries to do

var stream = new BufferedStream(args.PipeStream);
base.ProcessRequest(stream);

On a pipe that is already closing (or closed already).
So far my quick investigation of the issue.
Not really critical, but closing should be smooth process without error messages in the log file I assume.

ToType does not resolve DataTable

Hi,
I try to use ServiceWire with a DataTable in full framework 4.8.

ServiceWire.NetExtensions.ToConfigName(typeof(System.Data.DataTable)) return "System.Data.DataTable, System.Data", which seems correct.
But from this string, ServiceWire.NetExtensions.ToType return null.

Is it possible to add a custom type resolver ?
Or any other solution ?

Thansk
Eric
Screenshot 2023-05-16 161921

Named Pipe performance drop going from 5.3.4 to 5.3.5

I noticed a significant performance drop in named pipes in ServiceWire 5.3.5 and up. ServiceWire 5.3.4 is nearly 3X faster compared to 5.3.5 on the attached MRE.

To test, just run the tester console application referencing ServiceWire 5.3.4 twice, one in 'server' mode and one in 'client' mode. It'll time 5000 calls to a simple interface and report the average time over 5 runs. Repeat it again with the tester referencing ServiceWire 5.3.5.

image

TestIPC.zip

Calls to the proxy in a WinUI application using NamedPipe client & BinaryFormatterSerializer fail.

I am trying to use ServiceWire (NamedPipe & BinaryFormatterSerializer) with a WinUI based desktop application targeting .NET 6. I can successfully start the service, but any calls to the proxy made from the WinUI app is failing in SyncInterface method:

image

Calls to the proxy work if I don't use BinaryFormatterSerializer, or if I change the application to use WinForms rather than WinUI as the UI framework.

Attached reproducer solution has the latest ServiceWire projects along with two clients: one WinUI based and the other WinForms based. They share the code referencing ServiceWire (based on the published named pipes example) via a shared C# project. When using the default serializer, both applications can use ServiceWire without any errors. When using BinaryFormatterSerializer, only the WinForms application works.

Any help with resolving this issue is deeply appreciated!

Berk

ServiceWire.WinUI.zip

Support for nested types and deep APIs?

I am considering moving some code to .NET 5/6 which means I can no longer use .NET Remoting. My application is a desktop C# app with a deep object oriented API with calls like:

var myApp = new App();
myApp.OpenFile("filename");
myApp.IntProperty = 5;
myApp.SubObject.StringProperty = "string";
IChild childObj = myApp.AddChild();
childObj.Name = "new child";

Working through the examples, I get an end of stream error when attempting to chain calls together. This worked in .NET Remoting. Is it possible to implement this syntax with ServiceWire?

Can I use this repo to intercept RPC calls?

Hello:
I found this repo, I want to know if I can use it to intercept some RPC calls. One example use case is that for some custom wallet, which uses RPC to get blanance from a blockchain RPC server. But it is not easy to find the RPC server IP address, or URL.
I can find the localhost port number used by wallet, which is a browser extension, like MetaMask but for BTC like tokens.
If it is possible, give me an idea on how to proceed, what information is necessary, I can get localhost PORT, may be user name & password, but no other information, I want to use this repo to find other information like: RPC server IP, port number, etc.
Thanks,

Any way for Bidirectional communication?

I'm trying to upgrade a WCF application to use ServiceWire as a replacement. I have multiple uses of WCF DuplexClientBase, which allows the host to use a callback object.

Is there anything in ServiceWire to mimic this functionality?
Thanks!

Named Pipe in a Excel DNA project blows with NotSupportedException

System.NotSupportedException: A non-collectible assembly may not reference a collectible assembly.
at System.Reflection.Emit.ModuleBuilder.GetTypeRef(QCallModule module, String strFullName, QCallModule refedModule, String strRefedModuleFileName, Int32 tkResolution)
at System.Reflection.Emit.ModuleBuilder.GetTypeRefNested(Type type, Module refedModule, String strRefedModuleFileName)
at System.Reflection.Emit.ModuleBuilder.GetTypeTokenWorkerNoLock(Type type, Boolean getGenericDefinition)
at System.Reflection.Emit.ModuleBuilder.GetTypeTokenInternal(Type type, Boolean getGenericDefinition)
at System.Reflection.Emit.TypeBuilder..ctor(String fullname, TypeAttributes attr, Type parent, Type[] interfaces, ModuleBuilder module, PackingSize iPackingSize, Int32 iTypeSize, TypeBuilder enclosingType)
at System.Reflection.Emit.ModuleBuilder.DefineType(String name, TypeAttributes attr, Type parent)
at ServiceWire.ProxyFactory.CreateProxyBuilder(String proxyName, Type interfaceType, Type channelType, Type ctorArgType)
at ServiceWire.ProxyFactory.<>c__DisplayClass5_01.<CreateProxy>b__0() at ServiceWire.PooledDictionary2.Request(TKey key, Func1 creator) at ServiceWire.ProxyFactory.CreateProxy[TInterface](Type channelType, Type ctorArgType, Object channelCtorValue, ISerializer serializer, ICompressor compressor) at ServiceWire.NamedPipes.NpProxy.CreateProxy[TInterface](NpEndPoint npAddress, ISerializer serializer, ICompressor compressor) at ServiceWire.NamedPipes.NpClient1..ctor(NpEndPoint npAddress, ISerializer serializer, ICompressor compressor)
at DnaClassLibrary.SpinFunctions.GetObject(String typeId, String objectId) in ExcelDNA\DnaClassLibrary\DnaClassLibrary\Class1.cs:line 38
[ExcelFunction(Description = "My first .NET function")]
    public static string GetObject(string typeId, string objectId)
    {
        try
        {
            Debug.WriteLine("DNA - GetObject starting");

            using (client = new NpClient<IMyProxyService>(new NpEndPoint(MyObjectProxy.PipeName)))

it blows on new NpClient..

This is .Net 6 project (because Excel DNA only supports up up to v 6).

support IEnumerable<string> namedPipe

It seems that if I use in the interface IEnumerable for named pipe I get an error: cannot match method to its server equivalent.

Ienumerable for non primitive types seems to work fine.

User password hash authentication failed

1.serviceWire verson :4.0.1
2..net framework 4.0
3. exception info
=======================2019/6/13 11:58:31=======================
System.Reflection.TargetInvocationException: 调用的目标发生了异常。 ---> System.IO.EndOfStreamException: 无法在流的结尾之外进行读取。
在 System.IO.BinaryReader.FillBuffer(Int32 numBytes)
在 System.IO.BinaryReader.ReadInt32()
在 ServiceWire.StreamingChannel.SyncInterface(Type serviceType, String username, String password) 位置 d:\Code\GitHub\ServiceWire\src\ServiceWire\StreamingChannel.cs:行号 104
在 ServiceWire.TcpIp.TcpChannel.Initialize(String username, String password, Type serviceType, IPEndPoint endpoint, Int32 connectTimeoutMs) 位置 d:\Code\GitHub\ServiceWire\src\ServiceWire\TcpIp\TcpChannel.cs:行号 108
在 ServiceWire.TcpIp.TcpChannel..ctor(Type serviceType, TcpZkEndPoint endpoint) 位置 d:\Code\GitHub\ServiceWire\src\ServiceWire\TcpIp\TcpChannel.cs:行号 38
在 IWebRpcModelProxy..ctor(Type , TcpZkEndPoint )
--- 内部异常堆栈跟踪的结尾 ---
在 System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
在 System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
在 ServiceWire.ProxyFactory.CreateProxy[TInterface](ProxyBuilder proxyBuilder, Object channelCtorValue) 位置 d:\Code\GitHub\ServiceWire\src\ServiceWire\ProxyFactory.cs:行号 53
在 ServiceWire.ProxyFactory.CreateProxy[TInterface](Type channelType, Type ctorArgType, Object channelCtorValue) 位置 d:\Code\GitHub\ServiceWire\src\ServiceWire\ProxyFactory.cs:行号 35
在 ServiceWire.TcpIp.TcpProxy.CreateProxy[TInterface](TcpZkEndPoint endpoint) 位置 d:\Code\GitHub\ServiceWire\src\ServiceWire\TcpIp\TcpProxy.cs:行号 9
在 ServiceWire.TcpIp.TcpClient`1..ctor(TcpZkEndPoint endpoint) 位置 d:\Code\GitHub\ServiceWire\src\ServiceWire\TcpIp\TcpClient.cs:行号 19
在 IOTMP.Operator.Client.SoketRpc.Client.WebClient..ctor(String ip, Int32 port, IntPtr webHwnd) 位置 F:\HaoYunProject(11-1-1)MonitorClient - 备份(11-1-1)MonitorClient\Main\IOTMP.Operator.Client\IOTMP.Operator.Client.SoketRpc\Client\WebClient.cs:行号 24
在 IOTMP.Operator.Client.WebBrowser.MainWindow.<.ctor>b__3_0(Object , RoutedEventArgs ) 位置 F:\HaoYunProject(11-1-1)MonitorClient - 备份(11-1-1)MonitorClient\Main\IOTMP.Operator.Client\IOTMP.Operator.Client.WebBrowser\MainWindow.xaml.cs:行号 55
在 System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
在 System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
在 System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
在 System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
在 System.Windows.BroadcastEventHelper.BroadcastEvent(DependencyObject root, RoutedEvent routedEvent)
在 System.Windows.BroadcastEventHelper.BroadcastLoadedEvent(Object root)
在 MS.Internal.LoadedOrUnloadedOperation.DoWork()
在 System.Windows.Media.MediaContext.FireLoadedPendingCallbacks()
在 System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
在 System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
在 System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
在 System.Windows.Media.MediaContext.Resize(ICompositionTarget resizedCompositionTarget)
在 System.Windows.Interop.HwndTarget.OnResize()
在 System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
在 System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
在 MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
在 MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
在 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

InvokeMethod: Cannot match method due to string being in different corelib

I have one process in .NET FW and one in .NET Core.
I get an Exception in InvokeMethod due to type not matching:
System.String, mscorlib on one side and System.String, System.Private.CoreLib on the other side.

One possible fix is to alter ToConfigName to not append assembly name if it belongs to corelib (i.e. t.Assembly == typeof(String).Assembly).
Should I submit such a PR, or do you think another approach is better?

not strongly named

Could not load file or assembly 'ServiceWire, Version=5.3.4.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. A strongly-named assembly is required. (Exception from HRESULT: 0x80131044)

after giving it a strong name I get this exception:

Severity Code Description Project File Line Suppression State
Error Error Starting Transformation: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.Serialization.SerializationException: Unable to find assembly 'ServiceWire, Version=5.3.0.0, Culture=neutral, PublicKeyToken=04ff4e57e61e2a6f'.
at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at ServiceWire.DefaultSerializer.Deserialize[T](Byte[] bytes)
at ServiceWire.StreamingChannel.SyncInterface(Type serviceType, String username, String password)
at ServiceWire.NamedPipes.NpChannel..ctor(Type serviceType, NpEndPoint npEndPoint, ISerializer serializer)
at ITransformationRunFactoryServiceProxy..ctor(Type , NpEndPoint , ISerializer )
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)
at ServiceWire.ProxyFactory.CreateProxy[TInterface](ProxyBuilder proxyBuilder, Object channelCtorValue, ISerializer serializer)
at ServiceWire.ProxyFactory.CreateProxy[TInterface](Type channelType, Type ctorArgType, Object channelCtorValue, ISerializer serializer)
at ServiceWire.NamedPipes.NpProxy.CreateProxy[TInterface](NpEndPoint npAddress, ISerializer serializer)
at ServiceWire.NamedPipes.NpClient1..ctor(NpEndPoint npAddress, ISerializer serializer) at SubSonic.Core.VisualStudio.Services.SubSonicTemplatingService.<GetTransformationRunFactoryAsync>d__104.MoveNext() in D:\Source\home\SubSonic.Core.VisualStudio\Services\SubSonicTemplatingService\TextTemplating.cs:line 480 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
at SubSonic.Core.VisualStudio.Services.SubSonicTemplatingService.d__92.MoveNext() in D:\Source\home\SubSonic.Core.VisualStudio\Services\SubSonicTemplatingService\TextTemplating.cs:line 95 TemplateIntegrationTest D:\Source\home\Integration\TemplateIntegrationTest\DAL\DataContext.stt 0

public T Deserialize<T>(byte[] bytes)
        {
            if (null == bytes || bytes.Length == 0) return default(T);
            using (var ms = new MemoryStream(bytes))
            {
                return (T)_formatter.Deserialize(ms); <--- this is when the above exception is thrown
            }
        }

Passing null string in an array of string in service method parameter throws ArgumentNullException

If a service method parameter is an array of string, then passing in a null value causes an ArgumentNullException to be thrown.

Service method:

public interface ITestService
{
    void PassArrayOfString(string[] passedObject);
}

Calling the proxy:

testServiceProxy.PassArrayOfString(new[] { "abc", "def", null });

Throws an ArgumentNullException:

Message: 
  System.ArgumentNullException : Value cannot be null. (Parameter 'value')

Stack Trace: 
  BinaryWriter.Write(String value)
  ParameterTransferHelper.SendParameters(Boolean useCompression, Int32 compressionThreshold, BinaryWriter writer, Object[] parameters)
  StreamingChannel.InvokeMethod(String metaData, Object[] parameters)
  ITestServiceProxy.PassArrayOfString(String[] )
  TestServiceProxy.PassArrayOfString(String[] passedObject) line 78

If the parameter is a List<string> then null string values in the list serialize okay. It only fails when it's a string[] or params string[].

If a RPC service returns an instantiated interface should methods on interface execute on the object created by the service.

I have a transformation run factory service that creates a run factory instance on the named pipe server. the return type of this method is an interface. When the run factory creates a transformation runner, its currently running the framework code in generating a runner on the client side. It should be creating the runner using the netcoreapp code on the server to create the runner. The execution of the runner must happen in the process for the named pipe service.

Is it possible for service wire to generate proxy for each method return type exposed by the service interface? I realize non interface types would be impossible to proxy if said method could not be overridden.

I realize the service interface will need functionality to dispatch the requests made against the objects created by the service, pretty sure service wire lacks that part.

Is my thinking flawed or is this a reasonable expectation on how a RPC service should work?

I have been thinking about this for two hours and this may not be a feature that service wire itself needs to implement. but the infrastructure to do this could sit on top of the named pipe and the service would expose the infrastructure to do this.

Fails to re-throw exceptions for async methods

Hi,

I try to invoke an async method through named pipe channel it is working fine unless my app logic throws an exception! When my app logic throws an exception, I am getting something like the following,

Object of type 'Tests.PipeException' cannot be converted to type 'System.Double'.
   at System.RuntimeType.CheckValue(Object& value, ParameterCopyBackAction& copyBack, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
   at System.Reflection.MethodBase.CheckArguments(Span`1 copyOfParameters, IntPtr* byrefParameters, Span`1 shouldCopyBack, ReadOnlySpan`1 parameters, RuntimeType[] sigTypes, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at ServiceWire.StreamingChannel.InvokeMethod(String metaData, Object[] parameters)
   at ISumProxy.Divide(Double, Int32)
   at Tests.NamedPipeTests.<>c__DisplayClass1_0.<<Divide_ShouldThrow_Exception>b__0>d.MoveNext()

The issue seems to be in this line https://github.com/tylerjensen/ServiceWire/blob/master/src/ServiceWire/StreamingChannel.cs#L268 where it sets the outparam to Task.CompeltedTask and the next if conditions try to throw the exception from outparam. Perhaps we should assign the task value only if it is not faulted?

Am I doing something incorrect? Is there a better way to do this?

Below is a reproducible test scenario

using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using ServiceWire;
using ServiceWire.NamedPipes;

namespace Tests;

public class NamedPipeTests
{
    private NpHost _namedPipeHost;

    [Fact]
    public async Task Divide_ShouldThrow_Exception()
    {
        Task.Factory.StartNew(StartPipeListener, TaskCreationOptions.LongRunning);

        await Task.Delay(2000);

        var npClient = new NpClient<ISum>(new NpEndPoint("8642D0EA-13B4-408F-8DBB-BB8CDEAAA0EC"), new CustomPipeSerializer());

        var exception = await Assert.ThrowsAsync<PipeException>(async () =>
        {
            await npClient.Proxy.Divide(4.0, 0).ConfigureAwait(false);
        }).ConfigureAwait(false);

        Assert.IsType<PipeException>(exception);
    }

    async Task StartPipeListener()
    {
        _namedPipeHost = new NpHost("8642D0EA-13B4-408F-8DBB-BB8CDEAAA0EC", null, null, new CustomPipeSerializer());
        _namedPipeHost.UseCompression = true;
        _namedPipeHost.AddService<ISum>(new Sum());
        _namedPipeHost.Open();
    }

}

public interface ISum
{
    Task<double> Divide(double a, int b);
}

public class Sum : ISum
{
    public Task<double> Divide(double a, int b)
    {
        if (b == 0)
            throw new PipeException("Trying to divide by zero.");

        return Task.FromResult(a / b);
    }
}

internal class PipeException : ApplicationException
{
    public PipeException(string? message = null)
        :base(message)
    {
    }
}

internal class CustomPipeSerializer : ISerializer
{
    private readonly JsonSerializerOptions _customOptions;

    public CustomPipeSerializer()
    {
        _customOptions = new JsonSerializerOptions()
        {
            Converters = { new PipeExceptionJsonConverter(), new JsonStringEnumConverter() },
        };
    }

    public byte[]? Serialize<T>(T obj) => obj == null ? null : JsonSerializer.SerializeToUtf8Bytes<T>(obj);

    public byte[]? Serialize(object? obj, string typeConfigName) =>
        obj == null ? null : JsonSerializer.SerializeToUtf8Bytes(obj, typeConfigName.ToType(), _customOptions);

    public T? Deserialize<T>(byte[]? bytes) => bytes == null || bytes.Length == 0
        ? default(T)
        : JsonSerializer.Deserialize<T>((ReadOnlySpan<byte>)bytes, _customOptions);

    public object? Deserialize(byte[]? bytes, string? typeConfigName)
    {
        Type t = typeConfigName != null ? typeConfigName.ToType() : throw new ArgumentNullException(nameof(typeConfigName));
        return  bytes == null || bytes.Length == 0
            ? t.GetDefault()
            : JsonSerializer.Deserialize((ReadOnlySpan<byte>)bytes, t, _customOptions);
    }
}

internal class PipeExceptionJsonConverter : JsonConverter<PipeException>
{
    public override PipeException? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
        {
            throw new JsonException();
        }

        string message = "Message Not Available.";

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
            {
                break;
            }

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                var propertyName = reader.GetString();
                reader.Read();

                switch (propertyName)
                {
                    case "Message":
                        var messageRead = reader.GetString();
                        if( messageRead != null) message = messageRead;
                        break;
                }
            }
        }

        return new PipeException(message);
    }

    public override void Write(Utf8JsonWriter writer, PipeException value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        writer.WriteString( "Message", value.Message);
        writer.WriteEndObject();
    }
}

Is it possible to use this library in a two-way fashion?

The implementation suggests that the pipe is duplex, but the documentation suggests that the API is one-way. Is it possible for two clients to talk to each other (without resorting to something like polling) or would it require a second pipe?

Unable to use type System.Collections.Generic.List in F#

I have attempted to follow the Named Pipes sample code with translation into F#.

in the sample code the interface is:

 public interface IMyTester
 {
    Guid GetId(string source, double weight, int quantity);
    TestResponse Get(Guid id, string label, double weight, out int quantity);
    List<string> GetItems(Guid id, int[] vals);
 }

Which translates to

type IMyTester = 
    abstract member GetId: source:string * weight:double * quantity:int -> Guid
    abstract member Get: id:Guid * label:string * weight:double * quantity: int outref -> TestResponse
    abstract member GetItems: id:Guid * vals:int array -> ResizeArray<string>

When used like this with a .Net 6 host and a .Net Framework 4.8 client I get the following exception:

System.ArgumentNullException: 'Value cannot be null.Parameter name: conversionType'

   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at ServiceWire.DefaultSerializer.Deserialize(Byte[] bytes, String typeConfigName)
   at ServiceWire.ParameterTransferHelper.ReceiveParameters(BinaryReader reader)
   at ServiceWire.StreamingChannel.InvokeMethod(String metaData, Object[] parameters)
   at IMyTesterProxy.GetItems(Guid , Int32[] )
   at [email protected](NpClient`1 client) in C:\Projects\ServiceWireTesting\ServiceWireTesting\ConsoleAppFramework\FramewrkProgram.fs:line 15
   at Microsoft.FSharp.Core.Operators.Using[T,TResult](T resource, FSharpFunc`2 action) in D:\a\_work\1\s\src\fsharp\FSharp.Core\prim-types.fs:line 4806
   at FramewrkProgram.main(String[] argv) in C:\Projects\ServiceWireTesting\ServiceWireTesting\ConsoleAppFramework\FramewrkProgram.fs:line 9

I found the culprit is ResizeArray<string>.
Array<string> works. System.Collections.Generic.List<string> also fails with the same exception.

I am using ServiceWire 5.3.4 from NuGet on both libraries.

Manage exception in defaultserializer (Json)

Hi,
Exception are not managed by system.text.JSON serializer.
So if exception is thrown on client side, exception is lost.
Maybe we should add an exceptionConverter class that implement JsonConvertor to manage exception.

Avoid dynamic code generation by providing a custom Proxy implementation

This idea stems from me using ServiceWire in .Net 5 with CoreRT compiler, attempting to do ahead-of-time compilation to an unmanaged library.

CoreRT currently does not allow dynamic code generation:

Unhandled Exception: System.PlatformNotSupportedException: Dynamic code generation is not supported on this platform.
   at LightspaceCompositorServiceClientNative!<BaseAddress>+0x15e5f5
   at ServiceWire.ProxyFactory.CreateProxyBuilder(String, Type, Type, Type) + 0x3b
   at ServiceWire.PooledDictionary`2.Request(TKey, Func`1) + 0xce
   at ServiceWire.ProxyFactory.CreateProxy[TInterface](Type, Type, Object, ISerializer) + 0x10d
   at ServiceWire.NamedPipes.NpProxy.CreateProxy[TInterface](NpEndPoint, ISerializer) + 0x47
   at LightspaceCompositorServiceClientNative!<BaseAddress>+0x1823a7

As such, I am looking to implement a mechanism to avoid calls to CreateProxy, and instead provide an existing Proxy implementation.

A couple questions:

  1. If I succeed, would you be interested in a pull request on the feature?
  2. Any tips on what to consider while implementing this - any underwater stones I might hit, and not see right now?

Async requests?

Hi,

Sorry that I'm writing this question here but this library has support for async/await usage? I mean if I can create contract with Task<> methods and it will be really async or not?

Thank you.

TcpHost accepting new client synchronously when AcceptAsync returns false

Hi there,

I was taking a look at the code for TcpHost.cs and noticed that inside of the loop in Listen() if _listener.AcceptAsync(_acceptEventArg) returns false it will call AcceptNewClient(_acceptEventArg) synchronously which means that until this client disconnects the listener will not be connecting to any new clients.

On https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.acceptasync it says this about AcceptAsync(SocketAsyncEventArgs) returning false:

false if the I/O operation completed synchronously. The Completed event on the e parameter will not be raised and the e object passed as a parameter may be examined immediately after the method call returns to retrieve the result of the operation.

I'm not exactly sure how to trigger this condition but it seems like it would be easy to fix if AcceptNewClient(_acceptEventArg) was run on a separate thread if this condition were met, allowing other clients through once this client is accepted.

Unable to find assembly in client via named pipes?

Hello, we've been trying to replace our custom named pipe implementation with ServiceWire but have been getting issues where we get errors such as:

System.Runtime.Serialization.SerializationException: 'Unable to find assembly 'ServiceWireServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.'

That was actually taken from a direct copy/paste of the sample code in the wiki for named pipes. We were getting the same issue with our actual project.

Are we doing something wrong? I'd really like to use this library as it cleans up the code so nicely. Thanks!

Does ServiceWire support events?

I really like the ServiceWire API, and would love to use it. The only thing I'm not sure if it fully supports, is something like Events. Something a client can subscribe to receive notifications from the server. Is this supported, or would I have to create 2 pipes to do this?

Permissions issue in 5.3.2

Hello,

We've been using ServiceWire with no issue for some time now. Our use case is a Framework 4.6.2 tray agent communicating over named pipe with a Framework 4.6.2 service. After upgrading from 5.3.1 to 5.3.2 suddenly the tray agent started crashing with no output. On a hunch I ran it as administrator and it worked normally. After reverting to 5.3.1 our vanilla install works as expected.

Idea to add Wire serializer in addition to Json.Net

Hi

Just found ServiceWire lib and will give it a try. So far I have only skimmed the docs, but I noticed that Json.Net is used which is good. This also made me think, that it would be great to be able select other serializers, espcially high performance binary serializers. Here I am thinking of both Wire (https://rogeralsing.com/2016/08/16/wire-writing-one-of-the-fastest-net-serializers/) and of course Google Protocol buffers. Maybe I can make pull request later on, if I start using ServiceWire.

Strong Name

Without Strong names it is not possible to use the nuget package in our environment.

Topshelf incompatibility?

Hello, I'm getting the error : 'Cannot match method 'ReAuthenticate' to its server side equivalent'

This worked prior to modifying the project to use topshelf. Are there any known issues here?

These are the relevant servicewire implementation details:

interface:

    public interface IAuthorize
    {
        bool IsAuthValid();
        bool ReAuthenticate(string authDomain, string username, string hashedPassword);
        AuthState GetAuthState();
    }

server:

    public class IpcAuthorize : IpcBase, IAuthorize
    {
        public bool ReAuthenticate(string AuthDomain, string Username, string HashedPassword)
        {
          ...
        }
    }

client:

        public static bool DoProxyAuth()
        {
            using (var client = GetClient<IAuthorize>())
            {
                return client.Proxy.ReAuthenticate(
                    string,
                    string,
                    string                );
            }
        }

NewtonSoft binding exception

Hello,

Trying to use the nuget package on a project that uses NewtonSoft 10 but I get an fail to load exception requesting for NewtoSoft 9

any ideas?

System.Security.Principal.IdentityNotMappedException on creating Named Pipe

The problem is here
_pipeSecurity.AddAccessRule(new PipeAccessRule(@"Everyone", PipeAccessRights.ReadWrite, AccessControlType.Allow));
Not every locale has the "Everyone" group. In other locale's it's named differently.
You should pass a security indentifier like this:
SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
Then use that one instead of the "Everyone" string.

Crash when running on a 32-bit machine

When I make an RPC call, if the program is running on a 32-bit machine I get the following error:

jit compiler encountered an internal limitation

Is this problem known? Am I doing anything wrong?

Regards

Task support

Task works just fine but when using a non-generic Task an error throws claiming VoidTaskResult is not marked as ISerializable. This only occurs when using an async Task:

Error in ProcessRequest: System.Runtime.Serialization.SerializationException: Type 'System.Threading.Tasks.VoidTaskResult' in Assembly 'System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' is not marked as serializable.::   at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(Type type)::   at System.Runtime.Serialization.FormatterServices.<>c.<GetSerializableMembers>b__5_0(MemberHolder mh)::   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)::   at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)::   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()::   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)::   at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, BinaryFormatterWriter serWriter, Boolean fCheck)::   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Boolean check)::   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)::   at ServiceWire.DefaultSerializer.Serialize(Object obj, String typeConfigName)::   at ServiceWire.ParameterTransferHelper.SendParameters(Boolean useCompression, Int32 compressionThreshold, BinaryWriter writer, Object[] parameters)::   at ServiceWire.Host.ProcessInvocation(ZkSession session, BinaryReader binReader, BinaryWriter binWriter, Stopwatch sw)::   at ServiceWire.Host.ProcessRequest(Stream readStream, Stream writeStream)

When returning Task.CompletedTask this works just fine. However that is rarely the case.

I have also noticed another issue, the tasks are not actually async but instead somehow wait synchronously on the result. On the client side i experience ui thread lag when periodically executing RPC's, when i wrap the synchronous call in Task.Run() it does work properly and does not hang.

Connection timeout is not working while creating TcpClient against suspended process

TcpClient is used from ServiceWire.TcpIp library in our project to communicate between the processes to know the application instance is running already.

_tcpClient = new TcpClient(_tcpZkEndPoint); is working for fresh instance/second instance is launched on existence of first instance (Not suspended state).

It fails, in case first instance is in suspended state and trying to run another instance. Problem is, execution will not come out from this line of code and no connection timeout error as well for any duration.

Default timeout is 2500ms and tried for different numbers as well.

PipeSecurity for connection from user to elevated service

I'm trying to connect a Windows application to an elevated service on the same machine using ServiceWire's NamedPipe functionality, but keep getting a System.UnauthorizedAccessException. I'd like to configure the PipeSecurity settings with a few PipeAccessRules, but it seems this isn't possible right now.

Is that correct? I'd really like to use namedpipes over tcp. I saw a few closed issues in this regard, but I didn't fully understand them - but what I got from them, is that you're not going to add it to preserve compatiblity with other OS's?

Could you perhaps give me a pointer where I can add the config myself, I'm fine with compiling my own library for the time being.

Thanks for sharing your hard work, this project is awesome ❤️

BinaryFormatter depreciated and prohibited

Hello!

Microsoft has depreaciated and prohibited the use of the BinaryFormatter in ASP dotnet applications. Is there an alternative that can be used in ServiceWire?

Thanks!

service method with generic parameters support

Hello

Please help me to understand is there a chance to have generic service methods supported?
like

    interface IGenCustomType
    {
        T Load<T>(int id) where T : new();
    }

    class GenCustomType : IGenCustomType
    {
        public T Load<T>(int id) where T : new()
        {
            return new T();
        }
    }

the Host.AddService fails to get method metadata and CreateMethodMap fails to get the MethodSyncInfo.MethodReturnType value

[Fact]
public void AddService()
{
	var host = new Mock<Host>(null);

	var h = host.Object;
	h.AddService<IGenCustomType>(new GenCustomType());
}

I think it may work since MethodSyncInfo.MethodReturnType is used to check is-it-a-Task condition by the StreamingChannel.InvokeMethod only

var returnType = methodSyncInfo.MethodReturnType.ToType();
if (IsTaskType(returnType) && outParams.Length > 0)
{
    if (returnType.IsGenericType)
    {
        MethodInfo methodInfo = typeof(Task).GetMethod(nameof(Task.FromResult))
            .MakeGenericMethod(new[] { returnType.GenericTypeArguments[0] });
        outParams[0] = methodInfo.Invoke(null, new[] { outParams[0] });
	}
    else
    {
        outParams[0] = Task.CompletedTask;
    }
}

so, probably it may be adjusted with if (methodSyncInfo.MethodReturnType != null) check to avoid null reference exception in the methodSyncInfo.MethodReturnType.ToType for T Load<T>(int id) interface method.

Getting "IOException: Pipe is broken" on new NpClient<TInterface>(new NpEndPoint(pipeName)) when running on a net6.0 ASP.NET Core app

Hi @tylerje,

I'm getting the following exception when I try running a system using ServiceWire from an ASP,NET Core web application targetting net6.0:

System.Reflection.TargetInvocationException
  HResult=0x80131604
  Message=Exception has been thrown by the target of an invocation.
  Source=System.Private.CoreLib
  StackTrace:
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)
   at ServiceWire.ProxyFactory.CreateProxy[TInterface](ProxyBuilder proxyBuilder, Object channelCtorValue, ISerializer serializer)
   at ServiceWire.ProxyFactory.CreateProxy[TInterface](Type channelType, Type ctorArgType, Object channelCtorValue, ISerializer serializer)
   at ServiceWire.NamedPipes.NpProxy.CreateProxy[TInterface](NpEndPoint npAddress, ISerializer serializer)
   at ServiceWire.NamedPipes.NpClient`1..ctor(NpEndPoint npAddress, ISerializer serializer)
   at MyProject.Remoting.ServiceWire.Common.V1.RequestSubmitter.CreateNpClient() in C:\Projects\MyProject\src\MyProject\Remoting\ServiceWire\Common\V1\RequestSubmitter.cs:line 116

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
IOException: Pipe is broken.

The exception is thrown when executing the following line of code:

new NpClient<TInterface>(new NpEndPoint(pipeName))

If I compile the exact same project against both netcoreapp3.1 and net48 everything works fine. It also works fine targetting net6.0 if I run the system as a console application by changing the SDK in my csproj file from Microsoft.NET.Sdk.Web to Microsoft.NET.Sdk. I did some digging and found this in the ASP.NET Core 6.0 release notes, could this be relevant?

Do you have any idea if the change in ASP.NET Core I mentioned could be causing this issue and if so, if there is a way to get it to work?

Thanks!

Expose PipeSecurity

Hello.

Feature request: could you expose PipeSecurity for modification?

Thanks.

Socket exception on ubuntu box.

Hello.
I tried ServiceWire on my ubuntu box as TcpHost with following code :

var mytester = new MyTester();
var tcphost = new TcpHost(8090);
tcphost.AddService(mytester);
tcphost.Open();
Console.WriteLine("Press Enter to stop the dual host test.");
Console.ReadLine();
tcphost.Close();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();

its works on windows perfect but on linux its throwing following exception :

dotnet ServiceWireTest.dll
Unhandled Exception: System.Net.Sockets.SocketException: Operation not supported
at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue, Boolean silent)
at System.Net.Sockets.Socket.SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, Int32 optionValue)
at ServiceWire.TcpIp.TcpHost.Initialize(IPEndPoint endpoint, ILog log, IStats stats, IZkRepository zkRepository)
at ServiceWireServer.Program.Main(String[] args)
Aborted (core dumped)

typeConfigName.ToType returns null in a framework client to netcore server

image
image

type is null but the object that was deserialized is already translated to the correct type, System.Private.Uri looks to be the netcore type configuration name instead of the framework type configuration name.

Type.GetType("System.Uri[], System.Private.Uri") | null
obj.GetType().Assembly | {System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
typeConfigName | System.Uri[], System.Private.Uri

if typeConfigName was set to "System.Uri[], System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". the type would not be null.

I wonder if this is the reason why you have not strong named service wire. but not having a strong name limits the library to applications that do not use strong names. would it break anything to return the object without converting if the type is null?

would this address the situation:
image

Exception in the named pipe Serverloop creates huge logfiles and high CPU usage

The Serverloop in NpListener.cs calls ProcessNextClient() in a while loop. If an exception is thrown in the ProcessNextClient method, a message is logged and the loop continues. From the comment line I understand that this is done on purpose, but the result is that it writes log messages as fast as it can when an exceptions happens repeatedly. In my case that resulted in a logfile over 1 gigabyte within 1 or 2 minutes and a high CPU usage. Exceptions can happen there for more reasons than reaching the connection limit only. In our case it was an UnauthorizedAccessException. Another reason could be an invalid pipename e.g.

I don't know what the best solution would be. Maybe silently catch the specific exception that is triggered by exceeding the number of available connections, pause for 50ms and continue? And re-throw all other exceptions?

private void ServerLoop()
{
    while (running)
    {
        ProcessNextClient();
    }
}

public void ProcessNextClient()
{
    try
    {
        // pipe code
        // every exception thrown here causes a log message 
    }
    catch (Exception e)
    {
        //If there are no more avail connections (254 is in use already) then just keep looping until one is avail
        _log.Error("ProcessNextClient error: {0}", e.ToString().Flatten());
     }
}

DataSet return type - EndOfStreamException

Hello
I’m exploring the possibility to substitute the .NET Remoting in a range of legacy applications that have to be ported on .NET Core.
I’ve simply setup an hello word project, by following your useful documentation and basically everything works great, apart from an issue regarding the DataSet object when it’s used as a return type.
Every time I try to invoke remote methods that return System.Data.DataSet objects, I'm getting a System.IO.EndOfStreamException.
Strangely, by encapsulating the DataSet in a class like the following and by using this new type as return type, no error occurs:
`[Serializable]
public class DataSetObject : DataSet
{
public DataSetObject() : base() { }

    public DataSetObject(string dataSetName) : base(dataSetName) { }

    public DataSetObject(SerializationInfo info, StreamingContext context) : base(info, context) { }

    public DataSetObject(SerializationInfo info, StreamingContext context, bool ConstructSchema) : base(info, context, ConstructSchema) { }

}`

This solution does not fit very well to me, because it implies a lot of changes in the existing server side code.
From my testing, the DataSet can even be successfully used as a byref parameter in a remote method. Honestly I would not expect this to work :-) so I don’t understand why it should not be transported as it is as a return type.
Could you please tell me if this is a bug, or possibly provide me with a workaround?
I’m available to send the prototype code if it’s useful.
Regards
Ruggero

Cannot call a dotnetcore service from a donetframework client

I was playing around the demo host/client and I noticed that it fails to call methods if the server and client don't run on the same runtime. It fails when trying to match the types because the qualified names are different:

  • Int32, System.Private.CorLib vs Int32, mscorlib
  • Same with Task

However, if I hijacked the running code on the client to remove the assembly qualification, it works fine. Given that the purpose of the library is to be able to serialize primitive types, do you think that scenario should be allowed? If so, we might either need to not qualify the type, or add an alias for types from the core library.

Exception in SyncInterface

Hello,

Using ServiceWire over TCP/IP in .NET 4.8 to replace WCF. The first issue we found is the ServiceWire assembly does not have a strong name. Therefore, I used the StrongNamer to add a strong name to ServiceWire.dll across 2 projects we use it in. The first project is the server and the second project is the client. Locally in debug mode everything works fine (after using StrongNamer). I can communicate from client to server. When we made our release mode assemblies and deployed, I get the following error when spinning up a connection and trying to make a remote method call from the client.

Related LogID = 206686441 Callstack: System.Exception: The GJSE instance "appserver_qafeature_mt_1" is not running ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeAccessException: SyncInterface failed. Type or version of type unknown. at ServiceWire.StreamingChannel.SyncInterface(Type serviceType, String username, String password) at ServiceWire.TcpIp.TcpChannel.Initialize(String username, String password, Type serviceType, IPEndPoint endpoint, Int32 connectTimeoutMs) at GJSESWInterfaceProxy..ctor(Type , IPEndPoint , ISerializer , ICompressor ) --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at ServiceWire.ProxyFactory.CreateProxy[TInterface](ProxyBuilder proxyBuilder, Object channelCtorValue, ISerializer serializer, ICompressor compressor) at ServiceWire.ProxyFactory.CreateProxy[TInterface](Type channelType, Type ctorArgType, Object channelCtorValue, ISerializer serializer, ICompressor compressor) at ATWebBusinessLogic.BusinessLogic.GJSE.GJSEBL.ManageServiceWireClientConnection(GJSEInstance instance) in e:\Staging_Autobuild\BuildSources\7_2_1\ATWebBusinessLogic\BusinessLogic\GJSE\GJSEBL.cs:line 61 --- End of inner exception stack trace --- at ATWebBusinessLogic.BusinessLogic.GJSE.GJSEBL.ManageServiceWireClientConnection(GJSEInstance instance) in e:\Staging_Autobuild\BuildSources\7_2_1\ATWebBusinessLogic\BusinessLogic\GJSE\GJSEBL.cs:line 81 at ATWebBusinessLogic.BusinessLogic.GJSE.GJSEBL.IsInstanceRunning(String instanceName) in e:\Staging_Autobuild\BuildSources\7_2_1\ATWebBusinessLogic\BusinessLogic\GJSE\GJSEBL.cs:line 327

I traced this to the following lines of code in the SyncInterface methd.

            //read sync data
            var len = _binReader.ReadInt32();
            //len is zero when AssemblyQualifiedName not same version or not found
            if (len == 0) throw new TypeAccessException("SyncInterface failed. Type or version of type unknown.");
            var bytes = _binReader.ReadBytes(len);
            if (null != _zkCrypto)

Any idea what could be the issue?

Thanks

Byref Enums

When I try to use an enumeration passed as a reference in my interface with ServiceWire, I am getting the following exception:

"Non-primitive native types (e.g. Decimal and Guid) ByRef are not supported."

A simple interface like below can be used as a reproducer:

    public enum eTest
    {
        OK,
        NoGood
    }

    public interface ITest
    {
        void Test(ref eTest aTest);
    }

Now, since (most) enumerations are simple integers, I was wondering if it would be possible to allow ByRef enums by casting the enum to an integer before sending it out to the client and casting it back to the original enum after client returns from the call?

I have multiple interfaces with ByRef enums, and I'd love to be able to use ServiceWire with them without changing the argument list (and breaking compatibility). I tried adding [Serializable] attribute to the enum but it didn't help.

Any help is appreciated.

TcpClient is failing to create instance in .net framework 6

Getting exception as "SyncInterface failed: Type or version of type unknown". It's in .net framework and it's packages are directly added from nuget. However, same code is working in .net core and it's packages are directly added from nuget.

Remove conditional compile flags for pipe security

Hello.

Cloud you remove the conditional compiles for pipe security (e.g. in src/ServiceWire/NamedPipes/NpListener.cs)? AFAIK all supported versions of .net should also support PipeSecurity.

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.