【问题标题】:System.Runtime.Serialization.InvalidDataContractException 'System.Security.Cryptography.X509Certificates.X509Certificate2'System.Runtime.Serialization.InvalidDataContractException 'System.Security.Cryptography.X509Certificates.X509Certificate2'
【发布时间】:2021-07-07 15:49:03
【问题描述】:

我有三个无状态应用程序 Application-A、Application-B 和 Application-C。 Application-B 和 Application-C 正在使用远程处理 V1 与 Application-A 通信。

最近我将 Application-C 迁移到 .Net 5.0。由于 .Net Core 不支持 V1 Remoting,我在 Application-A(服务应用程序)中创建了两个侦听器,如下所示,以支持 V1 和 V2_1 侦听器。

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new[]
    {
        new ServiceInstanceListener(this.CreateHeadersAwareServiceInstanceListener),
        new ServiceInstanceListener((c) =>
        {
            var settings = new FabricTransportRemotingListenerSettings {UseWrappedMessage = true};
            return new FabricTransportServiceRemotingListener(c, this,settings);

        },"ServiceEndpointV2_1")
    };
}

public async Task<ClientInfo> GetClientInfo(string clinetId, CancellationToken cancellationToken = default(CancellationToken))
{
        var data = await _logic.GetClientData(clinetId, cancellationToken);
        return data.FromInternalModel();
}

Application-B 应该使用 V1 Remoting 与 Application-A 通信,Application-C 将使用 Remoting V2_1 堆栈与 Application-A 通信。下面是Application-C如何调用Application-A

 var client ServiceProxy.Create<IBackEndService>(new Uri(_serviceURL), listenerName: "ServiceEndpointV2_1");
await clinet.GetClientInfo(clinetId);

GetClinetInfo 方法返回 ClinetInfo 对象和 ClientInfo 的样子

    [DataContract]
    public class ClientInfo : IExtensibleDataObject
    {

        [DataMember]
        public string ClinetId { get; set; }

        [DataMember]
        public ClientAddress Address { get; set; }

        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public X509Certificate2 ClientCertificate { get; set; }

        public virtual ExtensionDataObject ExtensionData { get; set; }
    }

当 Application-C 调用 GetClinetInfo() 时,我遇到了异常

Exception Summary:
======================================
Message:Type 'System.Security.Cryptography.X509Certificates.X509Certificate2' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.
UTC Timestamp: 04/12/2021 11:34:39.298
Machine Name: id-b3000000
Assembly Full Name: Temp.MyAppDomain, Version=3.16.0.0, Culture=neutral, PublicKeyToken=null
Assembly Version: 3.16.0.0
App Domain Name: Temp.MyAppDomain 
Windows Identity: 
Additional Context: 

Exception Information Details:
======================================
Exception Type: System.Runtime.Serialization.InvalidDataContractException
Message: Type 'System.Security.Cryptography.X509Certificates.X509Certificate2' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.
Help Link: 
HResult: -2146233088
Source: Microsoft.ServiceFabric.Services
Target Site: Void MoveNext()

Stack Trace Information Details: 
======================================
   at Microsoft.ServiceFabric.Services.Communication.Client.ServicePartitionClient`1.InvokeWithRetryAsync[TResult](Func`2 func, CancellationToken cancellationToken, Type[] doNotRetryExceptionTypes)
   at Microsoft.ServiceFabric.Services.Remoting.V2.Client.ServiceRemotingPartitionClient.InvokeAsync(IServiceRemotingRequestMessage remotingRequestMessage, String methodName, CancellationToken cancellationToken)
   at Microsoft.ServiceFabric.Services.Remoting.Builder.ProxyBase.InvokeAsyncV2(Int32 interfaceId, Int32 methodId, String methodName, IServiceRemotingRequestMessageBody requestMsgBodyValue, CancellationToken cancellationToken)
   at Microsoft.ServiceFabric.Services.Remoting.Builder.ProxyBase.ContinueWithResultV2[TRetval](Int32 interfaceId, Int32 methodId, Task`1 task)
   at Temp.MyAppDomain.Utils.DataProvider.GetMyData(String deviceId) in F:\Test\GH-LSU0BCDS-JOB1\Sources\MyLogic\Utils\MyProvider.cs:line 40
   at Temp.MyAppDomain.Logic.GetMyCertificate() in F:\Test\GH-LSU0BCDS-JOB1\Sources\MyLogic\MyLogic.cs:line 462
   at Temp.MyAppDomain.Logic.VerifySignature(Message message) in F:\Test\GH-LSU0BCDS-JOB1\Sources\MyLogic\MyLogic.cs:line 387

【问题讨论】:

    标签: c# .net .net-core service-fabric-stateless service-fabric-remoting


    【解决方案1】:

    正如异常所表明的那样,您正在查看的在服务之间发送的证书不可序列化,因此它会在尝试时抛出。仅仅因为你用[DataMember] 标记它并不能神奇地使它成为可以序列化的东西。

    相反,我建议您将证书转换为易于序列化的字符串(例如字符串),然后改用该值:

    [DataContract]
    public class ClientInfo : IExtensibleDataObject
    {
    
        [DataMember]
        public string ClinetId { get; set; }
    
        [DataMember]
        public ClientAddress Address { get; set; }
    
        [DataMember]
        public string Name { get; set; }
    
        private X509Certificate2 _clientCertificate;
        [IgnoreDataMember]
        public X509Certificate2 ClientCertificate 
        {
             get => _clientCertificate;
             set 
             {
                  _clientCertificate = value;
    
                  //Set the PEM value - from https://stackoverflow.com/a/4740292/845356
                  var sb = new StringBuilder();
                  sb.AppendLine("-----BEGIN CERTIFICATE-----");
                  sb.AppendLine(Convert.ToBase64String(value.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
                  sb.AppendLine("-----END CERTIFICATE-----");
                  CertificateAsPem = sb.ToString();
             }
        }
    
        [DataMember]
        public string CertificateAsPem { get; set; }
    
        public virtual ExtensionDataObject ExtensionData { get; set; }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-18
      • 1970-01-01
      相关资源
      最近更新 更多