Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interesting Bug...version 2.0.34 #16

Closed
GeoDirk opened this issue Mar 16, 2022 · 6 comments
Closed

Interesting Bug...version 2.0.34 #16

GeoDirk opened this issue Mar 16, 2022 · 6 comments

Comments

@GeoDirk
Copy link

GeoDirk commented Mar 16, 2022

Using H.Pipes, H.Formatter & H.Formatters.BinaryFormatteer version 2.0.34 NuGets.

I'm writing a plugin for a WinForms 4.7.2 program (server) which is trying to talk to a .NET 6.0 WPF application (client). It uses a separate Pipes_Shared .NET Standard 2.0 class for the messages between the two applications:

    [Serializable]
    public class PipeMessage
    {
        public PipeMessage()
        {
            Id = Guid.NewGuid();
        }

        public Guid Id { get; set; }
        public ActionType Action { get; set; }
        public string Text { get; set; } = string.Empty;
    }

    public enum ActionType
    {
        Unknown,
        SendText,
    }

The two ends of the pipe connect just fine. I get a message back from the server that goes through the PipeMessage to send a "You have connected!" message to the WPF client. No problems there. But I send some text back from the client to the server, the

            _PipeServer.ExceptionOccurred += (o, args) =>
            {
                OnExceptionOccurred(args.Exception);
            };

trips with the very odd message:

Exception: System.Runtime.Serialization.SerializationException: Unable to find assembly 'pipes_shared, Version=1.0.1.0, Culture=neutral, PublicKeyToken=null'.
   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.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 H.Formatters.BinaryFormatter.DeserializeInternal[T](Byte[] bytes) in D:\DotNET_Proj\H.Pipes\src\libs\H.Formatters.BinaryFormatter\BinaryFormatter.cs:line 22
   at H.Formatters.FormatterBase.Deserialize[T](Byte[] bytes) in D:\DotNET_Proj\H.Pipes\src\libs\H.Formatters\FormatterBase.cs:line 39
   at H.Pipes.PipeConnection`1.<<Start>b__37_0>d.MoveNext() in D:\DotNET_Proj\H.Pipes\src\libs\H.Pipes\PipeConnection.cs:line 124

How is that possible that the server found the assembly pipes_shared the first time around to generate the message to the client, but now it can't find it for deserialization?

Thanks,

  • Dirk
@HavenDV
Copy link
Owner

HavenDV commented Mar 17, 2022

Hello.

There are differences here in what happens during serialization and deserialization. C# is designed to load libraries the first time you explicitly use any type from that library. As I understand it, when deserializing, BinaryFormatter requires that the required library has already been loaded. Therefore, to fix it, you just need to explicitly call any type from your library at the time of server initialization like:

_ = new PipeMessage()

@HavenDV
Copy link
Owner

HavenDV commented Mar 17, 2022

I'm actively developing a SourceGenerator that generates client/server code based on a C# interface. I would be glad if you take a look at it (if you are still interested) and provide any feedback - https://github.com/HavenDV/H.Ipc

@GeoDirk
Copy link
Author

GeoDirk commented Mar 17, 2022

Hmm...that didn't seem to fix the issue. Here is what I put on the server (see second line):

            _PipeServer = new PipeServer<PipeMessage>(PipeName);
            _ = new PipeMessage();
            _PipeServer.ClientConnected += async (o, args) =>
            {
                Clients.Add(args.Connection.PipeName);
                UpdateClientList();

                AddLine($"{args.Connection.PipeName} connected!");

                try
                {
                    await args.Connection.WriteAsync(new PipeMessage
                    {
                        Action = ActionType.SendText,
                        Id = new Guid(),
                        Text = "Welcome! You are now connected to the server."
                    }).ConfigureAwait(false);
                }
                catch (Exception exception)
                {
                    OnExceptionOccurred(exception);
                }
            };
            _PipeServer.ClientDisconnected += (o, args) =>
            {
                Clients.Remove(args.Connection.PipeName);
                UpdateClientList();

                AddLine($"{args.Connection.PipeName} disconnected!");
            };
            _PipeServer.MessageReceived += (sender, args) =>
            {
                if (args.Message != null)
                {
                    OnMessageReceivedAsync(args.Message);
                }
            };

            _PipeServer.ExceptionOccurred += (o, args) =>
            {

                OnExceptionOccurred(args.Exception);
            };

On the client I did the same. Unfortunately, the same error message pops up.

@HavenDV
Copy link
Owner

HavenDV commented Mar 17, 2022

Please try this:
https://stackoverflow.com/questions/14990980/system-runtime-serialization-serializationexception-unable-to-find-assembly-mya
I have added BinaryFormatter.InternalFormatter property.
You need to use an explicit BinaryFormatter:

var formatter = new BinaryFormatter();
formatter.InternalFormatter.Binder = new CustomizedBinder();
_PipeServer = new PipeServer<PipeMessage>(PipeName, formatter: formatter);

@GeoDirk
Copy link
Author

GeoDirk commented Mar 18, 2022

Hi @HavenDV

Thanks to your pointers and your latest code changes, I was able to get it to work with the following:

            var formatter = new BinaryFormatter();
            formatter.InternalFormatter.Binder = new CustomizedBinder();
            _PipeServer = new PipeServer<PipeMessage>(PipeName, formatter: formatter);

and then the CustomizedBinder:

        sealed class CustomizedBinder : SerializationBinder
        {
            public override Type BindToType(string assemblyName, string typeName)
            {
                Type returntype = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
                return returntype;
            }

            public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
            {
                base.BindToName(serializedType, out assemblyName, out typeName);
                assemblyName = "Pipes_Shared, Version=1.0.1.0, Culture=neutral, PublicKeyToken=null";
            }
        }

Fantastic support! How can I buy you a beer?

@HavenDV
Copy link
Owner

HavenDV commented Mar 18, 2022

Fantastic support! How can I buy you a beer?

Thanks. Not at the moment, I'm from Russia. Your star will be enough for me 😉

@HavenDV HavenDV closed this as completed Mar 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants