使用DataContractJsonSerializer进行部分序列化

时间:2015-03-26 09:28:42

标签: c# wcf serialization

我在旧版WCF服务中使用了以下类

[MessageContract()]
public class Document
{
    [MessageHeader(MustUnderstand = true)]
    public MetaData Data { get; set; }

    [MessageHeader(MustUnderstand = true)]
    public string Name { get; set; }

    [MessageBodyMember(Order = 1)]
    public Stream File { get; set; }
}

这是一个名为AddDocument的方法,用于将文档推送到商店。

在过去的某个时刻,我通过Castle.Windsor拦截器添加了对我们所有服务的日志记录,这些拦截器序列化了传递的数据,以便跟踪传递给服务的内容。

public void Intercept(IInvocation invocation)
{
    Logger.Debug(() =>
    {
        StringBuilder sb = new StringBuilder(1000);
        sb.AppendFormat("{2} -> {0}.{1}(", invocation.TargetType.Name, invocation.Method.Name, SomeCode);
        sb.Append(string.Join(", ", invocation.Arguments.Select(a => a == null ? "null" : DumpObject(a)).ToArray()));
        sb.Append(")");
        return sb.ToString();
    });

    invocation.Proceed();

    Logger.Debug(() =>
    {
        StringBuilder sb = new StringBuilder(1000);
        sb.AppendFormat("OUT {0}", invocation.ReturnValue != null ? DumpObject(invocation.ReturnValue) : "void");
        return sb.ToString();
    });
}

使用DumpObject

DataContractJsonSerializer中进行序列化
private string DumpObject(object argument)
{
    using (var ms = new MemoryStream())
    {
        try
        {
            var ser = new System.Runtime.Serialization.Json.DataContractJsonSerializer(argument.GetType());
            ser.WriteObject(ms, argument);
            return System.Text.Encoding.UTF8.GetString(ms.GetBuffer(), 0, Convert.ToInt32(ms.Length));
        }
        catch (Exception)
        {
            return "NA";
        }
    }
}

我无法序列化Document类,因为它包含Stream,并且参数始终被序列化为' NA'。但是,我想知道是否可以在没有流的情况下序列化对象的其余部分。

我考虑过更改对象类型只是为了序列化,例如通过将其映射到具有原始对象子集的另一个对象,但是这个解决方案并不让我满意,因为我正在检查和交换一个应该是非常低调的操作的大量数据。

1 个答案:

答案 0 :(得分:1)

这可以通过实施IDataContactSurrogate并将其提供给DataContractJsonSerializer来完成。

var settings = new DataContractJsonSerializerSettings() { DataContractSurrogate = new SkipStreamSurrogate()};
var serializer = new DataContractJsonSerializer(argument.GetType(), settings);

serializer.WriteObject(ms, argument);

实现:

public sealed class SkipStreamSurrogate : IDataContractSurrogate
{
    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        return null;
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
    {
        return null;
    }

    public Type GetDataContractType(Type type)
    {
        return type;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        return obj;
    }

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
    {
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        // Skip serialization of a System.Stream
        if (obj is Stream)
        { return null; }

        return obj;
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        return null;
    }

    public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
    {
        return typeDeclaration;
    }
}