Async and await methods in MvvmCross - mvvmcross

I am creating PCL using MvvmCross.
I am calling one method in Command which fetch data by calling web service.
I want to do this data fetch operation asynchronously.
How can I apply async and await to methods in Command ?
Any ideas?

There are a couple of options.
1) You can implement the command with an async void method/delegate. If you do this, I recommend you have the async void method just await a Task from an async Task method that contains the actual logic because async Task methods are easier to unit test. Also, you'll need a try/catch for proper error handling.
2) You can have the command just start a method returning Task<T> and expose the result of the operation as a property using NotifyTaskCompletion from my AsyncEx library. This allows you to data bind to the result as well as errors. However, AsyncEx does not support all the platforms MvvmCross does (in particular, Windows Phone 7.0 and Xamarin.Mac).
Update - examples:
Using the first option:
public ICommand ContactSlodgeCommand
{
get
{
return new MvxCommand(async () =>
{
await ComposeEmailAsync("me#slodge.com", "About MvvmCross and the SQL Bits app", "I've got a question"));
}
}
}
Using the second option:
private INotifyTaskCompletion<MyResource> _resource;
public INotifyTaskCompletion<MyResource> Resource
{
get { return _resource; }
set { _resource = value; NotifyPropertyChanged(); }
}
public ICommand LoadResourceCommand
{
get
{
return new MvxCommand(() =>
{
Resource = NotifyTaskCompletion.Create(LoadResourceAsync());
}
}
}

You should do data-binding for that property by using databinding of mvvmcross and use async await or Task like #Stephen Cleary said
void FetchData(Action<T> callback)
{
Task.Run<T>(()=>{
return Service.GetDataSynchronous();
}).ContinueWith((data)=>{
callback(data);
});
}
public MvxCommand
{
get
{
return new MvxCommand(()=>{
FetchData((data)=>{
this.Property = data;
});
});
}
}

Related

Conditionally skip a Junit 5 test

In my Junit Jupiter API 5.5 test, I am calling my method which internally makes a HTTP call to a remote service.
Now the remote service can be down or behave incorrectly. I want to skip my test in case the remote service is not behaving expectedly.
#Test
void testMe() {
// do something
Result res1 = myObject.retrieveResults(params)
// assert something
Result res2 = myObject.retrieveResults(param2)
//asert on results
}
Result retrieveResults(Parameters param) {
// do something
// call to remote service
// if they do not give result throw CustomException()
// return Result
}
So basically in my test i would want to check if myObject.retrieveResult is throwing CustomException then skip that test, otherwise evaluate normally.
We have 2 different ways to accomplish this tasks in JUnit 5.
For demo purposes, I have created a basic class which sends a request to the url
that is passed as an argument to its call(String url) method and
returns true or false depending on the request result.
The body of the method is irrelevant here.
Using Assumptions.assumeTrue()/assumeFalse() methods
Assumptions class provides us with two overloaded methods - assumeTrue
and assumeFalse. The idea is that, if the assumption is wrong, the test will be skipped.
So, the test will be something like this.
#Test
void call1() {
Assumptions.assumeTrue(new EndpointChecker(), "Endpoint is not available");
Assertions.assertTrue(HttpCaller.call("https://www.google.com"));
}
Here is the code for EndpointChecker class.
static class EndpointChecker implements BooleanSupplier {
#Override
public boolean getAsBoolean() {
// check the endpoint here and return either true or false
return false;
}
}
When the test is run, the availability of the endpoint will be checked first, if it is up, then the test will run.
Using JUnit 5 extension mechanisms.
So, let's start with creating the annotation. It is pretty straightforward.
#Retention(RetentionPolicy.RUNTIME)
#ExtendWith(EndpointAvailabilityCondition.class)
public #interface SkipWhenEndpointUnavailable {
String uri();
}
And EndpointAvailabilityCondition class. Even though, it looks big, overall logic is very simple.
import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation;
public class EndpointAvailabilityCondition implements ExecutionCondition {
#Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
final var optional = findAnnotation(context.getElement(), SkipWhenEndpointUnavailable.class);
if (optional.isPresent()) {
final SkipWhenEndpointUnavailable annotation = optional.get();
final String uri = annotation.uri();
// check connection here start
boolean result = false; // dummy value
// check connection here end
if (result) {
return ConditionEvaluationResult.enabled("Connection is up");
} else {
return ConditionEvaluationResult.disabled("Connection is down");
}
}
return ConditionEvaluationResult.enabled("No assumptions, moving on...");
}
}
Hence, we can do the following in our tests.
#Test
#SkipWhenEndpointUnavailable(uri = "https://www.google.com")
void call2() {
Assertions.assertTrue(HttpCaller.call("https://www.google.com"));
}
We can go ahead and add #Test annotation over #SkipWhenEndpointUnavailable and remove it from our test code. Like, so:
#Retention(RetentionPolicy.RUNTIME)
#ExtendWith(EndpointAvailabilityCondition.class)
#Test
public #interface SkipWhenEndpointUnavailable {
String uri();
}
class HttpCallerTest {
#SkipWhenEndpointUnavailable(uri = "https://www.google.com")
void call2() {
Assertions.assertTrue(HttpCaller.call("https://www.google.com"));
}
}
I hope it helps.

Return an existing razor view from middleware in asp.net core

In my custom exception middleware, I want to get exceptions processed and return the same resource with a user friendly message.
E.g When Account/Add throws an SqlException, I return Account/Add response with a message which stored in TempData from exception middleware. I already
got these view engine things done.
I found this extension method and usage for this purpose, with this, you can return all IActionResult implementations from middleware, great extension.
However, I could not find out how to return my conventional view that resides in my views folder such as Views/Account/Add
Exception Middleware
private readonly RequestDelegate _next;
public ExceptionHandler(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
HandleException(context, ex);
}
}
private void HandleException(HttpContext context, Exception exception)
{
//handle exception, log it and other stuff...
//....
var result = new ViewResult
{
ViewName = context.Request.Path.ToString(),
};
//WithDanger is an extension method writes message to tempdata
result.WithDanger("Error", exception.ToString());
//Extension method
context.WriteResultAsync(result);
}
This is what I tried but it is not working as I expected, it returns a blank page, it seems it does not make the razor view engine run to build my request page.
How can I make my middleware to return a ViewResult with my existing view properley?
There's a couple of things missing. In order to return a view using a relative path, you need to trim off the leading slash:
ViewName = context.Request.Path.ToString().TrimStart('/')
You're also not awaiting the WriteResultAsync call. Change it to something like
private TaskHandleException(HttpContext context, Exception exception)
{
//handle exception, log it and other stuff...
//....
var result = new ViewResult
{
ViewName = context.Request.Path.ToString().TrimStart('/'),
};
//WithDanger is an extension method writes message to tempdata
result.WithDanger("Error", exception.ToString());
//Extension method
return context.WriteResultAsync(result);
}
And make sure you await the call to HandleException:
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
await HandleException(context, ex);
}
}
That should work :)

Why does this handler not return anything?

I'm just starting the ASP.NET tutorial and I don't understand why there is no return statement in the method:
public async Task OnGetAsync()
{
Movie = await _context.Movie.ToListAsync();
}
Are one line methods automatically returned like arrow statements or does it have to do with the Task in ASP?
Its a model that have property Movie. That property gets set when method OnGetAsync is called. So, you don't need return.
Method return type is Task because it has await. Its analogous to void type if it would be a sync method.
if you want to return the list of Movie
then your function should be :
public async Task<List<Movie>> OnGetAsync()
{
return await _context.Movie.ToListAsync();
}

Windows Run Time GetFileFromPathAsync Not Returning

I am hoping someone can shed some light on a problem I am having. I am writing a Windows Store app which on startup needs to copy a "seed" database from the App installation folder Windows.ApplicationModel.Package.Current.InstalledLocation.Path to the Local data folder Windows.Storage.ApplicationData.Current.LocalFolder. To do this I have used the following called from my OnNavigatedTo method in Main().
protected override void OnNavigatedTo(NavigationEventArgs e)
{
//Calls method in Dal Class which ensures database is in correct location and if not copies it
Dal.LoadData();
RefreshScenarioList();
ScenarioList.SelectedIndex = 0; //this is the Default Item
}
public static async void LoadData()
{
await CopyIfNotExists(dbName);
}
private static async Task CopyIfNotExists(string dbName)
{
if (await GetIfFileExistsAsync(dbName) == null)
{
StorageFile seedFile = await StorageFile.GetFileFromPathAsync(
Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path,
dbName));
await seedFile.CopyAsync(Windows.Storage.ApplicationData.Current.LocalFolder);
}
}
private static async Task<StorageFile> GetIfFileExistsAsync(string key)
{
try
{
return await ApplicationData.Current.LocalFolder.GetFileAsync(key);
}
catch (FileNotFoundException) { return default(StorageFile); }
}
Please also note that I have also used GetFileAsync and also tried using a uri to obtain the seed file (to see if there was any difference). With the combination here I seem to be having the highest success rate. This seems to work 2-3 times out of every 4 tries but I would be much more comfortable with something that works 100% of the time. It only needs to copy the database once on startup.
When it doesn't work it "seems" to never return (ie CopyIfNotExists never seems to complete). The issue appears to be in the CopyIfNotExists method. The problem is that virtually the next line of code in my OnNavigatedTo method is a query on the database and it falls over when the database doesn't copy.
Any insights that anyone may have would be greatly appreciated.
From what I can see, the problem here is that your use of async and await does not go as far up the call stack as it can.
When writing async code, there are a couple of general rules to follow -
If a function Foo uses the async keyword, then any other function that calls Foo must also use the async keyword.
Never use async void in a function signature - use async Task instead. The exceptions are:
your function is an event handler (e.g. button press)
or you are overriding a method that happens to return void
Let's take a look at the method signatures on your call stack. OnNavigatedTo is shown here at the top:
override void OnNavigatedTo()
async void LoadData()
async Task CopyIfNotExists()
async Task<StorageFile> GetIfFileExistsAsync()
The bottom two methods of the call stack uses async Task in the method signatures. Above those on the call stack is LoadData, which follows rule 1 above, but breaks rule 2. LoadData should be changed to this:
public static async Task LoadData()
{
await CopyIfNotExists(dbName);
}
Next we try to make OnNavigatedTo follow the above rules:
async protected override void OnNavigatedTo(NavigationEventArgs e)
Note that we cannot use async Task, since your method is an override. We have to stick to async void.
Now you just need to add await to your LoadData call since it is an async method. We do this so that your program waits for LoadData to complete prior to calling RefreshScenarioList:
async protected override void OnNavigatedTo(NavigationEventArgs e)
{
//Calls method in Dal Class which ensures database is in correct location and if not copies it
await Dal.LoadData();
RefreshScenarioList();
ScenarioList.SelectedIndex = 0; //this is the Default Item
}
Now you will want to also ensure that the call stack for RefreshScenarioList follows the async rules above.
One more thing that I noticed with your code. In Windows 8.1 or later, you should use TryGetItemAsync instead of GetFileAsync:
private static async Task<StorageFile> GetIfFileExistsAsync(string key)
{
return await ApplicationData.Current.LocalFolder.TryGetItemAsync(key) as StorageFile;
}
The new method returns null when it cannot find a file. The old method throws an exception. Throwing exceptions on a UI thread can cause your UI to stall, so it is advantageous to use the new method.

JsonSerializationException on lazy loaded nHibernate object in WebApi when called from Angularjs service

I am calling a WebApi controller Get method from an Angularjs service.
The angular service:
app.service('MyService', ['$http', function ($http) {
var getMyObjects = function () {
var myObjects;
var promise = $http.get('/api/objects/').success(function (data) {
myObjects = data;
}).error(function (data, status, headers, config) {
});
return promise;
};
return {
myObjects: myObjects
};
}]);
The WebApi Get method:
public class ObjectsController : ApiController
{
public IEnumerable<MyObject> Get()
{
return _objectRepository.GetAll().ToArray();
}
}
I am getting a 500 server error on the client, the inner exception of which is:
ExceptionMessage: "Error getting value from 'IdentityEqualityComparer' on
'NHibernate.Proxy.DefaultLazyInitializer'."
ExceptionType: "Newtonsoft.Json.JsonSerializationException"
What should I do to resolve this issue?
EDIT:
I resolved the above exception by adding the following one liner to WebApiConfig.cs as per this answer:
((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.
ContractResolver).IgnoreSerializableAttribute = true;
Now I have this exception:
ExceptionMessage: "Error getting value from 'DefaultValue'
on 'NHibernate.Type.DateTimeOffsetType'."
ExceptionType: "Newtonsoft.Json.JsonSerializationException"
Any ideas on if there is something similar I can do to fix this?
Based on this answer and this answer, I have fixed the issue by adding the following class
public class NHibernateContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
if (typeof(NHibernate.Proxy.INHibernateProxy).IsAssignableFrom(objectType))
return base.CreateContract(objectType.BaseType);
return base.CreateContract(objectType);
}
}
and then setting it as the contract resolver in Application_Start in Global.asax.cs:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ContractResolver = new NHibernateContractResolver();
Eager loading is worth having whole DB crash. Lazy load prevents you from loading unnecessary referenced data. But also you must ensure that you have pointed hibernate which references to load.
But your exception is thrown because of Serialization issue