C# 没有注释的WCF合同

C# 没有注释的WCF合同,c#,wcf,C#,Wcf,我想知道是否有任何方法可以在不使用[DataContract]和[DataMember]注释的情况下定义WCF契约类。原因是我们目前拥有的域模型相当干净,所以我们希望保持这种方式。这里的最佳做法是什么?创建一个传输对象,并将域模型对象复制到一个传输对象中(该对象具有所需的注释,并且合同是否在客户端和服务器之间传输)?或者不以某种方式注释对象模型并以不同的方式指定契约。您可以使用MetadataType属性和元数据模型类将注释与模型分开 例如: [MetadataType(typeof(MyMod

我想知道是否有任何方法可以在不使用[DataContract]和[DataMember]注释的情况下定义WCF契约类。原因是我们目前拥有的域模型相当干净,所以我们希望保持这种方式。这里的最佳做法是什么?创建一个传输对象,并将域模型对象复制到一个传输对象中(该对象具有所需的注释,并且合同是否在客户端和服务器之间传输)?或者不以某种方式注释对象模型并以不同的方式指定契约。

您可以使用
MetadataType属性和元数据模型类将注释与模型分开

例如:

[MetadataType(typeof(MyModelMetadata))]
public class MyModel : MyModelBase {
  ... /* the current model code */
}

[DataContract]
public class MyModelMetadata {
    [DataMember] 
    public string Name { get; set; }
}
[DataContract(Name = "Customer")]
public class Customer
{
    [DataMember(Name = "FirstName")]
    public string FirstName { get; set; }

    [DataMember(Name = "LastName")]
    public string LastName { get; set; }
}
如果不向类添加任何序列化属性,并将其作为WCF服务协定方法的一部分使用,WCF仍将使用默认序列化规则生成数据协定。这意味着该类将隐式成为
[DataContract]
每个公共属性,同时具有一个
get
set
访问者将隐式成为
[DataMember]

您需要应用属性的唯一时间是,如果要覆盖默认行为,例如隐藏某些属性、应用名称空间等。通常认为这样做是一种良好的做法,因为依赖默认行为可能会在以后给您带来麻烦。(它还明确表示您的类是供WCF使用的)。但这并不是严格要求的,只要默认行为满足您的需要


针对您的后续行动:

据我所知,没有完全外部的方法来更改给定类的
DataContractSerializer
的序列化行为;每个选项都至少需要序列化的类具有某种级别的属性。正如@Yair-Nevet在下面所描述的,将现有域对象转换为数据契约的首选方法是
MetadataType
属性

或者,您可以按照问题中的建议绕过整个问题:不要序列化域对象,而是创建自定义DTO对象并序列化它们。例如,每当我使用实体框架时,我都倾向于这样做,因为序列化这些框架可能很棘手。如果您的域对象内置了许多行为,那么这也是一种很好的方法——您可以将“传递的数据”与“参与我的业务逻辑的对象”明确区分开来


您通常会得到大量冗余代码,但它确实实现了对现有对象零更改的目标。

WCF能够在不使用属性的情况下序列化对象。这些属性允许进行自定义。例如,这两个类将通过以下方式进行相同的序列化:


值得一提的是,您确实应该用属性标记类。它们不像你想象的那样“凌乱”。事实上,它会让你在未来免于头痛。例如:

[MetadataType(typeof(MyModelMetadata))]
public class MyModel : MyModelBase {
  ... /* the current model code */
}

[DataContract]
public class MyModelMetadata {
    [DataMember] 
    public string Name { get; set; }
}
[DataContract(Name = "Customer")]
public class Customer
{
    [DataMember(Name = "FirstName")]
    public string FirstName { get; set; }

    [DataMember(Name = "LastName")]
    public string LastName { get; set; }
}

在前面的代码示例中,我显式设置了类和成员的名称。这将允许我在不破坏用户代码的情况下重构名称。因此,如果有人决定将我的类命名为CustomerDetail而不是Customer,我仍然可以将该名称保留为Customer,以便我的服务的使用者继续工作。

您可以始终使用DTO。创建一个单独的类,该类包含序列化对象所需的所有内容。然后将域模型投影到DTO上。您可以使用AutoMapper之类的工具来简化此过程

关于绩效的问题

除非每个类有成百上千个对象或大量属性,否则与DTO之间的转换可能不会带来太大的性能开销

如果您使用的是类似EF的东西,并且没有序列化每个属性,那么您甚至可以通过将EF查询直接投影到DTO上来减少一些开销


这是一个戏剧性的例子,但我有(设计糟糕的)数据库模型,每种类型有50多个属性。通过改为只有我所关心的10-15个属性的DTO,我几乎可以将WCF服务的性能提高一倍。

请您进一步说明?与我的问题相关的部分类的目的是什么?看看我更新的答案。我仍然需要修改我的域模型来实现这一点。这并不总是可能或可取的。我正在寻找一种保持域模型不变的解决方案。但是谢谢你的回答。好吧,这就像JSON序列化一样,使用相同的属性。但是,如果我确实需要一个自定义序列化程序,比如一个名为Person的类,有没有办法在不更改Person类中的任何内容的情况下实现这一点?我不知道。如果默认序列化不合适,则至少需要对原始类定义进行一些更改。@Yair的回答中给出的是我通常的处理方式,因为它占用的空间最小。非常感谢-如果我确实需要一个自定义序列化程序,比如一个名为Person的类,有没有办法在不更改Person类中的任何内容的情况下实现这一点?如果您选择创建一个自定义序列化程序来代替
DataContractSerializer
,然后简单地构建一些默认行为,就像
DataContractSerializer
那样。不管属性是否存在,序列化程序都应该能够处理您的类。谢谢-我在发布之前搜索了一段时间,所以的“相关问题”功能没有帮助。看看其他帖子中的答案,我希望我的问题保持开放,因为我在下面评论中的一些问题仍然没有得到回答。是的,这也是我所想的。只是想知道现在是否有一个更好的内置替代方案