2

I'm fairly new to tasks and want to implement them on my application. What I want is to do an ajax request on my client side when the page loads, to a function that calls all the catalogs that I need and returns a JSON of all the objects to my client. This function on the server side is the one I created to have multiple tasks. So I have the following questions regarding this:

  1. Is it a good practice to load all catalogs needed for that page and return a JSON object?
  2. Does it actually work as multi thread if the tasks call the same instance of a class? Or is it better to create the instance inside each task?

        public JsonResult GetCatalogs()
        {
            JsonResult jSonResult = new JsonResult();
    
            try
            {
                CatalogsRepository catalogsRepository = new CatalogsRepository();
    
                Task<IList<CustomObject1>> task1 = Task.Factory.StartNew(() =>
                {
                    IList<CustomObject1> resultList1 = catalogsRepository.getFirstCatalog();
                    return resultList1;
                });
    
                Task<IList<CustomObject2>> task2 = Task.Factory.StartNew(() =>
                {
                    IList<CustomObject2> resultList2 = catalogsRepository.getSecondCatalog();
                    return resultList2;
                });
    
                Task<IList<CustomObject3>> task3 = Task.Factory.StartNew(() =>
                {
                    IList<CustomObject3> resultList3 = catalogsRepository.getThirdCatalog();
                    return resultList3;
                });
    
                jSonResult = Json(new
                {
                    result1 = task1.Result,
                    learningMaterialTypeList = task2.Result,
                    contentAssociatedList = task13.Result
                });
                jSonResult.MaxJsonLength = int.MaxValue;
                jSonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
            }
            catch (Exception ex)
            {
                log.Error(ex);
                return Json(new Error { messageCode = 1, message = ex.Message });
            }
    
            return jSonResult;
        }
    
  3. Or is it better to create the instance inside each task?

        public JsonResult GetCatalogs()
        {
            JsonResult jSonResult = new JsonResult();
    
            try
            {
                Task<IList<CustomObject1>> task1 = Task.Factory.StartNew(() =>
                {
                    CatalogsRepository catalogsRepository = new CatalogsRepository();
                    IList<CustomObject1> resultList1 = catalogsRepository.getFirstCatalog();
                    return resultList1;
                });
    
                Task<IList<CustomObject2>> task2 = Task.Factory.StartNew(() =>
                {
                    CatalogsRepository catalogsRepository = new CatalogsRepository();
                    IList<CustomObject2> resultList2 = catalogsRepository.getSecondCatalog();
                    return resultList2;
                });
    
                Task<IList<CustomObject3>> task3 = Task.Factory.StartNew(() =>
                {
                    CatalogsRepository catalogsRepository = new CatalogsRepository();
                    IList<CustomObject3> resultList3 = catalogsRepository.getThirdCatalog();
                    return resultList3;
                });
    
                jSonResult = Json(new
                {
                    result1 = task1.Result,
                    learningMaterialTypeList = task2.Result,
                    contentAssociatedList = task13.Result
                });
                jSonResult.MaxJsonLength = int.MaxValue;
                jSonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
            }
            catch (Exception ex)
            {
                log.Error(ex);
                return Json(new Error { messageCode = 1, message = ex.Message });
            }
    
            return jSonResult;
        }
    

I'm using MVC .NET 4.0 with jQuery, Thank you in advance.

Mario
  • 39
  • 7
  • Do you use classic asp.net MVC or Web API with some front-end framework like ReactJS or Angular? Do you plan to plug some mobile app into your project? – GoldenAge Aug 27 '18 at 23:21
  • I'm using MVC .NET 4.0 with jQuery, I'm still not using React or Angular, and no mobile app at the moment. – Mario Aug 27 '18 at 23:24
  • Are these catalogues to be edited? or are they just to give search results? –  Aug 27 '18 at 23:27
  • Just to give search results – Mario Aug 27 '18 at 23:28
  • so ultimately this is to populate the UI for the user? As what, a drop down list with options that will offer navigation for the user? –  Aug 27 '18 at 23:30
  • That is correct – Mario Aug 27 '18 at 23:33

2 Answers2

2

Your action method should be async:

public async Task<JsonResult> GetCatalogs()

Once your method is async, everything else is much easier. You can do away with those Task.Run() calls and just call the methods normally (as long as they as async) and await them. It may make sense to make those lambdas into separate, async methods (or even C#7 local methods):

protected async Task<IList<CustomObject1>> GetResults1()
{
    CatalogsRepository catalogsRepository = new CatalogsRepository();
    var resultList1 = catalogsRepository.getFirstCatalog();
    return await resultList1.ToListAsync();
});

Important: To get results you should use await. Never use Result in an async ASP.NET environment because it will deadlock.

var jsonResult = Json(new
{
    result1 = await task1,
    learningMaterialTypeList = await task2,
    contentAssociatedList = await task3
});

As for your questions:

Is it a good practice to load all catalogs needed for that page and return a JSON object?

There is no rule against it. It's a design decision for you to make. The pro is fewer round trips, the con is coupling all those things together in a public interface makes the architecture a bit more brittle.

Does it actually work as multi thread if the tasks call the same instance of a class? Or is it better to create the instance inside each task?

In true multithreading, it is better in general to work on separate instances so that each thread can have its own independent memory cache. That being said, async is not the same as multithreading, and in fact in ASP.NET you're guaranteed that no two of your tasks will be executing simultaneously (unless you do something special to make that happen). Instead you get one thread at a time. The thread might change, and your async code will jump around await points, but only one piece of code gets to run at once, by design.

John Wu
  • 50,556
  • 8
  • 44
  • 80
1

1.I think that by returning a JSON object you mean an action which returns a JsonObject and is called by ajax from the client side. You can do this in most places of your app but keep in mind that you can lose a lot of benefits from pure MVC. The second thing is jQuery and Ajax are a bit hard to maintain and in case of complex views you will have to write a lot of code, very often hard to test. A very common concept in asp.net MVC is returning ViewModels/Models via GET methods and then sending data from forms with the use of asp.net helpers back to the controllers. If you use data annotation attributes and jQuery unobtrusive library you can build really nice validation, very easy to maintain on the backend and on the client side. The client-side validation will be generated just for FREE based on the .net attributes which shorten your time in development. With Ajax calls, you can do similar but the code will be more clunky.

2 and 3.Your controller should contain as less business logic as possible and all the logic should be moved to other layers, services etc. Your actual code is over too complicated.

Try to use interfaces and IOC. Avoid creating instances of objects like you do now in the controller. It’s hard to write tests for such a class. I think something like this would be better:

private readonly ICatalogService _catalogService;

// Dependency injection thanks to Inversion of Control
public BlahController(ICatalogService catalogService){
     _catalogService=catalogService;
}

public async JsonResult GetCatalogs(params..){
     return await catalogService.getCatalogs(params..); //or catalogRepository
}

So you can move all the business logic out of the controller to some separate class.

GoldenAge
  • 2,918
  • 5
  • 25
  • 63