Ron
Ron

Reputation: 1894

Calling To Method Async Without Waiting For Answer

I've MVC application and I want to keep Activity Log about the activity in my site, so for example, if user is log-in successfully ill insert to my database a row that describe this activity (user with the name X log-in in time Y with ip of Z.

The problem is that I need to wait for the result, I don't care for the result, I don't want the result to hold me back, I want to send it to the function (the update Activity table in the DB function) and to continue.

I'll start for the bottom up :

This is my Data Query function :

public static void InsertLogRecord(LogRecord lg)
{
    try
    {
         string query = "INSERT INTO ActivityLog VALUES('" + lg.Id + "','" + lg.Time + "','" + lg.Executor + "','" + lg.ExecutedOn + "','" + lg.Action + "','" + lg.StartState + "','" + lg.EndState + "','" + lg.IP + "')";

         AdoHelper.ExecuteNonQuery(query);
    }

    catch(Exception ex)
    {
         throw ex;
    }

}

This is my Controller function (that called the previous "InsertLogRecord" function)

public void UpdateLog(string exeOn, string action, string sState, string eState)
{
     LogRecord lg = new LogRecord(Guid.NewGuid().ToString(), DateTime.Now, User.Identity.Name, exeOn, action, sState, eState, Request.ServerVariables["REMOTE_ADDR"]);

     DataQueries.InsertLogRecord(lg);
}

Use Example: (store an action record on the log, "user log-in")

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);

    switch (result)
    {
        case SignInStatus.Success:

              // Just before redirecting the user to the site I want to store the info' on my DB

             UpdateLog("", "Log in", "", "");

            return RedirectToLocal(returnUrl);


        case SignInStatus.LockedOut:
            return View("Lockout");
    }
}

How can I do it properly ?

Upvotes: 2

Views: 7275

Answers (2)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149538

What you need is a reliable way to queue the item in a "Fire and Forget" fasion. What you could do is use HostingEnvironment.QueueBackgroundWorkItem introduced in .NET 4.5.2 which queues work and notifies the ASP.NET environment, such that when it attempts to recycle your app, it will know pending work is still at play.

If you're using previous version of the .NET framework, you could use Stephan Clearys BackgroundTaskManager.

I also recommend reading stephans post on Fire and Forget in ASP.NET

Edit:

In order to queue work using HostingEnvironment, simply pass it a delegate. It can be either an Action<CancellationToken> or a Func<CancellationToken, Task>.

Here's an example using a Lambda Expression:

HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
   // Put code here.
});

Upvotes: 9

Brad
Brad

Reputation: 314

Have you tried just using the async version of ExecuteNonQuery?

http://msdn.microsoft.com/en-us/library/hh223678(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

AdoHelper.ExecuteNonQueryAsync(query);

Upvotes: 0

Related Questions