tags:

views:

67

answers:

2

I have created two WCF Services (Shipping & PDFGenerator). They both, along with my ClientApp, share an assembly named Kyle.Common.Contracts. Within this assembly, I have three classes:

namespace Kyle.Common.Contracts
{
    [MessageContract]
    public class PDFResponse
    {
        [MessageHeader]
        public string fileName { get; set; }
        [MessageBodyMember]
        public System.IO.Stream fileStream { get; set; }
    }

    [MessageContract]
    public class PDFRequest
    {
        [MessageHeader]
        public Enums.PDFDocumentNameEnum docType { get; set; }
        [MessageHeader]
        public int? pk { get; set; }
        [MessageHeader]
        public string[] emailAddress { get; set; }
        [MessageBodyMember]
        public Kyle.Common.Contracts.TrackItResult[] trackItResults { get; set; }
    }

    [DataContract(Name = "TrackResult", Namespace = "http://kyle")]
    public class TrackResult
    {
        [DataMember]
        public int SeqNum { get; set; }
        [DataMember]
        public int ShipmentID { get; set; }
        [DataMember]
        public string StoreNum { get; set; }
    }
}

My PDFGenerator ServiceContract looks like:

namespace Kyle.WCF.PDFDocs
{
    [ServiceContract(Namespace="http://kyle")]
    public interface IPDFDocsService
    {
        [OperationContract]
        PDFResponse GeneratePDF(PDFRequest request);

        [OperationContract]
        void GeneratePDFAsync(Kyle.Common.Contracts.Enums.PDFDocumentNameEnum docType, int? pk, string[] emailAddress);

        [OperationContract]
        Kyle.Common.Contracts.TrackResult[] Test();
    }
}

If I comment out the GeneratePDF stub, the proxy generated by VS2010 realizes that Test returns an array of Kyle.Common.Contracts.TrackResult. However, if I leave GeneratePDF there, the proxy refuses to use Kyle.Common.Contracts.TrackResult, and instead creates a new class, ClientApp.PDFDocServices.TrackResult, and uses that as the return type of Test.

Is there a way to force the proxy generator to use Kyle.Common.Contracts.TrackResult whenever I use a MessageContract? Perhaps there's a better method for using a Stream and File Name as return types?

I just don't want to have to create a Copy method to copy from ClientApp.PDFDocServices.TrackResult to Kyle.Common.Contracts.TrackResult, since they should be the exact same class.

Thanks in advance, Kyle

A: 

You can instruct Visual Studio to re-use classes from referenced assemblies. So if your test project has an assembly reference to the Kyle.Common.Contracts assembly, it should re-use those types defined in there rather than adding new client-side proxy classes.

The switch to enable this is on the Advanced page in the Add Service Reference dialog window - it should be on by default:

alt text

Make sure that your project

  • has an assembly reference to the common data contract assembly
  • that this setting is really ON when you add the service reference
marc_s
marc, thanks for the prompt reply. I've double-checked this, and it is DEFINITELY checked.If I comment out the OperationContract that uses MessageContracts, and update my reference in my client, the client will use the correct assembly.However, as soon as I uncomment that OperationContract and then again update my reference, the client creates the new class.This makes me think it has something to do with the way MessageContracts work.
DaleyKD
@DaleyKD: ok, interesting to hear - I never use MessageContracts myself, so I can't really tell from my own experience what could cause this behavior. Seems a bit odd, though....
marc_s
A: 

After a lot of extra digging, I realize that it was actually the Enum that "broke" it. It has do with the way DataContractSerializer works vs. XmlSerializer. Long story short, the solution was to turn the Enum into a nullable.

[MessageContract]
public class PDFRequest
{
    [MessageHeader]
    public Enums.PDFDocumentNameEnum? docType { get; set; }
    [MessageHeader]
    public int? pk { get; set; }
    [MessageHeader]
    public string[] emailAddress { get; set; }
    [MessageBodyMember]
    public Kyle.Common.Contracts.TrackItResult[] trackItResults { get; set; }
}
DaleyKD