【问题标题】:What could be causing a "Cannot access a disposed object" error in WCF?什么可能导致 WCF 中出现“无法访问已处置的对象”错误?
【发布时间】:2011-01-01 08:13:22
【问题描述】:

我正在使用以下代码:

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

登录是我的构造函数:

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

我就是这样使用服务的:

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

当用户输入有效的用户名和密码时,一切正常。当用户输入错误的用户名和密码时,第一次尝试正确显示“未输入”消息,但在第二次尝试时,用户看到此消息:

{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()

如何修复我的代码以防止发生此错误?

【问题讨论】:

    标签: c# wcf objectdisposedexception


    【解决方案1】:

    Srv_LoginChannelFactory.Close() 是处理它的地方。当您调用 close 时,您将放弃您拥有的任何非托管资源。尝试执行其他操作然后检查其状态或重新打开它会导致“无法访问已处置的对象”异常。

    每当您关闭一次性对象并随后尝试对其进行操作时,都是如此。例如写入已关闭的文件,或在已关闭的数据库连接上执行 sql 语句。

    要解决这个问题,您有三个选择。

    1. 不要将 Srv_LoginChannelFactory 设为字段。而是将其设置为按钮单击的本地。如果这是您唯一使用它的地方,那么这样做可能很有意义,因为它可以缩短您使用非托管资源的时间。

    2. 实现 IDisposable(只要有 Disposable 字段,就应该这样做)不要关闭 Srv_LoginChannelFactory,除非在 Login.Dispose 中。

    3. 更改按钮单击以检查 Srv_LoginChannelFactory 的状态,然后再尝试使用它创建通道。如果按钮单击没有发生,您仍然需要实现 IDisposable。

    注意EnsureOpened 看起来可以用来检查状态,但它只在打开之前有效。一旦关闭它就会抛出。

    关于 Close() 与 Dispose 相同。

    来自开发类库的设计指南中Implementing Finalize and Dispose to Clean Up Unmanaged Resources 中的“自定义处理方法名称”部分

    有时特定于域的名称是 比 Dispose 更合适。为了 例如,文件封装可能 想使用方法名 Close。在 这种情况下,私下实现 Dispose 并创建一个公共 Close 方法 调用处置。以下代码 示例说明了这种模式。你 可以用方法名替换 Close 适合您的域。这 示例需要 System 命名空间。

    这里的想法是对 Open 方法进行奇偶校验。我个人认为这会引起很多混乱,但我想不出更好的方法(CloseAndDispose?)

    【讨论】:

    • 感谢@Conrad,但奇怪的是我在其他表单上使用了这种样式代码,但它们工作正常。为什么用 Close() 方法处理我的对象?这是正常的行为吗?
    • 是的,这很正常。 Close 和 Dispose 通常做同样的事情。
    • 我不太明白。为什么这个代码:LoginService = Srv_LoginChannelFactory.CreateChannel();抛出异常?考虑状态是关闭,我要创建一个新实例,关闭状态无关紧要
    • @Nima,我重写了我的答案。希望它能更好地解释您遇到问题的原因。
    • 也许您也回答了这个问题,这是对这个问题的跟进,并且基于您的回答? codereview.stackexchange.com/questions/220818/…
    【解决方案2】:

    这里的问题(我认为康拉德错过了)是 Kerezo 正在关闭 ChannelFactory (Srv_LoginChannelFactory),它关闭(处置)其所有通道,而他可能只想关闭通道 (LoginService)。

    所以改变:

        Srv_LoginChannelFactory.Close();
    

    到:

        try
        {
            LoginService.Close();
        }
        catch
        {
            LoginService.Abort();
        }
    

    【讨论】:

      【解决方案3】:

      在使用之前使用序列化和反序列化 使文件原始 用于序列化对象

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

      用于反序列化对象

      var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };        
      var getUserObj = JsonConvert.DeserializeObject<OBJECT_TYPE>("SERIALIZED_OBJ", settings);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-29
        • 1970-01-01
        • 2023-01-11
        • 2011-05-19
        • 1970-01-01
        相关资源
        最近更新 更多