2011-10-20 27 views
18

Vì vậy, tôi đã quyết định tăng hiệu suất một chút trong ứng dụng WCF của mình và cố gắng lưu trữ Kênh và ChannelFactory. Có hai câu hỏi tôi có về tất cả những điều này mà tôi cần phải làm sáng tỏ trước khi tôi bắt đầu.Kênh WCF và ChannelFactory Caching

1) ChannelFactory có nên được triển khai dưới dạng singleton không?

2) Tôi không chắc chắn về cách lưu vào bộ nhớ cache/sử dụng lại các kênh riêng lẻ. Bạn có bất kỳ ví dụ nào về cách thực hiện điều này bạn có thể chia sẻ không?

Điều quan trọng cần lưu ý là dịch vụ WCF của tôi đang được triển khai dưới dạng ứng dụng độc lập, chỉ với một điểm cuối.

EDIT:

Cảm ơn bạn đã trả lời. Tôi vẫn có một số câu hỏi mặc dù ...

1) Tôi đoán tôi đang nhầm lẫn về nơi lưu bộ nhớ cache sẽ xảy ra. Tôi đang cung cấp API ứng dụng khách sử dụng mã này cho một bộ phận khác trong công ty của chúng tôi. Liệu bộ nhớ đệm này có xảy ra trên máy khách không?

2) API ứng dụng khách sẽ được sử dụng như một phần của ứng dụng Silverlight, điều này có thay đổi gì không? Cụ thể, cơ chế lưu trữ bộ nhớ đệm nào có sẵn trong kịch bản như vậy?

3) Tôi vẫn chưa rõ về thiết kế của phương pháp GetChannelFactory. Nếu tôi chỉ có một dịch vụ, chỉ nên một ChannelFactory được tạo và lưu vào bộ nhớ cache?

tôi vẫn chưa thực hiện bất kỳ tính năng bộ nhớ đệm (vì tôi hoàn toàn nhầm lẫn về cách nó nên được thực hiện!), Nhưng đây là những gì tôi có cho các proxy client cho đến nay:

namespace MyCompany.MyProject.Proxies 
{ 
    static readonly ChannelFactory<IMyService> channelFactory = 
     new ChannelFactory<IMyService>("IMyService"); 

    public Response DoSomething(Request request) 
    { 
     var channel = channelFactory.CreateChannel(); 

     try 
     { 
      Response response = channel.DoSomethingWithService(request); 
      ((ICommunicationObject)channel).Close(); 
      return response; 
     } 
     catch(Exception exception) 
     { 
      ((ICommenicationObject)channel).Abort(); 
     } 
    } 
} 
+0

Đối với # 3, vâng, chỉ nên tạo một nhà máy kênh. Về cơ bản, bạn sẽ có một nhà máy kênh cho từng dịch vụ mà bạn có. Trong trường hợp của tôi, chúng tôi có khoảng 6 cho đến nay, lây lan chủ yếu qua 2 tầng. Trong trường hợp của bạn, nếu bạn chỉ sẽ có một dịch vụ, sử dụng bởi một ứng dụng, bạn có thể chỉ cần làm những gì bạn đang làm ở trên. Bạn đang ở trên mã đang đi đúng hướng. Caching sẽ dựa trên nhu cầu của ứng dụng. – Tim

+0

@Tim -thanks cho tất cả sự giúp đỡ của bạn. Tôi thực sự đánh giá cao nó! Tôi nghĩ trong trường hợp của tôi, sự thật là dịch vụ của tôi quá "đơn giản" đã khiến tôi bối rối nhìn qua những ví dụ khác nơi có nhiều điểm cuối. Tôi = ít bối rối hơn bây giờ = Tim đã làm một công việc tuyệt vời giải thích! Cảm ơn anh bạn! – Didaxis

+0

Bạn đang khá hoan nghênh. Vui vì tôi có thể giúp - mã hóa vui vẻ! – Tim

Trả lời

20

Sử dụng ChannelFactory để tạo một thể hiện của nhà máy, sau đó lưu vào bộ nhớ cache ví dụ đó. Sau đó bạn có thể tạo các kênh communicatino khi cần/mong muốn từ istance được lưu trong bộ nhớ cache.

Bạn có cần thiết cho nhiều nhà máy kênh (tức là .., có nhiều dịch vụ) không? Theo kinh nghiệm của tôi, đó là nơi bạn sẽ thấy lợi ích lớn nhất về hiệu suất. Tạo một kênh là một nhiệm vụ khá rẻ tiền; nó thiết lập mọi thứ vào lúc bắt đầu cần có thời gian.

Tôi sẽ không lưu các kênh riêng lẻ - tôi sẽ tạo chúng, sử dụng chúng cho một hoạt động và sau đó đóng chúng lại. Nếu bạn cache chúng, chúng có thể hết thời gian và kênh sẽ bị lỗi, sau đó bạn sẽ phải hủy bỏ nó và tạo một cái mới.

Không chắc chắn lý do tại sao bạn muốn sử dụng singleton để triển khai ChannelFactory, đặc biệt nếu bạn định tạo và lưu trữ bộ nhớ cache và chỉ có một điểm cuối.

Tôi sẽ đăng một số mã mẫu sau này khi tôi có thêm một chút thời gian.

UPDATE: Mã Ví dụ

Dưới đây là một ví dụ về cách tôi thực hiện điều này cho một dự án tại nơi làm việc. Tôi đã sử dụng ChannelFactory<T> vì ứng dụng tôi đang phát triển là một ứng dụng n-tier với một số dịch vụ và nhiều ứng dụng khác sẽ được thêm vào. Mục đích là để có một cách đơn giản để tạo ra một khách hàng một lần cho mỗi cuộc đời của ứng dụng, và sau đó tạo ra các kênh truyền thông khi cần thiết. Những điều cơ bản của ý tưởng không phải của tôi (tôi đã nhận nó từ một bài viết trên web), mặc dù tôi đã sửa đổi việc thực hiện cho các nhu cầu của tôi.

Tôi có một lớp trợ giúp tĩnh trong ứng dụng của mình, và trong lớp đó tôi có một từ điển và một phương pháp để tạo các kênh truyền thông từ nhà máy channelf.

Từ điển như sau (đối tượng là giá trị vì nó sẽ chứa các nhà máy kênh khác nhau, một cho mỗi dịch vụ). Tôi đặt "Cache" trong ví dụ dưới dạng một trình giữ chỗ - thay thế cú pháp bằng bất kỳ cơ chế bộ nhớ đệm nào bạn đang sử dụng.

public static Dictionary<string, object> OpenChannels 
{ 
    get 
    { 
     if (Cache["OpenChannels"] == null) 
     { 
      Cache["OpenChannels"] = new Dictionary<string, object>(); 
     } 

     return (Dictionary<string, object>)Cache["OpenChannels"]; 
    } 
    set 
    { 
     Cache["OpenChannels"] = value; 
    } 
} 

Tiếp theo là phương pháp tạo kênh liên lạc từ phiên bản gốc. Phương pháp này kiểm tra xem nhà máy có tồn tại trước không - nếu không, nó tạo ra nó, đặt nó vào từ điển và sau đó tạo ra kênh. Nếu không, nó chỉ đơn giản là tạo ra một kênh từ thể hiện được lưu trữ của nhà máy.

public static T GetFactoryChannel<T>(string address) 
{ 

    string key = typeof(T.Name); 

    if (!OpenChannels.ContainsKey(key)) 
    { 
     ChannelFactory<T> factory = new ChannelFactory<T>(); 
     factory.Endpoint.Address = new EndpointAddress(new System.Uri(address)); 
     factory.Endpoint.Binding = new BasicHttpBinding(); 
     OpenChannels.Add(key, factory); 
    } 

    T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel(); 

    ((IClientChannel)channel).Open(); 

    return channel; 
} 

Tôi đã rút ví dụ này xuống một số từ những gì tôi sử dụng tại nơi làm việc. Có rất nhiều thứ bạn có thể làm trong phương pháp này - bạn có thể xử lý nhiều ràng buộc, gán thông tin xác thực để xác thực, v.v. của nó khá nhiều trung tâm mua sắm của bạn để tạo khách hàng.

Cuối cùng, khi tôi sử dụng nó trong ứng dụng, tôi thường tạo một kênh, thực hiện công việc kinh doanh của mình và đóng nó (hoặc hủy bỏ nó nếu cần). Ví dụ:

IMyServiceContract client; 

try 
{ 
    client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress"); 

    client.DoSomething(); 

    // This is another helper method that will safely close the channel, 
    // handling any exceptions that may occurr trying to close. 
    // Shouldn't be any, but it doesn't hurt. 
    Helper.CloseChannel(client); 
} 
catch (Exception ex) 
{ 
    // Something went wrong; need to abort the channel 
    // I also do logging of some sort here 
    Helper.AbortChannel(client); 
} 

Hy vọng các ví dụ trên sẽ cho bạn điều gì đó để tiếp tục. Tôi đã sử dụng một cái gì đó tương tự như thế này trong khoảng một năm nay trong một môi trường sản xuất và nó đã làm việc rất tốt. 99% của bất kỳ vấn đề chúng tôi gặp phải thường có liên quan đến một cái gì đó bên ngoài ứng dụng (hoặc khách hàng bên ngoài hoặc nguồn dữ liệu không thuộc kiểm soát trực tiếp của chúng tôi).

Hãy cho tôi biết nếu mọi thứ không rõ ràng hoặc bạn có thêm câu hỏi.

+0

Cảm ơn Tim. Bạn thực sự đã cung cấp một số thông tin có giá trị. Tôi chắc chắn sẽ tìm kiếm ví dụ của bạn! – Didaxis

+0

@ user384080 - mã nằm trong câu trả lời của tôi. Nếu điều đó không rõ ràng, hãy cho tôi biết. Cảm ơn. – Tim

+0

@Tim Có lỗi trong quá trình triển khai của bạn. Bạn lưu trữ các nhà máy theo loại hợp đồng bất kể địa chỉ là gì. Bạn nên có khóa chứa cả loại hợp đồng và địa chỉ. – Anubis

5

Bạn có thể luôn luôn chỉ cần đảm ChannelFactory bạn tĩnh cho mỗi hợp đồng WCF ...

Bạn nên biết rằng từ Net 3.5 các đối tượng proxy được gộp vì lý do hiệu suất của các nhà máy kênh. Gọi phương thức ICommunicationObject.Close() thực sự trả về đối tượng vào hồ bơi với hy vọng nó có thể được sử dụng lại.

Tôi sẽ xem xét hồ sơ nếu bạn muốn thực hiện tối ưu hóa, nếu bạn có thể ngăn chặn chỉ một cuộc gọi IO được thực hiện trong mã của bạn, nó có thể vượt xa bất kỳ tối ưu hóa nào bạn sẽ thực hiện với nhà máy kênh. Không chọn một khu vực để tối ưu hóa, sử dụng trình hồ sơ để tìm nơi bạn có thể nhắm mục tiêu tối ưu hóa. Ví dụ, nếu bạn có một cơ sở dữ liệu SQL, có thể bạn sẽ tìm thấy một số kết quả treo thấp trong các truy vấn của mình, điều này sẽ giúp bạn có được các đơn đặt hàng có hiệu suất lớn nếu chúng chưa được tối ưu hóa.

3

Tạo kênh sẽ làm tăng hiệu suất rất nhiều. trên thực tế, WCF đã có cơ chế cache cho ChannelFactory nếu bạn sử dụng ClientBase trong máy khách thay vì ChannelFactory thuần túy. Nhưng bộ nhớ cache sẽ hết hạn nếu bạn thực hiện một số thao tác có điều kiện (Vui lòng google nó để biết chi tiết nếu bạn muốn). Đối với vấn đề của ErOx tôi có một giải pháp khác, tôi nghĩ nó tốt hơn. xem bên dưới:


namespace ChannelFactoryCacheDemo 
{ 
    public static class ChannelFactoryInitiator 
    { 
     private static Hashtable channelFactories = new Hashtable(); 

     public static ChannelFactory Initiate(string endpointName) 
     { 
      ChannelFactory channelFactory = null; 

      if (channelFactories.ContainsKey(endpointName))//already cached, get from the table 
      { 
       channelFactory = channelFactories[endpointName] as ChannelFactory; 
      } 
      else // not cached, create and cache then 
      { 
       channelFactory = new ChannelFactory(endpointName); 
       lock (channelFactories.SyncRoot) 
       { 
        channelFactories[endpointName] = channelFactory; 
       } 
      } 
      return channelFactory; 
     } 
    } 
    class AppWhereUseTheChannel 
    { 
     static void Main(string[] args) 
     { 
      ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint"); 
     } 
    } 

    interface IMyContract { } 
} 

bạn có thể tùy chỉnh logic và tham số của chính phương pháp khởi tạo nếu bạn có yêu cầu khác. nhưng lớp khởi tạo này không chỉ giới hạn một điểm cuối. nó là mạnh mẽ cho tất cả các điểm cuối trong ứng dụng của bạn. hy vọng. nó hoạt động tốt cho bạn. BTW. giải pháp này không phải từ tôi. tôi đã nhận được từ một cuốn sách.

+0

Lưu ý rằng 'khóa' được sử dụng không chính xác. Khóa nên được thực hiện trên cuộc gọi đến 'ContainsKey' là tốt. –

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