I'm trying to wrap my Operations Contracts to the try-catch block. The problem is that my EF context destroyed in the same time scope. I guess the problem compiler doesn't know what to do properly. Also my catch block doesn't handle any exceptions. Sorry for my English, I hope my code show what I mean:
private static async Task<T> SurroundWithTryCatch<T>(Action t, T response) where T : BaseResponse
{
try
{
await Task.Run(t);
}
catch (Exception e)
{
response.Success = false;
response.Errors.Add(e.Message);
}
return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
var response = new CreateResponse();
return await SurroundWithTryCatch(async delegate
{
var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
await Database.UserManager.CreateAsync(newUser, request.Password);
//Some another logic...
await Database.CommitAsync();
}, response);
}
The problem in the second line of CreateAsync method. UserManager was cleaned by GC earlier. So I have ObjectDisposedException. Database is the IUnitOfWork implementation and injected by Autofac.
You're breaking the await chain - t no longer returns a task. Since you no longer have a task, the execution will continue after the first await, rather than after the whole method is done. Think of await as return - if you don't return (and await/wait for) a Task, you lose your chance at synchronization.
Instead, you want to pass Func<Task>, and await it directly:
private static async Task<T> SurroundWithTryCatch<T>(Func<Task> t, T response) where T : BaseResponse
{
try
{
await t();
}
catch (Exception e)
{
response.Success = false;
response.Errors.Add(e.Message);
}
return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
var response = new CreateResponse();
return await SurroundWithTryCatch(async () =>
{
var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
await Database.UserManager.CreateAsync(newUser, request.Password);
//Some another logic...
await Database.CommitAsync();
}, response);
}
Task.Run also works, but you probably don't want that anyway - your code is asynchronous, and (a guess) you're running in a ASP.NET request, so there's no benefit to launching a task just to wait on the result of another task. Task.Run is used for doing CPU work in a separate thread, something you usually want to avoid in ASP.NET.
Related
Context - I am using Azure CosmosDB GraphAPI - and azure doesn't have logging for it, Sad!
So we came up with using our own logging of queries and its metaproperties
I implemented a Singleton class that is used by other services for DB Calls and I want to have a fire and forget the call to the logger.
public class GraphDatabaseQuery : IGraphDatabaseQuery
{
private readonly GremlinClient gremlinClient;
public GraphDatabaseQuery()
{
if (gremlinClient == null)
{
gremlinClient = CosmosDbClient.Instance;
}
else
{
if (gremlinClient.NrConnections == 0)
{
gremlinClient = CosmosDbClient.Instance;
}
}
}
public async Task<ResultSet<dynamic>> SubmitQueryAsync(string query, string fullName)
{
var response = await gremlinClient.SubmitAsync<dynamic>(query);
_ = SendQueryAnalytics(response, query, fullName);
return response;
}
public async Task<dynamic> SubmitQueryWithSingleSingleResultAsync(string query, string fullName)
{
var response = await gremlinClient.SubmitWithSingleResultAsync<dynamic>(query);
return response;
}
private async Task<bool> SendQueryAnalytics(ResultSet<dynamic> response, string query, string fullName)
{
try
{
await new QueryAnalytics().pushData(response, query, fullName); // breakpoint here
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return true;
}
}
in startup.cs
services.AddSingleton<IGraphDatabaseQuery, GraphDatabaseQuery>();
and the interface
public interface IGraphDatabaseQuery
{
public Task<ResultSet<dynamic>> SubmitQueryAsync(string query, string fullName);
public Task<dynamic> SubmitQueryWithSingleSingleResultAsync(string query, string fullName);
}
Whenever I test it the breakpoint hits "SendQueryAnalytics" but i assume at that moment the response from the calling function would be sent back
is this not working because I am using the singleton pattern?
Whenever I test it the breakpoint hits "SendQueryAnalytics" but i assume at that moment the response from the calling function would be sent back
No. All asynchronous methods begin executing synchronously.
So what happens is that SendQueryAnalytics is called and begins executing, enters the try block, creates a new QueryAnalytics instance, and calls pushData. pushData also begins executing and (presumably) returns an incomplete Task. Then the await in SendQueryAnalytics observes that that Task is incomplete and returns an incomplete Task to SubmitQueryAsync, which discards that Task instance and then returns the response.
Thus, seeing the response returned after that breakpoint is normal.
I don't think that the singleton pattern has something to do with it. Since you want a 'fire and forget' why don't you use something like hangfire?
I learning Xamarin, I use a function to delete all my sqlite database, add new elements and refesh my listview.
the code stop, I thinks it is because it has not time for delete first,add in database then refresh thelist view. When I add a timer (2 seconds) it works.
Here is the error at the line "mywordsdatabase.DeleteAllWords();" : System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index'
I am using this sqlite plugin enter link description here
Here is the function :
public async void DeleteAndUpdate(){
mywordsdatabase.DeleteAllWords(); // the error occur here
List<MyWords> WordUserList = await wordmanager.GetWordAsync(UserConnected.MyId);
foreach (MyWords w in WordUserList)
{
mywordsdatabase.AddWord(w);
}
var WordList = await mywordsdatabase.GetWords();
Device.BeginInvokeOnMainThread(() => { WordSList.ItemsSource = WordList; });
}
Here is the Delete function for sqlite:
class MyWordsDatabase
{
private SQLiteAsyncConnection conn;
//CREATE
public MyWordsDatabase()
{
conn = DependencyService.Get<ISQLite>().GetConnection();
conn.CreateTableAsync<MyWords>();
}
public string AddWord(MyWords mywords)
{
conn.InsertAsync(mywords);
return "success";
}
public string DeleteAllWords()
{
conn.DeleteAllAsync<MyWords>();
return "success";
}
}
Thanks for your help
Few things to check, first of ensure the database actually has words to delete, as the error would suggest that it tried to operate upon a null element. Secondly, since the method is async, see if changing the signature will help.
So instead of public string DeleteAllWords() it becomes public async string DeleteAllWords() then inside of the method we can say await conn.DeleteAllAsync<MyWords>(); and where we call it we can then do await mywordsdatabase.DeleteAllWords();
As jmcil said, async code won't wait for its operation to stop execution unless told to do so.
The whole point of asynchronous methods is that they are asynchronous, i.e. they return immediately while the work they initiated continues in the background. If you call that DeleteAllAsync method and then immediately start executing code as though it has finished deleting everything then of course you'll have issues. If you need the deletion to be completed before subsequent code is executed then you need to wait until the deletion is completed before executing that subsequent code. The way to do that is most likely to await the awaitable methods in your code. This:
public string DeleteAllWords()
{
conn.DeleteAllAsync<MyWords>();
return "success";
}
probably ought to be this:
public async Task<string> DeleteAllWordsAsync()
{
await conn.DeleteAllAsync<MyWords>();
return "success";
}
That means that you can either await the call to that method:
await mywordsdatabase.DeleteAllWordsAsync();
or you can trap the Task it returns, execute some code that doesn't depend on it completing and then await the Task later:
var t = mywordsdatabase.DeleteAllWordsAsync();
// ...
await t;
Please change your DeleteAllWords method like following method.
public Task<int> DeleteAllNotesAsync()
{
return conn.DeleteAllAsync<MyWords>();
}
Then judge the return value if it greater than 0, it the return value greater than 0, it means delete success like this simple code.
private async void Button_Clicked(object sender, EventArgs e)
{
int deleteRecord= await App.Database.DeleteAllNotesAsync();
if (deleteRecord>0)
{
await DisplayAlert("Success", "delete" + deleteRecord, "OK");
}
}
public async Task<string> AddWord(MyWords mywords)
{
string result=string.Empty;
try
{
await conn.InsertAsync(mywords);
}
catch (Exception ex)
{
}
return result;
}
public async Task<string> DeleteAllWords()
{
string result = string.Empty;
try
{
await conn.DeleteAllAsync<MyWords>();
}
catch (Exception ex)
{
}
return result;
}
public async void DeleteAndUpdate()
{
try
{
await mywordsdatabase.DeleteAllWords(); // the error occur here
List<MyWords> WordUserList = await wordmanager.GetWordAsync(UserConnected.MyId);
foreach (MyWords w in WordUserList)
{
await mywordsdatabase.AddWord(w);
}
var WordList = await mywordsdatabase.GetWords();
Device.BeginInvokeOnMainThread(() => { WordSList.ItemsSource = WordList; });
}
catch (Exception ex)
{
}
}
I have a method called StartAsync which await different task, this is the design:
public async Task StartAsync(int instance)
{
await SomeController.Foo();
await AnotherController.Foo2();
}
Now I need to run the StartAsync method multiple times, so I have created different Task, in this way I can manage a single execution of the Task of StartAsync:
Task bot1 = new Task(async () => { await new Bot().StartAsync(1); });
Task bot2 = new Task(async () => { await new Bot().StartAsync(2); });
these Tasks can be started by the input, essentially, if the user press 1 then the bot1 Task will start:
public async Task<bool> StartBotInstanceAsync(int instance)
{
try
{
switch(instance)
{
case 1:
await bot1.Start(); //<- Problem here
break;
case 2:
bot2.Start();
break;
}
return true;
}
catch(Exception ex)
{
Logger.Info(ex.ToString());
return false;
}
}
Essentially I need to write a log when an exception happen in side the try catch block, but for doing this I need to await the Task result, unfortunately I get this error:
Cannot await void
on await bot1.Start();
How can I manage the exception in this type of situation?
If you wish to do it with your current structure then you will need 2 separate statements.
case 1:
bot1.Start();
await bot1;
break;
If you want to use multiple bot instances, store them in an array and use the instance parameter as the index, eg :
_bots=new[]{ new Bot(),new Bot()};
public async Task<bool> StartBotInstanceAsync(int instance)
{
try
{
await _bots[instance-1].StartAsync();
return true;
}
catch(Exception ex)
{
Logger.Info(ex.ToString());
return false;
}
}
Or even better :
public async Task<bool> StartBotInstanceAsync(Bot bot)
{
try
{
await bot.StartAsync();
return true;
}
catch(Exception ex)
{
Logger.Info(ex.ToString());
return false;
}
}
var myBot=_bots[instance-1];
var started=await StartBotInstanceAsync(myBot);
More complex flows can be created easily by using async functions that take the bot as a parameter, eg :
public async Task SomeComplexFlow(Bot bot)
{
try
{
await bot.StartAsync();
await bot.DoSomething();
...
}
catch(Exception exc)
{
...
}
}
var myBot=_bots[instance-1];
await SomeComplexFlow(myBot);
It's possible to await multiple tasks for completion too. One coud use Task.WhenAll to wait for all bots to terminate, eg :
await Task.WhenAll(_bots[0].StopAsync()...);
Or, better yet :
var tasks=_bots.Select(bot=>bot.StopAsync());
await Tasks.WhenAll(tasks);
I'm fairly new to the new async/await stuff. However, I have the following classes:
public abstract class PluginBase
{
//Using EF to store log info to database
private EFContext _context = new EFContext();
private int Id = 1;
protected void LogEvent(string event, string details)
{
_context.LogEvents.Add(new LogItem(){
PluginId = this.Id,
Event = event,
Details = details,
User = Thread.CurrentPrincipal.Identity.Name
});
}
}
public class Plugin : PluginBase
{
public void Process()
{
CallWebService();
}
public async void CallWebService()
{
using(var http = new HttpClient())
{
...
var result = await http.PostAsync(memberURI, new StringContent(content, Encoding.UTF8,"application/json"));
if(result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
So, the idea is that Plugin.Process gets called. It in turn calls CallWebService(). CallWebService makes an asynchronous call to http.PostAsync. When I return from that call and try to call base.LogEvent(), I get an ObjectDisposedException stating that "Safe Handle has been Closed".
I know there is something going on where when the awaitable finishes, the rest of the code of the method has to be run. Maybe its being run in some other thread or context? If this is the case, how do I get the current user at the time of writing to the log?
Thanks for your help with this.
Edit
Based on the answer from Yuval, I made the following changes and it seems to work fine.
public void Process()
{
var task = CallWebService();
task.Wait();
}
public async Task CallWebService(List<Member> members)
{
using(var http = new HttpClient())
{
...
using(var result = await http.PostAsync(memberURI, new StringContent content, Encoding.UTF8, "application/json")))
{
if(result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
}
When I return from that call and try to call base.LogEvent(), I get an
ObjectDisposedException stating that "Safe Handle has been Closed".
That's because somewhere higher up the call-chain, someone is disposing your plugin object, which hasn't really finished the asynchronous operation. Using async void is doing a "fire and forget" operation. You don't actually await on Process, hence anyone calling it assumes it finished and disposes of your object.
Change your async void method to async Task, and await it:
public Task ProcessAsync()
{
return CallWebServiceAsync();
}
public async Task CallWebServiceAsync()
{
using (var http = new HttpClient())
{
var result = await http.PostAsync(memberURI,
new StringContent(content,
Encoding.UTF8,
"application/json"));
if (result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
Note you will need to await ProcessAsync somewhere higher up the call-stack as well.
Below is the code from the Intercept method on a custom type that implements IInterceptor of the Castle Dynamic Proxy library. This snippet is from an AOP based logging proof-of-concept console app that is posted here.
public void Intercept(IInvocation invocation)
{
if (Log.IsDebugEnabled) Log.Debug(CreateInvocationLogString("Called", invocation));
try
{
invocation.Proceed();
if (Log.IsDebugEnabled)
if (invocation.Method.ReturnType != typeof(void))
Log.Debug("Returning with: " + invocation.ReturnValue);
}
catch (Exception ex)
{
if (Log.IsErrorEnabled) Log.Error(CreateInvocationLogString("ERROR", invocation), ex);
throw;
}
}
This is working as expected on regular method calls, but not when tried with async methods (using the async/await keywords from C# 5.0). And I believe, I understand the reasons behind this as well.
For the async/await to work, the compiler adds the functional body of the method into a state machine behind the scenes and the control will return to the caller, as soon as the first awaitable expression that cannot be completed synchronously, is encountered.
Also, we can interrogate the return type and figure out whether we are dealing with an async method like this:
if (invocation.Method.ReturnType == typeof(Task) ||
(invocation.Method.ReturnType.IsGenericType &&
invocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)))
Log.Info("Asynchronous method found...");
This works for only those async methods that returns either Task or Task<> and not void but I am fine with that.
What changes have to made within the Intercept method so that the awaiter would return to there rather than the original caller?
Presumably the "problem" is that it's just logging that it's returning a task - and you want the value within that task?
Assuming that's the case, you still have to return the task to the caller, immediately - without waiting for it to complete. If you break that, you're fundamentally messing things up.
However, before you return the task to the caller, you should add a continuation (via Task.ContinueWith) which will log the result (or failure) when the task completes. That will still give the result information, but of course you'll be logging it potentially after some other logging. You may also want to log immediately before returning, leading to a log something like this:
Called FooAsync
Returned from FooAsync with a task
Task from FooAsync completed, with return value 5
The business of getting the result out of the task (if it completed successfully) would have to be done with reflection, which is a bit of a pain - or you could use dynamic typing. (Either way it will be a bit of a performance hit.)
Thanks to Jon's answer, this is what I ended up with:
public void Intercept(IInvocation invocation)
{
if (Log.IsDebugEnabled) Log.Debug(CreateInvocationLogString("Called", invocation));
try
{
invocation.Proceed();
if (Log.IsDebugEnabled)
{
var returnType = invocation.Method.ReturnType;
if (returnType != typeof(void))
{
var returnValue = invocation.ReturnValue;
if (returnType == typeof(Task))
{
Log.Debug("Returning with a task.");
}
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
{
Log.Debug("Returning with a generic task.");
var task = (Task)returnValue;
task.ContinueWith((antecedent) =>
{
var taskDescriptor = CreateInvocationLogString("Task from", invocation);
var result =
antecedent.GetType()
.GetProperty("Result")
.GetValue(antecedent, null);
Log.Debug(taskDescriptor + " returning with: " + result);
});
}
else
{
Log.Debug("Returning with: " + returnValue);
}
}
}
}
catch (Exception ex)
{
if (Log.IsErrorEnabled) Log.Error(CreateInvocationLogString("ERROR", invocation), ex);
throw;
}
}
Trying to clarify with a generic and clean solution for:
Intercepting async methods adding custom code as a continuation task.
I think the best solution is to use the dynamic keyword to bypass the compiler type checking and resolve the difference between Task and Task<T> at run time:
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
var method = invocation.MethodInvocationTarget;
var isAsync = method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null;
if (isAsync && typeof(Task).IsAssignableFrom(method.ReturnType))
{
invocation.ReturnValue = InterceptAsync((dynamic)invocation.ReturnValue);
}
}
private static async Task InterceptAsync(Task task)
{
await task.ConfigureAwait(false);
// do the logging here, as continuation work for Task...
}
private static async Task<T> InterceptAsync<T>(Task<T> task)
{
T result = await task.ConfigureAwait(false);
// do the logging here, as continuation work for Task<T>...
return result;
}
Below is my async interceptor adapter implementation that correctly handles async methods.
abstract class AsyncInterceptor : IInterceptor
{
class TaskCompletionSourceMethodMarkerAttribute : Attribute
{
}
private static readonly MethodInfo _taskCompletionSourceMethod = typeof(AsyncInterceptor)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.Single(x => x.GetCustomAttributes(typeof(TaskCompletionSourceMethodMarkerAttribute)).Any());
protected virtual Task<Object> InterceptAsync(Object target, MethodBase method, object[] arguments, Func<Task<Object>> proceed)
{
return proceed();
}
protected virtual void Intercept(Object target, MethodBase method, object[] arguments, Action proceed)
{
proceed();
}
[TaskCompletionSourceMethodMarker]
Task<TResult> TaskCompletionSource<TResult>(IInvocation invocation)
{
var tcs = new TaskCompletionSource<TResult>();
var task = InterceptAsync(invocation.InvocationTarget, invocation.Method, invocation.Arguments, () =>
{
var task2 = (Task)invocation.Method.Invoke(invocation.InvocationTarget, invocation.Arguments);
var tcs2 = new TaskCompletionSource<Object>();
task2.ContinueWith(x =>
{
if (x.IsFaulted)
{
tcs2.SetException(x.Exception);
return;
}
dynamic dynamicTask = task2;
Object result = dynamicTask.Result;
tcs2.SetResult(result);
});
return tcs2.Task;
});
task.ContinueWith(x =>
{
if (x.IsFaulted)
{
tcs.SetException(x.Exception);
return;
}
tcs.SetResult((TResult)x.Result);
});
return tcs.Task;
}
void IInterceptor.Intercept(IInvocation invocation)
{
if (!typeof(Task).IsAssignableFrom(invocation.Method.ReturnType))
{
Intercept(invocation.InvocationTarget, invocation.Method, invocation.Arguments, invocation.Proceed);
return;
}
var returnType = invocation.Method.ReturnType.IsGenericType ? invocation.Method.ReturnType.GetGenericArguments()[0] : typeof(object);
var method = _taskCompletionSourceMethod.MakeGenericMethod(returnType);
invocation.ReturnValue = method.Invoke(this, new object[] { invocation });
}
}
and sample usage:
class TestInterceptor : AsyncInterceptor
{
protected override async Task<Object> InterceptAsync(object target, MethodBase method, object[] arguments, Func<Task<object>> proceed)
{
await Task.Delay(5000);
var result = await proceed();
return DateTime.Now.Ticks % 2 == 0 ? 10000 :result;
}
}
My 2 cents:
It has been correctly established that for async methods the purpose of the interceptor would be to "enhance" the task returned by the invocation, via a continuation.
Now, it is precisely this task continuation the one that has to be returned to make the job of the interceptor complete.
So, based on the above discussions and examples, this would work perfectly well for regular methods as well as "raw" async Task methods.
public virtual void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
var task = invocation.ReturnValue as Task;
if (task != null)
{
invocation.ReturnValue = task.ContinueWith(t => {
if (t.IsFaulted)
OnException(invocation, t.Exception);
});
}
}
catch (Exception ex)
{
OnException(invocation, ex);
}
}
public virtual void OnException(IInvocation invocation, Exception exception)
{
...
}
But when dealing with async Task<T> methods, the above would incorrectly change the type of the task returned by the interception, from Task<T> to regular Task
Notice that we are calling Task.ContinueWith() and not Task<TResult>.ContinueWith(), which is the method we want to call.
This would be the resulting exception when ultimately awaiting the such an interception:
System.InvalidCastException: Unable to cast object of type 'System.Threading.Tasks.ContinuationTaskFromTask' to type 'System.Threading.Tasks.Task`1
Having a need to intercept methods returning Task<TResult>, I've created an extension to Castle.Core that simplifies the process.
Castle.Core.AsyncInterceptor
The package is available to download on NuGet.
The solution is largely based on this answer from #silas-reinagel, but simplifies it by providing a new interface to implement IAsyncInterceptor. There are also further abstractions to that make interception similar to implementing Interceptor.
See the readme of the project for further details.
void IInterceptor.Intercept(IInvocation invocation) {
try {
invocation.Proceed();
var task = invocation.ReturnValue as Task;
if (task != null && task.IsFaulted) throw task.Exception;
}
catch {
throw;
}
}
Instead of:
tcs2.SetException(x.Exception);
You should use:
x.Exception.Handle(ex => { tcs2.SetException(ex); return true; });
to bubble up the real exception...