2

I have created some sample ViewModel to test usage of DPs with asyncCtp:

public class SampleVm : DependencyObject
{

    public static readonly DependencyProperty SampleDependencyPropertyProperty =
        DependencyProperty.Register("SampleDependencyProperty", typeof (int), typeof (SampleVm), new PropertyMetadata(default(int)));

    public int SampleDependencyProperty
    {
        get { return (int) GetValue(SampleDependencyPropertyProperty); }
        set { SetValue(SampleDependencyPropertyProperty, value); }
    }
    public ISampleModel _model;
    public SampleVm(ISampleModel model)
    {
        _model = model;
    }

    public async Task SetDependencyProperty()
    {
        var modelData = await TaskEx.Run(() => _model.GetSomeIntegerValue());
        SampleDependencyProperty = modelData;
    }
}

and the model which injected to ViewModel is:

public interface ISampleModel
{
    int GetSomeIntegerValue();
}

public class SampleModel : ISampleModel
{
    public int GetSomeIntegerValue()
    {
        return 10;
    }
}

when I run the WPF application there is no problem, but when I want to test it with the following code:

[Fact]
public async Task CheckValueSetting()
{
    var model = new Mock<ISampleModel>();
    model.Setup(x => x.GetSomeIntegerValue()).Returns(5);
    var viewModel =new SampleVm(model.Object);

    await viewModel.SetDependencyProperty();

    Assert.Equal(5, viewModel.SampleDependencyProperty);
}

I got the following error:

System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.

Server stack trace: 

    at System.Windows.Threading.Dispatcher.VerifyAccess()
    at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
    at WpfApplication4.SampleVm.set_SampleDependencyProperty(Int32 value) in SampleVM.cs: line 19
    at WpfApplication4.SampleVm.<SetDependencyProperty>d__1.MoveNext() in SampleVM.cs: line 30

    Exception rethrown at [0]: 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    at WpfApplication4.SampleVmFixture.<CheckValueSetting>d__0.MoveNext() in SampleVmFixture.cs: line 16 

so what is the solution?

mehdi.loa
  • 579
  • 1
  • 5
  • 23
  • Can I check: why are you still using the async CTP? Isn't that all in core .NET now? – Marc Gravell Dec 09 '12 at 11:47
  • I have to use .Net framework 4 because of the restrictions in the company. – mehdi.loa Dec 09 '12 at 12:45
  • that makes precisely no sense. By definition a CTP is completely unsupported, and in this case is now obsolete. There is no universe where using a CTP is a better option than facing the upgrade. IMO: take the upgrade (even if that means some work internally), or forget about async. Finally: much of the async stuff is in 4.0 anyway!!! – Marc Gravell Dec 09 '12 at 13:34
  • Targeting .NET 4 makes sense, particularly since the "in-place" 4.5 upgrade doesn't support XP. He probably just doesn't know about Microsoft.Bcl.Async. – Stephen Cleary Dec 09 '12 at 13:39
  • thanks to @MarcGravell and StephenCleary for their suggestions. after reading this [question](http://stackoverflow.com/questions/9898441/do-the-new-c-sharp-5-0-async-and-await-keywords-use-multiple-cores/9899487#9899487) and this [blog on MSDN](http://blogs.msdn.com/b/lucian/archive/2011/04/17/async-ctp-refresh-what-bugs-remain-in-it.aspx) I think the solution is not to continue with AsyncCtp. – mehdi.loa Dec 09 '12 at 15:23

1 Answers1

1

First, I recommend that you upgrade to VS2012 with the Microsoft.Bcl.Async package. This will enable you to target .NET 4.0 with the newest tools. The Async CTP has known bugs that will not be fixed, and it has installation issues (that won't be fixed) that will make setting up new development machines quite difficult.

But before you delete the Async CTP, check out your (C# Testing) Unit Testing directory under the Async CTP directory. You'll find several types to help with unit testing, such as GeneralThreadAffineContext:

[Fact]
public async Task CheckValueSetting()
{
    var model = new Mock<ISampleModel>();
    model.Setup(x => x.GetSomeIntegerValue()).Returns(5);
    SampleVm viewModel;
    await GeneralThreadAffineContext.Run(async () =>
    {
        viewModel = new SampleVm(model.Object);
        await viewModel.SetDependencyProperty();
    });

    Assert.Equal(5, viewModel.SampleDependencyProperty);
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • The example from the CTP is not available elsewhere? Also, I think you forgot to `await` the result of `Run()`. – svick Dec 09 '12 at 17:26
  • I'm not aware of an official source for the "extras" from the Async CTP; `AsyncContext` in my AsyncEx library is a pretty close match for `GeneralThreadAffineContext`, but I'm not aware of anything equivalent to `WindowsFormsContext` or `WpfContext`. Also, `Run` returns `void` (it does not complete until all `async` methods have completed). – Stephen Cleary Dec 09 '12 at 21:25
  • The `GeneralThreadAffineContext` I have has several overloads of `Run()`: `void Run(Action asyncAction)` and `Task Run(Func asyncMethod)` and since you're using the second one, I think you have to `await` it. – svick Dec 09 '12 at 23:51
  • @svick: You are correct; I had modified my copy. Technically, that `Run` overload will wait for the `async` method to complete, but there's no harm in `await`ing it. – Stephen Cleary Dec 10 '12 at 01:00