Tôi đã đấu tranh với WCF Proxies. Cách chính xác để vứt bỏ một WCF Proxy là gì? Câu trả lời không phải là tầm thường.Cách chính xác để vứt bỏ một Proxy WCF là gì?
System.ServiceModel.ClientBase vi phạm của Microsoft riêng Vứt bỏ-pattern
không thực hiện IDisposable
nên người ta phải thừa nhận rằng nó nên được xử lý hoặc sử dụng trong một -block using
. Đây là những thực hành tốt nhất cho bất cứ thứ gì dùng một lần. Tuy nhiên, việc triển khai là rõ ràng, do đó, một người phải bỏ rõ ràng các trường hợp ClientBase
đến IDisposable
, hãy giải quyết vấn đề.
Các nguồn lớn nhất của sự nhầm lẫn, tuy nhiên, đó là kêu gọi Dispose()
trên ClientBase
trường hợp mà faulted, thậm chí kênh mà faulted vì họ không bao giờ mở ra ở nơi đầu tiên, sẽ dẫn đến một ngoại lệ được ném. Điều này, chắc chắn, có nghĩa là ngoại lệ có ý nghĩa giải thích lỗi ngay lập tức bị mất khi ngăn xếp thư giãn, phạm vi using
kết thúc và Dispose()
ném một ngoại lệ vô nghĩa nói rằng bạn không thể vứt bỏ một kênh bị lỗi.
Hành vi trên là anathema đối với mẫu vứt bỏ mẫu nêu rõ rằng đối tượng phải chịu được nhiều cuộc gọi rõ ràng đến Dispose()
. (Xem http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx, "... cho phép các phương pháp Dispose(bool)
được gọi là nhiều hơn một lần. Phương pháp này có thể chọn để làm gì sau khi cuộc gọi đầu tiên.")
Với sự ra đời của đảo ngược-of-kiểm soát , việc triển khai kém này trở thành một vấn đề thực sự. I.O.C. container (cụ thể là Ninject) phát hiện giao diện IDisposable
và gọi Dispose()
rõ ràng trên các phiên bản được kích hoạt ở cuối phạm vi tiêm.
Giải pháp: Proxy ClientBase và Intercept gọi Dispose()
Giải pháp của tôi là để proxy ClientBase
bởi subclassing System.Runtime.Remoting.Proxies.RealProxy
và chiếm quyền điều khiển hoặc cuộc gọi chặn để Dispose()
. thay thế đầu tiên của tôi cho Dispose()
đi một cái gì đó như thế này:
if (_client.State == CommunicationState.Faulted) _client.Abort();
else ((IDisposable)_client).Dispose();
(Lưu ý rằng _client
là một tài liệu tham khảo đánh máy với mục tiêu của proxy.)
Vấn đề với NetTcpBinding
Tôi nghĩ rằng điều này đã đóng đinh nó, ban đầu, nhưng sau đó tôi phát hiện ra một vấn đề trong sản xuất: trong một số trường hợp khó tạo ra, tôi thấy rằng các kênh sử dụng NetTcpBinding
không đóng đúng cách trong trường hợp không có lỗi, mặc dù Dispose
đã được gọi trên _client
.
Tôi đã có ứng dụng ASP.NET MVC bằng cách triển khai proxy để kết nối với Dịch vụ WCF bằng cách sử dụng NetTcpBinding
trên mạng cục bộ, được lưu trữ trong Dịch vụ Windows NT trên một cụm dịch vụ chỉ với một nút. Khi tôi tải thử nghiệm ứng dụng MVC, một số điểm cuối trên Dịch vụ WCF (đang sử dụng chia sẻ cổng) sẽ ngừng đáp ứng sau một thời gian.
Tôi đã cố gắng để tái tạo điều này: các thành phần tương tự chạy trên mạng LAN giữa hai máy của nhà phát triển đã hoạt động hoàn hảo; một ứng dụng giao diện điều khiển đóng búa các điểm cuối WCF thực (chạy trên cụm dịch vụ dàn dựng) với nhiều quy trình và nhiều luồng trong mỗi tác vụ; cấu hình ứng dụng MVC trên máy chủ dàn dựng để kết nối với các điểm cuối trên máy của nhà phát triển làm việc dưới tải; chạy ứng dụng MVC trên máy của nhà phát triển và kết nối với các điểm cuối WCF dàn dựng đã làm việc. Kịch bản cuối cùng chỉ làm việc dưới IIS Express, tuy nhiên, và đây là một bước đột phá. Các thiết bị đầu cuối sẽ sieze lên khi tải thử nghiệm ứng dụng MVC dưới IIS đầy chất béo trên máy của nhà phát triển, kết nối với cụm dịch vụ dàn dựng.
Giải pháp: Đóng Channel
Sau khi thất bại trong việc hiểu được vấn đề và đọc nhiều, rất nhiều trang của MSDN và các nguồn khác khẳng định vấn đề không nên tồn tại ở tất cả, tôi đã cố gắng một lâu-shot và thay đổi Dispose()
tôi làm việc xung quanh để ...
if (_client.State == CommunicationState.Faulted) _client.Abort();
else if (_client.State == CommunicationState.Opened)
{
((IContextChannel)_client.Channel).Close();
((IDisposable)_client).Dispose();
}
else ((IDisposable)_client).Dispose();
... và các vấn đề ngừng xảy ra trong tất cả các thiết lập kiểm tra và theo tải trọng trong môi trường chạy thử!
Tại sao?
Bất cứ ai có thể giải thích những gì có thể đã xảy ra và tại sao phải đóng một cách rõ ràng Channel
trước khi gọi Dispose()
giải quyết được không? Theo như tôi có thể nói, điều này không cần thiết.
Cuối cùng, tôi quay trở lại câu hỏi mở: Cách chính xác để Vứt bỏ một Proxy WCF là gì? Là sự thay thế của tôi cho Dispose()
đầy đủ?