首页 > 解决方案 > 我能否在 WCF 中使非原始 .NET 类型可序列化?

问题描述

当我尝试通过 url ~/MyNamespace.MyServiceClass.svc 从公司 Intranet 上的 Web 浏览器访问 myWCF 服务时,我收到以下消息:

无法序列化类型“System.DirectoryServices.AccountManagement.PrincipalContext”。考虑使用 DataContractAttribute 属性对其进行标记,并使用 DataMemberAttribute 属性标记您想要序列化的所有成员。如果该类型是一个集合,请考虑使用 CollectionDataContractAttribute 对其进行标记。有关其他支持的类型,请参阅 Microsoft .NET Framework 文档。

MyClass 在我的界面中实现每个 [OperationContract] 存根,我在 MyClass : MyInterface 的正上方添加了 [DataContract()] 装饰器,但是当我尝试使用 [DataMember] 装饰我的类中的 PricipalContext 成员时,Visual Studio 通过智能感知告诉我属性“DataMember”在此声明类型上无效,它仅在属性、索引器和字段声明上有效。

    public PrincipalContext GetPrincipalContext()
    {
        PrincipalContext principalContext = new PrincipalContext(
            ContextType.Domain, GetUserDomainName()
        );
        return principalContext;
    }

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.datacontractattribute?view=netframework-4.7.2

我不确定 MSDN 文档中的一些内容(如上所示),这些内容表明 DataContract 属性的要点:“指定类型定义或实现数据协定并且可由序列化程序(如 DataContractSerializer)序列化。要使他们的类型可序列化,类型作者必须为他们的类型定义数据协定。”

1.) 当我不是所述类类型 (System.DirectoryServices.AccountManagement.PrincipalContext) 的作者时,我应该如何从 .NET 框架中使可序列化成为预先存在的非原始类类型

2.) 我在 MSDN 上找到的所有示例都解决了这个问题,但只提供了实现用户创建的自定义类类型(例如 Person())的示例。

3.) System.DirectoryServices.AccountManagement.PrincipalContext 是否必须可序列化才能使 MyWCFService 类包含所述类型作为成员?创建 MyWCFService 的主要原因是在我的组织内公开 System.DirectoryServices 和 System.DirectoryServices.AccountManagement dll 的功能。

标签: wcfdatacontract

解决方案


这是设计使然。这些类型不可序列化。您可以通过创建包装类来解决此问题。您可以执行以下操作:

    [DataContract]
    public class MyClass
    {
        public PrincipalContext PrincipalContext { get; set; }

        [DataMember(Name="PrincipalContext")]
        public PrincipalContextSurrogate PrincipalContextWrapper
        {
            get
            {
                return new PrincipalContextSurrogate(PrincipalContext);
            }
            set
            {
                PrincipalContext = value.ToPrincipalContext();
            }
        }
    }

    [DataContract]
    public class PrincipalContextSurrogate
    {
        public PrincipalContextSurrogate() { }

        public PrincipalContextSurrogate(PrincipalContext context)
        {
            ContextType = context.ContextType;
            Name = context.Name;
        }

        [DataMember]
        public ContextType ContextType { set; get; }

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

        public PrincipalContext ToPrincipalContext()
        {
            return new PrincipalContext(ContextType, Name);
        }
    }

推荐阅读