WCF 客户端代理在被 hangfire 工作人员服务使用时陷入故障状态

Posted

技术标签:

【中文标题】WCF 客户端代理在被 hangfire 工作人员服务使用时陷入故障状态【英文标题】:WCF Client Proxy stuck in faulted state when being used by hangfire worker services 【发布时间】:2021-12-17 10:43:50 【问题描述】:

编辑 - 现在使用 WCF 客户端代理创建移出 DI 并进入 CustomerUpdateProcessor

  using (OperationContextScope scope = new OperationContextScope(starClient.InnerChannel))
                
                    AddHeaders(appSettings, fordHeader, dcs, token);
                    var message = new ProcessMessage()
                    

                        payload = customerPayload
                    ;
                    task = starClient.ProcessMessageAsync(null, message);
                
                var result = await task;
                return result.ProcessMessageResponse.payload;

如果有人可以推荐一种处理方式,仍然希望它与 DI 一起工作

我有一个 .NET5.0 应用程序。它使用hangfire来触发重复性工作

每个循环作业都会创建一个 WCF 客户端代理以连接到 SOAP 服务和 ProcessMessages。

我面临的问题是,当 WCF 代理创建时,它陷入故障状态,因此无法再使用。我尝试调用 _client.Abort(),但随后发生的只是错误消息更改为 @ 987654324@

我正在使用microsoft.extensions.dependencyinjection 注册我的所有服务,包括容器中的临时代理,如下所示:

服务注册

public static IServiceCollection AddCustomerUpdate(this IServiceCollection services, IConfigurationRoot config)
    
        services.AddTransient<ICustomerUpdateService, CustomerUpdateService>();
        services.AddTransient<ICustomerUpdateProcessor, CustomerUpdateProcessor>();
        services.AddTransient<IDmsCustomerUpdateMessageService, DmsCustomerUpdateMessageService>();
        services.AddCustomerUpdateClient(config);
        return services;
    


public static IServiceCollection AddCustomerUpdateClient(this IServiceCollection services, IConfigurationRoot config)
    
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
                | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
        BasicHttpsBinding binding = new BasicHttpsBinding()
        
            SendTimeout = TimeSpan.FromMinutes(1),
            OpenTimeout = TimeSpan.FromMinutes(1),
            CloseTimeout = TimeSpan.FromMinutes(1),
            ReceiveTimeout = TimeSpan.FromMinutes(10),
            
            Namespace = "http://www.starstandards.org/webservices/2005/10/transport",
            //HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
            TextEncoding = System.Text.Encoding.UTF8,
            //MessageEncoding = WSMessageEncoding.Text,
            UseDefaultWebProxy = true,
            
        ;
        binding.MaxReceivedMessageSize = 50000000;
        binding.ReaderQuotas.MaxArrayLength = 50000000;
        binding.ReaderQuotas.MaxStringContentLength = 50000000;
        binding.ReaderQuotas.MaxNameTableCharCount = 50000000;
        var endpointConfig = config.GetSection(nameof(EndPointConfig));
        EndpointAddress endpointAddress = new EndpointAddress($"endpointConfig[nameof(EndPointConfig.CuUrl)]");
        
        var starClient = new CustomerUpdateStarTransportPortTypesClient(binding, endpointAddress);
        services.AddTransient(x => starClient);
        return services;
    

服务执行

然后,在每次执行 hangfire RecurringJob 时,它都会调用 ICustomerUpdateProccesor 并循环处理每个客户的更新列表。为此,应使用 WCF 客户端代理的单个实例

public class CustomerUpdateProcessor : ICustomerUpdateProcessor

    private readonly ICustomerRepository _customerRepository;
    private readonly ICustomerIntegrationRepository _customerIntergrationRepository;
    private readonly IDmsCustomerUpdateMessageService _dmsCustomerUpdateMessageService;
    private readonly ICustomerUpdateService _customerUpdateService;
    private readonly IFordOauthService _authService;
    private readonly IIntegrationRepository _integrationRepository;

    public CustomerUpdateProcessor(
        ICustomerIntegrationRepository customerIntegrationRepository, 
        ICustomerRepository customerRepository,
        IDmsCustomerUpdateMessageService dmsCustomerUpdateMessageService,
        ICustomerUpdateService customerUpdateService,
        IFordOauthService authService,
        IIntegrationRepository integrationRepository
        )
    
        _authService = authService;
        _customerIntergrationRepository = customerIntegrationRepository;
        _integrationRepository = integrationRepository;
        _customerRepository = customerRepository;
        _dmsCustomerUpdateMessageService= dmsCustomerUpdateMessageService;
        _customerUpdateService = customerUpdateService;
    

    [DisableConcurrentExecution(3600)]
    [AutomaticRetry(Attempts = 0)]
    public async Task ProcessUpdatesForActiveCustomersAsync()
    
        var customers = _customerRepository.GetAllCustomers();

        foreach (var customer in customers)
        
            var integrations = _customerIntergrationRepository.GetIntegrationsForCustomer(customer.Id);
            
            foreach (var integration in integrations)
            
                if (integration.Name == "Xfi.CustomerUpdate" && integration.Enabled)
                
                    var integrationParams = integration.Paramaters;
                   
                    var dealerCode = integrationParams.Single(x => x.Name == "DealerCode").Value;
                    var appArea = new ApplicationAreaModel()
                    
                        DealerCode = dealerCode
                    ;
                    var messages = await _dmsCustomerUpdateMessageService.GetMessagesAsync(customer.ServerAddress, appArea);
                    if (messages != null)
                    
                        foreach (var message in messages)
                        
                            var cuMessage = message as CustomerUpdateMessage;
                            var builder = new ProcessCustomerInformationBuilder();
                            builder.AddApplicationArea(cuMessage.ApplicationArea);
                            builder.AddHeader();
                            if (cuMessage.CustomerModel is IndividualCustomerModel)
                            
                                builder.AddIndivualCustomer(cuMessage.CustomerModel as IndividualCustomerModel);

                            
                            else
                            
                                builder.AddSpecifiedOrganization(cuMessage.CustomerModel as BusinessCustomerModel);
                            
                            var payload = builder.BuildPayload();
                            var token = await GetAccessTokenAsync(integrationId: integration.Id);
                            var appsettings = new ApplicationSetttings()
                            
                                XmotiveAppId = ""
                            ;
                            await _customerUpdateService.ProcessCustomerUpdateAsync(payload, dealerCode, appsettings, token.ToString(), customer.Name);
                              
                    
                
            
        
    

肥皂服务

在此处理器中,ICustomerUpdateService 用于调用 WCF 客户端代理并调用 SOAP 服务。

 public class CustomerUpdateService : StarService, ICustomerUpdateService

    private readonly CustomerUpdateStarTransportPortTypesClient _starClient;
    private readonly IServiceProvider _serviceProvider;

    public CustomerUpdateService(CustomerUpdateStarTransportPortTypesClient starClient, IServiceProvider serviceProvider)
    
        _starClient = starClient;
        _serviceProvider = serviceProvider;
    

    [OperationContract]
    public async Task<AcknowledgeCustomerInformationPayload> ProcessCustomerUpdateAsync(
        ProcessCustomerInformationPayload customerPayload,
        string siteCode,
        ApplicationSetttings appSettings,
        string token,
        string customerName
        )
    

        var fordHeader = new FordDealerIdentity()
        
            SiteCode = siteCode
        ;

        DataContractSerializer dcs = new DataContractSerializer(typeof(FordDealerIdentity));
        Task<ProcessMessageResponse1> task;

        using (OperationContextScope scope = new OperationContextScope(_starClient.InnerChannel))
        
            AddHeaders(appSettings, fordHeader, dcs, token);
            var message = new ProcessMessage()
            

                payload = customerPayload
            ;
            task = _starClient.ProcessMessageAsync(null, message);
        
        var result = await task;
        return result.ProcessMessageResponse.payload;
    

使用(OperationContextScope scope = new OperationContextScope(_starClient.InnerChannel))在这一行抛出错误

它抛出错误“对象不能被用作其处于故障状态”

问题似乎与多线程和 WCF 客户端代理有关,但我不确定如何正确处理和遇到 WCF 的 .NETCores 端口和System.ServiceModel.Primitives中缺少功能的障碍@

【问题讨论】:

也许你可以从这个链接找到解决方案:***.com/questions/9409329/… 通过将 WCF 客户端代理创建移出 DI 并进入包装在使用中的服务本身来解决我的问题 更新了问题 【参考方案1】:

也许你可以试试try...catch 而不是using 声明

【讨论】:

以上是关于WCF 客户端代理在被 hangfire 工作人员服务使用时陷入故障状态的主要内容,如果未能解决你的问题,请参考以下文章

WCF 客户端代理初始化

从代理客户端将参数传递给 WCF 服务中心

为整个应用程序保留一个 wcf 客户端代理

WCF中的几种地址总结

终于解决:升级至.NET 4.6.1后VS2015生成WCF客户端代理类的问题

WCF 服务代理中伪装的类型?