簡體   English   中英

MVVM + WCF異步回調

[英]MVVM + WCF Async callbacks

我有一個WCF服務(IMyService),可以包裝到一個服務(ICentralService)中,這樣我就可以在ViewModels中注入一個中央服務。 這將使我受益於在調用WCF服務之前在一個位置更改/添加內容的優點。

現在,因為我需要進行異步wcf調用,所以我的viewmodel也需要是異步的。 我的視圖模型有一個回調,但是CentralService也有自己的回調來調用End ...方法。

問題 :將我的viewmodel-callback傳遞給中央服務中的EndTest方法的最佳方法是什么,以便該EndTest方法可以通知viewmodel上的回調?

還是有更好的方法? 我可以在ViewModel中直接注入IMyService,但是我沒有中央位置(CentralService),可以在其中通過WCF將數據發送到服務器之前對其進行操作/注入。

注意:我在.NET 4.0上,不能使用“等待”,我也在使用WCF IAsyncResult模型(服務器端)。

碼:

[ServiceContract(....)]
public interface IMyService {
    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginTest(int x, AsyncCallback, object state);

    int EndTest(IAsyncResult result);
}

public interface ICentralService {
    void WorkItAsync(int x, AsyncCallback callback);
}

public class CentralService : ICentralService 
{
    private IMyService _Srv;

    public CentralService(IMyService srv) 
    {
        _Srv = srv;
    }

    public void WorkItAsync(int x, AsyncCallback callback) 
    {
        // callback is the callback from my viewmodel

        _Srv.BeginTest(x, new AsyncCallback(WorkItCompleted));
    }

    private void WorkItCompleted(IAsyncResult r) 
    {
        // ...
        int result = _Srv.EndTest(r);

        // Need to call callback from viewmodel now to notify it is ready.
    }
}


public class SomeViewModel : INotifyPropertyChanged 
{
    private ICentralService _Central;

    public SomeViewModel(ICentralService central) {
        _Central = central;
    }

  private void A() {
    _Central.WorkItAsync(5, new AsyncCallback(B));
  }

  private void B(object test) {
    // do something with the result
  }
}

更新:我設法將IMyService包裝到我的ICentralService中,並將結果從WCF(IMyService)通過ICentralService傳遞到我的視圖模型。

第一次嘗試/想法 ,但這沒有將我的“ dataResult”值返回給我的viewmodel:

public void WorkItAsync(int x, AsyncCallback callback) 
{
    var task = Task<int>.Factory.StartNew(() => 
    {
        int dataResult = -1;
        _Srv.BeginTest(x, (ar) => { 
            dataResult  = _Srv.EndTest(ar);
        }, null);

        return dataResult ;
    });

    if (callback != null)
        task.ContinueWith((t) => callback(t));

    return task;
}

第二次嘗試(有效):

public void WorkItAsync(int x, AsyncCallback callback) 
{
    TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>();
    Task<int> t1 = tcs1.Task;

    Task<int>.Factory.StartNew(() => 
    {
        int dataResult = -1;
        _Srv.BeginTest(x, (ar) => { 
            dataResult = _Srv.EndTest(ar);
            tcs1.SetResult(dataResult);
        }, null);

        return dataResult;
    });

    if (callback != null)
        t1.ContinueWith((t) => callback(t));

    return t1;
}

我不確定使用TaskCompletionSource這是否是一個好的解決方案,但目前看來似乎可行。 (太糟糕了,我必須返回一個無用的-1 dataResult值)。

第二個更新看起來不錯,但是我認為您可以使用TaskFactory.FromAsync暫時避免TaskCompletionSource。 這是FromAsync的參考頁和示例。 我還沒有測試過,但是方法可能看起來像這樣:

public interface ICentralService
{
    // Just use .ContinueWith to call a completion method
    Task<int> WorkItAsync(int x);
}

public class CentralService : ICentralService 
{
    private IMyService _Srv;

    public CentralService(IMyService srv) 
    {
        _Srv = srv;
    }

    public Task<int> WorkItAsync(int x) 
    {
        // Callback is handled in ViewModel using ContinueWith
        return Task<int>.Factory.FromAsync(_Src.BeginTest, _Src.EndTest, x);
    }
}

public class SomeViewModel : INotifyPropertyChanged 
{
    private ICentralService _Central;

    public SomeViewModel(ICentralService central)
    {
        _Central = central;
    }

    private void A()
    {
        _Central.WorkItAsync(5)
                .ContinueWith(prevTask =>
                {
                    // Handle or throw exception - change as you see necessary
                    if (prevTask.Exception != null)
                        throw prevTask.Exception;

                    // Do something with the result, call another method, or return it...
                    return prevTask.Result;
                });
    }
}

您可以使用lambdas:

public void WorkItAsync(int x, AsyncCallback callback) 
{
    // callback is the callback from my viewmodel

    _Srv.BeginTest(x, ar=>{
        int result = _Srv.EndTest(ar);
        callback(ar);
    });
}

如果需要,ar將是您的IAsyncResult。 您甚至可以並行運行多個請求,因為回調變量將在每個並行調用的本地范圍內。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM