您的数据合约代表您的服务向外界公开的公共 API。一旦您的服务开始被客户端使用,您希望避免对本合同进行重大更改 - 特别是如果您的服务正被您无法控制的客户端使用。当然,如果您的服务仅用于“内部”使用,那么您对此具有一定的灵活性。
凭借“程序到抽象 - 而不是实现”理念 - WCF 服务的数据(和服务)契约在面向服务的上下文中提供抽象,类似于面向对象世界中的接口。
如果您使用 .dll 共享您的数据合同,那么在我看来 - 您无法绕过这样一个事实,即您需要单独的类来表示您的服务数据合同和您的数据模型。使用像AutoMapper这样的映射工具可以显着减少转换代码的数量。如果你试图在你的数据合约中塞入额外的信息(比如通过数据成员的属性)——你最终会将关于你的数据访问方法的信息泄露到你发布的二进制文件中。如果将来您切换到另一种数据访问方法——甚至是 NoSQL 数据库,会发生什么?您对数据合同的更改可能会破坏使用旧版本二进制文件的现有客户端。
在我提出替代方案之前 - 让我说以上是我在所有情况下都会做的事情。你的数据模型和你的服务 API 代表着根本不同的野兽,它们会因不同的因素而相互独立地变化。尽管事实上它们通常看起来很相似,但两者的使用环境和可能发生的变化是完全不同的。
现在进行黑客攻击...
如果您通过 MEX 端点发布服务 API,则当 Visual Studio(或真正的 svcutil.exe)生成代理时 - 客户端会获得自己的服务和数据合同版本。在服务方面,您可以执行以下操作:
[DataContract]
public class Entity
{
[DataMember]
public int? Temp { get; set; }
[Description]
public int? DbTemp { get; set; }
[OnSerializing()]
internal void OnSerializingMethod(StreamingContext context)
{
Temp = DbTemp;
}
}
从Entity
数据库填充实例时,将DbTemp
设置属性。只有当实例被序列化以准备发送到客户端时,Temp
才会填充该属性。
当您的客户端从 MEX 端点生成代理和数据合约时,Entity
数据合约如下所示:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Entity", Namespace="http://schemas.datacontract.org/2004/07/WcfService1")]
[System.SerializableAttribute()]
public partial class Entity : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private System.Nullable<int> TempField;
[global::System.ComponentModel.BrowsableAttribute(false)]
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
get {
return this.extensionDataField;
}
set {
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public System.Nullable<int> Temp {
get {
return this.TempField;
}
set {
if ((this.TempField.Equals(value) != true)) {
this.TempField = value;
this.RaisePropertyChanged("Temp");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
不是您的数据访问实现的嗅探!
最后 - 请注意,您可以通过发布 .dll 来完成上述技巧 - 您只需发布包含上述“精简”数据合同的 .dll。但是,这意味着您必须有效地管理两个不同版本的Entity
- 您的服务内部使用的版本和已发布的 .dll 中的版本。如果这些不同步 - 祝你调试成功!