none
WCF client generation fails when reusing types in portable library (code reproducing error included in question) RRS feed

  • Question

  • Hi!

    I have some sample code here that demonstrates how WCF client generation fails. Switching base class for the Price class will make or break the code generation and I do not understand why.

    The WCF Service project contains the following single code file. It's a console application.

    using System;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    using System.Text;
    using Wcf.DM;
    
    namespace WcfService
    {
        [ServiceContract]
        public interface ISampleService
        {
            [OperationContract]
            RiskGroup[] GetRiskGroups();
    
            [OperationContract]
            Price[] GetSpanPrices();
        }
    
        public class SampleService : ISampleService
        {
            public RiskGroup[] GetRiskGroups()
            {
                return new RiskGroup[0];
            }
    
            public Price[] GetSpanPrices()
            {
                return new Price[0];
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var binding = new BasicHttpBinding
                {
                    Name = "MyBinding",
                    TextEncoding = Encoding.UTF8,
                    TransferMode = TransferMode.Buffered,
                };
    
                Uri baseAddress = new Uri("http://localhost:9997/SampleService");
                var selfHost = new ServiceHost(typeof(SampleService), baseAddress);
                selfHost.AddServiceEndpoint(typeof(ISampleService), binding, "MyEndpoint");
                
                // Enable Mex
                ServiceMetadataBehavior smb = new ServiceMetadataBehavior {HttpGetEnabled = true};
                selfHost.Description.Behaviors.Add(smb);
    
                // Start the service
                selfHost.Open();
    
                Console.WriteLine("The service is ready.");
                Console.WriteLine("Press <ENTER> to terminate service.");
                Console.WriteLine();
                Console.ReadLine();
    
                selfHost.Close();
            }
        }
    }
    

    The datamodel is also a single code file and should be placed in a default portable class library (vs2013).

    using System.Runtime.Serialization;
    
    namespace Wcf.DM
    {
        [DataContract(IsReference = true)]
        public class NamedObject : Object
        {
            [DataMember]
            public string Name { get; set; }
        }
    
        [DataContract(IsReference = true)]
        public class Object
        {
            [DataMember]
            public int Id { get; set; }
        }
    
        [DataContract(IsReference = true)]
        public class RiskGroup : NamedObject
        {
        }
    
        [DataContract(IsReference = true)]
        public class Product : NamedObject
        {
        }
    
        [DataContract(IsReference = true)]
        //public class Price : NamedObject
        public class Price : Object
        {
            [DataMember]
            public double Amount { get; set; }
            [DataMember]
            public Product Product { get; set; }
        }
    }
    

    If the Price class inherits from NamedObject it works fine but if it inherits from Object instead generation fails.

    To run this sample simply place the first piece of code in a console application project and the second piece of code in a portable class library project. Then, reference the PCL in the console application. Finally, create a new project, include the PCL and then try to add a service reference. (You need to run the service console app first, naturally, so you have something to connect to.

    Please do not advice me to uncheck "reuse types in referenced assemblies" since reusing those types is exactly what I want to do.

    All other help would be much appreciated.

    Sunday, July 19, 2015 7:08 PM

Answers

  • Hi Måns Tånneryd,

    I try to achieve this issue, but it works fine. So , I'd like to suggest you to  remove the reference and add it again after adding service reference.

    My Test Code like below:

    using (ServiceReference1.SampleServiceClient proxy = new ServiceReference1.SampleServiceClient())
                {
                    ServiceReference1.Price[] prices;
                    prices = proxy.GetSpanPrices();
                    Console.WriteLine("{0},{1},{2},{3}", prices[0].Amount,prices[0].id,prices[0].Product.Name,prices  [0].Product.id);
                    Console.Read();
                }

    public Price[] GetSpanPrices()
            {
                Price[] a = new Price[1];
                Price price = new Price { id = 1, Amount = 10.0, Product = new Product { id=1,Name="Test"} };
                a[0] = price;
                return a;
            }

    I Hope that will be helpful to you.

    Best Regards,

    Tracy Dj


    Best Regards, Tracy Dj

    Wednesday, July 22, 2015 8:15 AM
    Moderator

All replies

  • Could you post the error message you got?
    Monday, July 20, 2015 2:00 PM
  • Detail: An exception was thrown while running a WSDL import extension: System.Se
    rviceModel.Description.DataContractSerializerMessageContractImporter
    Error: Referenced type 'Wcf.DM.Price, Wcf.DM, Version=1.0.0.0, Culture=neutral,
    PublicKeyToken=null' with data contract name 'Price' in namespace 'http://schema
    s.datacontract.org/2004/07/Wcf.DM' cannot be used since it does not match import
    ed DataContract. Need to exclude this type from referenced types.
    XPath to Error Source: //wsdl:definitions[@targetNamespace='http://tempuri.org/'
    ]/wsdl:portType[@name='ISampleService']
    Tuesday, July 21, 2015 1:55 PM
  • Hi Måns Tånneryd,

    I try to achieve this issue, but it works fine. So , I'd like to suggest you to  remove the reference and add it again after adding service reference.

    My Test Code like below:

    using (ServiceReference1.SampleServiceClient proxy = new ServiceReference1.SampleServiceClient())
                {
                    ServiceReference1.Price[] prices;
                    prices = proxy.GetSpanPrices();
                    Console.WriteLine("{0},{1},{2},{3}", prices[0].Amount,prices[0].id,prices[0].Product.Name,prices  [0].Product.id);
                    Console.Read();
                }

    public Price[] GetSpanPrices()
            {
                Price[] a = new Price[1];
                Price price = new Price { id = 1, Amount = 10.0, Product = new Product { id=1,Name="Test"} };
                a[0] = price;
                return a;
            }

    I Hope that will be helpful to you.

    Best Regards,

    Tracy Dj


    Best Regards, Tracy Dj

    Wednesday, July 22, 2015 8:15 AM
    Moderator