WCF silently fails to deserialize list if item types don't match
Asked Answered
B

0

6

With WCF, assume the following service interface:

[ServiceContract]
public interface IForDataTypeA
{
    [OperationContract]
    List<DataTypeA> GetValues();
}

[DataContract]
public class DataTypeA { }

This is how it's defined on the server side (service host).

Now, someone - with no access to the server's source code - tries to use this WCF service. He defines the service interface himself but accidentally changes the name of the data type to DataTypeB:

[ServiceContract]
public interface IForDataTypeA
{
    [OperationContract]
    List<DataTypeB> GetValues();
}

[DataContract]
public class DataTypeB { }

When he now calls GetValues() (via ChannelFactory<IForDataTypeA>) the returned list will always be empty but no exception is thrown.

Is there a way to make WCF throw an exception when the elements in the list can't be deserialized (instead of returning an empty list)?


Here's the complete code to reproduce the problem:

using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace TestProj
{
    [DataContract]
    public class DataTypeA { }

    [DataContract]
    public class DataTypeB { }

    [ServiceContract]
    public interface IForDataTypeA
    {
        [OperationContract]
        List<DataTypeA> GetValues();
    }

    [ServiceContract(Name = "IForDataTypeA")]
    public interface IForDataTypeB
    {
        [OperationContract]
        List<DataTypeB> GetValues();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    internal class ServiceImpl : IForDataTypeA
    {
        public List<DataTypeA> GetValues()
        {
            return new List<DataTypeA>
            {
                new DataTypeA(),
                new DataTypeA(),
            };
        }
    }

    class Program
    {
        static void Main()
        {
            var serviceHost = new ServiceHost(new ServiceImpl());
            var binding = new NetTcpBinding();
            var endpointUrl = "net.tcp://127.0.0.1:5555/MyService";

            serviceHost.AddServiceEndpoint(typeof(IForDataTypeA), binding, endpointUrl);
            serviceHost.Open();

            var channelFactory = new ChannelFactory<IForDataTypeB>(binding, endpointUrl);
            var channel = channelFactory.CreateChannel();

            List<DataTypeB> values = channel.GetValues();
            // values will always be empty
        }
    }
}
Bowery answered 11/6, 2014 at 11:34 Comment(3)
This is a versioning feature. It allows you to change the service definition without breaking callers. One day you'll be thankful for this. On the other hand your request is totally valid as a debugging aid.Luthanen
Ideally Service interface should be shared with clients. What if you give Name to DataContract["Name="TypeA"] , tried this ?Andri
@AjayKelkar Yes, this will work. (He could also rename the class.) But that's not the point. The point is that the developer changed the name by mistake but doesn't get any error from this.Bowery

© 2022 - 2024 — McMap. All rights reserved.