Вызов метода ChannelFactory увеличивает память

У меня есть winform приложение, которое использует службу Windows, я пользователь ChannelFactoryЧтобы подключиться к сервису, проблема заключается в том, что когда я вызываю метод сервиса с использованием канала, увеличивается использование памяти, а после выполнения метода не уменьшается память (даже после закрытия формы), я вызываю GC.Collect но без изменений

канал Создать класс

public class Channel1
{
List<ChannelFactory> chanelList = new List<ChannelFactory>();
ISales salesObj;

public ISales Sales
{
    get
    {
        if (salesObj == null)
        {
            ChannelFactory<ISales> saleschannel = new ChannelFactory<ISales>("SalesEndPoint");
            chanelList.Add(saleschannel);
            salesObj = saleschannel.CreateChannel();
        }
        return salesObj;
    }
}

public void CloseAllChannels()
{
    foreach (ChannelFactory chFac in chanelList)
    {
        chFac.Abort();
        ((IDisposable)chFac).Dispose();            
    }
    salesObj = null;
}
}

базовый класс

public class Base:Form
    {    
       public Channel1 channelService = new Channel1();        
       public Channel1 CHANNEL
       {
           get
           {
               return channelService;
           }
       }                  
    }

класс winform
Form1:Base

 private void btnView_Click(object sender, EventArgs e)
        {
            DataTable _dt = new DataTable();
            try
            {
                gvAccounts.AutoGenerateColumns = false;
                _dt = CHANNEL.Sales.GetDatatable();
                gvAccounts.DataSource = _dt;

            }
            catch (Exception ex)
            {    
                MessageBox.Show("Error Occurred while processing...\n" + ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            finally
            {
                CHANNEL.CloseAllChannels();
                _dt.Dispose();
                //GC.Collect();
            }
        }

1 ответ

Решение

Вы на правильном пути с точки зрения использования ChannelFactory<T>, но ваша реализация немного отклонена.

ChannelFactory<T> создает фабрику для генерации каналов типа T. Это относительно дорогая операция (по сравнению с простым созданием канала из существующей фабрики), и обычно выполняется один раз в течение жизни приложения (обычно при запуске). Затем вы можете использовать этот экземпляр фабрики, чтобы создать столько каналов, сколько нужно вашему приложению.

Как правило, после создания фабрики и ее кэширования, когда мне нужно позвонить в службу, я получаю канал от фабрики, выполняю звонок, а затем закрываю / отменяю канал.

Используя ваш отправленный код в качестве отправной точки, я бы сделал что-то вроде этого:

public class Channel1
{

    ChannelFactory<ISales> salesChannel;

    public ISales Sales
    {
        get
        {
            if (salesChannel == null)
            {
                salesChannel = new ChannelFactory<ISales>("SalesEndPoint");
            }
            return salesChannel.CreateChannel();
        }
    }       
}

Обратите внимание, что я заменил salesObj с salesChannel (фабрика). Это создаст фабрику при первом вызове и каждый раз будет создавать новый канал с фабрики.

Если у вас нет особого требования, я не буду отслеживать различные каналы, особенно если придерживаюсь метода open/do /close.

В вашей форме это будет выглядеть примерно так:

private void btnView_Click(object sender, EventArgs e)
{

    DataTable _dt = new DataTable();

    try
    {
        gvAccounts.AutoGenerateColumns = false;
        ISales client = CHANNEL.Sales
        _dt = client.GetDatatable();
        gvAccounts.DataSource = _dt;
        ((ICommunicationObject)client).Close();
    }
    catch (Exception ex)
    {    
        ((ICommunicationObject)client).Abort();
        MessageBox.Show("Error Occurred while processing...\n" + ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
    }
}

Приведенный выше код получает новый канал ISales от фабрики в CHANNEL, выполняет вызов, а затем закрывает канал. Если происходит исключение, канал прерывается в блоке catch.

Я бы не стал использовать Dispose() из коробки на каналах, поскольку реализация в платформе имеет недостатки и выдаст ошибку, если канал находится в неисправном состоянии. Если вы действительно хотите использовать Dispose() и заставить сборщик мусора, вы можете - но вам придется обойти проблему утилизации WCF. Google предложит вам несколько обходных путей (Google WCF использует для начала).

Другие вопросы по тегам