c# - MVVM + WCF 异步回调

标签 c# wpf wcf asynchronous mvvm

我有一个 WCF 服务 (IMyService),我将它包装到一个服务 (ICentralService) 中,这样我就有一个可以注入(inject)到 ViewModel 中的中央服务。这将使我在调用 WCF 服务之前在一个位置更改/添加内容的优势。

现在因为我需要进行异步 wcf 调用,所以我的 View 模型也需要是异步的。我的 View 模型有一个回调,但我的 CentralService 也有自己的回调来调用 End... 方法。

问题 :将我的 View 模型回调传递给中央服务中的 EndTest 方法的最佳方法是什么,以便此 EndTest 方法可以通知 View 模型上的回调?

或者也许有更好的方法?
我可以直接在我的 ViewModel 中注入(inject) IMyService,但是我没有可以在通过 WCF 将数据发送到服务器之前操作/注入(inject)数据的中心位置 (CentralService)。

注意:我在 .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 中,并通过 ICentralService 将 WCF (IMyService) 的结果传递给我的 View 模型。

第一次尝试/想法 ,但这并没有将我的“dataResult”值返回给我的 View 模型:
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。这是 reference page对于 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;
                });
    }
}

关于c# - MVVM + WCF 异步回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29119214/

相关文章:

c# - 为什么输入重定向默认适用于 sudo 而不是 passwd? (。网)

C# WPF - ListView 项目到 TextBox

.net - 带有 PHP 客户端的 WCF 服务 - 复杂类型作为参数不起作用

c# - OxyPlot - 如何删除轴

c# - 不使用大整数库的阶乘算法

c# - WPF XAML 绑定(bind)列表和组合框

WPF GroupBox 标题对齐问题

c# - MVVM WPF : Get usercontrol name from ViewModel

c# - 为什么基本身份验证无法与我的 Java SOAP Web 服务 WCF 客户端一起使用?

.net - 即使设置为 Tls12,WCF 也会继续使用 TLS 1.0 和 RSA