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

ArgumentException: Could not cast or convert from System.String to System.Type. #18

Closed
heartacker opened this issue Apr 19, 2022 · 6 comments
Assignees
Labels
question Further information is requested

Comments

@heartacker
Copy link

Newtonsoft.Json.JsonSerializationException
  HResult=0x80131500
  Message=Error converting value "System.NotSupportedException, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" to type 'System.Type'. Path '', line 1, position 121.
  Source=Newtonsoft.Json
  StackTrace:
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at HandyIpc.Serializer.Json.Extensions.ToObject(Byte[] bytes, Type type)
   at HandyIpc.Serializer.Json.JsonSerializer.Deserialize(Byte[] bytes, Type type)
   at HandyIpc.Core.Response.TryParse(Byte[] bytes, Type valueType, ISerializer serializer, Object& value, Exception& exception)
   at HandyIpc.Core.GeneratorHelper.UnpackResponse[T](Byte[] bytes, ISerializer serializer)
   at IpcServer.ClientProxyIDriver.global::IpcServer.IDriver.AddFloat(Single x_, Single y_) in D:\heart\Git\IpcDemo\IpcClientDll\HandyIpc.Generator\HandyIpc.Generator.SourceGenerator\IDriver.ClientProxy.g.cs:line 33
   at IpcClientDll.IpcDriver.AddFloat(Single x, Single y) in D:\heart\Git\IpcDemo\IpcClientDll\IpcDriver.cs:line 91
   at IpcClient.Program.Main(String[] args) in D:\heart\Git\IpcDemo\IpcClient\Program.cs:line 23

  此异常最初是在此调用堆栈中引发的: 
    [外部代码]

内部异常 1:
ArgumentException: Could not cast or convert from System.String to System.Type.

image

    [IpcContract]
    public interface IDriver
    {
        float AddFloat(float x, float y);

        void WriteMemery(uint addr, byte[] data);

        byte[] ReadMemery(uint addr, uint lens);
    }
@heartacker heartacker changed the title [IpcContract] public interface IDriver { float AddFloat(float x, float y); void WriteMemery(uint addr, byte[] data); byte[] ReadMemery(uint addr, uint lens); } ArgumentException: Could not cast or convert from System.String to System.Type. Apr 19, 2022
@DingpingZhang DingpingZhang added the bug Something isn't working label Apr 20, 2022
@DingpingZhang DingpingZhang self-assigned this Apr 20, 2022
@DingpingZhang
Copy link
Member

你好,请确认一下你所安装的 HandyIpc 的版本,是否与下方相同?

    <PackageReference Include="HandyIpc" Version="0.5.2" />
    <PackageReference Include="HandyIpc.NamedPipe" Version="0.5.0" />
    <PackageReference Include="HandyIpc.Serializer.Json" Version="0.5.0" />

我对你提供的 Demo 进行了测试,在该版本下,不可复现此问题。

这是我的最小复现 Demo:

TestHandyIpc.zip

@heartacker
Copy link
Author

你好,是不是 contract要在同一个命名空间内,如你的代码 TestHandyIpc.Contracts

我这边的情况是这个contract 代码是一样的,但是放在不同的文件和项目内部。
image

@DingpingZhang
Copy link
Member

你好,是不是 contract要在同一个命名空间内,如你的代码 TestHandyIpc.Contracts
我这边的情况是这个contract 代码是一样的,但是放在不同的文件和项目内部。

这不是推荐做法,因为共用相同的合同接口,才能做到统一管理,你在两边分别复制了一份接口,这在 C# 中实际上算两个不同的类型,当你修改了其中一个接口,导致其与另一个接口匹配不上时,将无法得到编译错误的提示,有潜在的维护隐患。

但具体到这个问题,其实有办法正常使用(不推荐)。出现这个问题的原因是:两个程序集中的 IDriver 本质上是不同的类型,所以框架会生成不同的标识符(key)来标识他们的代理实例,那么客户端的调用请求将匹配不上服务器的实例。

但是框架提供了自定义这个标识符的功能,你可以手动覆盖默认的标识符。只需要确保服务端和客户端的 "unique-key" 一致就可以正常调用,你可以看到,甚至服务端注册的接口 IDriver222 和客户端获取的接口 IDriver 连名字都不一样,但也能正常调用,只要方法的签名一致即可(相当于“鸭子类型”了):

// 在服务端注册这个接口时:
builder.Register<IDriver222, Driver>("unique-key");

// 在客户端获取这个接口时:
var driver = client.Resolve<IDriver>("unique-key");

@DingpingZhang DingpingZhang added question Further information is requested and removed bug Something isn't working labels Apr 20, 2022
@heartacker
Copy link
Author

谢谢你的耐心解答。非常感谢 💯

@heartacker
Copy link
Author

对了,顺便问一下,如果 server 没有运行的话, client 起来后调用会卡住不动,还不知道如何退出, 有没有办法检测server是否运行了?

@DingpingZhang
Copy link
Member

有没有办法检测server是否运行了?

框架目前没有支持,但可以使用 Mutex、 EventWaitHandle 等确保进程单例的方法来检查服务进程是否已启动,理论上服务器的进程是要确保单例的,否则,无法保证消息被发往哪个进程处理。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants