Is there any thumbrule for a beginner to understand when to use which life cycle methods, when developing a Blazor Server app.
OnInitialized() vs OnInitializedAsync()
OnParametersSet() vs OnParametersSetAsync()
OnAfterRender() vs OnAfterRenderAsync()
OnInitialized() vs OnInitializedAsync()
Prefer the simple OnInitialized() to set data without async, like message="hello";.
As soon as you have to call and await async methods, for instance on HttpClient, switch to OnInitializedAsync().
More rules of thumb:
do not use .Result or .Wait() on async methods
do not start async methods without awaiting them
do not use async void except in very rare cases.
When you get it wrong there will be an Error (can't await) or a Warning:
CS4032 The 'await' operator can only be used within an async method.
Is obvious, you should have used a *Async method. But do not 'fix' it by using async void or .Result.
CS1998 This async method lacks 'await' operators and will ...
means you should not have used the *Async method.
CS4014 Because this call is not awaited, ...
means you are not awaiting something you should.
Related
Here's the code that I have:
public App()
{
InitializeComponent();
DB.CreateTables();
DB.GetSettings();
DB.PopulateTables();
SetResourceColors();
SetResourceDimensions();
MainPage = new MainPage();
activity = Helpers.Activity.Create();
VersionTracking.Track();
DeviceDisplay.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
}
protected override void OnStart()
{
}
Can someone explain to me. Is there any difference between me placing the code such as I have in the constructor or in the OnStart() method? What's the normal way to do this?
I have been working with Xamarin.Forms for a long time now and this is how I and my fellow developers use the OnStart Method.
If you check the Microsoft documents it says the following about it :
OnStart - Called when the application starts.
So, first of all, you should know that there is no specific use of the OnStart method, to be very honest there is no major difference in between using the constructor or this lifecycle method because both get called on XF framework startup, first the constructor then the OnStart method.
Now let's come to the differences.
As Jason pointed out, the OnStart method is a lifecycle method and hence has a return type unlike the constructor, so you can even call an asynchronous piece of code in the OnStart method but you cannot do the same in the constructor as constructors cannot be asynchronous.
Which means if you have the below method:
public async Task<bool> IsSomeThingWorkingAsync(//SomeParams)
{
// Code
}
Now, this method cannot be asynchronously called from the constructor since constructors are forcefully synchronous and have no return types. But if you try doing that from the on start method it's quite easy and it will work. In this case, you use the OnStart method. Something like below:
protected override async void OnStart()
{
bool WasWorkSuccess=await IsSomeThingWorkingAsync();
//do something with the boolean
}
A constructor is intended to be used for wiring. In the constructor, you want to avoid doing actual work. You basically prepare the class to be used. Methods are intended to do actual work.
Note: There are no performance gains whatsoever by choosing one over the other - it's really a matter of preference and standard.
Please go through the details here
You can write the initialisation codes in App() constructor. But you need to be very careful abut registering events.
Reason is,
For example in Android, If the app is launched and it is in task list and if you try to launch the app again by clicking on app icon. The constructor of App() will call again. This will register the event multiple times and will create issues.
So for events I will suggest you to use overriden methods for registering events.
Again as Jason pointed it out, It is your personal preference where to write your code.
In my ViewModel I load data in (overrided) Start method, like so:
public override async void Start()
{
base.Start();
await ProcessItems();
// or the following (no difference for Start method behavior)
await ProcessItems().ConfigureAwait(false);
}
However, it doesn't look like the await/async logic actually works with the method (I tested it with Android only, though).
"Doesn't work" means that right after calling my awaitable ProcessItems all the rest of ViewModel pipeline is called (like Initialize, ViewCreated, ViewAppearing etc.) before the awaitable method actually finished work.
Which brings up some further issues as the rest of methods expect the data initialization already finished.
So, what should I take into consideration here and how handle this situation.
Thanks!
The calling code can't await Start because it is returning void. Any exceptions being thrown in there are being swallowed. If the method returned Task or Task<T> then this would work as you expect. You pretty much never want to use async void except in an event handler. There is an MSDN article going further into detail as to why async void should be avoided.
This problem is fixed in MvvmCross 5 and later where you would do this same kind of initialization in Task Initialize method in place of this void Start method.
Since MvvmCross 5.0 there is a new lifecycle. https://www.mvvmcross.com/documentation/fundamentals/viewmodel-lifecycle#initialize
Please use Initialize for your stuff instead of Start.
Initialize: All heavy work should be run here. This method returns a Task, which means you can mark it as async and use await safely. If this method fails, the Navigate call that you are probably awaiting will fail, so you might want to catch that exception.
public async Task Initialize()
{
await base.Initialize();
await ProcessItems();
}
I just converted my Visual Studio 2015 ASP.NET MVC Core project to Visual Studio 2017...and I get the following Informational messages in my Error List
Message IDE1006 Naming rule violation: Missing suffix: 'Async'
This message occurs in my Controllers that focus on the following:
public async Task<IActionResult> Index()
This also applies to Create, Delete, Details and Edit. The messages show as Informational and applies to over 1,000 occurences in my project. It appears that I need to change Index to IndexAsync
ie.
Change from:
public async Task<IActionResult> Index()
public async Task<IActionResult> Create()
public async Task<IActionResult> Delete(int? id)
public async Task<IActionResult> Details(int? id)
Change to:
public async Task<IActionResult> IndexAsync()
public async Task<IActionResult> CreateAsync()
public async Task<IActionResult> DeleteAsync(int? id)
public async Task<IActionResult> DetailsAysnc(int? id)
This appears to be optional at this time as my project will Build and it's not an issue in VS 2015. I don't mind doing the work,I need confirmation that changing this in Visual Studio 2017 ASP.NET Core is the correct approach.
Microsoft is nudging you in the direction of suffixing your your asynchronous methods with the word async. Why? The release notes for Visual Studio 2017 mention this tidbit.
Task-like return types for async methods: This introduces the ability
to return any task-like type from an async method. Previously these
return types were constrained to Task<T> and Task.
Sounds like it's going to become less obvious which methods are asynchronous just from examining their return types. Suffixing them with async may be a good idea. Before VS was making this "suggestion" there was a previous stack overflow question debating the convention. Stephen Toub from Microsoft addressed it, and I quote.
If a public method is Task-returning and is asynchronous in nature (as
opposed to a method that is known to always execute synchronously to
completion but still returns a Task for some reason), it should have
an “Async” suffix. That’s the guideline. The primary goal here with
the naming is to make it very obvious to a consumer of the
functionality that the method being invoked will likely not complete
all of its work synchronously; it of course also helps with the case
where functionality is exposed with both synchronous and asynchronous
methods such that you need a name difference to distinguish them. How
the method achieves its asynchronous implementation is immaterial to
the naming: whether async/await is used to garner the compiler’s help,
or whether types and methods from System.Threading.Tasks are used
directly (e.g. TaskCompletionSource) doesn’t really matter, as that
doesn’t affect the method’s signature as far as a consumer of the
method is concerned.
Of course, there are always exceptions to a guideline. The most
notable one in the case of naming would be cases where an entire
type’s raison d’etre is to provide async-focused functionality, in
which case having Async on every method would be overkill, e.g. the
methods on Task itself that produce other Tasks.
As for void-returning asynchronous methods, it’s not desirable to have
those in public surface area, since the caller has no good way of
knowing when the asynchronous work has completed. If you must expose a
void-returning asynchronous method publicly, though, you likely do
want to have a name that conveys that asynchronous work is being
initiated, and you could use the “Async” suffix here if it made sense.
Given how rare this case should be, I’d argue it’s really a
case-by-case kind of decision.
I hope that helps, Steve
Bottomline, it's informational. But as Microsoft has expanded the return types beyond Task, it it beggining to look more and more like best practice. Use your own judgement.
I noticed that for MVC Controller classes, that in addition to adding Async to the method name, I needed to add [ActionName("MethodName")] as a method attribute where "MethodName" did not have Async at the end. If I didn't add the ActionName attribute, the code would compile, but the URL would not route to the method unless I added Async in the URL as well. I don't want Async in my URLs so I ended up adding ActionName attributes everywhere. It seems like the MVC routing engine should try to find the Async methods, but it doesn't.
I am starting a new project and am thinking of using Simple Injector interception (https://simpleinjector.readthedocs.io/en/latest/InterceptionExtensions.html) for tracing method entry/exit and logging parameters and return values etc. I have used this interceptor in the past and it works great. But my previous projects were not async/await. This new project has a lot of methods that are all async/await and I was wondering
will this interceptor work for async/await methods?
what changes are required in this interceptor to make it work for async/await methods?
I understand that decorators are a much better pattern than interception but writing a decorator for each and every interface that I want to trace is not something that I am looking forward to doing.
UPDATE:
I have tried this interceptor in my async/await code and it does inject my tracing code. However, I was getting weird results in some parts of my application. I didn't get chance to dig deeper into why disabling interception would make it work fine and why when interception was enabled it would not work as expected. It could very well be something wrong with my code.
I was hoping if someone, who has already used this interception extension in their code, would be able to point me in the right direction.
will this interceptor work for async/await methods?
Async code in C# is syntactic sugar on top of Task. This means that if your code needs to do anything useful after a call to an async method, you will have call ContinueWith on the returned Task (or use the C# syntax). If you take asynchronous into consideration in your interceptor, you won't be able to execute logic after the wrapped object.
So to make this work, you will have to explicitly check whether the wrapped method returns Task and if that's the case, you should make things async by hooking your 'after' code using ContinueWith.
This is one of the many reasons I consider interception to be inferior to using decorators. Decorators allow your code to be much cleaner, refrain from using reflection, give complete compile time support, give better performance, prevent having to depend on an interception library, and force you into a much more SOLID application design.
That said, the documentation's MonitoringInterceptor will look as follows when it takes asynchronicity into consideration:
class MonitoringInterceptor : IInterceptor
{
private readonly ILogger logger;
public MonitoringInterceptor(ILogger logger) {
this.logger = logger;
}
public void Intercept(IInvocation invocation) {
var watch = Stopwatch.StartNew();
// Calls the decorated instance.
invocation.Proceed();
var task = invocation.ReturnValue as Task;
if (task != null) {
invocation.ReturnValue = LogElapsedAsync(task, invocation, watch);
} else {
LogElapsed(invocation, watch);
}
}
private async Task LogElapsedAsync(Task task, IInvocation i, Stopwatch w) {
await task;
LogElapsed(i, w);
}
private void LogElapsed(IInvocation invocation, Stopwatch watch) {
var decoratedType = invocation.InvocationTarget.GetType();
this.logger.Log(string.Format("{0} executed in {1} ms.",
decoratedType.Name, watch.ElapsedMilliseconds));
}
}
Most of the articles on async/await best practices suggest that async void methods should be avoided unless the method is an event handler.
What are the best practices for handling situations where you need to call an async method during initialization of a view?
I've seen code that marks lifecycle methods such as ViewDidLoad, ViewWillAppear, OnCreate, OnResume etc as async void so that a method can be await-ed in the method body - but my gut reaction to this is that it is dangerous if the method is an override from the framework - since the consumer might not be aware of the context in which the method is being used internally.
An alternate approach could be to assign the result of the async method to a Task. Then await that Task before any dependent code runs:
Foo.cs:
async Task SomeMethodForInit()
{
//some code here for Init
}
Android Fragment:
Task _initTask;
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_initTask = fooInstance.SomeMethodForInit();
}
...
//call this before doing anything dependent on that task
await _initTask;
Is this the right approach?
I like this post on async/await best practices. The biggest problem imho is from exceptions not getting handled properly when encountering async void.
To answer your question: Is there a specific reason why you have to use await or maybe can you choose a different approach to solving your problem? If you can, great, if not, the "downside" should be negligible.