我们有一个使用多个DataContracts的现有WCF服务。我们希望根据设备修改序列化,这样当从移动设备访问时,服务应该只序列化一些重要的数据成员(不是全部)
我们这里有2个选项
我们不想使用第一个选项,因为它在将来引入了许多冗余代码问题
小型研究表明,我们需要使用IXmlSerializable并覆盖readXML()和writeXML()方法。但与此同时,我已经看到DataContract和IXmlSerializable不应该一起使用的地方
非常感谢任何搞乱实际序列化的例子。
[DataContract]
public class TokenMessage
{
string tokenValue;
string extraValue;
[DataMember]
public string Token
{
get { return tokenValue; }
set { tokenValue = value; }
}
[DataMember]
public string Extra
{
get { return extraValue; }
set { extraValue = value; }
}
}
现在,当我从移动设备访问返回典型TokenMessage数据协定的服务时,我不希望序列化“额外”数据成员,即当我为操作合同提供不同的参数时,它应该能够序列化一些/所有数据成员(取决于操作)
PS:现在请忽略设备检测部分。让我们假设我们在操作合同中有一个参数,这有助于我们识别设备
答案 0 :(得分:3)
我不相信@Pranav Singh的某些变体的答案不是更好的设计,但那不是你的问题......
正如您在评论中提到的,.NET中的属性是静态设计。这意味着动态添加/删除[DataMember]
不是一个好选择。有可能的。有一些选项,比如使用Reflection.Emit来重新创建元数据更改的实例(请参阅Can attributes be added dynamically in C#?的所有答案),但所有这些路径都很复杂。
我看到两个合理的选择:
1)为服务实施IParameterInspector 。在AfterCall()方法中,您可以检查并更改在序列化之前返回到客户端的参数。有一些工作要使用反射来动态确定参数类型并设置它们的值,但它并不复杂。这是更好的设计,可以在许多合同或服务中重用行为。 Carlos Figueira's blog是WCF扩展示例的最佳来源。
2)使用[OnSerializing]
和[OnSerialized]
事件。在[DataContract]中,您可以临时更改序列化期间返回的属性。 事件实际上是为了启用初始化而设计的,因此这个解决方案有点像黑客。此解决方案也不是线程安全的。但它确实将代码保存在DataContract类中并快速解决问题(我认为您正在寻找快速的问题)。
解决方案#2可能看起来像:
[DataContract]
public class TokenMessage
{
string tokenValue;
string extraValue;
bool enableExtraValue = true;
[DataMember]
public string Extra
{
get {
if (enableExtraValue)
return extraValue;
return null;
}
set { extraValue = value; }
}
[OnSerializing()]
internal void OnSerializingMethod(StreamingContext context)
{
enableExtraValue = false;
}
[OnSerialized()]
internal void OnSerializedMethod(StreamingContext context)
{
enableExtraValue = true;
}
}
解决方案#2是一个快速修复(我认为你正在寻找)。
解决方案#1是更好的设计。
答案 1 :(得分:1)
有一种方法,但我认为这将需要生成额外的DataContract,但仍然不需要针对不同类型的设备进行单独的操作和数据合同。 它可以经典实现到运行时多态。我只想提出想法:
假设你有一个通用的DataContract:
[DataContract]
[KnownType(typeof(Extra))]
[KnownType(typeof(Extra2))]
public class TokenMessage
{
string tokenValue;
string extraValue;
[DataMember]
public string Token
{
get { return tokenValue; }
set { tokenValue = value; }
}
}
其他特定于设备的合同可以将TokenMessage作为基类继承,如:
[DataContract]
public class Extra:TokenMessage
{
[DataMember]
public string Extra
{
get ;set;
}
}
[DataContract]
public class Extra2:TokenMessage
{
[DataMember]
public string Extra2
{
get ;set;
}
}
现在在运行时你说你知道操作合同中的参数,这有助于我们识别设备。假设基于设备类型,您可以使用派生类来实例化基类,如:
TokenMessage tm= new Extra();
OR
TokenMessage tm= new Extra2();
因此,在运行时,您将决定哪个设备合同将成为genric响应的一部分。
注意:添加KnownType
将在wsdl中为基类中的所有已知类型生成单独的xsd,但在运行时保存数据的序列化,因为这应取决于所选的实际继承。
答案 2 :(得分:0)
答案 3 :(得分:-2)
在您的模型中添加属性“ShouldSerializeYOUR_PROPERTY_NAME”,当您不希望序列化属性时将其设置为false。 点击此处:http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.shouldserializeproperty(v=vs.110).aspx