2011-01-01 3 views
8

Я использую следующий код:Что может быть причиной ошибки «Не удается получить доступ к объекту» в WCF?

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

Когда пользователь вводит действительное имя пользователя и пароль, все в порядке. Когда пользователь вводит неверный логин и пароль, то первая попытка корректно отображает сообщение «Не Enter», но со второй попытки, пользователь видит это сообщение:

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

Как я могу исправить мой код, чтобы предотвратить это ошибка?

ответ

12

Srv_LoginChannelFactory.Close(), где он находится. Когда вы звоните, вы отказываетесь от неуправляемого ресурса. Попытка сделать что-то другое, а затем проверить его состояние или повторное открытие, приводит к исключению «Невозможно получить доступ к удаленному объекту».

Это правда, когда вы закрываете одноразовый объект и затем пытаетесь что-то сделать с ним. Например, запись в закрытый файл или выполнение инструкции sql при закрытом соединении с базой данных.

Для этого у вас есть три варианта.

  1. Не устанавливайте поле Srv_LoginChannelFactory. Вместо этого сделайте его локальным нажатием кнопки. Если это единственное место, которое вы используете, это, вероятно, имеет смысл сделать, потому что это сокращает время, в течение которого вы используете неуправляемый ресурс.

  2. Реализовать IDisposable (вы должны делать это каждый раз, когда у вас есть одноразовое поле), не закрывайте Srv_LoginChannelFactory, кроме Login.Dispose.

  3. Нажмите кнопку, чтобы проверить состояние Srv_LoginChannelFactory, прежде чем пытаться создать канал с ним. Вам все равно нужно реализовать IDisposable в случае, если нажатие кнопки не произойдет.

Примечание: EnsureOpened выглядит, как он может быть использован для проверки состояния, но он работает только до его открытия. Как только он будет закрыт, он бросит.

Относительно Close(), аналогичного Dispose.

В разделе «Индивидуальная настройка метода Dispose Имя» в Implementing Finalize and Dispose to Clean Up Unmanaged Resources в Руководстве дизайна по разработке библиотек классов

Иногда имя домена специфичный более подходящим, чем Dispose. Например, для примера инкапсуляция файла может использовать метод name Close. В этот случай реализует Dispose private и создайте общедоступный метод Close, который вызывает Dispose. Следующий пример иллюстрирует этот шаблон.Вы можете заменить Закрыть с именем метода , соответствующим вашему домену. Для примера требуется пространство имен System.

Идея здесь состоит в том, чтобы дать четность методу Open. Лично я думаю, что это вызывает много путаницы, но я не могу придумать ничего лучше (CloseAndDispose?)

+0

Спасибо @Conrad но странно вещь я использую этот стиль код на других формах, но они работают correctly.Why Close() Метод утилизация моего объекта ? Это нормальное поведение? – Arian

+1

да, это нормально. Close и Dispose обычно делают то же самое. –

+0

Я действительно не понимаю. Почему этот код: LoginService = Srv_LoginChannelFactory.CreateChannel(); выведите исключение? Учтите, что состояние закрыто, я создам новый экземпляр, и закрытое состояние не имеет значения – Arian

2

Проблема здесь (я думаю, что Конрад пропустил) заключается в том, что Kerezo закрывает ChannelFactory (Srv_LoginChannelFactory), который закрывается (распоряжается) всеми его каналами, когда он, вероятно, хочет закрыть только канал (LoginService).

Меняет:

Srv_LoginChannelFactory.Close(); 

к:

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