【问题标题】:Problem with knowntype attribute in wcfwcf 中 knowntype 属性的问题
【发布时间】:2011-08-23 11:44:34
【问题描述】:

我的 wcf 客户端出现以下错误。

NetDispatcherFaultException 未处理。

格式化程序在尝试反序列化消息时抛出异常:尝试反序列化参数http://tempuri.org/:GetVehicleResult 时出错。 InnerException 消息是“第 1 行位置 266 中的错误。元素“http://tempuri.org/:GetVehicleResult”包含映射到名称“http://schemas.datacontract.org/2004/07/WCFServer:Car”的类型的数据。反序列化器不知道映射到此名称的任何类型。考虑使用 DataContractResolver 或将与“Car”对应的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将其添加到传递给 DataContractSerializer 的已知类型列表中。有关详细信息,请参阅 InnerException。

谁能帮我看看哪里错了。

WCF 服务器


IVehicle
--------
[ServiceContract]   
public interface IVehicleService
{
    [OperationContract]
    Vehicle GetVehicle(int type);

    [OperationContract]
    int GetNumberOfWheels(Vehicle vehicle);
}

车辆服务


[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]   
public class VehicleService : IVehicleService
{        
    public Vehicle GetVehicle(int type)
    {
        switch (type)
        {
            case 0:
                return new Car()
                {
                   ID = 10,
                   Brand = "Volvo",
                   SteeringWheelPosition = "left"
                };

            case 1:
                return new bike()
                {
                    ID = 11,
                    Brand = "Scott",
                    HasFrontWheelBreak = true
                };

            case 2:
                return new Kidsbike()
                {
                    ID = 12,
                    Brand = "Kid Scott",
                    HasFrontWheelBreak = false,
                    HasSupportingWheels = true
                };

            default:
                return null;
        }
    }

    public int GetNumberOfWheels(Vehicle vehicle)
    {
        return vehicle.NoOfWheels;
    }
}

抽象类


[KnownType(typeof(Car))]
[KnownType(typeof(bike))]
[DataContract]
public abstract class Vehicle
{       
    [DataMember]
    public int ID { get; set; }

    abstract public int NoOfWheels { get; }

    [DataMember]
    public string Brand { get; set; }
}

具体类


[DataContract]
public class Car : Vehicle
{          
    override public int NoOfWheels { get { return 4; } }
    [DataMember]
    public string SteeringWheelPosition { get; set; }  
}

[KnownType(typeof(Kidsbike))]
[DataContract]
public class bike : Vehicle 
{           
    override public int NoOfWheels { get { return 2; } }
    [DataMember]
    public bool HasFrontWheelBreak { get; set; }  
}

[DataContract]
public class Kidsbike : bike
{
    [DataMember]
    public bool HasSupportingWheels { get; set; }  
}

WCF 客户端


namespace WCFClient
{
    [ServiceContract]   
    public interface IVehicleService
    {
        [OperationContract]       
        Vehicle GetVehicle(int type);

        [OperationContract]       
        int GetNumberOfWheels(Vehicle vehicle);
    } 
}

namespace WCFClient
{
    [KnownType(typeof(Car))]
    [KnownType(typeof(bike))]
    [DataContract]
    public abstract class Vehicle
    {
        [DataMember]
        public int ID { get; set; }

        abstract public int NoOfWheels { get; }
        [DataMember]
        public string Brand { get; set; }
    }
    [DataContract]
    public class Car : Vehicle
    {
        override public int NoOfWheels { get { return 0; } }
        [DataMember]
        public string SteeringWheelPosition { get; set; }
    }

    [KnownType(typeof(Kidsbike))]
    [DataContract]
    public class bike : Vehicle
    {
        override public int NoOfWheels { get { return 0; } }
        [DataMember]
        public bool HasFrontWheelBreak { get; set; }
    }
    [DataContract]
    public class Kidsbike : bike
    {
        [DataMember]
        public bool HasSupportingWheels { get; set; }
    }
}

private void btnGetVehicle_Click(object sender, EventArgs e)
{
    Car carObj = (Car)fclient.GetVehicle(0);          
}

只是在客户端创建代理。我可以成功调用该服务,但作为响应,我遇到了问题。我尝试使用 Knowntype 属性。这有什么问题。

【问题讨论】:

    标签: wcf known-types


    【解决方案1】:

    以下代码可以正常工作,没有错误。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.Text;
    
    namespace WcfService1 {
        [ServiceKnownType(typeof(Car))]
        [ServiceKnownType(typeof(bike))]
        [ServiceKnownType(typeof(Kidsbike))]
        [ServiceContract]
        public interface IVehicleService {
            [OperationContract]
            Vehicle GetVehicle(int type);
    
            [OperationContract]
            int GetNumberOfWheels(Vehicle vehicle);
        }
    
          [DataContract]
        public abstract class Vehicle
        {
            [DataMember]
            public int ID { get; set; }
    
            abstract public int NoOfWheels { get; }
            [DataMember]
            public string Brand { get; set; }
        }
        [DataContract]
        public class Car : Vehicle
        {
            override public int NoOfWheels { get { return 0; } }
            [DataMember]
            public string SteeringWheelPosition { get; set; }
        }
    
        [KnownType(typeof(Kidsbike))]
        [DataContract]
        public class bike : Vehicle
        {
            override public int NoOfWheels { get { return 0; } }
            [DataMember]
            public bool HasFrontWheelBreak { get; set; }
        }
        [DataContract]
        public class Kidsbike : bike
        {
            [DataMember]
            public bool HasSupportingWheels { get; set; }
        }
    
    [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]   
    public class VehicleService : IVehicleService
    {        
        public Vehicle GetVehicle(int type)
        {
            switch (type)
            {
                case 0:
                    return new Car()
                    {
                       ID = 10,
                       Brand = "Volvo",
                       SteeringWheelPosition = "left"
                    };
    
                case 1:
                    return new bike()
                    {
                        ID = 11,
                        Brand = "Scott",
                        HasFrontWheelBreak = true
                    };
    
                case 2:
                    return new Kidsbike()
                    {
                        ID = 12,
                        Brand = "Kid Scott",
                        HasFrontWheelBreak = false,
                        HasSupportingWheels = true
                    };
    
                default:
                    return null;
            }
        }
    
        public int GetNumberOfWheels(Vehicle vehicle)
        {
            return vehicle.NoOfWheels;
        }
    }
    
    }
    

    Svc 文件:

    <%@ ServiceHost Language="C#" Debug="true" Service="WcfService1.VehicleService" CodeBehind="Service1.svc.cs" %>
    

    测试服务:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using WcfService1;
    
    namespace Test {
        class Program {
            static void Main(string[] args) {
                BasicHttpBinding hproxy = new BasicHttpBinding();
                hproxy.MaxReceivedMessageSize = 2147483647;
                hproxy.MaxBufferSize = 2147483647;
                hproxy.MaxBufferPoolSize = 2147483647;
                EndpointAddress eaddrr = new EndpointAddress("http://localhost:62807/Service1.svc");
                ChannelFactory<IVehicleService> CFactoryobj1 = new ChannelFactory<IVehicleService>(hproxy, eaddrr);
                IVehicleService isclientobj1 = CFactoryobj1.CreateChannel(); 
                Car ve = (Car)isclientobj1.GetVehicle(0);
            }
        }
    }
    

    【讨论】:

    • @rgpmaker- 我是自托管而不是 svcutil。但我得到了同样的错误。
    • 我在客户端和服务器端都有抽象类 car,bike,但在服务器端实际实现,在客户端是虚拟的。
    【解决方案2】:

    KnownType 应该用在服务契约接口本身而不是车辆类上,因为它是为其一项操作返回 Vehicle 对象的类。我认为将 KnownType 添加到 Vehicle 类中没有任何作用。因为现在默认情况下,您不需要将 DataContract 添加到您的类中,它们就可以在 WCF 中使用。所以你应该有类似下面的东西。

    [ServiceKnownType(typeof(Car))]
    [ServiceKnownType(typeof(bike))]
    [ServiceKnownType(typeof(Kidsbike))]
    [ServiceContract]   
    public interface IVehicleService
    {
        [OperationContract]
        Vehicle GetVehicle(int type);
    
        [OperationContract]
        int GetNumberOfWheels(Vehicle vehicle);
    }
    

    【讨论】:

    • 我也试过了。但仍然遇到同样的错误。
    • 谁能建议一些使用 knowntype 属性的示例,使用 wcf 客户端(代码级客户端代理,客户端存根)来调用 wcf 服务并获取响应。
    • 这应该是可行的,因为您正在告诉服务预期的类型。请记住,您需要在服务器端和客户端服务合同接口上都有 ServiceKnownType 属性。另请记住,您不需要 Vehicle 类的 knowntype 属性,您只需要具有使用 Vehicle 类型的属性的类具有其返回类型。请参阅 ServiceKnownType 上的此链接,msdn.microsoft.com/en-us/library/…
    • 我从车辆类中删除了所有 knowntype 属性。我在客户端和服务器端的接口中都添加了ServiceKnownType。最后,服务器端有上面提到的接口,实现接口的具体类和抽象类(车辆)及其子类。在客户端,相同的接口和抽象类(车辆)及其子类没有实现(如存根)。我的按钮事件有以下代码,字符串 iport ="192.168.86.206:8080"
    • BasicHttpBinding hproxy = new BasicHttpBinding(); hproxy.MaxReceivedMessageSize = 2147483647; hproxy.MaxBufferSize = 2147483647; hproxy.MaxBufferPoolSize = 2147483647; EndpointAddress eaddrr = new EndpointAddress("http://" + iport + "//cvehicle"); ChannelFactory CFactoryobj1 = new ChannelFactory(hproxy, eaddrr); IVehicleService isclientobj1 =Factoryobj1.CreateChannel(); Car ve = (Car)isclientobj1.GetVehicle(0);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多