我想制定一个人为的方案,但它具有坚实的实际基础。想象一个集合类型COuter,它是另一个集合类型CInner的实例的包装器。两者都实现了IList(更别提了T)。
此外,COuter实例被隐藏在一些对象图中,其根(我们将其称为R)从WCF服务方法返回。
我的问题是如何自定义WCF序列化过程,以便在返回R时,序列化COuter实例的请求将通过我的代码路由,这将提取CInner并将其传递给序列化器。因此,接收端仍然获得R,只在对象图中找不到COuter实例。
我希望How does WCF serialize the method call?将包含答案,遗憾的是,那里提到的文章(http://msdn.microsoft.com/en-us/magazine/cc163569.aspx)几乎没有提到使用IDataContractSurrogate接口可以实现高级序列化方案,但没有给出详细信息。另一方面,我真的很想看到一个有效的例子。
非常感谢你。
修改
我创建了一个简单的WCF示例,它演示了这个问题。存档位于此处 - https://docs.google.com/leaf?id=0B2pbsdBJxJI3NzFiNjcxMmEtMTM5Yy00MWY2LWFiMTUtNjJiNjdkYTU1ZTk4&sort=name&layout=list&num=50
它包含三个小项目:
该服务定义了一个方法,该方法返回HelloServiceResult
类型的实例,其中包含对COuterList
类型的引用,该类型包含CInnerList
类型。该引用被指定为IMyListInterface
,其中COuterList
和CInnerList
都实现了此接口。我需要的是,当结果在传输到客户端之前被序列化时,COuterList
引用将被包装的CInnerList
引用替换。我知道这可以通过利用WCF的现有功能来完成,我只是不知道如何。
答案 0 :(得分:8)
以下是您实施自己的代理人的方法:
class YourCustomTypeSurrogate : IDataContractSurrogate
{
public Type GetDataContractType(Type type)
{
// Just for reference
//if (typeof(OldType).IsAssignableFrom(type))
//{
// return typeof(NewType);
//}
return type;
}
public object GetObjectToSerialize(object obj, Type targetType)
{
// This method is called on serialization.
//if (obj is OldType)
//{
// // ... use the XmlSerializer to perform the actual serialization.
// NewType newObj = new NewType();
// return newObj;
//}
return obj;
}
public object GetDeserializedObject(object obj, Type targetType)
{
// This method is called on deserialization.
// If PersonSurrogated is being deserialized...
//if (obj is NewType)
//{
// OldType newObj = new OldType();
// return newObj;
//}
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
// This method is called on schema import.
//if (typeNamespace.Equals("Your Type Namespace"))
//{
// if (typeName.Equals("NewType"))
// {
// return typeof(OldType);
// }
//}
return null;
}
public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
// Not used in this sample.
// You could use this method to construct an entirely
// new CLR type when a certain type is imported, or modify a generated
// type in some way.
return typeDeclaration;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
// Not used in this sample
return null;
}
public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
// Not used in this sample
return null;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
// Not used in this sample
}
}
然后创建自定义序列化程序操作行为:
public class CustomDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public CustomDataContractSerializerOperationBehavior(OperationDescription operationDescription) : base(operationDescription) { }
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractSerializer(
type /*typeof OldType*/,
knownTypes,
int.MaxValue /*maxItemsInObjectGraph */,
false /*ignoreExtensionDataObject*/,
true /*preserveObjectReferences*/,
new YourCustomTypeSurrogate());
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(
type /*typeof OldType*/,
knownTypes,
int.MaxValue /*maxItemsInObjectGraph */,
false /*ignoreExtensionDataObject*/,
true /*preserveObjectReferences*/,
new YourCustomTypeSurrogate());
}
}
之后,您创建一个属性以将上述操作行为应用于操作合同:
public class CustomDataContractFormatAttribute : Attribute, IOperationBehavior
{
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
public void Validate(OperationDescription description)
{
}
private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description)
{
DataContractSerializerOperationBehavior dcs = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcs != null)
description.Behaviors.Remove(dcs);
description.Behaviors.Add(new CustomDataContractSerializerOperationBehavior(description));
}
}
最后,将此属性应用于操作:
[OperationContract]
[CustomDataContractFormat]
void DoWork();
如果要将此应用于整个服务,则可以自定义“服务行为”而不是“操作行为”。
以下是用于创建此示例的参考:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.idatacontractsurrogate.aspx
http://social.msdn.microsoft.com/forums/en-US/wcf/thread/e4d55f3f-86d1-441d-9187-64fbd8ab2b3d/
答案 1 :(得分:0)
你有没有尝试过好的OnSerializingAttribute
?
[Serializable]
[KnownType(typeof(COuterList))]
public class HelloServiceResult
{
public IMyListInterface List;
[OnSerialized]
void OnSerializing(StreamingContext context)
{
if (List is COuterList)
{
List = ((List as COuterList).InnerList as CInnerList);
}
}
}