dbarnes
dbarnes

Reputation: 1833

Trying to understand Tasks in .net

Ok I've been messing around with tasks in .net 4.5 and I'm trying to get my head around everything so I created a small app that does some work and I have a few questions about it.

Here is the code:

Account Controller.cs:

namespace MvcApplication1.Controllers
{
    public class AccountController : Controller
    {
        private readonly UserManager _manager;

        public AccountController()
        {
            _manager = new UserManager(ContextFactory.GetContext());
        }

    [HttpPost]
    public async Task<ActionResult> Register(LoginModel model)
    {
        var user = await _manager.FindAsync(model.UserName);
        if (user != null)
        {
            //do some work
        }
        else
        {
            ModelState.AddModelError("", "Cannot Find User");
            return View(model);
        }
    }
  }
}

User Manager.cs:

 namespace MvcApplication1
 {
   public class UserManager
   {
     private readonly IDBContext _context;

     public UserManager(IDBContext context)
     {
       _context = context;
     }
     public Task<UserProfile> FindAsync(string ID)
     {
       var queryHelper = new UserQueries(_context);
       var localID = ID;

        return Task.Factory.StartNew(() => queryHelper.GetProfile(localID));
      }
   }
 }

UserQueries.cs:

public class UserQueries
{
    private readonly IDBContext _context;
    public UserQueries(IDBContext context)
    {
        _context = context;
    }

    public UserProfile GetProfile(string ID){
        DataTable dt = _context.ExecuteDataTable(...)
        //do work with dt and return UserProfile
    }
  }
}

IDBContext.cs

public interface IDBContext
{
    DataTable ExecuteDataTable(string sql, IEnumerable<SqlParameter> parameters);
}

So I have a few questions here.

Do I have to create a new instance of the UserQuery class in every function? Not sure if it needs to be sync locked or not, still confused there.

Do I need to copy the ID to localID, I'm worried about scoping and reference changes when the function is called, is that even something to worry about in any case?

Should UserQueries be Task<UserProfile> as well?

If UserQueries should be Task<UserProfile> should the DBContext that returns a DataTable also be Task<DataTable>, does .net have a function for Taskable sql calls?

I'm not 100% sure how deep you go with Task

Upvotes: 7

Views: 772

Answers (1)

Scott Chamberlain
Scott Chamberlain

Reputation: 127543

unless ExecuteDataTable has a Async version built in I would recommend against using Tasks. If you have to use Task.Factory.StartNew or Task.Run to make it work, you should likely not be doing it and you will get worse performance under load than you have gotten just leaving it synchronous.

Task.Run (and Task.Factory.StartNew) should only be used when you are waiting on a task that is CPU bound. ExecuteDataTable is a I/O operation, you are waiting for the database to respond, whatever API you are using to talk to the database may expose functions that return Task and those you could await on (and you would need to await all the way up your chain of calls to the first call) but if it does not expose a function that returns a Task you should just do it the normal way.

Upvotes: 7

Related Questions