Catel call ShowDialogAsync sync - catel

I try to call ShowDialogAsync in a synchron code. I'm not very familiar with async programming. If I run this code, I end up in a deadlock. If I change Command to TaskCommand, it will work, but I have to change all Code to async.
public MainWindow()
{
InitializeComponent();
Abc = new Command(() => Asd());
}
public Command Abc { get; set; }
private void Asd()
{
var b = StartDialog(true).GetAwaiter().GetResult();
}
private async Task<bool> StartDialog(bool isMultiple)
{
await ServiceLocator.Default.ResolveType<IUIVisualizerService>().ShowDialogAsync<PersonVm>(new PersonM());
return true;
}
Here I have used the answer from here.
Could someone help me please?

The recommended way is to migrate your code to async. Most features in Catel are async (such as vm initialization, etc). At first it might be a bit overwhelming, but once you get how it works, it's a very convenient way of programming. In the meantime, you can use a workaround (this is not best practice, but will get you through this task):
private async void Asd()
{
var b = await StartDialog(true);
}
Note that async void is not recommended and should really be avoided unless no other options are available (such as non-async event handlers, etc).

Related

Threads not working properly

I've the following code, used to test the Task framework on C#
static void Main(string[] args)
{
Task<string> task1 = AsyncA();
task1.ContinueWith(Print);
Task<string> task2 = AsyncB();
task2.ContinueWith(Print);
Task.WaitAll(new Task[] {task1, task2});
}
static async Task<string> AsyncA()
{
Thread.Sleep(1500);
return "A";
}
static async Task<string> AsyncB()
{
Thread.Sleep(430);
return "B";
}
static async void Print(Task<string> str)
{
Console.WriteLine(str.Result);
}
My output is the following:
A
B
What am I doing wrong?
Thanks in advance.
you are running the methods AsyncA and AsyncB synchronously. If you are using async you need to await the end of a task. Change your methods to
static async Task<string> AsyncA()
{
await Task.Delay(1500);
return "A";
}
static async Task<string> AsyncB()
{
await Task.Delay(430);
return "B";
}
and you will get your expected output of
BA
For further reference have a look on the MSDN example
EDIT:
For the sake of completeness you should also change the Print method in the same manner, otherwise it also is running synchronously up to now.
Since in this method you get the task via the parameter you can actually await the result directly in the Console.WriteLine method:
static async void Print(Task<string> str)
{
Console.WriteLine(await str);
}
Firstly, when using asynchronous methods, it's generally more accepted to use the awaitable Task.Delay(ms) rather than Thread.Sleep(ms).
In the MSDN documentation, the ContinueWith(task) method:
Creates a continuation that executes asynchronously when the target Task completes.
For this reason, only once task1 is completed, it will execute the remainder of the code - this is why your ouput is A B rather than B A.
By using Task.Delay(ms) and awaiting the methods as opposed to using ContinueWith(task), you'll get your expected output.

Binding a ReactiveCommand prevents a ViewModel from being garbage collected

When I bind a "back button" to a the router in ReactiveUI, my ViewModel is no longer garbage collected (my view too). Is this a bug, or is this me doing something dumb?
Here is my MeetingPageViewModel:
public class MeetingPageViewModel : ReactiveObject, IRoutableViewModel
{
public MeetingPageViewModel(IScreen hs, IMeetingRef mRef)
{
HostScreen = hs;
}
public IScreen HostScreen { get; private set; }
public string UrlPathSegment
{
get { return "/meeting"; }
}
}
Here is my MeetingPage.xaml.cs file:
public sealed partial class MeetingPage : Page, IViewFor<MeetingPageViewModel>
{
public MeetingPage()
{
this.InitializeComponent();
// ** Comment this out and both the View and VM will get garbage collected.
this.BindCommand(ViewModel, x => x.HostScreen.Router.NavigateBack, y => y.backButton);
// Test that goes back right away to make sure the Execute
// wasn't what was causing the problem.
this.Loaded += (s, a) => ViewModel.HostScreen.Router.NavigateBack.Execute(null);
}
public MeetingPageViewModel ViewModel
{
get { return (MeetingPageViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(MeetingPageViewModel), typeof(MeetingPage), new PropertyMetadata(null));
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (MeetingPageViewModel)value; }
}
}
I then run, and to see what is up, I use VS 2013 Pro, and turn on the memory analyzer. I also (as a test) put in forced GC collection of all generations and a wait for finalizers. When that line is uncommented above, when all is done, there are three instances of MeetingPage and MeetingPageViewModel. If I remove the BindCommand line, there are no instances.
I was under the impression that these would go away on their own. Is the problem the HostScreen object or the Router that refers to an object that lives longer than this VM? And that pins things down?
If so, what is the recommended away of hooking up the back button? Using Splat and DI? Many thanks!
Following up on the idea I had at the end, I can solve this in the following way. In my App.xaml.cs, I make sure to declare the RoutingState to the dependency injector:
var r = new RoutingState();
Locator.CurrentMutable.RegisterConstant(r, typeof(RoutingState));
then, in the ctor of each view (the .xaml.cs code) with a back button for my Windows Store app, I no longer use the code above, but replace it with:
var router = Locator.Current.GetService<RoutingState>();
backButton.Click += (s, args) => router.NavigateBack.Execute(null);
After doing that I can visit the page as many times as I want and never do I see the instances remaining in the analyzer.
I'll wait to mark this as an answer to give real experts some time to suggest another (better?) approach.

Why is my call to Azure killing HttpContext.Current

I have an MVC application in which I have a controller that receives data from the user and then uploads a file to Azure blob storage. The application is using Unity IoC to handle dependency injection.
During the workflow I have isolated the following code as demonstrating the problem
public class MvcController : Controller
{
private IDependencyResolver _dependencyResolver;
public MvcController() : this(DependencyResolver.Current)
{
}
public MvcController(IDependencyResolver dependencyResolver)
{
this._dependencyResolver = dependencyResolver;
}
public GetService<T>()
{
T resolved = _dependencyResolver.GetService<T>()
if (resolved == null)
throw new Exception(string.Format("Dependency resolver does not contain service of type {0}", typeof(T).Name));
return resolved;
}
}
public class MyController : MvcController
{
[NoAsyncTimeout]
public async Task<ActionResult> SaveFileAsync(/* A bunch of arguments */)
{
/* A bunch of code */
//This line gets a concrete instance from HttpContext.Current successfully...
IMyObject o = GetService<IMyObject>();
await SaveFileToAzure(/* A bunch of parameters */);
.
.
/* Sometime later */
Method2(/* A bunch of parameters */);
}
private Method2(/* A bunch of parameters */)
{
//This line fails because HttpContext.Current is null
IMyObject o = GetService<IMyObject>();
/* A bunch of other code */
}
private async Task SaveFileToAzure(/* A bunch of parameters */)
{
//Grab a blob container to store the file data...
CloudBlobContainer blobContainer = GetBlobContainer();
ICloudBlob blob = blobContainer.GetBlockBlobReference(somePath);
Stream dataStream = GetData();
System.Threading.CancellationToken cancelToken = GetCancellationToken();
//All calls to DependencyResolver.GetService<T>() after this line of code fail...
response = await blob.UploadStreamAsync(dataStream, cancelToken);
/* A bunch of other code */
}
}
Unity has a registration for my object:
container.RegisterType<IMyObject, MyObject>(new HttpLifetimeManager());
My lifetime manager is defined as follows:
public sealed class HttpRequestLifetimeManager : LifetimeManager
{
public Guid Key { get; private set; }
public HttpRequestLifetimeManager()
{
this.Key = Guid.NewGuid();
}
public override object GetValue()
{
return HttpContext.Current.Items[(object)this.Key];
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[(object)this.Key] = newValue;
}
public override void RemoveValue()
{
HttpContext.Current.Items.Remove((object)this.Key);
}
}
Nothing complicated.
Stepping into the HttpRequestLifetimeManager on the failing GetService() calls shows that after the UploadStreamAsync() call HttpContext.Current is null...
Has anyone else come across this problem? If so, is this a bug? Is this expected behaviour? Am I doing something out of the ordinary? What should I do to resolve it?
I can hack around it by storing a reference to HttpContext.Current prior to the offending call and restoring it after, but that doesn't seem like the right approach.
Any ideas?
To echo #Joachim - http context may not be available to your async thread. Compare the current thread id where you can see httpcontext is available, to the thread id where you can see that it isn't - i'm assuming you will see they are 2 different threads. If my assumption is correct this may be a sign that your main thread (the one with httpcontext) does not have a "synchronizationcontext". (you can see http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx for more details of how that works) If so, it may mean that the code immediately after your await statement is actually not running on the same thread as the code prior to the await statement! So from your perspective, one moment you have http context and the next you don't because execution has actually been switched to another thread! You should probably look at implementing / setting a synchronizationcontext on your main thread if that's the case and then control will be returned to your original thread with http context and that should fix your problem, or alternatively you could retrieve your object from http context on the original thread and find a way to pass it as a parameter to the async method/s so that they don't need to access http context to get their state.

construct GUI with event dispatch thread and make assignment

I'd like to do the following without making the variable gui final:
public class MainClass
{
GUIClass gui;
Runnable r = new Runnable()
{
public void run()
{
// this won't work!
gui = new GUIClass();
}
};
SwingUtilities.invokeLater(r);
Controller c = new Controller(gui);
}
How can I achieve that? I want to construct the gui via the EDT. At the same time I want to assign that new instance to the variable gui. But this won't work without making gui final. I don't want to use final because it's not possible in my context. Anyone any idea how this could be solved? The code above is of course executed within the main method. But for some reasons I couldn't post it here as an error occured.
For all those who should be interested in this issue someday, here's the solution:
I made a mistake. Actually you should differentiate between constructing the GUI-Object and making it visible. So here is the way to do that:
public class MainClass
{
final GUIClass gui = new GUIClass();
Runnable r = new Runnable()
{
public void run()
{
gui.pack();
gui.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
Controller c = new Controller(gui);
}

mvvm light async call in viewmodel constructor

I'm developing a win phone 8 app using portable version of mvvmlight.
In the creation of a ViewModel I have to do a call to a service that read data from a Azure Mobile Service using the Azure Mobile Service Sdk.
Sdk apis use async /await to do the work, and I can't do async calls in the ViewModel or in Service costructor.
The code is like this:
public ListaArtiModel(INavigate navigationService)
{
_navigationService = navigationService;
ArtiMarzialiService artiService = new ArtiMarzialiService();
List<ArteMarziale>risultato = await artiService.ListaArti();
}
and the compiler tells
Error 1 The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
How can I solve this?
thanks,
Luca
I have a "task notifier" type in my AsyncEx library that is essentially an INotifyPropertyChanged wrapper for Task<T>. You can use it like this:
public ListaArtiModel(INavigate navigationService)
{
_navigationService = navigationService;
ArtiMarzialiService artiService = new ArtiMarzialiService();
Arti = NotifyTaskCompletion.Create(LoadArti(artiService));
}
private async Task<ObservableCollection<ArtiMarziali>> LoadArti(ArtiMarzialiService artiService)
{
return new ObservableCollection<ArtiMarziali>(await artiService.ListaArti());
}
public INotifyTaskCompletion<ObservableCollection<ArtiMarziali>> Arti { get; private set; }
Then your databinding code can use Arti.Result, Arti.IsFaulted, Arti.ErrorMessage, etc.
You should redesign your ViewModel to have a LoadDataAsync() or InitializeAsync() method that is used to set up the ViewModel
In general, class constructors should be kept as simple as possible and you should avoid doing any long running or potentially exception-prone work in the constructor
I think i found a better solution:
declared the service interface this way:
void ListaArti(Action<List<ArtiMarziali>, Exception> callback);
implemented it this way:
public async void ListaArti(Action<List<ArtiMarziali>, Exception> callback)
{
Exception err = null;
List<ArtiMarziali> risultato = null;
try
{
risultato = await MobileService.GetTable<ArtiMarziali>().ToListAsync();
}
catch (Exception ex)
{
err = ex;
}
callback(risultato, err);
}
called the service in the viewmodel constructor this way:
IArtiMarzialiService artiService = new ArtiMarzialiService();
artiService.ListaArti((arti, err) =>
{
if (err != null)
{
/// if there is an error should create a property and bind to it for better practices
System.Diagnostics.Debug.WriteLine(err.ToString());
}
else
{
/// set the property
Arti = new ObservableCollection<ArtiMarziali>(arti);
}
});
using an async function that returns a void I don't have to use the await statement in the caller, and I use the callback to set the property in the viewmodel when the data are available.

Resources