I am looking at the EchoBot sample and trying to understand it. I see that BotController is mapped to api/messages and HttpPost which in turn invokes Adapter.ProcessAsync. But how does this translate into EchoBot.OnMessageActivityAsync call? I tried to set up a breakpoint and see the call stack but that doesn't help ( see attached screenshot).
I understand BotFrameworkHttpAdapter is invoked via dependency injection. But I don't know how we end up in EchoBot eventually.
To find the answer to this you really have to dive into the source code, so I hope you've got your scuba diving gear because we're going deep.
Step 1
Inside the BotController.cs file the following piece of code is called:
await Adapter.ProcessAsync(Request, Response, Bot);
which calls the ProcessAsync method on the IBotFrameworkHttpAdapter interface.
Step 2
Inside the Startup.cs file we have the following line:
services.AddSingleton<IBotFrameworkHttpAdapter, BotFrameworkHttpAdapter>();
which says that every time we ask for an IBotFrameworkHttpAdapter, provide the same instance of BotFrameworkHttpAdapter - essentially a static variable, you can read more about dependency injection service lifetimes here.
Step 3
Inside the Microsoft.Bot.Builder package we have the implementation for the ProcessAsync method, that can for our purposes be reduced to the following line:
var invokeResponse = await ProcessActivityAsync(authHeader, activity, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);
which calls ProcessActivityAsync which is another function that lives in this library - the important part here is the bot.OnTurnAsync parameter being passed in.
Step 5
Also inside the Microsoft.Bot.Builder package is the implementation for ProcessActivityAsync:
return await ProcessActivityAsync(claimsIdentity, activity, callback, cancellationToken).ConfigureAwait(false);
which calls an overload of the same method, but before we move on from here, the callback parameter is the bot.OnTurnAsync parameter that was passed through before.
Step 6
The overload of ProcessActivityAsync is also implemented inside the Microsoft.Bot.Builder package, and can be simplified to this line:
await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false);
where callback is bot.OnTurnAsync.
Step 7
Digging deeper still we find the implementation of the RunPipelineAsync method inside of the Microsoft.Bot.Builder package which is were things start to get a bit fuzzy... Theoretically we want to fall through to the else block where the callback (i.e. bot.OnTurnAsync) is called:
// Call any registered Middleware Components looking for ReceiveActivityAsync()
if (turnContext.Activity != null)
{
// Other code
}
else
{
// call back to caller on proactive case
if (callback != null)
{
await callback(turnContext, cancellationToken).ConfigureAwait(false);
}
}
However, back in Step 6 we also had this line:
using (var context = new TurnContext(this, activity))
where the context is created, and the activity property is initialised. This same context is pass through to the RunPipelineAsync call, which means that we will not fall through to the else block...
But there are the following comment on the RunPipelineAsync method:
/// <param name="callback">A callback method to run at the end of the pipeline.</param>
and inside the remarks section:
...Once control reaches the end of the pipeline, the adapter calls
the <paramref name="callback"/> method...
So I believe is it safe to say that our callback method is being executed which means that we continue by bubbling back up the chain to resolve the function that callback maps to (bot.OnTurnAsync).
Step 8
In BotController we pass in an instance of IBot to the ProcessAsync method, and in Startup we wire up all requests for an IBot to return an instance of EchoBot like so:
// Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
services.AddTransient<IBot, EchoBot>();
The EchoBot implementation inherits from the ActivityHandler class:
public class EchoBot : ActivityHandler
Step 9
The ActivityHandler class provides a default implementation for the OnTurnAsync method which I will simplify to:
switch (turnContext.Activity.Type)
{
case ActivityTypes.Message:
return OnMessageActivityAsync(new DelegatingTurnContext<IMessageActivity>(turnContext), cancellationToken);
// Other cases
}
which the OnMessageActivityAsync method on the same class that has an implementation that returns a completed task, i.e. is a no-op, however it is a virtual method - classes which inherit ActivityHandler can provide their own implementation.
Step 10
A custom implementation for OnMessageActivityAsync is provided inside the EchoBot class:
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text}"), cancellationToken);
}
where the user's input is echoed back to them, and thus our journey ends.
Regarding Step 7, the Microsoft team are pretty active on SO for things tagged with botframework so it might be best to get #mdrichardson or #tdurnford to clarify what happens here.
As an aside in Visual Studio you can debug some library code by enabling the following option:
Tools --> Options --> Debugger
Uncheck "Enable Just my Code"
Also if you enable navigation to decompiled sources (you will have to accept a legal notification popup) by doing this:
Tools --> Options --> Text Editor --> C# --> Advanced
Check "Enable navigation to decompiled sources"
You will be able to inspect the source code of external packages within Visual Studio itself.
Related
I have my application designed using Xamarin Prism .
I have a command that should be executed when the user navigate to this given page .
it runs in a different project , but when I rewrote the same code , it will not run .
I compared the codes and almost identical . however , it still will not run in this code .
first I defined the command :
public IAsyncCommand InitCommand { get; }
in my view model constructor I have this code :
InitCommand = new AsyncCommand(InitAsync);
and this is my InitAsync method :
private async Task InitAsync()
{
await GetTransactionsByWallet(WalletId).ConfigureAwait(false); ;
}
and in my OnNavigatedTo part of prism , i have this code :
public void OnNavigatedTo(INavigationParameters parameters)
{
WalletId = parameters.GetValue<IWallets>("wallet").Id;
InitCommand.ExecuteAsync();
}
note :
InitCommand.ExecuteAsync(); will not execute even if i put a stop at it to debug it , the debugger also wont stop to it .
im using AsyncAwaitBestPractices.MVVM for the creation of the command .
Any reason you have decided to run the command rather than the method directly? i.e. instead of InitCommand.ExecuteAsync(); why not just await InitAsync().
Note: you can make OnNavigatedTo an async method. And since it is an eventhandler (the events being fired during navigation), async void is allowed - https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
Here - https://forums.xamarin.com/discussion/91897/prism-calling-async-method-in-onnavigatedto-or-any-of-the-methods-from-inavigationaware
As mentioned by Brian Lagunas (manager of the Prism Library)
But if that option doesnt sound good - another option is to run the method during the "Loaded" event of the view. These are not workarounds, these are the proper mvvm ways to do this. For running the method on loaded, you have two ways of doing it -
(1) Use Xaml Behavior Library's CallMethodAction or
(2) Use Prism's inbuilt InvokeCommandAction with the XAML Interactivity.
On a page in a web app, a loading screen/widget continue to appear after the user leaves the text field.
The app is using version 1.6.0.3. I looked at the most recent version of Prototype 1.7.3 and I did not find that function.
I also tested other instances when this method is called. If there is no user input, the widget does not hang-up.
This error is displayed in the console of Chrome’s developer tools.
at E (framework.pack.js:1699)
at Function.stopObserving (framework.pack.js:1732)
at A.hide (ui.pack.js:13410)
at A.render (ui.pack.js:13591)
at A.updateChoices (ui.pack.js:13650)
at A.onComplete (ui.pack.js:13786)
at Object.oncomplete (framework.pack.js:76)
at framework.pack.js:2748
The specific method in questions seems to be in the Prototype.js file this =>
if (element._prototypeEventID) return element._prototypeEventID[0];
arguments.callee.id = arguments.callee.id || 1;
return element._prototypeEventID = [++arguments.callee.id];
}
I expect the loading widget to disappear after the save is done, but it is still on the page. The console of Chrome's developer tools also has a second error:
validateFormCheck # common.js:1031
It looks like the getEventID method is being called where the undefined warning/error triggers.
In version 1.6.0.3 getEventID is only called in createWrapper and stopObserving, I see stopObserving is in the call stack that you posted so let's go with that one.
stopObserving() takes 1 required parameter and 2 optional parameters (element, eventName, handler) if you only pass the element to the function it looks it up and then deletes all the PrototypeJS observers attached to that element. If you pass eventName and/or handler as well stopObserving will only specifically delete the observer you tell it to.
That being said, if the element is removed from the DOM before stopObserving is called this could cause the error you are seeing.
2 fixes that could work
move the call to stopObserving() above the call to remove()
comment out the call to stopObserving() and see if page behaves like you want it to
This question already has answers here:
Am I right to ignore the compiler warning for lacking await for this async call?
(3 answers)
Closed 7 years ago.
Below is my code. Compiler gives warning because AddLog is not awaited. I do not want to await this call and want to continue executing next lines. I dont have any concern if the exception is consumed also. Is it fine to ignore the warning?
public async Task Add()
{
this.AddLog( "Add executing" );
// Logic to Add Customer
}
public async Task AddLog( string message )
{
// Write to DB
}
Assuming you truly want to call the AddLog method in a fire-and-forget way, then you have a few options.
If, by design, you want AddLog to always be invoked as a fire-and-forget method, then you could change the signature to not return a Task.
public async void AddLog( string message ) // change Task to void
{
// Write to DB
// WARNING: Make sure that exceptions are handled in here.
}
However, if you do this, you better make sure that exceptions are properly handled from within the AddLog method. If any exception goes unhandled, it will crash your process.
Another option is to change the way you invoke AddLog to clearly state your intent that you don't care about when the Task completes, or about any exceptions that may be raised. You can do this by defining an empty continuation (Well, almost empty. See my edit at the bottom of the post for why it's a good idea to read the Task.Exception property at the very least).
// see EDIT for why the Task.Exception property is read here.
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
With either option, unless you are awaiting on other code inside your Add method that you are not showing us, then there is no longer any point in defining your Add method as async. You can simply turn it into a regular synchronous method. Otherwise, you'll then get another warning telling you that This async method lacks 'await' operators and will run synchronously....
public void Add() // no need for "async Task"
{
// see EDIT for why the Task.Exception property is read here.
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
// Logic to Add Customer
}
In any case, I wouldn't simply ignore the warning. Much like sometimes we get the warning Use of unassigned local variable 'x' in cases where we know that our code is fine, we typically don't ignore the warning. Instead, we may explicitly initialize the variable to null just to make our intent clear, and make the warning go away. Similarly, you can make the warning go away by making your intentions more explicit to the compiler using one of the above options.
EDIT: Word of caution about unobserved exceptions
I should also mention that even with the ContinueWith option, you may have to be careful about unhandled exceptions that come from your AddLog method.
According to this article, the way unobserved exceptions from tasks are handled has changed between .NET 4.0 and .NET 4.5. So, if you are still running .NET 4.0, or if you forcing .NET 4.0 exception behavior via configuration, you run the risk that unhandled exceptions will crash your process whenever the task gets GC-collected and finalized.
To make sure that this is not a problem, you can adjust the continuation to explicitly observe the exception, if any is present. You don't actually need to do anything with it, you just need to read it. This is one way to do it safely:
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
I've updated my earlier examples above to use the safer version of the continuation.
I would make add() non async since it isn't...and then task.run on add log
I have a WebApi method looking more or less like this:
public async Task<HttpResponseMessage> Get(Guid id)
{
var foo = await Store.GetFooAsync(id);
if (foo.BelongsTo != User.Identity.Name)
throw new HttpResponseException(HttpStatusCode.Forbidden);
//return foo here
}
This seems to work fine in the actual application, where a custom IHttpModule sets the principal in both HttpContext.User and Thread.CurrentPrincipal.
However, when calling from a unit test:
Thread.CurrentPrincipal = principal;
var response = controller.Get(id).Result;
User is reset after await (i.e. on the continuation), so the test fails. This happens when running under R#8, and it wasn't happening with R#7.
My workaround was to save the current principal before the first await, but it's just a hack to satisfy the test runner needs.
How can I call my controller method and make sure continuations have the same principal as the original call?
I fixed this by upgrading the MVC packages. The new version keeps the principal in ApiController.RequestContext.Principal, separate from Thread.CurrentPrincipal, avoiding the problem completely.
My new test code starts with:
controller.RequestContext.Principal = principal;
The short version is, use HttpContext.Current.Use instead of Thread.Principal.
The short version is, use Request.LogonUserIdentity or Request.RequestContext.HttpContext.User.
async/await preserves the original request context, not the thread that started the method. This makes senses, otherwise ASP.NET would have to freeze the thread and have it available for when await returns. The thread you run after await is a thread from the ThreadPool, so modifying its CurrentPrincipal is a very bad idea.
Check the transcript from Scott Hanselman's podcast "Everything .NET programmers know about Asynchronous Programming is wrong" for more.
I'm trying to use a task launcher in WP7.1 Mango with the latest version of Caliburn Micro, but my code is not getting called back once the task has completed. Probably I'm doing something stupid somewhere, but I cannot see where. Here is what I did for a sample repro application you can download from:
http://www.filesonic.com/file/2750397005/PhoneTaskTest.zip
1) create a new WP7.1 application;
2) add a Lib folder in the solution, add there CM dll's, and add a reference to them;
3) change the generated files as specified by CM documentation and add a bootstrapper.
Now up to this point everything is OK and the application starts with no issues. I then do the following for taking a photo:
4) add a button in the main page to the view and a corresponding method in its VM, named TakePhoto.
5) change the VM as follows:
a) add a readonly IEventAggregator member injected in the constructor;
b) add OnActivate/OnDeactivate overrides to let the aggregator subscribe and unsubscribe this VM;
c) add the TakePhoto method which is just:
_aggregator.RequestTask<CameraCaptureTask>();
d) derive the VM from interface IHandle<TaskCompleted<CameraCaptureTask>> and implement it:
public void Handle(TaskCompleted<CameraCaptureTask> message)
{
if (message.Result.TaskEventArgs.TaskResult != TaskResult.OK) return;
SetPhoto(message.Result.TaskEventArgs.ChosenPhoto);
}
Now, when I click the button the camera task starts in the emulator and I can take a photo; then I'm taken back to my application, but nothing happens and my Handle method is NEVER called. You can just place a breakpoint there to confirm this.
So, what I'm doing wrong here?
You need to handle TaskCompleted<PhotoResult> instead of TaskCompleted<CameraCaptureTask>. Because Caliburn.Micro creates theTaskCompleted<T> message with the event args of the Task's Completed event which is in the case of CameraCaptureTask is PhotoResult. So you should implement IHandle<TaskCompleted<PhotoResult>> and your Handle method should look like this
public void Handle(TaskCompleted<PhotoResult> message)
{
if (message.Result.TaskResult != TaskResult.OK) return;
SetPhoto(message.Result.ChosenPhoto);
}