C# 自定义值类型的DataContractSerializer
我有一个WCF服务,它公开了一个类型C# 自定义值类型的DataContractSerializer,c#,wcf,datacontractserializer,C#,Wcf,Datacontractserializer,我有一个WCF服务,它公开了一个类型TestTypeOne,该类型当前有一个名为ProductId的字符串属性: 公共类TestTypeOne { [DataMember(Name=“ProductId”)] 公共字符串ProductId{get;set;}//注意,它现在是一个字符串 } 我想将此属性的类型从string更改为名为ProductId的自定义值类型,但不破坏WCF契约(这仅适用于服务器端,客户端仍应将ProductId视为字符串。) 公共类TestTypeOne { [Data
TestTypeOne
,该类型当前有一个名为ProductId
的字符串属性:
公共类TestTypeOne
{
[DataMember(Name=“ProductId”)]
公共字符串ProductId{get;set;}//注意,它现在是一个字符串
}
我想将此属性的类型从string
更改为名为ProductId
的自定义值类型,但不破坏WCF契约(这仅适用于服务器端,客户端仍应将ProductId
视为字符串。)
公共类TestTypeOne
{
[DataMember(Name=“ProductId”)]
public ProductId ProductId{get;set;}
}
自定义类型如下所示(为简洁起见,删除了大多数代码):
public struct ProductId:IEquatable
{
只读字符串productId;
公共产品ID(字符串ProductId)
{
this.productId=productId
}
公共重写字符串ToString()=>productId??string.Empty;
}
使用以下测试代码:
var sb=new StringBuilder();
使用(var writer=newXMLTextWriter(newStringWriter(sb)))
{
var dto=新的TestTypeOne{
ProductId=新ProductId(“1234567890123”)
};
var serializer=新的DataContractSerializer(typeof(TestTypeOne));
serializer.WriteObject(writer,dto);
writer.Flush();
}
Console.WriteLine(sb.ToString());
序列化时的预期输出应为:
1234567890123
我已经尝试过实现ISerializable
,但这似乎只让我控制ProductId
xml标记的内容,而不是标记本身(因此我可以实现1234113
之类的事情)
理想情况下,我想对
ProductId
类型本身做点什么,因为这种类型在许多地方和许多合同中都使用。您是否也尝试过将DataContract/DataMember属性添加到此ProductId类中
i、 e:
[DataContract]
public struct ProductId:IEquatable
{
[数据成员]
只读字符串productId;
公共产品ID(字符串ProductId)
{
this.productId=productId
}
公共重写字符串ToString()=>productId??string.Empty;
}
此外,本例中不需要name属性(name=“ProductId”),因为变量名与覆盖它的变量名相同。我认为最简单的方法是实现
IXmlSerializable
:
public struct ProductId : IXmlSerializable
{
readonly string productId;
public ProductId(string productId)
{
this.productId = productId;
}
public override string ToString() => productId ?? string.Empty;
XmlSchema IXmlSerializable.GetSchema() {
return null;
}
void IXmlSerializable.ReadXml(XmlReader reader) {
this = new ProductId(reader.ReadString());
}
void IXmlSerializable.WriteXml(XmlWriter writer) {
writer.WriteString(this.productId);
}
}
要针对这种情况调整WCF xsd生成(强制生成xs:string
)-可以使用数据契约代理生成xsd。例如,您可以使用这样的suggorate:
public class ProductIdSurrogate : IDataContractSurrogate {
public Type GetDataContractType(Type type) {
if (type == typeof(ProductId))
return typeof(string);
return type;
}
public object GetObjectToSerialize(object obj, Type targetType) {
throw new NotImplementedException();
}
public object GetDeserializedObject(object obj, Type targetType) {
throw new NotImplementedException();
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) {
return null;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType) {
return null;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes) {
throw new NotImplementedException();
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) {
throw new NotImplementedException();
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) {
throw new NotImplementedException();
}
}
您可以将这种方法用于序列化本身,但我发现它更复杂
您可以阅读有关代理和WCF的更多信息,最底层有一个示例,说明如何将代理用于WSDL生成端点(“将代理用于元数据导出”部分)。是的,不幸的是,这在xml中产生了:
1234567890123
,与想要的1234567890123
不同,您也需要反序列化此类型吗?@Evk是的,但仍然只在服务器端(因此客户端应该以字符串属性结束,只有服务器正在进行ProductId的转换),这非常接近-序列化和反序列化时的xml是正确的,现在我只需要弄清楚wcf合同(它现在将其标记为值类型,但仍然显式指定类型,而不是使用“xs:string”)@Pondidum我已经添加了一些与此相关的信息。这将涵盖我所追求的-我想我今天在某个时候已经研究了代理,但很明显,它忽略了底部有用的部分。感谢您的帮助:)@Pondidum-您还可以使用获取正确的模式。参见或。
public class ProductIdSurrogate : IDataContractSurrogate {
public Type GetDataContractType(Type type) {
if (type == typeof(ProductId))
return typeof(string);
return type;
}
public object GetObjectToSerialize(object obj, Type targetType) {
throw new NotImplementedException();
}
public object GetDeserializedObject(object obj, Type targetType) {
throw new NotImplementedException();
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) {
return null;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType) {
return null;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes) {
throw new NotImplementedException();
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) {
throw new NotImplementedException();
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) {
throw new NotImplementedException();
}
}
var exporter = new XsdDataContractExporter();
exporter.Options = new ExportOptions();
exporter.Options.DataContractSurrogate = new ProductIdSurrogate();
exporter.Export(typeof(TestTypeOne));