18

我正在使用以下代码:

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

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

4

3 回答 3

16

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

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

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

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

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

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

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

关于 Close() 与 Dispose 相同。

来自开发类库的设计指南中实现 Finalize 和 Dispose 以清理非托管资源中的“自定义 Dispose 方法名称”部分

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

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

于 2011-01-01T08:33:26.010 回答
2

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

所以改变:

    Srv_LoginChannelFactory.Close();

到:

    try
    {
        LoginService.Close();
    }
    catch
    {
        LoginService.Abort();
    }
于 2013-11-14T03:41:01.280 回答
-2

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

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);
于 2018-08-19T22:55:19.060 回答