诊断“;RPC服务器不可用错误”;这是由Windows服务调用WCF引起的

本文关键字:服务 Windows 调用 WCF 服务器 RPC 诊断 错误 | 更新日期: 2023-09-27 18:28:11

我有一个windows服务,它使用WCF连接到其他服务。它检查它们是否处于活动状态,获取这些服务包含的任何错误消息,并报告这些消息。使用通道工厂每30秒检查一次,为符合接口的配置中找到的每个服务创建代理。运行几天后,服务器变得没有响应,并开始报告"RPC服务器不可用错误"。我可以使用计算机管理连接到它,它的内存足迹似乎不会攀升,尽管如果我停止服务,它会完全解决问题。我已经附上了我正在使用的渠道工厂经理,但如果需要其他任何东西,请告诉我。可能是服务通道没有被正确释放吗?我该怎么诊断?以前有人见过这个吗?

public class ChannelFactoryManager : IDisposable
{
    private static Dictionary<Tuple<Type, string>, ChannelFactory> _factories = new Dictionary<Tuple<Type, string>, ChannelFactory>();
    private static readonly object _syncRoot = new object();
    public virtual T CreateChannel<T>() where T : class
    {
        return CreateChannel<T>("*", null);
    }
    public virtual T CreateChannel<T>(string endpointConfigurationName) where T : class
    {
        return CreateChannel<T>(endpointConfigurationName, null);
    }
    public virtual T CreateChannel<T>(string endpointConfigurationName, string endpointAddress) where T : class
    {
        T local = GetFactory<T>(endpointConfigurationName, endpointAddress).CreateChannel();
        ((IClientChannel)local).Faulted += ChannelFaulted;
        return local;
    }
    protected virtual ChannelFactory<T> GetFactory<T>(string endpointConfigurationName, string endpointAddress) where T : class
    {
        lock (_syncRoot)
        {
            ChannelFactory factory;
            if (!_factories.TryGetValue(new Tuple<Type, string>(typeof(T), endpointConfigurationName), out factory))
            {
                factory = CreateFactoryInstance<T>(endpointConfigurationName, endpointAddress);
                _factories.Add(new Tuple<Type, string>(typeof(T), endpointConfigurationName), factory);
            }
            return (factory as ChannelFactory<T>);
        }
    }
    private ChannelFactory CreateFactoryInstance<T>(string endpointConfigurationName, string endpointAddress)
    {
        ChannelFactory factory = null;
        if (!string.IsNullOrEmpty(endpointAddress))
        {
            factory = new ChannelFactory<T>(endpointConfigurationName, new EndpointAddress(endpointAddress));
        }
        else
        {
            factory = new ChannelFactory<T>(endpointConfigurationName);
        }
        factory.Faulted += FactoryFaulted;
        factory.Open();
        return factory;
    }
    private void ChannelFaulted(object sender, EventArgs e)
    {
        IClientChannel channel = (IClientChannel)sender;
        channel.Abort();
    }
    private void FactoryFaulted(object sender, EventArgs args)
    {
        ChannelFactory factory = (ChannelFactory)sender;
        factory.Abort();            
        Type[] genericArguments = factory.GetType().GetGenericArguments();
        if ((genericArguments != null) && (genericArguments.Length == 1))
        {
            Type type = genericArguments[0];
            string endPointName = factory.Endpoint.Name;
            Tuple<Type, string> key = new Tuple<Type, string>(type, endPointName);
            if (_factories.ContainsKey(key))
            {
                _factories.Remove(key);
            }
        }
    }
    public void Dispose()
    {
        Dispose(true);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            lock (_syncRoot)
            {
                foreach (Tuple<Type, string> type in _factories.Keys)
                {
                    ChannelFactory factory = _factories[type];
                    try
                    {
                        factory.Close();
                        continue;
                    }
                    catch
                    {
                        factory.Abort();
                        continue;
                    }
                }
                _factories.Clear();
            }
        }
    }
}

谢谢Rob

诊断“;RPC服务器不可用错误”;这是由Windows服务调用WCF引起的

如果您按照需要使用实例化服务代理路由,那么这个SO问题中的答案提供了一些选项和处理代理实例的基本原理。作为一个基本的开始,我建议:

//Your client type could be ICommunicationObject or ClientBase:
var client = new YourServiceProxyType();
try {
    var result = client.MakeCall();
    //do stuff with result...
    //Done with client. Close it:
    client.Close();
}
catch (Exception ex) {
    if (client.State != System.ServiceModel.CommunicationState.Closed)
        client.Abort();
}

设计一个好的WCF代理处理模式的根本问题是,Microsoft的WCF团队决定以一种可以引发异常的方式实现Dispose,从而在调用Abort()或完全垃圾收集代理实例之前阻止释放非托管资源。他们写了框架,这样他们就可以做出选择,不幸的是,我们必须承受后果。