WCF:具有共享服务契约的客户端上的 IEnumerable 实现

WCF: IEnumerable implementation on client side with shared servicecontract

提问人:Charles HETIER 提问时间:8/29/2013 最后编辑:Charles HETIER 更新时间:8/31/2013 访问量:567

问:

我有一个应用程序,它使用 WCF 与客户端和服务之间的共享服务协定进行通信。 对于此类服务合同:

[ServiceContract]
public interface IMyContract
{
    [OperationContract]
    IEnumerable<string> MyOperation();
}

IEnumerable 的默认实现是 Array,我想将实现自定义为另一个实现:例如 List、Hashset......

我的客户端代理不是自动生成的(所以没有 svcmap 文件),我不想在我的协定中更改另一种类型的 IEnumerable(因此,据我所知 WCF 反序列化,已知类型在这种情况下不起作用,CollectionDataContractAttribute...是吗?

由于我已经创建了一个 RealProxy 包装通道生成(用于回收管理),因此我现在可以拦截其中的结果以动态更改收集类型......

但是,也许有一种方法可以以某种方式影响反序列化,以便在客户端选择 IEnumerable 的实现,而无需从头开始创建我自己的序列化程序或类似的东西。

如果我的问题不清楚,请不要犹豫,我的问题是由于某个地方的不良方法造成的。

提前致谢!

更新:陪审团Soldatenkov为我指出了一个很好的解决方案!

这是我允许选择 IEnumerable 实现的 POC:

private class CustomDataContractResolver<TCollection> : DataContractResolver where TCollection : class, IEnumerable<object>
{
    /// <summary>
    /// Maps a data contract type to an xsi:type name and namespace during serialization.
    /// </summary>
    /// <param name="type">The type to map.</param>
    /// <param name="declaredType">The type declared in the data contract.</param>
    /// <param name="knownTypeResolver">The known type resolver.</param>
    /// <param name="typeName">The xsi:type name.</param>
    /// <param name="typeNamespace">The xsi:type namespace.</param>
    /// <returns>
    /// true if mapping succeeded; otherwise, false.
    /// </returns>
    public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
    {
        if (declaredType != null 
            && declaredType.IsGenericType 
            && declaredType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        {
            typeName = new XmlDictionary().Add(typeof(IEnumerable<>).Name);
            typeNamespace = new XmlDictionary().Add("custom");
            return true;
        }

        return knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace);
    }

    /// <summary>
    /// Maps the specified xsi:type name and namespace to a data contract type during deserialization.
    /// </summary>
    /// <param name="typeName">The xsi:type name to map.</param>
    /// <param name="typeNamespace">The xsi:type namespace to map.</param>
    /// <param name="declaredType">The type declared in the data contract.</param>
    /// <param name="knownTypeResolver">The known type resolver.</param>
    /// <returns>
    /// The type the xsi:type name and namespace is mapped to.
    /// </returns>
    public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
    {
        if (typeNamespace == "custom" 
            && typeName == typeof(IEnumerable<>).Name)
        {
            var argumentType = declaredType.GetGenericArguments()[0];
            var collectionType = typeof(TCollection).GetGenericTypeDefinition().MakeGenericType(argumentType);
            return collectionType;
        }

        return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? declaredType;
    }
}

我不想更改 IEnumerable 的序列化方式,但如果我不更改 IEnumerable 序列化,则不会为枚举调用反序列化方法。 这就是为什么我选择“custom”作为命名空间,我应该将所有自定义内容放在 message 中......希望这不是一个糟糕的方式...... 我想我也应该在名称中使用 IEnumerable 的全名,但我对上下文中的带宽有一些担忧。

我以这种方式使用我的 CustomDataContractResolver:

private class CustomDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
    [...]

    public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
    {
        return new DataContractSerializer(type, [...], new CustomDataContractResolver<HashSet<object>>());
    }
}
C# .NET WCF 反序列化 客户端

评论

0赞 Jury Soldatenkov 8/30/2013
您尝试过ServiceKnownTypeAttribute吗?
0赞 Charles HETIER 8/30/2013
感谢您的关注。我已经尝试过 List<object>、List<string>,如果合约仍然公开 IEnumerable,它不会改变任何内容......
1赞 Jury Soldatenkov 8/30/2013
接口没有任何状态,它描述行为。但是你唯一可以通过电报发送的是状态。这种冲突不容易解决。我可以建议的唯一解决方法 DataContractResolver。如果客户端和服务器都使用相同的 .NET 库,它将起作用。
0赞 Charles HETIER 8/30/2013
没有真正理解界面上的状态:-)但是 DataContractResolver 是一个非常好的建议!我将使用我的 POC 解决方案更新帖子。谢谢!

答: 暂无答案