What could be causing a "Cannot access a disposed object" error in WCF?
Asked Answered
C

3

19

I am using the following code:

private WSHttpBinding ws;
private EndpointAddress Srv_Login_EndPoint;
private ChannelFactory<Srv_Login.Srv_ILogin> Srv_LoginChannelFactory;
private Srv_Login.Srv_ILogin LoginService;

The Login is my constructor:

public Login()
        {
            InitializeComponent(); 
            ws = new WSHttpBinding();
            Srv_Login_EndPoint = new EndpointAddress("http://localhost:2687/Srv_Login.svc");
            Srv_LoginChannelFactory = new ChannelFactory<Srv_Login.Srv_ILogin>(ws, Srv_Login_EndPoint);
        }

And I'm using service this way:

private void btnEnter_Click(object sender, EventArgs e)
{
    try
    {

        LoginService = Srv_LoginChannelFactory.CreateChannel();
        Srv_Login.LoginResult res = new Srv_Login.LoginResult();
        res = LoginService.IsAuthenticated(txtUserName.Text.Trim(), txtPassword.Text.Trim());
        if (res.Status == true)
        {
            int Id = int.Parse(res.Result.ToString());
        }
        else
        {
            lblMessage.Text = "Not Enter";
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    finally
    {
        Srv_LoginChannelFactory.Close();
    }
}

When the user enters a valid username and password, everything is fine. When the user enters a wrong username and password, the first try correctly displays a "Not Enter" message, but on the second try, the user sees this message:

{System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.ServiceModel.ChannelFactory`1[Test_Poosesh.Srv_Login.Srv_ILogin]'.
   at System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposed()
   at System.ServiceModel.ChannelFactory.EnsureOpened()
   at System.ServiceModel.ChannelFactory`1.CreateChannel(EndpointAddress address, Uri via)
   at System.ServiceModel.ChannelFactory`1.CreateChannel()

How can I fix my code to prevent this error from occurring?

Conciliatory answered 1/1, 2011 at 8:13 Comment(0)
U
18

Srv_LoginChannelFactory.Close() is where it's being disposed. When you call close you are giving up whatever unmanaged resource you had. Attempting to do something other then inspecting its state or re-opening it results in the "Cannot access a disposed object" exception.

This is true whenever you close a disposable object and try and do something with it afterwards. For example writing to a file that's closed, or executing a sql statement on a closed database connection.

To address this you have three options.

  1. Don't make the Srv_LoginChannelFactory a field. Instead make it local to the button click. If this is the only place you are using it, this probably makes sense to do because it shortens the amount of time you are using an unmanaged resource.

  2. Implement IDisposable (you are supposed do this whenever you have field that is Disposable) don't close Srv_LoginChannelFactory except in Login.Dispose.

  3. Change the button click to check the State of Srv_LoginChannelFactory before you try and create a channel with it. You still need to implement IDisposable in case the button click doesn't happen.

Note: EnsureOpened looks like it could be used to check the state, but it only works before its opened. Once its been closed it will throw.

Regarding Close() being the same as Dispose.

From the section 'Customizing a Dispose Method Name' in Implementing Finalize and Dispose to Clean Up Unmanaged Resources in the Design Guidelines for Developing Class Libraries

Occasionally a domain-specific name is more appropriate than Dispose. For example, a file encapsulation might want to use the method name Close. In this case, implement Dispose privately and create a public Close method that calls Dispose. The following code example illustrates this pattern. You can replace Close with a method name appropriate to your domain. This example requires the System namespace.

The idea here is to give parity to the Open method. Personally I think it causes a lot of confusion, but I can't think of anything better (CloseAndDispose?)

Usually answered 1/1, 2011 at 8:33 Comment(5)
Thanks @Conrad but strange thing is I use this style code on other forms but they work correctly.Why Close() Method dispose my object?Is this normal behaivior?Conciliatory
yes, that is normal. Close and Dispose typically do the same thing.Diskin
I Don't really understand.Why this code: LoginService = Srv_LoginChannelFactory.CreateChannel(); throw an exception?Consider that the state is Closed,I gonna create a new instance and Closed state is not mattersConciliatory
@Nima, I rewrote my answer. Hopefully it will better explain why you're having the problem.Usually
Maybe you answer this question as well which is a follow up to this one and is based on your answer? codereview.stackexchange.com/questions/220818/…Concatenate
F
2

The problem here (which I think Conrad missed) is that Kerezo is closing the ChannelFactory (Srv_LoginChannelFactory) which closes (disposes) all its channels, when he probably wants to close just the Channel (LoginService).

So change:

    Srv_LoginChannelFactory.Close();

to:

    try
    {
        LoginService.Close();
    }
    catch
    {
        LoginService.Abort();
    }
Festinate answered 14/11, 2013 at 3:41 Comment(0)
I
-3

use Serialized and deserialize before using it that makes file original For Serializing object

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var SerializedFile = JsonConvert.SerializeObject(file, settings); 

and For deserializing Object

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };        
var getUserObj = JsonConvert.DeserializeObject<OBJECT_TYPE>("SERIALIZED_OBJ", settings);
Incision answered 19/8, 2018 at 22:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.