【问题标题】:Application does not recognize WCF service client when reuse types in referenced assemblies在引用的程序集中重用类型时,应用程序无法识别 WCF 服务客户端
【发布时间】:2014-10-20 03:27:54
【问题描述】:

我有一个 WCF 服务,它使用一个外部程序集作为它的 DTO。服务的使用者也有对此外部程序集的引用。计划是使用这些实体在服务和消费者之间传递信息。我已经用其他服务多次这样做了,没有问题。

在这种情况下,它不起作用。 Intellisense 识别驻留在 WCF 服务中的类(即:CreateEventRequest),但不显示标准的 TrackingServiceClient,这意味着无法实例化该服务。

如果我取消选中“在引用的程序集中重用类型”,一切都会按预期工作。虽然很明显,我想重用 DTO 程序集。

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

}

服务接口

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

    }

}

服务的实现

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

}

谁能看到我在这里错过/做错了什么?

编辑

根据@ErikFunkenbusch 的要求,这里是生成的reference.cs 文件的相关部分。

当“在引用的程序集中重用类型”没有选中时(按预期工作的版本):

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

当“在引用的程序集中重用类型” 被选中时(未按预期工作的版本)。注意:这是整个生成的文件。很明显它没有正确生成:

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 {
    }
}

【问题讨论】:

  • 您是否查看了您的 reference.cs 文件以查看该类的名称?您需要确保在解决方案资源管理器中打开显示所有文件
  • @ErikFunkenbusch:你指的是哪个类?
  • 你的客户端类。一个是生成的,你只是不知道名字是什么。查看 reference.cs 文件,查找派生自 ClientBase 的类。
  • @ErikFunkenbusch:我已经更新了我的问题。
  • IServiceContracts 来自哪里?我在你的代码中没有看到......这会导致错误,从而中止生成吗?

标签: c# .net wcf


【解决方案1】:

显然,DataContract 上的 [Required] 在生成可重用类型时会混淆 SvcUtil。可能是错误,也可能只是不受支持。

我不建议直接在视图中使用 WCF DTO,而是使用视图模型。或者,使用 Buddy Classes。

Why are buddy classes used for validation?

【讨论】:

  • 顺便说一句,我没有在视图中使用 DTO。我正在实现 [Required] 属性以在将 DTO 返回发送到服务时对其进行验证。
  • @ShaiCohen - 啊..在那种情况下,我也不会直接将您的 EF 实体用作 WCF DTO(假设这就是您的意思)。无论哪种方式,都应该从实体或模型转换 DTO。
  • 我没有使用 EF。只是 POCO。在这种情况下,您是否建议在 POCO 之外创建 DTO?如果是的话,您可以提供任何讨论此问题的链接将不胜感激。
  • @ShaiCohen - 所以你正在编写自定义反射代码来寻找你需要的属性?还是使用其他库?您可能需要考虑使用自定义行为来进行验证。 DTO 通常严格用于数据传输,因此来回进行序列化。如果您按原样使用它就可以了。但是如果您开始在其上挂其他东西,是时候考虑将其转换为不同的了模型。到那时,您就违反了单一责任原则。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-14
相关资源
最近更新 更多