System.ObjectDisposedException: 'Cannot access a disposed object. while using ISession.connect

saipramod
saipramod Member Posts: 1
edited October 2022 in General Discussions #1

Hi Team,

We are incorporating Solace in our .Net core API and trying to create session object in one cs file and adding it to a property in another cs file where I am using session.Connect(). When we try to connect to session it is showing an exception "that object is disposed". Below is code for your reference.

=========================================================================

public static ISession GetSolacecConnection(SolaceConnectionRequest solaceConnectionRequest)
    {
      //Initialize Solace Systems Messaging API with logging to console at Warning level
      ContextFactoryProperties cfp = new ContextFactoryProperties()
      {
        SolClientLogLevel = SolLogLevel.Warning
      };
      cfp.LogToConsoleError();
      ContextFactory.Instance.Init(cfp);
      try
      {
        using (IContext context = ContextFactory.Instance.CreateContext(new ContextProperties(), null))
        {
          // Validate parameters
          if (context == null)
          {
            throw new ArgumentException("Solace Systems API context Router must be not null.", "context");
          }
          if (string.IsNullOrWhiteSpace(solaceConnectionRequest.Host))
          {
            throw new ArgumentException("Solace Messaging Router host name must be non-empty.", "host");
          }
          if (string.IsNullOrWhiteSpace(solaceConnectionRequest.VpnName))
          {
            throw new InvalidOperationException("VPN name must be non-empty.");
          }
          if (string.IsNullOrWhiteSpace(solaceConnectionRequest.UserName))
          {
            throw new InvalidOperationException("Client username must be non-empty.");
          }

          cfp.LogToConsoleError(); //We can log it to a file later
          ContextFactory.Instance.Init(cfp);
          var sessionProps = GetSessionProperties(solaceConnectionRequest.Host, solaceConnectionRequest.VpnName, solaceConnectionRequest.UserName,
            solaceConnectionRequest.Password, solaceConnectionRequest.DefaultReconnectRetries);
          ISession session = context.CreateSession(sessionProps, null, HandleSessionEvent);
          if (session != null)
          {
            //ReturnCode returnCode = session.Connect();
            //return returnCode;

            return session;
          }
        }
        return null;
      }
      catch (Exception ex)
      {
        return null;
      }
    }

=======================================================================

private readonly ISession _session;
public async Task Run(SolaceRequest solaceRequest)
    {
      try
      {
        if (_session != null)
        {
          ReturnCode returnCode = _session.Connect(); // failing while connecting
          if (returnCode == ReturnCode.SOLCLIENT_OK)
          {
            _logger.LogInformation("Session successfully connected.");

            await SendMessage(_session, solaceRequest);
            _logger.LogInformation("Waiting for a message to be published...");
          }
          else
          {
            _logger.LogError("Error connecting, return code: {0}", returnCode);
          }
        }         
      }
      catch (Exception ex)
      {
        _logger.LogError("Exception thrown: {0}", ex.Message);
      }
      finally
      {
        // Dispose Solace Systems Messaging API
        //ContextFactory.Instance.Cleanup();
      }
      _logger.LogInformation("Finished.");      

    }

Answers

  • nicholasdgoodman
    nicholasdgoodman Member, Employee Posts: 43 Solace Employee
    edited October 2022 #2

    Greetings and welcome to the community!

    This issue you are facing is because of the parent-child relationship between IContext and ISession. Within the GetSolaceConnection(...) method, you create a context from the context factory, and then a session on that context; however, the context creation is performed within a using block, and as such, the context is disposed immediately before the method returns.

    So even though the session instance is not disposed, its underlying context has been; so calling .Connect() will generate an ObjectDisposedException with the following message:

    Cannot access a disposed object.

    Object name: 'Cannot Connect an already disposed session'.

    To remedy this, the lifecycle of the IContext and ISession instances should be more-or-less the same. If you have a global static class holding a reference to ISession _session  , then you should likewise hold a reference to the context via a field IContext _context to be safe.

    In short, for long-lived session variables, be sure both ISession and IContext are not prematurely disposed within a using statement.