2010-10-07 25 views
6

Từ những gì tôi hiểu, khi một thành phần COM được đánh dấu là sử dụng STA được sử dụng từ một chủ đề MTA, các cuộc gọi được coi là marshalled đến một chuỗi STA và được thực hiện từ chuỗi chuyên dụng đó. Trong trường hợp của một ứng dụng máy khách Windows, điều này có nghĩa là nó sẽ thực hiện trên luồng UI (nếu được đánh dấu là STA), và các cuộc gọi lại từ thành phần COM đến tôi sẽ được xử lý bởi các tin nhắn Windows được gửi đến một cửa sổ ẩn và được xử lý vòng lặp tin nhắn Windows.Các thành phần COM STA được xử lý như thế nào khi được sử dụng trong dịch vụ WCF được lưu trữ trong IIS (7+)?

Điều gì sẽ xảy ra nếu tôi sử dụng thành phần COM STA trong dịch vụ WCF được lưu trữ trong IIS? Quy trình công nhân có vòng lặp tin nhắn Windows trên chuỗi STA không? Tôi có thể kích hoạt chuỗi STA của riêng mình bằng vòng lặp tin nhắn của riêng mình không?

Trả lời

4

Thời gian chạy COM trông sau khi gửi các cuộc gọi đến các phương thức trên đối tượng COM bên trong STA: bạn đúng là dựa trên cùng một cơ chế HĐH được sử dụng để gửi thư Windows, nhưng bạn không cần phải lo lắng về làm điều này xảy ra - COM thực hiện điều này cho bạn dưới mui xe.

Những gì bạn làm cần phải lo lắng về STA đối tượng COM của bạn sẽ sống. Nếu bạn nhanh chóng tạo đối tượng COM căn hộ bằng COM Interop từ dịch vụ WCF, bạn cần phải cẩn thận.

Nếu chuỗi mà bạn thực hiện điều này không phải là một chuỗi STA, thì tất cả các đối tượng COM trong quá trình sẽ hoạt động trong mặc định Host STA cho quy trình công nhân IIS. Bạn không muốn điều này xảy ra: tất cả các đối tượng COM của bạn cho tất cả các hoạt động dịch vụ sẽ kết thúc trong cùng một STA này. Các đầu mối là trong tên - chỉ có một sợi cho tất cả các đối tượng - và tất cả các cuộc gọi đến phương pháp của họ sẽ được serialized chờ đợi cho một và chỉ thread trong căn hộ để thực hiện chúng. Dịch vụ của bạn sẽ không mở rộng để xử lý nhiều khách hàng đồng thời.

Bạn cần đảm bảo rằng đối tượng COM bạn khởi tạo để phục vụ một yêu cầu WCF cụ thể nằm trong STA riêng của chúng khỏi các đối tượng được tạo cho các yêu cầu khác. Có một cách rộng rãi hai cách để làm điều này:

  • spin up Thread riêng của bạn, xác định ApartmentState.STA trong SetApartmentState() trước khi bạn bắt đầu nó, mà trên đó để nhanh chóng các đối tượng COM cho một yêu cầu cụ thể. Đây là cách tiếp cận chi tiết của Scott Seely trong the link in Kev's answer: ông đảm bảo rằng mỗi cuộc gọi hoạt động dịch vụ được gọi trên một chủ đề mới được khởi tạo STA. Một giải pháp khó khăn hơn nhưng có khả năng mở rộng hơn dọc theo các dòng này sẽ là để thực hiện một nhóm các chủ đề được khởi tạo lại STA.
  • Lưu trữ các đối tượng COM của bạn trong ứng dụng COM +, để chúng tồn tại trong một quá trình DllHost riêng biệt, nơi COM + (thông qua sự trừu tượng của nó được gọi là the Activity) có thể xử lý các đối tượng cho các yêu cầu khác nhau vào các STA khác nhau.

Tôi không chắc chắn chính xác ý bạn là gì khi bạn tham chiếu đến gọi lại. Có lẽ bạn có nghĩa là các cuộc gọi phương thức COM trên một số giao diện COM được triển khai trong mã được quản lý của bạn, thông qua một tham chiếu được truyền vào đối tượng COM làm đối số cho một trong các phương thức của đối tượng COM: nếu vậy, điều này chỉ hoạt động. Nhưng có lẽ bạn có ý nghĩa gì đó khác, trong trường hợp đó có lẽ bạn có thể sửa đổi câu hỏi để làm rõ.

3

Tôi đã tìm thấy rằng bạn cần phải bơm thư trên chuỗi STA của bạn trong dịch vụ WCF hoặc bạn bỏ lỡ cuộc gọi lại từ đối tượng COM.

Mã sau hoạt động, nhưng nó yêu cầu bạn gọi đối tượng COM thông qua Bộ điều phối.

ComWrapper comWrapper; 
Thread localThread; 
Dispatcher localThreadDispatcher; 

public Constructor() 
{ 
    localThread = new Thread(ThreadProc) 
    { 
     Name = "test" 
    }; 
    localThread.SetApartmentState(ApartmentState.STA); 

    AutoResetEvent init = new AutoResetEvent(false); 

    localThread.Start(init); 

    init.WaitOne(); 
} 

private void ThreadProc(object o) 
{ 
    localThreadDispatcher = Dispatcher.CurrentDispatcher; 
    ((AutoResetEvent)o).Set(); 

    comWrapper = new ComWrapper() 

    Dispatcher.Run(); 

    localThreadFinished.Set(); 
} 

Và sau đó thực hiện cuộc gọi như sau.

public void UsefulComOperation() 
{ 
    localThreadDispatcher.Invoke(new Action(() => comWrapper.UsefulOperation); 
} 
+1

'localThreadFinished' không được định nghĩa bất cứ nơi nào, như xa như tôi có thể nói ... là ý định của bạn phải khai báo nó ở phía trên cùng của 'ThreadProc', là' AutoResetEvent localThreadFinished = (AutoResetEvent) O'? – transistor1

Các vấn đề liên quan