C# 为什么WCF需要知识

C# 为什么WCF需要知识,c#,.net,wcf,C#,.net,Wcf,我正在学习WCF,不了解KnowTypeAttribute的真正优势。有人能简单地解释一下我们为什么需要它吗?KnownTypeAttribute使您能够为给定的数据协定指定可接受的派生类。它指定在序列化或反序列化给定类型时DataContractSerializer应识别的类型 一个简单的例子 [ServiceContract()] interface ITaskManager { [OperationContract()] MyCollection<Task> G

我正在学习WCF,不了解KnowTypeAttribute的真正优势。有人能简单地解释一下我们为什么需要它吗?

KnownTypeAttribute使您能够为给定的数据协定指定可接受的派生类。它指定在序列化或反序列化给定类型时DataContractSerializer应识别的类型

一个简单的例子

[ServiceContract()]
interface ITaskManager
{
    [OperationContract()]
    MyCollection<Task> GetTaskByAssignedName(string name);
}

[DataContract()]
[KnownType(typeof(DerivedTask))]
class Task
{

}

[DataContract()]
class DerivedTask
{

}
[ServiceContract()]
接口ITaskManager
{
[运营合同()]
MyCollection GetTaskBySignedName(字符串名称);
}
[DataContract()]
[KnownType(typeof(DerivedTask))]
课堂任务
{
}
[DataContract()]
类派生任务
{
}
在服务契约中使用多态类型时,需要KnownTypeAttribute,因为多态性不属于面向服务的范例

将KnownTypeAttribute属性应用于要向 应在以下情况下识别的DataContractSerializer类型: 序列化或反序列化 属性被应用。此属性也可以被其他用户识别 理解数据协定的序列化程序


查看了解更多详细信息。

此属性用于在服务的元数据中包含其他类,以便客户端可以看到它们。让我们以以下内容为例:

[DataContract]
public class BaseModel
{
    [DataMember]
    public string Id { get; set; }
}

[DataContract]
public class ChildModel: BaseModel
{
    [DataMember]
    public string Foo { get; set; }
}
以及以下服务合同:

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    BaseModel Get();
}
您可以这样实现它:

public class MyService: IMyService
{
    public BaseModel Get()
    {
        return new ChildModel();
    }
}
现在,当WCF公开此服务的元数据时,它会查看服务契约和所涉及的操作,以便发现返回BaseModel类型的Get操作。因此,BaseModel类将自动公开在元数据中。问题是,当您尝试调用服务时,实际实现返回一个
ChildModel
,因为WCF不知道。该服务的客户端都不知道这种类型

因此,您需要明确指出您在实现中使用的这个类,但它不是契约的一部分。这可以通过使用KnownType属性来完成:

[DataContract]
[KnownType(typeof(ChildModel))]
public class BaseModel
{
    [DataMember]
    public string Id { get; set; }
}
指定此已知类型的另一种方法是使用配置文件:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="MyCompany.BaseModel, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
                <knownType type="MyCompany.ChildModel, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXX, processorArchitecture=MSIL"/>
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

DataContractSerializer是基于契约的,这意味着它不绑定到任何特定的类型模型。它所拥有的只是数据(通常是xml)。这意味着,如果您有如下模型:

 Customer
 SuperCustomer : Customer
 AwesomeCustomer : Customer
然后序列化程序需要事先知道如果在数据中看到每种类型,它意味着什么;否则它将不知道要创建什么类型。这可以通过多种方式实现,其中最简单的是KnownTypeAttribute

考虑替代方案;序列化程序只知道“Customer”,它希望在某些xml中看到它。取而代之的是,它得到了其他的东西(不管它是什么,但是我们说“代码>……/代码>”。现在它做了什么?它是否开始寻找可能看起来的类型?这是非常不精确和有风险的。还要考虑,它需要能够为这个数据生成WSDL/MEX导出-如果它所知道的都是“客户”的话。,它不可能警告调用方也期望超级客户/AwesomeCustomer,这意味着WSDL/MEX是不完整和无用的

XmlSerializer(XmlIncludeAttribute)和protobuf net(ProtoIncludeAttribute)使用了相同的方法,可能也是我最基于契约的序列化程序


另一种方法是基于类型的序列化程序(BinaryFormatter、NetDataContractSerializer等)-在这种方法中,它包括数据中的类型,意思是
你的.Namespace.type、你的.Assembly、blah
-这意味着它不需要事先知道(因为它在数据中是显式的),但也意味着它不可能适用于不同的型号(或者跨平台)。

+1.这不是一个
答案
。它是
超级答案
。事实上,
一个了不起的答案
:d你能给我解释一下吗:“问题是,当您尝试调用该服务时,实际实现会返回一个WCF的ChildModel,而WCF对此一无所知。"-为什么WCF不了解ChildModel,我们也在这个类上应用了DataContract属性。您已经将DataContract应用于这个属性,但是在生成WSDL时,WCF只使用在操作契约中可见的信息。并且这个类从来没有出现在任何操作契约中。这样想:您可以创建一些随机类并用DataContract和DataMember属性装饰它,但绝对不要在任何地方使用这个类。只需声明它。你不能期望这个类会出现在WSDL中,所以使用这个类的客户端都不会知道它的存在。谢谢!-我明白了,但还有一件事很麻烦我已经在下面添加了它。