Диагностика «Ошибка недоступности сервера RPC», вызванная службой Windows, вызывающей WCF - PullRequest
2 голосов
/ 19 марта 2012

У меня есть служба 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

1 Ответ

1 голос
/ 19 марта 2012

Если вы используете инстанцированные сервисные прокси-серверы по мере необходимости, ответы на этот 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 заключается в том, что команда WCF в Microsoft решила внедрить Dispose таким образом, чтобы можно было генерировать исключения, предотвращая тем самым выпускнеуправляемых ресурсов до тех пор, пока не будет вызван Abort () или экземпляр прокси не будет полностью очищен.Они написали структуру, чтобы они могли сделать выбор, к сожалению, мы должны страдать от последствий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...