2011-01-21 31 views
9

Có lý do gì để mọi dịch vụ WCF gọi là Async không?Có lý do gì để thực hiện mọi cuộc gọi WCF với Async không?

Tôi đã thảo luận với đối tác của tôi. Ông muốn làm cho mọi dịch vụ WPF gọi Async để tránh khóa giao diện người dùng (nó là một ứng dụng WPF trên máy tính để bàn). Tôi chống lại ý tưởng này. Tôi không cảm thấy một cuộc gọi Async là cần thiết trong hầu hết các trường hợp, và khi nó là cần thiết cả RequestingClass và DataManager nên được mã hóa đặc biệt để xử lý cuộc gọi Async.

Đối số của tôi cho điều này là có nhiều mã hơn để thiết lập gọi lại cho mọi thứ và nó rất khó hiểu. Tôi cũng nghĩ rằng điều này có thể làm giảm hiệu suất, mặc dù tôi chưa xác minh điều này. Lập luận của ông là đôi khi bạn đang nhận được rất nhiều dữ liệu và nó sẽ khóa giao diện người dùng, và nó không phải là nhiều công việc để thiết lập các cuộc gọi WCF như thế này (ông cũng không tìm thấy mã sau đây khó hiểu).

Cả hai chúng tôi chưa bao giờ làm việc với máy chủ WCF trước đây, vì vậy tôi nghĩ tôi sẽ cho anh ta lợi ích của sự nghi ngờ và hỏi ở đây về một số ý kiến ​​khác.

Ví dụ:

My Way:

public override User GetById(int id) 
{ 
    return new User(service.GetUserById(id)); 
} 

Nó khóa UI, UserDataManager, và kênh dịch vụ WCF đến khi trở về máy chủ WCF với người dùng DataTransferObject, tuy nhiên nó rất dễ dàng để hiểu và nhanh chóng viết mã. Nó sẽ được sử dụng cho hầu hết các cuộc gọi dịch vụ WCF trừ khi nó thực sự mong đợi một sự chậm trễ trong việc nhận dữ liệu, trong trường hợp đó DataManager sẽ được thiết lập để xử lý các cuộc gọi Async.

Way của ông: hàng đợi

public override void GetById(int id, Action<UserGroup> callback = null) 
{ 
    // This is a queue of all callbacks waiting for a GetById request 
    if (AddToSelectbyIdQueue(id, callback)) 
     return; 

    // Setup Async Call 
    var wrapper = new AsyncPatternWrapper<UserDTO>(
     (cb, asyncState) => server.BeginGetUserById(id, cb, asyncState), 
     Global.Instance.Server.EndGetUserById); 

    // Hookup Callback 
    wrapper.ObserveOnDispatcher().Subscribe(GetByIdCompleted); 

    // Run Async Call 
    wrapper.Invoke(); 
} 

private void GetByIdCompleted(UserDTO dto) 
{ 
    User user = new User(dto); 

    // This goes through the queue of callbacks waiting 
    // for this method to complete and executes them 
    RunSelectIdCallbacks(user.UserId, user); 
} 

Callback trên lớp cơ sở:

/// <summary> 
/// Adds an item to the select queue, or a current fetch if there is one 
/// </summary> 
/// <param name="id">unique object identifier</param> 
/// <param name="callback">callback to run</param> 
/// <returns>False if it needs to be fetched, True if it is already being 
/// fetched</returns> 
protected virtual bool AddToSelectbyIdQueue(int id, Action<T> callback) 
{ 
    // If the id already exists we have a fetch function already going 
    if (_selectIdCallbacks.ContainsKey(id)) 
    { 
     if(callback != null) 
      _selectIdCallbacks[id].Add(callback); 
     return true; 
    } 

    if (callback != null) 
    { 
     List<Action<T>> callbacks = new List<Action<T>> {callback}; 
     _selectIdCallbacks.Add(id, callbacks); 
    } 

    return false; 
} 

/// <summary> 
/// Executes callbacks meant for that object Id and removes them from the queue 
/// </summary> 
/// <param name="id">unique identifier</param> 
/// <param name="data">Data for the callbacks</param> 
protected virtual void RunSelectIdCallbacks(int id, T data) 
{ 
    if (_selectIdCallbacks.ContainsKey(id)) 
    { 
     foreach (Action<T> callback in _selectIdCallbacks[id]) 
      callback(data); 

     _selectIdCallbacks.Remove(id); 
    } 
} 

Nó không khóa UI, các DataManager, hoặc Kênh WCF Service, tuy nhiên rất nhiều thêm mã hóa đi vào nó.

AsyncPatternWrapper nằm trong ứng dụng của chúng tôi bất kể. Nó là cái gì đó cho phép chúng ta thực hiện cuộc gọi async WCF và đăng ký một sự kiện gọi lại

EDIT Chúng tôi có một wrapper mà chúng tôi có thể sử dụng từ thread UI để quấn bất kỳ cuộc gọi DataManager. Nó thực thi phương thức Synchronous trên một BackgroundWorker, và thực hiện một cuộc gọi lại với các kết quả.

Phần lớn mã bổ sung là để ngăn chặn khóa DataManager và kênh dịch vụ WCF.

+3

Cân nhắc đánh giá bản phát hành CTP của tính năng C# "không đồng bộ/đang chờ" mới. Nó được thiết kế để viết loại mã này dễ dàng hơn nhiều. Chúng tôi rất sẵn lòng nhận phản hồi của bạn tại diễn đàn async. http://msdn.microsoft.com/en-us/vstudio/async.aspx –

+0

@Eric: Cảm ơn, tôi đang xem xét nó ngay bây giờ và cho đến nay tôi thích nó! – Rachel

+0

@Eric: Bạn có thể chỉ cho tôi hướng tới bất kỳ hướng dẫn/hướng dẫn tốt nào về việc sử dụng dịch vụ này với dịch vụ WCF không? – Rachel

Trả lời

6

Đối tác của bạn là chính xác; bạn không nên chặn chuỗi giao diện người dùng.

Để thay thế cho cuộc gọi không đồng bộ, bạn cũng có thể thực hiện cuộc gọi đồng bộ trong chuỗi nền bằng cách sử dụng BackgroundWorker hoặc ThreadPool.

+0

Chúng ta thực sự có một wrapper thực hiện điều đó ... nó thực hiện cuộc gọi DataManager trong một chuỗi BackgroundWorker để dừng giao diện người dùng, tuy nhiên được gọi từ luồng UI không phải là DataManager (Lý do là WPF không thể thay đổi các đối tượng được tạo ra trên chuỗi giao diện người dùng từ một BackgroundWorker). Tôi lo lắng về tất cả các mã hóa thêm để chỉ dừng khóa DataManager và WCF Channel. Tôi sẽ cập nhật câu hỏi của mình. – Rachel

+0

Bạn vẫn muốn giới thiệu cách thứ 2? Tôi không có vấn đề gì với nó nếu đó là cách tốt hơn để làm mọi thứ, nhưng không muốn làm quá phức tạp mọi thứ nếu họ không cần thiết – Rachel

+0

@Rachel: Bạn vẫn nên sử dụng một chuỗi riêng biệt cho các cuộc gọi dịch vụ web, chỉ cần sử dụng Dispatcher.Invoke() để cập nhật giao diện người dùng khi cuộc gọi trả về - nhiều thông tin qua Google. –

2

Một vài điều đáng chú ý:

  1. Bất kỳ cuộc gọi WCF có khả năng có thể chặn cho đến khi thời gian timeout của nó và bạn nên thực hiện việc này vào tài khoản. Nó làm cho trải nghiệm người dùng kém khi giao diện người dùng bị chặn trong trường hợp kết nối bị mất.Các cuộc gọi cũng có thể chạy chậm hơn bình thường, nếu, ví dụ, máy chủ bị sa lầy.

  2. Ngay cả khi bạn không gói các cuộc gọi cho mục đích không đồng bộ, có thể bạn sẽ muốn một số gói cuộc gọi đến proxy. Điều này là do bất kỳ cuộc gọi nào trên proxy đều có khả năng đặt kênh ở trạng thái bị lỗi và nếu điều này xảy ra, bạn để gọi Abort() trên kênh hoặc bạn có thể làm rò rỉ tài nguyên. Xem this postthis other post để biết thêm thông tin. WCF proxy không thể được sử dụng như các lớp bình thường và nhất thiết phải liên quan đến gói bổ sung nếu bạn muốn sử dụng chúng trong một kịch bản sản xuất. Điều này phần lớn là không thể tránh khỏi, vì đó là hậu quả của các trường hợp biên giới bổ sung và hành vi không thể đoán trước được đưa ra bởi các yêu cầu giao tiếp từ xa.

+0

Tôi đã xóa rất nhiều mã để tôi chỉ có thể hiển thị mã có liên quan. Tất cả các cuộc gọi dịch vụ trong DataManagers được bao bọc trong một cái gì đó mà bắt ngoại lệ/lỗi và đảm bảo kênh vẫn mở. Hầu hết các cuộc gọi DataManager được gói trong một cái gì đó mà thực hiện chúng trên một BackgroundWorker và dừng chặn UI. Lời khuyên tốt mặc dù :) – Rachel

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