Problem with knowntype attribute in wcf
Asked Answered
S

2

6

I'm having the following error in my wcf client.

NetDispatcherFaultException was unhandled.

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:GetVehicleResult. The InnerException message was 'Error in line 1 position 266. Element 'http://tempuri.org/:GetVehicleResult' contains data from a type that maps to the name 'http://schemas.datacontract.org/2004/07/WCFServer:Car'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'Car' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.

Can anyone help me where is the fault.

WCF Server


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

    [OperationContract]
    int GetNumberOfWheels(Vehicle vehicle);
}

VehicleService


[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;
    }
}

abstract class


[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; }
}

concrete classes


[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 Client


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);          
}

just creating proxy in client side . I can able to call the service successfully, but in response im having the problem. I try with Knowntype attribute. Whats wrong in this.

Splutter answered 23/8, 2011 at 11:44 Comment(0)
P
7

The following code work fine without error.

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 file:

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

Testing service:

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);
        }
    }
}
Paulpaula answered 30/8, 2011 at 12:45 Comment(2)
@rgpmaker- Im selfhosting instead of svcutil. But im getting the same error.Splutter
Im having the abstract class car,bike in both client and server side but the actual implementation in Server side,dummy in client side.Splutter
P
6

The KnownType should be used on the service contract interface itself not the vehicle class since it is the one that is returning the Vehicle object for one of its operations. Adding KnownType to the Vehicle class does nothing I think. because by default now, you don't need to add DataContract to your class for them to be useable in WCF. so you should have something like below.

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

    [OperationContract]
    int GetNumberOfWheels(Vehicle vehicle);
}
Paulpaula answered 23/8, 2011 at 12:55 Comment(6)
I have tried out that also. But still getting the same error.Splutter
Can anyone suggest some example using knowntype attribute using wcf client (code level client Proxy,client side stub) to call wcf sevice and get the response.Splutter
That should have worked, since you are telling the service what type would be expected. Remember that you need to have the ServiceKnownType Attribute on both the server side and the client side service contract interface. Also remember that you don't need knowntype attribute on the Vehicle class, you only need it on a class that has a property that uses the Vehicle Type has its return type. refer to this link on ServiceKnownType, msdn.microsoft.com/en-us/library/…Paulpaula
I removed all knowntype attribute from the vehicle class. I added ServiceKnownType in both client side and server side interfaces.Finally, Server side has above mentioned interface,concrete class implementing the interface and the abstract class(vehicle) and its child classes. In Client side, same interface and the abstract class(vehicle) and its child classes with no implementations (like stub).My button event has the following code , string iport ="192.168.86.206:8080"Splutter
BasicHttpBinding hproxy = new BasicHttpBinding(); hproxy.MaxReceivedMessageSize = 2147483647; hproxy.MaxBufferSize = 2147483647; hproxy.MaxBufferPoolSize = 2147483647; EndpointAddress eaddrr = new EndpointAddress("http://" + iport + "//cvehicle"); ChannelFactory<IVehicleService> CFactoryobj1 = new ChannelFactory<IVehicleService>(hproxy, eaddrr); IVehicleService isclientobj1 =Factoryobj1.CreateChannel(); Car ve = (Car)isclientobj1.GetVehicle(0);Splutter
I just had that error, and [ServiceKnownType(...)] on the interface solved it, thank you!Farinaceous

© 2022 - 2024 — McMap. All rights reserved.