How do I use Dapper in an asynchronous controller? - c#

This is my first time using async/await with the Dapper ORM. I keep getting the message that my controller lacks the await method. How can I correctly insert the await method in my code?
public async Task<ActionResult> index(int? page)
{
if (page == null)
{
page = 1;
ViewBag.page = page;
}
else
{
ViewBag.page = page;
}
string Connectionstring = ConfigurationManager.ConnectionStrings["mycontext"].ConnectionString;
using (System.Data.SqlClient.SqlConnection sqlConnection = new System.Data.SqlClient.SqlConnection(Connectionstring))
{
sqlConnection.Open();
var sqlM = #"SELECT * from threads order by activities desc";
var resultM = sqlConnection.Query<thread>(sqlM).ToList();
await Task.WhenAll(resultM);
return View(new homepage { panel = resultM });
}
}
I have tried await Task.WhenAll(resultM); but it didn't change anything.

You're getting the warning because you aren't using any asynchronous methods in the controller. As it is, there's no reason to mark it as async.
In order to actually make the method asynchronous, you need to use Dapper's async methods and await them. See Using Async Await keywords with Dapper for another example of this.
In your code, it would look like:
public async Task<ActionResult> index(int? page)
{
if (page == null)
{
page = 1;
ViewBag.page = page;
}
else
{
ViewBag.page = page;
}
string Connectionstring = ConfigurationManager.ConnectionStrings["mycontext"].ConnectionString;
using (System.Data.SqlClient.SqlConnection sqlConnection = new System.Data.SqlClient.SqlConnection(Connectionstring))
{
await sqlConnection.OpenAsync();
var sqlM = #"SELECT * from threads order by activities desc";
var resultM = await sqlConnection.QueryAsync<thread>(sqlM);
return View(new homepage { panel = resultM });
}
}
If resultM must be a List<thread> instead of IEnumerable<T>, you can call ToList - but make sure it's after awaiting the asynchronous call.

Related

HttpClient in while loop only executed once

I am trying to call HttpClient request inside for loop as follows. It needs to do multiple consecutive calls to third party rest api.
But it only gives me fist service call result while loop exit before getting result from rest of the service call.
private void Search()
{
try
{
var i = 1;
using (var httpClient = new HttpClient())
{
while (i < 5)
{
string url = "https://jsonplaceholder.typicode.com/posts/" + i;
var response = httpClient.GetAsync(url).Result;
string jsonResult = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(jsonResult.ToString());
i++;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
When I run with debug points the program gives me all the result. But when I run it without debug points it gives me only the first result.
I tried this with using async, await methods too. It also gives me same result.
As I feel Program needs to wait until the async call returns data.
Please help me to solve this.
EDIT - async way
private async Task<string> SearchNew()
{
try
{
var i = 1;
var res = string.Empty;
using (var httpClient = new HttpClient())
{
while (i < 5)
{
string url = "https://jsonplaceholder.typicode.com/posts/" + i;
var response = httpClient.GetAsync(url).Result;
string jsonResult = await response.Content.ReadAsStringAsync();
res = res + jsonResult + " --- ";
i++;
}
}
return res;
}
catch (Exception ex)
{
return ex.Message;
}
}
Both are giving same result.
There's a few things here that you should be doing. First, move the HttpClient creation outside of your method and make it static. You only need one of them and having multiple can be really bad for stability (see here):
private static HttpClient _client = new HttpClient();
Next, extract the calls to the HttpClient into a single method, something simple like this:
//Please choose a better name than this
private async Task<string> GetData(string url)
{
var response = await _client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
And finally, you create a list of tasks and wait for them all to complete asynchronously using Task.WhenAll:
private async Task<string[]> SearchAsync()
{
var i = 1;
var tasks = new List<Task<string>>();
//Create the tasks
while (i < 5)
{
string url = "https://jsonplaceholder.typicode.com/posts/" + i;
tasks.Add(GetData(url));
i++;
}
//Wait for the tasks to complete and return
return await Task.WhenAll(tasks);
}
And to call this method:
var results = await SearchAsync();
foreach (var result in results)
{
Console.WriteLine(result);
}

C# Interacting with Database In async way, not working.

I just wanted to create a dummy ASP.NET MVC project where i wanted to explore more about async & await.I created async methods in DB access Layer and Repository Layer and i also make sure that the action is also written in async way. I noticed that a single method takes around 7ms to execute, so logically if i call the method 3 times i also should take 7 ms or around 7ms ! But its taking about 20-23 ms. I am sure that i am doing something terribly wrong. My Code snippet goes below:
DATA ACCESS LAYER:
public async Task<DataTable> DtGetAllCustomers()
{
await Task.Run(() =>
{
_dtCustomer = new DataTable();
_connectionString = Repo.GetConnString();
_spName = "spGetCus";
_spParameters = new SqlParameter[]
{
new SqlParameter("#QryOption",1)
};
using (var conn = new SqlConnection(_connectionString))
{
using (var cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = _spName;
cmd.Parameters.AddRange(_spParameters);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(_dtCustomer);
conn.Close();
da.Dispose();
}
}
}
});
return _dtCustomer;
}
REPOSITORY:
public async Task<List<CustomerModel>> GetAllCustomers()
{
_dtCustomer = await _customerDal.DtGetAllCustomers();
List<CustomerModel> allCustomers = new List<CustomerModel>();
return allCustomers = (from DataRow row in _dtCustomer.Rows
select new CustomerModel
{
CustomerId = (int)row["CustomerId"],
CustomerName = (string)row["CustomerName"]
}).ToList();
}
ACTION:
public async Task<ActionResult> Index()
{
var watch = System.Diagnostics.Stopwatch.StartNew();
List<CustomerModel> model = new List<CustomerModel>();
CustomerRepo2 aa = new CustomerRepo2();
await aa.GetAllCustomers();
await aa.GetAllCustomers();
await aa.GetAllCustomers();
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
ViewBag.time = elapsedMs;
return View();
}
You're awaiting each call, so before it can move onto the next, it will pause execution. Consider creating three tasks, and awaiting them all with Task.WhenAll():
var task1 = aa.GetAllCustomers();
var task2 = aa.GetAllCustomers();
var task2 = aa.GetAllCustomers();
await Task.WhenAll(task1, task2, task3);

context.SaveChanges() vs context.SaveChangesAsync()

I just started with EF Core and noticed that they have got all kind of XXXAsync methods now. I started using them and hit the rock with the use of context.SaveChnagesAsync() while doing simple basic insert operation. It went like this :
public async void SaveUserAsync(User user)
{
using (var context = GetContextTransient())
{
Model.User contextUser = new Model.User
{
EmailId = user.EmailId,
UserName = user.UserName,
JoinedDateTime = DateTime.Now
};
await context.User.AddAsync(contextUser).ConfigureAwait(false);
await context.SaveChangesAsync(true).ConfigureAwait(false);
}
}
The above implementation was not inserting any records to the DB but doing simple change as below, then it worked :
public async Task<int> SaveUserAsync(User user)
{
using (var context = GetContextTransient())
{
Model.User contextUser = new Model.User
{
EmailId = user.EmailId,
UserName = user.UserName,
JoinedDateTime = DateTime.Now
};
await context.User.AddAsync(contextUser).ConfigureAwait(false);
int result = await context.SaveChangesAsync(true).ConfigureAwait(false);
return result;
}
}
Now I know doing aysnc - await with void return type is not recommended but still shouldn't 1st implementation work because I am doing await on context.SaveChangesAsync() ? Is my understanding of async- await correct or am I missing something?

Testing the Patch odata webapi method

I need to test the following Patch method in my odata controller from my test project.
[ValidateModel]
[AcceptVerbs("PATCH", "MERGE")]
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<User> patch)
{
var user = await db.Users.FindAsync(key);
if (user == null)
{
return NotFound();
}
patch.Patch(user);
Validate(user);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try
{
db.Entry(user).Property(p => p.UserType).IsModified = false;
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!UserExists(key))
{
return NotFound();
}
throw;
}
return Updated(user);
}
The code in the test project is as follows. Could someone tell me how do I pass value to the Delta parameter. Currently I am getting compilation errors at line controller.Patch(1, user);.
[TestMethod]
public void TestPatch()
{
// Arrange
var controller = new UsersController();
var user = new User();
user.Id = 1;
user.Lastname = "Johanson";
// Act
controller.Patch(1, <System.Web.OData.Delta> user);
// Assert
}
You can also declare the delta using the dynamic keyword and set the properties directly:
dynamic delta = new Delta<User>();
delta.Id = 1;
delta.Lastname = "Johanson";
var delta = new Delta<User>(typeof(User));
delta.TrySetPropertyValue("Id", 1);
delta.TrySetPropertyValue("Lastname", "Johanson");
I don't know if there are any helpers to make that easier
#yenta's answer is perfectly fine, but if you can, also consider using the nameof (since C# 6.0)
var delta = new Delta<User>(typeof(User));
delta.TrySetPropertyValue(nameof(User.Id), 1);
delta.TrySetPropertyValue(nameof(User.Lastname), "Johanson");

Web Service Call Loop/Not Finishing

For my app I make calls to a web service to get customer data. The problem I am encountering is when I make this particular call it gets the the asynchronous await call and loops back without finishing the call and then storing the results.
private void DatabaseTest()
{
cNum = Convert.ToString(db.selectCustomerNumber());
callC = "SELECT * FROM dashboardCustomer WHERE period = 'C' AND customerNumber = " + cNum;
callB = "SELECT * FROM dashboardCustomer WHERE period = 'B' AND customerNumber = " + cNum;
callF = "SELECT * FROM dashboardCustomer WHERE period = 'F' AND customerNumber = " + cNum;
if (db.selectDashboard(callC).Count == 0)
{
GetDataSummary(passC);
}
if (db.selectDashboard(callB).Count == 0)
{
GetDataSummary(passB);
}
if (db.selectDashboard(callF).Count == 0)
{
GetDataSummary(passF);
}
}
private async void GetDataSummary(string r)
{
long customerNum = db.selectCustomerNumber();
pin = db.selectPinByCustomerNumber(customerNum);
string cType = r;
try
{
Windows.Security.Credentials.PasswordVault vault = new Windows.Security.Credentials.PasswordVault();
IReadOnlyList<PasswordCredential> userCredential = vault.FindAllByResource(pin);
userCredential[0].RetrievePassword();
try
{
getCustomerBillSummaryResponse billSum = await
UBPclient.getCustomerBillSummaryAsync(userCredential[0].UserName, userCredential[0].Password, customerNum, cType);
invoiceSummaryBean[] summaryList = billSum.#return;
rh.DashboardHandler(summaryList, customerNum);
}
catch
{
}
}
catch
{
}
}
it runs to the following part
getCustomerBillSummaryResponse billSum = await
UBPclient.getCustomerBillSummaryAsync(userCredential[0].UserName, userCredential[0].Password, customerNum, cType);
and then loops back to the try and runs again until it has ran three times.
How do I make it return the data it is suppose to for each call and store it in my database?
Also I have tested the web service in SoapUI and the call is returning results, so the problem is not with the web service.
You need to do this:
private async Task GetDataSummary(string r)
You need to return Task instead of void because your caller needs to have something to wait for. When you return void, the caller must treat method as "fire-and-forget". When you return Task, the caller can create the necessary code to await for async method to finish.
And don't forget to add the await keyword when you call it: await GetDataSummaryAsync(...);
You should avoid async void. Change GetDataSummary to return Task and then await it from DatabaseTest:
private async Task DatabaseTestAsync()
{
...
if (db.selectDashboard(callC).Count == 0)
{
await GetDataSummaryAsync(passC);
}
if (db.selectDashboard(callB).Count == 0)
{
await GetDataSummaryAsync(passB);
}
if (db.selectDashboard(callF).Count == 0)
{
await GetDataSummaryAsync(passF);
}
}
private async Task GetDataSummaryAsync(string r)

Categories