代码之家  ›  专栏  ›  技术社区  ›  Rachel

WCF客户端在识别ServiceKnownTypes时遇到问题?

  •  7
  • Rachel  · 技术社区  · 15 年前

    我知道我可以用 [ServiceKnownType] 属性,使服务调用在WCF测试服务器上正常运行,但在客户端仍然失败。我是不是漏了什么?

    [OperationContract]
    [ServiceKnownType(typeof(SubClassA))]
    [ServiceKnownType(typeof(SubClassB))]
    BaseClassZ GetObject();
    

    来自客户端的错误消息是:

    {“元素 包含来自映射到的类型的数据 名字 映射到此名称的任何类型。 考虑使用DataContractResolver “subassa”添加到已知类型列表中 将其添加到已知类型的列表中 已传递到DataContractSerializer。“}

    更新: 如果我将KnownType属性添加到基类中,似乎可以让客户机正确读取对象,但是如果可能的话,我仍在寻找解决方法,因为基类用于许多项,并且我不希望在添加新项时必须修改基类上的KnownType属性。

    [DataContract]
    [KnownType(typeof(SubClassA))]
    [KnownType(typeof(SubClassB))]
    public class BaseClassZ 
    {
        ...
    }
    
    3 回复  |  直到 15 年前
        1
  •  10
  •   Darin Dimitrov    15 年前

    为了避免阻止您的服务代码,请将已知类型放入web.config文件服务范围:

    <system.runtime.serialization>
        <dataContractSerializer>
            <declaredTypes>
                <add type="SomeNs.BaseClassZ, SomeAssembly">
                    <knownType type="SomeNs.SubClassA, SomeAssembly" />
                    <knownType type="SomeNs.SubClassB, SomeAssembly" />
                </add>
            </declaredTypes>
        </dataContractSerializer>
    </system.runtime.serialization>
    

    如果您想通过代码实现,则需要在服务接口上使用此属性,而不是在操作方法上,但我更喜欢声明性方法:

    [ServiceContract]
    [ServiceKnownType(typeof(SubClassA))]
    [ServiceKnownType(typeof(SubClassB))]
    public interface IFoo
    {
        [OperationContract]
        BaseClassZ GetObject();
    }
    

    sample project sample project 演示第二种方法。


    在使用Silverlight应用程序客户端查看更新的代码后,我们注意到以下定义:

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IService1")]
    public interface IService1 {
    
        [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetMany", ReplyAction="http://tempuri.org/IService1/GetManyResponse")]
        System.IAsyncResult BeginGetMany(System.AsyncCallback callback, object asyncState);
    
        System.Collections.ObjectModel.ObservableCollection<MyCommonLib.BaseClassZ> EndGetMany(System.IAsyncResult result);
    
        [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetSingle", ReplyAction="http://tempuri.org/IService1/GetSingleResponse")]
        [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassA))]
        [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassB))]
        System.IAsyncResult BeginGetSingle(System.AsyncCallback callback, object asyncState);
    
        MyCommonLib.BaseClassZ EndGetSingle(System.IAsyncResult result);
    }
    

    注意 BeginGetSingle 方法包含已知的类型属性,而 BeginGetMany

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IService1")]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassA))]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(MyCommonLib.SubClassB))]
    public interface IService1
    {
        [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetMany", ReplyAction="http://tempuri.org/IService1/GetManyResponse")]
        System.IAsyncResult BeginGetMany(System.AsyncCallback callback, object asyncState);
    
        System.Collections.ObjectModel.ObservableCollection<MyCommonLib.BaseClassZ> EndGetMany(System.IAsyncResult result);
    
        [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetSingle", ReplyAction="http://tempuri.org/IService1/GetSingleResponse")]
        System.IAsyncResult BeginGetSingle(System.AsyncCallback callback, object asyncState);
    
        MyCommonLib.BaseClassZ EndGetSingle(System.IAsyncResult result);
    }
    

    因为这是一个自动生成的类,所以在 SLsvcUtil.exe svcutil.exe 因为它表现出同样的行为。将已知的类型属性放在正确的位置可以解决问题。问题是这个类是由一个工具自动生成的,如果您试图从WSDL重新生成它,它会再次出错。

    [ServiceContract]
    [ServiceKnownType(typeof(SubClassA))]
    [ServiceKnownType(typeof(SubClassB))]
    public interface IService1
    {
        [OperationContract]
        BaseClassZ[] GetMany();
    
        [OperationContract]
        BaseClassZ GetSingle();
    }
    

    在导入服务定义时,这里使用的3个数据协定在客户机和服务器之间共享,返回集合的方法无法在生成的客户机代理中获得正确的已知类型属性。也许这是故意的。

        2
  •  1
  •   Hastarin    14 年前

    注意:.NET 4.0是必需的,因为它使用 DataContractResolver

    IDesign Downloads page .

    我要做的就是添加以下代码行:

    Client.AddGenericResolver( typeof ( K2Source ) );
    

    您可以在juvallowy的《编程WCF服务:掌握WCF和azureappfabric服务总线》一书中找到更多信息

        3
  •  0
  •   Shiraz Bhaiji    15 年前

    请参见: http://www.dnrtv.com/default.aspx?showNum=122

    注意:只有在同时控制服务器和客户机的情况下,这才有效。

    推荐文章