繁体   English   中英

ServiceKnownType无法按预期工作

[英]ServiceKnownType not working as expected

我有一个服务合同界面,如下所示:

[ServiceKnownType(typeof(GeometricModelDescriptor))]
[ServiceKnownType(typeof(TemplateModelDescriptor))]
[ServiceContract]
public interface IModelRepository
{
    [OperationContract]
    ModelDescriptor GetDescriptor(ModelHandle model);
}

它使用一些简单的数据合同类型,如下所示:

[DataContract]
public class ModelDescriptor
{
    //...
}

[DataContract]
public sealed class GeometricModelDescriptor : ModelDescriptor
{
    //...
}

当我尝试调用GetDescriptor方法时,出现一个序列化异常,指示客户端代理无法反序列化类型:

元素' http://tempuri.org/:GetDescriptorResult '包含来自映射到名称'MyNamespace:GeometricModelDescriptor'的类型的数据。 解串器不知道任何映射到该名称的类型。 考虑使用DataContractResolver或将与“ GeometricModelDescriptor”相对应的类型添加到已知类型的列表中-例如,通过使用KnownTypeAttribute属性或将其添加到传递给DataContractSerializer的已知类型的列表中。

我的理解是ServiceKnownType属性应防止出现此异常。 我想念什么?


人们要求提供客户代码。 涉及到一点,但这是生成客户端代理包装器的逻辑的症结所在:

                var baseType = typeof(ClientBase<>).MakeGenericType(typeof(TService));
                var proxyType = _module.DefineType("ProxyType" + typeof(TService).Name,
                                                     TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public,
                                                     baseType,
                                                     new[] { typeof(TService) });
                var constructor = proxyType.DefineConstructor(MethodAttributes.Public,
                                                              CallingConventions.HasThis,
                                                              new[] { typeof(ServiceEndpoint)});
                var il = constructor.GetILGenerator();
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Call, baseType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
                                                              null,
                                                              new[] {typeof(ServiceEndpoint)},
                                                              null));
                il.Emit(OpCodes.Ret);

                var interfaces = FlattenInterfaces(typeof(TService)).ToList();
                foreach (var interfaceType in interfaces)
                {
                    BuildInterfaceMethods(typeof(TService), proxyType, interfaceType);
                }

这将创建ClientBase<IService>子代,该IService也实现IService 接口实现(通过BuildInterfaceMethods构建)通过ClientBase提供的受保护的Channel属性路由每个方法调用。 发出的类与此等效:

    public sealed class ModelRepositoryProxy : ClientBase<IModelRepository>, IModelRepository
    {
        //Constructor omitted for brevity...
        ModelDescriptor IModelRepository.GetDescriptor(ModelHandle model)
        {
            return Channel.GetDescriptor(model);
        }
    }

我最终在构造此答案后不久,通过在客户端上为每种已知服务类型调用AddGenericResolver来使用此答案中概述的解决方案。 这将注册一个知道如何解析指定类型的DataContractSerializerOperationBehavior。 对我来说尚不清楚为什么为什么要让客户端解析类型是必需的,但是它确实有效。

看来您在客户端而不是服务器上有问题。 问题可能是由于生成客户端后添加了ServiceKnownType属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM