2011-01-01 9 views
8

Tôi đang sử dụng đoạn mã sau:Điều gì có thể gây ra lỗi "Không thể truy cập đối tượng được xử lý" trong WCF?

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

Các Login là constructor của tôi:

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

Và tôi đang sử dụng dịch vụ theo cách này:

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

Khi người dùng nhập vào một tên người dùng và mật khẩu hợp lệ, mọi thứ đều ổn. Khi người dùng nhập vào tên người dùng và mật khẩu sai, lần thử đầu tiên một cách chính xác sẽ hiển thị một thông báo "Không Enter", nhưng lần thử thứ hai, người dùng nhìn thấy thông báo này:

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

Làm thế nào tôi có thể sửa chữa mã của tôi để ngăn chặn điều này lỗi xảy ra?

Trả lời

12

Srv_LoginChannelFactory.Close() là nơi nó được xử lý. Khi bạn gọi gần bạn đang từ bỏ bất cứ tài nguyên không được quản lý nào bạn có. Cố gắng làm điều gì đó khác sau đó kiểm tra trạng thái của nó hoặc mở lại kết quả trong trường hợp "Không thể truy cập một đối tượng được xử lý" ngoại lệ.

Điều này đúng bất cứ khi nào bạn đóng đối tượng dùng một lần và thử làm một việc gì đó với nó sau đó. Ví dụ: ghi vào một tập tin được đóng, hoặc thực hiện một câu lệnh sql trên một kết nối cơ sở dữ liệu đã đóng.

Để giải quyết vấn đề này, bạn có ba tùy chọn.

  1. Không tạo trường Srv_LoginChannelFactory. Thay vào đó hãy làm cho địa phương trở thành nút bấm. Nếu đây là nơi duy nhất bạn đang sử dụng nó, điều này có thể có ý nghĩa để làm bởi vì nó rút ngắn lượng thời gian bạn đang sử dụng một tài nguyên không được quản lý.

  2. Triển khai IDisposable (bạn phải làm điều này bất cứ khi nào bạn có trường dùng một lần) không đóng Srv_LoginChannelFactory ngoại trừ trong Login.Dispose.

  3. Thay đổi nút bấm để kiểm tra trạng thái của Srv_LoginChannelFactory trước khi bạn thử và tạo một kênh với nó. Bạn vẫn cần phải triển khai IDisposable trong trường hợp nút bấm không xảy ra.

Note: EnsureOpened vẻ như nó có thể được sử dụng để kiểm tra nhà nước, nhưng nó chỉ hoạt động trước khi mở nó. Khi nó đã bị đóng, nó sẽ bị ném.

Về Close() giống với Dispose.

Từ phần 'Tùy biến một phương thức Dispose Tên' trong Implementing Finalize and Dispose to Clean Up Unmanaged Resources trong Hướng dẫn thiết kế cho phát triển Class Libraries

thoảng một tên miền cụ thể là thích hợp hơn Dispose. Ví dụ: , tệp đóng gói có thể muốn sử dụng tên phương thức Đóng. Trong trường hợp này, hãy thực hiện Vứt bỏ riêng tư và tạo phương thức Đóng công khai mà cuộc gọi Vứt bỏ. Đoạn mã sau đây minh họa mẫu này.Bạn có thể thay thế Đóng bằng tên phương thức phù hợp với miền của bạn. Ví dụ này yêu cầu không gian tên Hệ thống.

Ý tưởng ở đây là cung cấp sự tương đương với phương pháp Mở. Cá nhân tôi nghĩ rằng nó gây ra rất nhiều sự nhầm lẫn, nhưng tôi không thể nghĩ ra bất cứ điều gì tốt hơn (CloseAndDispose?)

+0

Cảm ơn @Conrad nhưng điều kỳ lạ là tôi sử dụng mã phong cách này trên các hình thức khác nhưng họ làm việc correctly.Why Close() Phương pháp xử lý đối tượng của tôi Đây có phải là hành vi bình thường không? – Arian

+1

có, điều đó là bình thường. Đóng và Vứt bỏ thường làm điều tương tự. –

+0

Tôi không thực sự hiểu.Tại sao mã này: LoginService = Srv_LoginChannelFactory.CreateChannel(); Xem xét rằng nhà nước là đóng cửa, tôi sẽ tạo một trường hợp mới và trạng thái đóng không phải là vấn đề – Arian

2

Vấn đề ở đây (mà tôi nghĩ Conrad bị mất) là Kerezo đang đóng ChannelFactory (Srv_LoginChannelFactory). phân phối) tất cả các kênh của nó, khi anh ấy có thể muốn đóng chỉ Kênh (LoginService).

Vì vậy, thay đổi:

Srv_LoginChannelFactory.Close(); 

tới:

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