I have a function imports a stored procedure, but I want to make it as async. How could I do that?
Any ideas?
public static async Task<List<ObtenerLayoutPor_Result>> GenerarArchivoPorBanco()
{
List<ObtenerLayoutPor_Result> result = new List<ObtenerLayoutPorBanco_Result>();
try
{
using (CobranzaEntities db = new CobranzaEntities())
{
return Task.Run(() => db.ObtenerLayoutPor(96)).GetAwaiter(); //one try
result = await db.ObtenerLayoutPor(96); //second try
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return result;
}
I would do it like that:
public static Task<List<ObtenerLayoutPor_Result>> GenerarArchivoPorBanco()
{
return Task.Run(()=>{ // no await here and function as a whole is not async
using (CobranzaEntities db = new CobranzaEntities())
{
return db.ObtenerLayoutPor(96).ToList(); // depending on your implementation, ToList may be requiered to make the actual trip to database
}
});
}
or, as suggested in comment, if you stored procedure returns IQueryable, you can simply use this code:
public static Task<List<ObtenerLayoutPor_Result>> GenerarArchivoPorBanco()
{
using (CobranzaEntities db = new CobranzaEntities())
{
return db.ObtenerLayoutPor(96).ToListAsync();
}
}
To sum up, the easiest way to make a funtion async is to wrap it in Task.Run. Then you can use it in your code:
var results = await GenerarArchivoPorBanco();
Related
I have a situation where I need to retrieve a particular document but I do not know it's PartitionKey.
The method looks like this:
public async Task<T> GetItemAsyncNoGroupId(string id)
{
try
{
Document document = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id),
new RequestOptions() { PartitionKey = new PartitionKey(Undefined.Value) });
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}
I passed in the Undefined.Value to the PartitionKey object and that didn't work. I also didn't pass any PartionKey object into the ReadDocumentAsync method and that didn't work. I always get 'No Content' passed back. Any suggestions on how I can get this to work?
You need to use a cross partition query. Read about it here.
I'm working on a class responsible for communicating with O365 using the Microsoft Graph Client Library. In each method, the call to NextPageRequest.GetAsync() is on a different type which also returns a different type, but otherwise the pagination logic is identical:
public async Task<List<Microsoft.Graph.User>> FindAllUsers()
{
var usersFound = new List<Microsoft.Graph.User>();
var usersPage = await GraphClient.Users.Request().GetAsync();
usersFound.AddRange(usersPage);
while (usersPage.NextPageRequest != null)
{
usersPage = await usersPage.NextPageRequest.GetAsync();
usersFound.AddRange(usersPage);
}
return usersFound;
}
public async Task<List<Microsoft.Graph.Group>> FindAllGroups()
{
var groupsFound = new List<Microsoft.Graph.Group>();
var groupsPage = await GraphClient.Groups.Request().GetAsync();
groupsFound.AddRange(groupsPage);
while (groupsPage.NextPageRequest != null)
{
groupsPage = await groupsPage.NextPageRequest.GetAsync();
groupsFound.AddRange(groupsPage);
}
return groupsFound;
}
public async Task<List<Microsoft.Graph.User>> FindGroupMembers(string groupId)
{
var usersFound = new List<Microsoft.Graph.User>();
var membersPage = await GraphClient.Groups[groupId].Members.Request().GetAsync();
usersFound.AddRange(membersPage.Where(d => d.ODataType.Equals("#microsoft.graph.user")).Cast<Microsoft.Graph.User>());
while (membersPage.NextPageRequest != null)
{
membersPage = await membersPage.NextPageRequest.GetAsync();
usersFound.AddRange((List<Microsoft.Graph.User>)membersPage);
}
return usersFound;
}
I would like to write generic method to reduce duplication, but in each of the above methods, the return type of GetAsync is a different interface that defines its own NextPageRequest property on itself. This makes it impossible to tell the generic method what specific type it will need to call NextPageRequest on so that the method can compile.
Is there a way to improve upon this, or do I just need to accept the duplicated logic for each query type I want to implement?
Thanks to Microsoft Graph API architects, it looks like we can only get rid of such sort of redundancy either by using reflection or dynamics. Since dynamics, in theory, should provide better performance, here's a version of sample code based on them:
private void ProcessAllResultPages<TResult, TItem>(IBaseRequest request,
Action<TResult> processorDelegate)
where TResult : ICollectionPage<TItem>
{
do
{
Task<TResult> task = ((dynamic)request).GetAsync();
processorDelegate(task.Result); // This will implicitly call Wait() on the task.
request = ((dynamic)task.Result).NextPageRequest;
} while (request != null);
}
Sample usage:
IGraphServiceGroupsCollectionRequest request = graphServiceClient.Groups.Request().
Filter(...).
Select(...).
Top(pageSize);
ProcessAllResultPages<IGraphServiceGroupsCollectionPage, Group>(request,
result =>
{
// Process page results here.
});
I used this to reduce duplication of code:
public async Task<List<T>> GetAllAsync<T>(IBaseRequest baseRequest)
where T : DirectoryObject
{
List<T> pagedItems = new();
try
{
var pageOfItems = await ((dynamic)baseRequest).GetAsync();
pagedItems.AddRange(pageOfItems);
while (pageOfItems.NextPageRequest != null)
{
pageOfItems = await pageOfItems.NextPageRequest.GetAsync();
pagedItems.AddRange(pageOfItems);
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
return pagedItems;
}
And then use it with:
var result = await GetAllAsync<Microsoft.Graph.Group>(_graphServiceClient.Groups.Request());
var result = await GetAllAsync<Microsoft.Graph.User>(_graphServiceClient.Users.Request());
How to overwrite delegated parameters
I do have a service with a method like the below:
public static IEnumerable<IntegracaoParoquia> GetMyStuffFromRepo(MainForm form, Decimal myId)
{
IEnumerable<MyStuffClass> stuffCollection = null;
using (var unitOfWork = new UnitOfWork())
{
try
{
unitOfWork.OpenConnection();
stuffCollection = GetRepo().GetStuff(myId, unitOfWork.GetConnection(), unitOfWork.GetTransaction());
}
catch (Exception ex)
{
unitOfWork.Rollback();
LogError(form, ex);
}
}
return stuffCollection;
}
but since a can end with dozen call like this I want to wrap them in a generic call like the below:
private static R CallMyRepoMethod<P, R>(MainForm form, P param, Func<P, IDbConnection, IDbTransaction, R> method)
{
R result = default(R);
using (var unitOfWork = new UnitOfWork())
{
try
{
unitOfWork.OpenConnection();
result = method(param, unitOfWork.GetConnection(), unitOfWork.GetTransaction());
}
catch (Exception ex)
{
unitOfWork.Rollback();
LogError(form, ex);
}
}
return result;
}
public static IEnumerable<IntegracaoParoquia> GetMyStuffFromRepo(MainForm form, Decimal myId)
{
return CallMyRepoMethod<Decimal, IEnumerable<MyStuffClass>>(form, myId, (x,y,z)=>GetRepo().GetStuff(myId, null, null) );
}
The problem is: I want to keep the using inside my delegate (and the provided connection and transaction) but due to the repository method signature. When (x,y,z)=>GetRepo().GetStuff(myId, null, null) is called it passes the null values instead of using the correct values from the delegate.
That's reasonable if you consider the using is not in the scope outside the delegate.
There's any way to get around it or do I need to rewrite it using invoke?
im refactoring out some try catch blocks with a ExcecuteWithLogging method, but exception that occurs in restHandler.GetResultAsync() never get caught, why?
public async Task<Aaa> SearchByPersonnummerAsync(string personnummer)
{
var restHandler = new RestHandler();
GenericResult<Aaa> aaa= await ExcecuteWithLogging(async () =>
{
var res = await restHandler.GetResultAsync<Aaa>(
_configurationManager.GetSetting("api"),
"url");
return res;
});
return aaa.Result;
}
private T ExcecuteWithLogging<T>(Func<T> function)
{
try
{
function();
}
catch (Exception ex)
{
var message = ex.Message;
// Log
}
return default(T);
}
Here is my solution which is working as i prefered:
var aaa = null;
await ExcecuteWithLogging(async () =>
aaa = await Method());
public async Task<string> ExcecuteWithLogging(Func<Task> action)
{
try
{
await action();
}
catch (Exception ex)
{
// handle exception
return null;
}
return "ok";
}
I had a similar problem and here is my solution. In my case I couldn't be sure about the functions type, so I simply created an overload for async ones:
public static T CallAndLogErrors<T, TLog>(Func<T> method, ILogger<TLog> logger)
{
try
{
return method();
}
catch (Exception e)
{
LogError(e, logger);
throw;
}
}
public static async Task<T> CallAndLogErrors<T, TLog>(Func<Task<T>> method, ILogger<TLog> logger)
{
try
{
return await method();
}
catch (Exception e)
{
LogError(e, logger);
throw;
}
}
This makes it possible to call methods with T, Task<T> or async Task<T> return types like:
var result = CallAndLogErrors(() => Method(), logger);
var result = await CallAndLogErrors(() => Method(), logger);
And all exceptions are catched.
The problem is that you are not implementing an overload of ExecuteWithLogging that resolves specifically for Func<Task<T>>. Remember that lambda expressions can be converted into any compatible delegate, that is why your async lambda is assigned succesfully to your current ExecuteWithLogging method.
Before you read the rest of the answer pleas have a look to the following article, it helped me a lot when I came across with exactly the same problem that you are facing now. I am pretty much sure that after reading that article you will understand what is happening here, but for completness sake here you have some samples that will make things clarer. I have modified your methodos in the following way:
public static async void SearchByPersonnummerAsync(string personnummer)
{
var aaa = await ExcecuteWithLogging(async () =>
{
Console.WriteLine("Executing function");
var res = await Task.Run(() =>
{
Thread.Sleep(100);
Console.WriteLine("Before crashing");
throw new Exception();
return 1;
});
Console.WriteLine("Finishing execution");
return res;
});
}
private static T ExcecuteWithLogging<T>(Func<T> function)
{
try
{
Console.WriteLine("Before calling function");
function();
Console.WriteLine("After calling function");
}
catch (Exception ex)
{
var message = ex.Message;
Console.WriteLine(message);
}
Console.WriteLine("Returning..");
return default(T);
}
This is just where you are now, I only added some console logging code, what is the output?
As you can see ExecutingWithLogging is returning when the async delegate has not even crashed!
Let's add an overload that accepts a Func<Task<T>>
private static async Task<T> ExcecuteWithLogging<T>(Func<Task<T>> function)
{
T result;
try
{
Console.WriteLine("Before calling function");
result = await function();
Console.WriteLine("After calling function");
}
catch (Exception ex)
{
var message = ex.Message;
Console.WriteLine(message);
return default(T);
}
Console.WriteLine("Returning..");
return result;
}
The compiler will pick this now, from the article mentioned above:
The compiler prefers the method call that expects a delegate that returns a Task. That’s good, because it’s the one you’d rather use. The compiler comes to this conclusion using the type inference rules about the return value of anonymous delegates. The “inferred return type” of any async anonymous function is assumed to be a Task. Knowing that the anonymous function represented by the lambda returns a Task, the overload of Task.Run() that has the Func argument is the better match.
Now the output is:
And you get your exeption catched. So what is the moral? Again, I quote the mentioned article:
First, avoid using async lambdas as arguments to methods that expect Action and don’t provide an overload that expects a Func. If you do that, you’ll create an async void lambda. The compiler will happily assume that’s what you want.
Second, if you author methods that take delegates as arguments,
consider whether programmers may wish to use an async lambda as that
argument. If so, create an overload that uses Func as the
argument in addition to Action. As a corollary, create an overload
that takes Func> in addition to Task for arguments that
return a value.
EDIT
As #Servy points out in the comments if you mantain only the original version of ExecuteWithLogging T is actually a Task<Aaa>... but the only way I can think of awaiting without the overload is:
private static async Task<T> ExcecuteWithLogging<T>(Func<T> function)
{
try
{
var result = function();
if (result is Task t)
{
return await t;
}
return result;
}
catch (Exception ex)
{
var message = ex.Message;
Console.WriteLine(message);
}
Console.WriteLine("Returning..");
return default(T);
}
But besides being ugly IMHO, it always fails since the call to function() runs synchronously and by the time you want to await the task has already ended or crashed. But the worst part of this approach is that it does not even compile, the compiler complains with: Can not implicitly convert type void to T
I have recently started using Dapper, everything seems nice and easy but there is one thing that keeps confusing me: Connection Management.
As per the documentation:
Dapper does not manage your connection's lifecycle, it assumes the
connection it gets is open AND has no existing datareaders enumerating
(unless MARS is enabled)
In light of this I started doing this inside the implementation of my repository methods:
using (var db = new SqliteConnection(connectionString)) {
// call Dapper methods here
}
Then I came across a table with a large number of records, so I though of returning an IEnumerable<T> by passing buffered: false to the Query<> method, and when I started enumerating the enumerable in the front end, boom an exception saying the connection was closed and disposed which is expected since I am wrapping my calls with the preceding using block.
Question: Best way to solve this ?
Side question: Is the way I am managing the connection the preferred way to go about it ?
I'd offer this repository pattern:
public class Repository
{
private readonly string _connectionString;
public Repository(string connectionString)
{
_connectionString = connectionString;
}
protected T GetConnection<T>(Func<IDbConnection, T> getData)
{
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
return getData(connection);
}
}
protected TResult GetConnection<TRead, TResult>(Func<IDbConnection, TRead> getData, Func<TRead, TResult> process)
{
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
var data = getData(connection);
return process(data);
}
}
}
For buffered queries you want to use first overload of GetConnection method, for non-buffered you use second, specifing callback for processing data:
public class MyRepository : Repository
{
public MyRepository(string connectionString) : base(connectionString)
{
}
public IEnumerable<MyMapObject> GetData()
{
return GetConnection(c => c.Query<MyMapObject>(query));
}
public IEnumerable<ResultObject> GetLotsOfData(Func<IEnumerable<MyMapObject>, IEnumerable<ResultObject>> process)
{
return GetConnection(c => c.Query<MyMapObject>(query, buffered: false), process);
}
}
Very basic usage:
static void Main(string[] args)
{
var repository = new MyRepository(connectionString);
var data = repository.GetLotsOfData(ProcessData);
}
public static IEnumerable<ResultObject> ProcessData(IEnumerable<MyMapObject> data)
{
foreach (var record in data)
{
var result = new ResultObject();
//do some work...
yield return result;
}
}
But keep in mind - connection may be opened for too long time in this case...
#Sergio, AWESOME! Thanks for such a great pattern. I modified it slightly to be async so that I can use it with Dapper's async methods. Makes my entire request chain async, from the controllers all the way back to the DB! Gorgeous!
public abstract class BaseRepository
{
private readonly string _ConnectionString;
protected BaseRepository(string connectionString)
{
_ConnectionString = connectionString;
}
// use for buffered queries
protected async Task<T> WithConnection<T>(Func<IDbConnection, Task<T>> getData)
{
try
{
using (var connection = new SqlConnection(_ConnectionString))
{
await connection.OpenAsync();
return await getData(connection);
}
}
catch (TimeoutException ex)
{
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL timeout", GetType().FullName), ex);
}
catch (SqlException ex)
{
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL exception (not a timeout)", GetType().FullName), ex);
}
}
// use for non-buffeed queries
protected async Task<TResult> WithConnection<TRead, TResult>(Func<IDbConnection, Task<TRead>> getData, Func<TRead, Task<TResult>> process)
{
try
{
using (var connection = new SqlConnection(_ConnectionString))
{
await connection.OpenAsync();
var data = await getData(connection);
return await process(data);
}
}
catch (TimeoutException ex)
{
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL timeout", GetType().FullName), ex);
}
catch (SqlException ex)
{
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL exception (not a timeout)", GetType().FullName), ex);
}
}
}
Use with Dapper like this:
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
// Assumes you have a Person table in your DB that
// aligns with a Person POCO model.
//
// Assumes you have an existing SQL sproc in your DB
// with #Id UNIQUEIDENTIFIER as a parameter. The sproc
// returns rows from the Person table.
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c =>
{
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(sql: "sp_Person_GetById", param: p, commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}