Question

I have an winform application which consumes windows service, i user ChannelFactory to connect to service, problem is when i call service method using channel the memory usage increase and after method execute memory not go down(even after form close), i call GC.Collect but no change

channel Create class

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

base class

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

winform class
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();
            }
        }
Was it helpful?

Solution

You're on the right track in terms of using ChannelFactory<T>, but your implementation is a bit off.

ChannelFactory<T> creates a factory for generating channels of type T. This is a relatively expensive operation (as compared to just creating a channel from the existing factory), and is generally done once per life of the application (usually at start). You can then use that factory instance to create as many channels as your application needs.

Generally, once I've created the factory and cached it, when I need to make a call to the service I get a channel from the factory, make the call, and then close/abort the channel.

Using your posted code as a starting point, I would do something like this:

public class Channel1
{

    ChannelFactory<ISales> salesChannel;

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

Note that I've replaced the salesObj with salesChannel (the factory). This will create the factory the first time it's called, and create a new channel from the factory every time.

Unless you have a particular requirement to do so, I wouldn't keep track of the different channels, especially if follow the open/do method/close approach.

In your form, it'd look something like this:

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

The code above gets a new ISales channel from the factory in CHANNEL, executes the call, and then closes the channel. If an exception happens, the channel is aborted in the catch block.

I would avoid using Dispose() out of the box on the channels, as the implementation in the framework is flawed and will throw an error if the channel is in a faulted state. If you really want to use Dispose() and force the garbage collection, you can - but you'll have to work around the WCF dispose issue. Google will give you a number of workarounds (google WCF Using for a start).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top