Shai Cohen
Shai Cohen

Reputation: 6249

Application does not recognize WCF service client when reuse types in referenced assemblies

I have a WCF service that uses an external assembly for it's DTOs. The consumer of the service also has a reference to this external assembly. The plan is to use these entities to pass information between the service and the consumer. I have done this multiple times with other services without a problem.

In this case, it is not working. Intellisense recognizes classes that reside in the WCF service (ie: CreateEventRequest), but does not display the standard TrackingServiceClient, meaning there is no way to instantiate the service.

If I uncheck "Reuse types in referenced assemblies", everything works as expected. Although, obviously, I would like to reuse the DTO assembly.

The DTO

[DataContract]
public class SiteTrackingEvent : IExtensibleDataObject
{
    #region Enums

    [DataContract]
    /// <summary>
    /// The different types of action categories that a user can perform
    /// </summary>
    public enum EventTypes
    {
        [EnumMember]
        None = 0,
        [EnumMember]
        Registrant = 1,
        [EnumMember]
        OnlineRequest = 2,
        [EnumMember]
        VTRequest = 3,
        [EnumMember]
        Download = 4,
        [EnumMember]
        ITRequest = 5
    }

    #endregion //Enums

    #region Properties
    [DataMember(Order = 1)]
    [Required]
    public string PolicyNumber { get; set; }
    [DataMember(Order = 2)]
    public EventTypes EventType { get; set; }
    [DataMember(Order = 3)]
    public string EventTypeDescription { get; set; }
    [DataMember(Order = 4)]
    public string PolicyOwnerSsnTin { get; set; }
    [DataMember(Order = 5)]
    public string PolicyOwnerName { get; set; }
    [DataMember(Order = 6)]
    public string SourcePath { get; set; }
    [DataMember(Order = 7)]
    public string SourceNumber { get; set; }
    [DataMember(Order = 8)]
    public string SaidPrimary { get; set; }
    [DataMember(Order = 9)]
    public string OfficeCode { get; set; }
    [DataMember(Order = 10)]
    public string BrokerDealerCode { get; set; }
    [DataMember(Order = 11)]
    public DateTime TimeStamp { get; set; }

    #endregion //Properties

    #region IExtensibleDataObject

    private ExtensionDataObject extensionDataObject_value;

    public ExtensionDataObject ExtensionData
    {
        get
        {
            return extensionDataObject_value;
        }
        set
        {
            extensionDataObject_value = value;
        }
    }

    #endregion //IExtensibleDataObject

}

The Service Interface

[ServiceContract]
public interface ITrackingService
{
    [OperationContract]
    void CreateEvent(ITrackingServiceContracts.CreateEventRequest trackingEvent);
}

namespace ITrackingServiceContracts
{
    [DataContract]
    public class CreateEventRequest
    {
        [DataMember(Order = 1)]
        [Required]
        public SiteTrackingEvent TrackingEvent { get; set; }

    }

}

The implementation of the service

public class TrackingService : ITrackingService
{

    public void CreateEvent(CreateEventRequest trackingEvent)
    {
        Validate(trackingEvent);
        //DO WORK HERE
    }

    public void Validate(CreateEventRequest request)
    {
        if (request == null)
            throw new FaultException("Request object is null.");

        List<ValidationResult> results = new List<ValidationResult>();
        if (!Validator.TryValidateObject(request, new ValidationContext(request, null, null), results, true))
        {
            throw new FaultException(String.Format("The request object is not valid: {0}.", String.Concat(results.Select(r => r.ErrorMessage))));
        }
    }

}

Can anybody see what I am missing/doing wrong here?

EDIT

As per @ErikFunkenbusch request, here are the relevant parts of the generated reference.cs files.

When "Reuse types in referenced assemblies" is not checked (the version that is working as expected):

public partial class TrackingServiceClient : System.ServiceModel.ClientBase<ServiceTester.UsageTracking.TrackingService.ITrackingService>, ServiceTester.UsageTracking.TrackingService.ITrackingService {

    public TrackingServiceClient() {
    }

    public TrackingServiceClient(string endpointConfigurationName) : 
            base(endpointConfigurationName) {
    }

    public TrackingServiceClient(string endpointConfigurationName, string remoteAddress) : 
            base(endpointConfigurationName, remoteAddress) {
    }

    public TrackingServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(endpointConfigurationName, remoteAddress) {
    }

    public TrackingServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
            base(binding, remoteAddress) {
    }

    public void CreateEvent(ServiceTester.UsageTracking.TrackingService.CreateEventRequest mlaEvent) {
        base.Channel.CreateEvent(mlaEvent);
    }
}

When "Reuse types in referenced assemblies" is checked (the version that is not working as expected). Note: This is the entire generated file. It's fairly obvious it is not generating correctly:

namespace ServiceTester.UsageTracking.TrackingService2 {
    using System.Runtime.Serialization;
    using System;


    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name="CreateEventRequest", Namespace="http://schemas.datacontract.org/2004/07/Services.UsageTracking.ServiceInterfaces." +
        "ITrackingServiceContracts")]
    [System.SerializableAttribute()]
    public partial class CreateEventRequest {
    }
}

Upvotes: 0

Views: 687

Answers (1)

Erik Funkenbusch
Erik Funkenbusch

Reputation: 93464

Apparently [Required] on a DataContract confuses SvcUtil when it generates reusable types. Could be a bug, or it could just be unsupported.

I would not suggest using your WCF DTO's in your view directly, and use View Models instead. Alternatively, use Buddy Classes.

Why are buddy classes used for validation?

Upvotes: 1

Related Questions