yallie / Zyanea

:zzz: Zyanea was the codename for the next version of Zyan Communication Framework, a proof of concept.
http://zyan.com.de
MIT License
21 stars 5 forks source link

Serializer freezes trying to serialize the ContainerException #1

Open guehmann opened 6 years ago

guehmann commented 6 years ago

Hi Yallie,

just tried your project. This is exactly what i was looking for. I'm very optimistic when Microsoft moves UWP10 to Net Standard i can communicate with my Raspberry Windows 10 IoT Core and my WebApi.

I setup a sample project you described here with a server and a client, unfortunately my client hangs. He is waiting forever. Even in debug mode I cannot see why.

Do you have any idea what i did wrong?

If i use

netstat -ano | findstr 5000

I cannot see onething is listening on port 5000.

Regards Jens

yallie commented 6 years ago

Hello Jens,

did you specify the endpoint address in ZyanServer constructor? If your use just new ZyanServer() then your server is not listening. This constructor is used to defer the server startup (i.e. when you need to register a lot of components and to make sure that no one can connect before the server is ready to go).

yallie commented 6 years ago

I've just tried to create a new console application to check it out. The program seems to work just fine:

>dotnet run
Starting up server. Endpoint: tcp://127.0.0.1:5800
Server started. Press ENTER to quit.

And the client:

Starting up server. Endpoint: tcp://127.0.0.1:5800
Connecting to: tcp://127.0.0.1:5800...
Connected. Running SayHello...
Done! Exiting.

Here is the complete source code for my test application:

using System;
using System.Threading.Tasks;
using Zyanea;

// shared library

public interface IHelloService
{
    Task SayHello(string message);
}

// executable code

class Program
{
    const string ServerUrl = "tcp://127.0.0.1:5800";

    static void Main()
    {
        try
        {
            RunServer();
        }
        catch
        {
            RunClient().Wait();
        }
    }

    // server code

    static void RunServer()
    {
        Console.WriteLine($"Starting up server. Endpoint: {ServerUrl}");

        using (var server = new ZyanServer(ServerUrl))
        {
            server.Register<IHelloService, HelloService>();

            Console.WriteLine("Server started. Press ENTER to quit.");
            Console.ReadLine();
        }
    }

    class HelloService : IHelloService
    {
        public async Task SayHello(string message)
        {
            await Task.Delay(500); // simulate computations
            Console.WriteLine($"Hello {message}!");
        }
    }

    // client code

    static async Task RunClient()
    {
        Console.WriteLine($"Connecting to: {ServerUrl}...");

        using (var client = new ZyanClient(ServerUrl))
        {
            Console.WriteLine("Connected. Running SayHello...");

            var proxy = client.CreateProxy<IHelloService>();
            await proxy.SayHello("World");

            Console.WriteLine("Done! Exiting.");
        }
    }
}
guehmann commented 6 years ago

Hi Yallie,

this is my server:

using System;
using System.Threading.Tasks;
using Zyanea;

namespace Server
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Server is running, wait for client");

            using (var server = new ZyanServer("tcp://127.0.0.1:5800"))
            {
                server.Register<IHelloService, HelloService>();
                Console.ReadLine();
            }
        }
    }

    public class HelloService : IHelloService
    {
        public Task SayHello(string message)
        {
            Console.WriteLine("Someone called the server for a hello...");
            return null;
        }
    }

    public interface IHelloService
    {
        Task SayHello(string message);
    }
}

and this my client code:

using System;
using System.Threading.Tasks;
using Zyanea;

namespace Client
{

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Try to connect to the server to say hello.");

            using (var client = new ZyanClient("tcp://127.0.0.1:5800"))
            {
                var proxy = client.CreateProxy<IHelloService>();
                Task t = proxy.SayHello("World");
                t.Wait();
            }
        }
    }

    public interface IHelloService
    {
        Task SayHello(string message);
    }
}

Referencing Zyanea which i downloaded from github and put to my project.

Regards Jens

guehmann commented 6 years ago

Hi,

just tried you piece of code. It's the same behaviour. The client is waiting on 'await proxy.SayHello'. Even it start the server a second time. Does not go to the catch section to start the client.

I have no result in netstat -ano | findstr 5000.

??? Do i use some wrong referenced assemblies?

Best Jens.

yallie commented 6 years ago

I see two things in your code sample:

1) IHelloService interface is defined in both client and server assemblies. So, they are two different types for the .NET runtime.

2) public Task SayHello returns null instead of the task. Perhaps the server shouldn't just ignore it.

I'm not sure if these errors are reported properly. Error handling is yet to be done. I'll try to add unit tests for these cases to find out how they would behave.

Do i use some wrong referenced assemblies?

That's hard to say, but if there's something wrong with your references, dotnet cli should report it as a warning. Please try my project file to build the application (put Zyanea.dll library to the same folder as your Program.cs file):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Zyanea.dll" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Castle.Core.AsyncInterceptor" Version="1.4.0" />
    <PackageReference Include="Castle.Core" Version="4.1.1" />
    <PackageReference Include="DryIoc.dll" Version="2.12.2" />
    <PackageReference Include="DryIoc.MefAttributedModel.dll" Version="3.1.3" />
    <PackageReference Include="Hyperion" Version="0.9.6" />
    <PackageReference Include="MessageWire" Version="1.1.1" />
    <PackageReference Include="NetMQ" Version="4.0.0.1" />
  </ItemGroup>
</Project>
yallie commented 6 years ago

Also, what's your platform? I've tested it on Windows, and my tests on Travis-CI run on Linux.

guehmann commented 6 years ago

Running on Windows. The only strange thing is that a get no result when i'm looking for my port 5000. On the Zyan Network you can see some process is listening on.

But don't matter. I'll give it a try tomorrow again and will report if i've any progress.. It's still weekend and thanks for the fast reply.

Regards Jens.

yallie commented 6 years ago

The only strange thing is that a get no result when i'm looking for my port 5000

In my sample code and in the sample you've posted the port is 5800, not 5000.

guehmann commented 6 years ago

Hy Yallie,

running on Windows 10 Enterprise.

It was my fault, I put the interface in a shared library now (the issue about different .net types was the key) and everthing works fine now.

Once again, thanks for your excellent support.

Now I have all I want. If Net Standard is supported on UWP 10 I'll do some test on Windows with UWP 10 and Raspberry with Windows 10 IoT Core. I'll report to you.

Thanks Jens.

yallie commented 6 years ago

Thanks for reporting Jens!

the issue about different .net types was the key

Great, that's an error that needs to be properly reported. I'll fix that :)

If you're going to use the library, perhaps it's the time to publish it as a Nuget package?

guehmann commented 6 years ago

Great, nuget would be great, but it works this way. you can close the issue if you want.

See us. Jens

yallie commented 6 years ago

Looks like serialization issue. My code reports an exception, but the serializer hangs up trying to serialize it. I'll look into it, hopefully tomorrow.

guehmann commented 6 years ago

Hi Yallie,

Supplement,

the issue 'netstat -ano | findstr 5000' has gone away, was my fault. The server binds correctly and is listening on the specified port.

I put the server code into the start method of an TopShelf service like this (Like in the .Net Zyan Framework):

try { using (Host = new ZyanServer($"tcp://{settings.Host}:{settings.Port}")) { Host.Register<IHelloService, HelloService>(); LogEx.Info(Subject, Identity, $"Service host '{settings.Host.ToLower()}' listening on port {settings.Port}."); } } catch (Exception e) { LogEx.Error(Subject, Identity, $"Initialize of communication contract failed due to incorrect configuration."); throw e; }

The host is registered but then executes to the end any the binding is lost.

Regards Jens.

yallie commented 6 years ago

Hello Jens,

your TopShelf service code shouldn't create the server in the using block. It applies both to Zyan and to Zyanea (actually, to any kind of TCP server). That's because you'll dispose of the listener at the end of the using block.

You should create ZyanServer instance in your start method and dispose of it in your stop method. Here is the gist sample of the TopShelf service using Zyan Framework (have a look at HostFactory.Run method):

https://gist.github.com/yallie/7a3a4a16ce8f4b9e74da

Cheers, Alex