Fundamentals of Methodical Tasks

Introduction

As done with value types and strings, a task can be performed on an object of a class. You can start by creating a class. You must then create a method that returns an object of the same class. Here is an example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace ROSH1.Controllers
{
    public class StudiesController : Controller
    {
        // GET: Studies
        public ActionResult Index()
        {
            return View();
        }

        public Semester Register()
        {
            return new Semester() { Course1 = 79, Course2 = 92, Course3 = 68, Course4 = 84, Course5 = 61 };
        }
    }

    public class Semester
    {
        public int Course1 { get; set; }
        public int Course2 { get; set; }
        public int Course3 { get; set; }
        public int Course4 { get; set; }
        public int Course5 { get; set; }
    }
}

To create a task, declare a Task<> variable that uses the desired class as parameter type. You can initialize the variable with a method that returns an object of the class. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ROSH1.Controllers
{
    public class StudiesController : Controller
    {
        // GET: Studies
        public ActionResult Index()
        {
            Task<Semester> grades = new Task<Semester>(Register);

            return View();
        }

        public Semester Register()
        {
            return new Semester() { Course1 = 95, Course2 = 77, Course3 = 84, Course4 = 79, Course5 = 68 };
        }
    }

    public class Semester
    {
        public int Course1 { get; set; }
        public int Course2 { get; set; }
        public int Course3 { get; set; }
        public int Course4 { get; set; }
        public int Course5 { get; set; }
    }
}

You can then call the Task.Start() method to launch the task. The Task<>.Result property produces an object of the class used as parameter. As a result, when you access that property, the Intellisense is aware of the members of that class and can appropriately assist you. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ROSH1.Controllers
{
    public class StudiesController : Controller
    {
        // GET: Studies
        public ActionResult Index()
        {
            double gpa = 0.00;

            Task<Semester> grades = new Task<Semester>(() =>
            {
                return new Semester() { Course1 = 95, Course2 = 77, Course3 = 84, Course4 = 79, Course5 = 68 };
            });

            grades.Start();

            double crs1GPA = grades.Result.Course1 / 25.00;
            double crs2GPA = grades.Result.Course2 / 25.00;
            double crs3GPA = grades.Result.Course3 / 25.00;
            double crs4GPA = grades.Result.Course4 / 25.00;
            double crs5GPA = grades.Result.Course5 / 25.00;

            ViewBag.SemesterGPA = ((crs1GPA + crs2GPA + crs3GPA + crs4GPA + crs5GPA) / 5).ToString("F");

            return View();
        }

        public Semester Register()
        {
            return new Semester() { Course1 = 95, Course2 = 77, Course3 = 84, Course4 = 79, Course5 = 68 };
        }
    }

    public class Semester
    {
        public int Course1 { get; set; }
        public int Course2 { get; set; }
        public int Course3 { get; set; }
        public int Course4 { get; set; }
        public int Course5 { get; set; }
    }
}

Once again, you can define the function directly where it is needed (instead of defining it separately). Here is an example:

Task<Semester> grades = new Task<Semester>(() =>
{
    return new Semester() { Course1 = 95, Course2 = 77, Course3 = 84, Course4 = 79, Course5 = 68 };
});

Practical LearningPractical Learning: Introducing Functional Tasks

  1. Start Microsoft Visual Studio
  2. On the main menu, click File -> New -> Project...
  3. In the New Project dialog box, click ASP.NET Application (.NET Framewoork) and change the project Name to RedOakHighSchool2
  4. Click OK
  5. In the New ASP.NET Application dialog box, click the MVC icon and click OK
  6. In the Solution Explorer, right-click Controllers -> Add -> New Scaffolded Item...
  7. In the Add Scaffold dialog box, click MVC 5 Controller - Empty and press Enter
  8. Type Academics as the name of the controller to get AcademicsController
  9. Click Add
  10. Create a method as follows:
    using System;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Threading.Tasks;
    
    namespace RedOakHighSchool21.Controllers
    {
        public class AcademicsController : Controller
        {
            private int number = -1;
    
            // GET: Academics
            public ActionResult Index()
            {
                return View();
            }
    
            // GET: Academics/StartGradeReport
            public ActionResult GradeReportStartUp()
            {
                return View();
            }
    
            // GET: Academics/GradeReportPreparation
            public ActionResult GradeReportPreparation(string CourseName1, string Course1Sem1NumericGrade, string Course1Sem2NumericGrade, string Course1Sem3NumericGrade,
                                                       string CourseName2, string Course2Sem1NumericGrade, string Course2Sem2NumericGrade, string Course2Sem3NumericGrade,
                                                       string CourseName3, string Course3Sem1NumericGrade, string Course3Sem2NumericGrade, string Course3Sem3NumericGrade,
                                                       string CourseName4, string Course4Sem1NumericGrade, string Course4Sem2NumericGrade, string Course4Sem3NumericGrade,
                                                       string CourseName5, string Course5Sem1NumericGrade, string Course5Sem2NumericGrade, string Course5Sem3NumericGrade)
            {
                number = int.Parse(Course1Sem1NumericGrade);
                int iCourse2Sem1NumericGrade = int.Parse(Course2Sem1NumericGrade);
                int iCourse3Sem1NumericGrade = int.Parse(Course3Sem1NumericGrade);
    
                Func<char> GetCourse2LetterGrade = () =>
                {
                    if (iCourse2Sem1NumericGrade >= 90)
                        return 'A';
                    else if (iCourse2Sem1NumericGrade >= 80)
                        return 'B';
                    else if (iCourse2Sem1NumericGrade >= 70)
                        return 'C';
                    else if (iCourse2Sem1NumericGrade >= 65)
                        return 'D';
    
                    return 'F';
                };
    
    
                Task<char> processCourse1Sem1NumericGrade = new Task<char>(GetCourse1LetterGrade);
                Task<char> processCourse2Sem1NumericGrade = new Task<char>(GetCourse2LetterGrade);
    
                Task<char> processCourse3Sem1NumericGrade = new Task<char>(() =>
                {
                    if (iCourse3Sem1NumericGrade >= 90)
                        return 'A';
                    else if (iCourse3Sem1NumericGrade >= 80)
                        return 'B';
                    else if (iCourse3Sem1NumericGrade >= 70)
                        return 'C';
                    else if (iCourse3Sem1NumericGrade >= 65)
                        return 'D';
    
                    return 'F';
                });
    
                processCourse1Sem1NumericGrade.Start();
                processCourse2Sem1NumericGrade.Start();
                processCourse3Sem1NumericGrade.Start();
    
                ViewBag.Course1Sem1LetterGrade = processCourse1Sem1NumericGrade.Result;
                ViewBag.Course2Sem1LetterGrade = processCourse2Sem1NumericGrade.Result;
                ViewBag.Course3Sem1LetterGrade = processCourse3Sem1NumericGrade.Result;
    
                int iCourse4Sem1NumericGrade = int.Parse(Course4Sem1NumericGrade);
                int iCourse5Sem1NumericGrade = int.Parse(Course5Sem1NumericGrade);
    
                Func<char> GetCourse4LetterGrade = () =>
                {
                    if (iCourse4Sem1NumericGrade >= 90)
                        return 'A';
                    else if (iCourse4Sem1NumericGrade >= 80)
                        return 'B';
                    else if (iCourse4Sem1NumericGrade >= 70)
                        return 'C';
                    else if (iCourse4Sem1NumericGrade >= 65)
                        return 'D';
    
                    return 'F';
                };
    
                Task<char> processCourse4Sem1NumericGrade = Task<char>.Run<char>(GetCourse4LetterGrade);
                Task<char> processCourse5Sem1NumericGrade = Task<char>.Run<char>(() =>
                {
                    if (iCourse5Sem1NumericGrade >= 90)
                        return 'A';
                    else if (iCourse5Sem1NumericGrade >= 80)
                        return 'B';
                    else if (iCourse5Sem1NumericGrade >= 70)
                        return 'C';
                    else if (iCourse5Sem1NumericGrade >= 65)
                        return 'D';
    
                    return 'F';
                });
    
                ViewBag.Course4Sem1LetterGrade = processCourse4Sem1NumericGrade.Result;
                ViewBag.Course5Sem1LetterGrade = processCourse5Sem1NumericGrade.Result;
    
                return View();
            }
    
            public char GetCourse1LetterGrade()
            {
                if (number >= 90)
                    return 'A';
                else if (number >= 80)
                    return 'B';
                else if (number >= 70)
                    return 'C';
                else if (number >= 65)
                    return 'D';
    
                return 'F';
            }
        }
    }
  11. In the document, right-click inside the GradeReportPreparation() method and click Add View...
  12. In the dialog box, make sure the text box displays GradeReportPreparation and click Add
  13. Create a form as follows:
    @{
        ViewBag.Title = "Grade Report Preparation";
    }
    
    <h1>Red Oak High School</h1>
    <h2>Grade Report Preparation</h2>
    
    @{
        char cCourse1Sem1LetterGrade = ViewBag.Course1Sem1LetterGrade;
        char cCourse2Sem1LetterGrade = ViewBag.Course2Sem1LetterGrade;
        char cCourse3Sem1LetterGrade = ViewBag.Course3Sem1LetterGrade;
        char cCourse4Sem1LetterGrade = ViewBag.Course4Sem1LetterGrade;
        char cCourse5Sem1LetterGrade = ViewBag.Course5Sem1LetterGrade;
    }
    
    @using (Html.BeginForm())
    {
        <table border="6">
            <tr>
                <td style="font-weight: 600;">Course Name</td>
                <td style="text-align: center; font-weight: 600;">Num Grd</td>
                <td style="text-align: center; font-weight: 600;">Ltr Grd</td>
            </tr>
            <tr>
                <td style="text-align: center">@Html.TextBox("CourseName1", @"CourseName1")</td>
                <td style="text-align: center">@Html.TextBox("Course1Sem1NumericGrade", @"Course1Sem1NumericGrade", new { style = "width: 60px;" })</td>
                <td style="text-align: center">@Html.TextBox("Course1Sem1LetterGrade", @cCourse1Sem1LetterGrade, new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td style="text-align: center">@Html.TextBox("CourseName2", @"CourseName2")</td>
                <td style="text-align: center">@Html.TextBox("Course2Sem1NumericGrade", @"Course2Sem1NumericGrade", new { style = "width: 60px;" })</td>
                <td style="text-align: center">@Html.TextBox("Course2Sem1LetterGrade", @cCourse2Sem1LetterGrade, new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td style="text-align: center">@Html.TextBox("CourseName3", @"CourseName3")</td>
                <td style="text-align: center">@Html.TextBox("Course3Sem1NumericGrade", @"Course3Sem1NumericGrade", new { style = "width: 60px;" })</td>
                <td style="text-align: center">@Html.TextBox("Course3Sem1LetterGrade", @cCourse3Sem1LetterGrade, new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td style="text-align: center">@Html.TextBox("CourseName4", @"CourseName4")</td>
                <td style="text-align: center">@Html.TextBox("Course4Sem1NumericGrade", @"Course4Sem1NumericGrade", new { style = "width: 60px;" })</td>
                <td style="text-align: center">@Html.TextBox("Course4Sem1LetterGrade", @cCourse4Sem1LetterGrade, new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td style="text-align: center">@Html.TextBox("CourseName5", @"CourseName5")</td>
                <td style="text-align: center">@Html.TextBox("Course5Sem1NumericGrade", @"Course5Sem1NumericGrade", new { style = "width: 60px;" })</td>
                <td style="text-align: center">@Html.TextBox("Course5Sem1LetterGrade", @cCourse5Sem1LetterGrade, new { style = "width: 60px;" })</td>
            </tr>
        </table>
        <hr />
    }
  14. In the Solution Explorer, below Views, right-click Academics -> Add -> New Scaffolded Item...
  15. In the Add Scaffold dialog box, click MVC 5 View
  16. Click Add
  17. Type GradeReportStartUp as the name of the view
  18. Press Enter
  19. Create a form as follows:
    @{
        ViewBag.Title = "Grade Report Start-Up";
    }
    
    <h1>Red Oak High School</h1>
    <h2>Grade Report Start-Up</h2>
    
    @using (Html.BeginForm("GradeReportPreparation", "Academics", FormMethod.Post))
    {
        <table border="6">
            <tr>
                <td style="font-weight: 600;">Course Name</td>
                <td style="text-align: center; font-weight: bold"><b>Numeric Grade</b></td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName1", "Math")</td>
                <td style="text-align: center">@Html.TextBox("Course1Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName2", "English")</td>
                <td style="text-align: center">@Html.TextBox("Course2Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName3", "Social Science")</td>
                <td style="text-align: center">@Html.TextBox("Course3Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName4", "Physical Science")</td>
                <td style="text-align: center">@Html.TextBox("Course4Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName5", "History/Geography")</td>
                <td style="text-align: center">@Html.TextBox("Course5Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
        </table>
        <hr />
        <p style="width: 600px; text-align: center"><input type="submit" name="btnPrepareGradeReport" value="Prepare Grade Report" style="width: 300px" /></p>
    }
  20. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    The Value of a Functional Task

  21. On the form, change Math to Algebra 1
  22. Change some values as follows:
    Course Name	Numeric Grade
    Algebra 1	        58
    English		    72
    Social Science    55
    Physical Science  64
    History/Geography 46

    The Value of a Functional Task

  23. Click the Prepare Grade Report button:

    The Value of a Functional Task

  24. Close the browser and return to your programming environment

A Task as Argument

As mentioned previously for tasks, Task<> can be used as a type.

To create a method that uses a parameter of a task type, in the parentheses of the method, type Task<>, include its parameter type, and follow it with a name for the parameter. In the body of the method, ignore the parameter if you don't need it. Otherwise, you can get the value of the parameter. For example, you can initialize it with a value or a method that produces its type of task. Here is an example:

private void GetCourseGrade(Task<char> grade)
{
    grade = new Task<char>(GetLetterGrade);
}

public char GetLetterGrade()
{
    return 'F';
}

You can involve the parameter or its value in any operation or processing you want. You can then use the method any way you want outside its body. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace Exercises.Controllers
{
    public class AcademicsController : Controller
    {
         int number = -1;

        public ActionResult Index()
        {
            return View();
        }

        public ActionResult StudentsGrades()
        {
            number = 85;

            Task<char> courseGradeProcessing = new Task<char>(GetLetterGrade);

            ViewBag.CourseComment = GetCourseGrade(courseGradeProcessing);

            return View();
        }

        public char GetLetterGrade()
        {
            if (number >= 90)
                return 'A';
            else if (number >= 80)
                return 'B';
            else if (number >= 70)
                return 'C';
            else if (number >= 65)
                return 'D';

            return 'F';
        }

        private string GetCourseGrade(Task<char> grade)
        {
            string comment = string.Empty;

            grade.Start();

            if (grade.Result == 'A')
                comment = "Excellent";
            else if (grade.Result == 'B')
                comment = "Good";
            else if (grade.Result == 'C')
                comment = "Average";
            else if (grade.Result == 'D')
                comment = "Pass";
            else // if (grade.Result == 'F')
                comment = "Fail";

            return comment;
        }
    }
}

Here is an example of accessing the result from the above code:

@{
    ViewBag.Title = "Students Grades";
}

<h2>Students Grades</h2>

<p>Student Grade: @ViewBag.CourseComment</p>

In the same way, you can pass a task of a class as parameter.

Returning a Valued Task

You can create a method that produces a task. To start this, on the left of the name of the method, specify the return type as Task<>. In the <> operator, specify the data type you want. The method may or may not use parameters. In the body of the method, do what you want. At the end of the method, you must return a task or a value/object compatible with the task. Probably the easiest way to initialize a task in the method is to declare a task variable and initialize it with a value/object or a method that produces a value or object of the parameter type. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ROSH1.Controllers
{
    public class AcademicsController : Controller
    {
        int number = -1;

        public char GetLetterGrade()
        {
            return 'F';
        }

        private Task<char> GetCourseGrade()
        {
            Task <char> grade = new Task<char>(GetLetterGrade);

            return grade;
        }
    }
}

When calling the method, you can assign its call to a local Task<> variable and use the value or object of that variable. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ROSH1.Controllers
{
    public class AcademicsController : Controller
    {
        int number = -1;

        public ActionResult Index()
        {
            return View();
        }

        public ActionResult StudentsGrades()
        {
            number = 85;

            Task<char> courseGradeProcessing = GetCourseGrade();

            courseGradeProcessing.Start();

            ViewBag.CourseComment = courseGradeProcessing.Result;

            return View();
        }

        public char GetLetterGrade()
        {
            if (number >= 90)
                return 'A';
            else if (number >= 80)
                return 'B';
            else if (number >= 70)
                return 'C';
            else if (number >= 65)
                return 'D';

            return 'F';
        }

        private Task<char> GetCourseGrade()
        {
            Task <char> grade = new Task<char>(GetLetterGrade);

            return grade;
        }
    }
}

Returning a Task as Object

A functional task is one that runs asynchronously. One of the most important features here is that the method may produce an object that is a task. Of course, you must create the method to produce such an object.

To create a method that produces a task, specify its data type as Task<>. Enter the name of the class as the parameter type. Here is an example:

public Task<Models.Semester> GetSemesterGrades()
{
}

As always, before the end of the method, make sure you return an object of type Task<>.

Practical LearningPractical Learning: Introducing Tasks and Classes

  1. In the Solution Explorer, right-click Models -> Add -> Class...
  2. Type Semester as the file name
  3. Click Add
  4. Change the class as follows:
    namespace RedOakHighSchool1.Models
    {
        public class Semester
        {
            public int Course1 { get; set; }
            public int Course2 { get; set; }
            public int Course3 { get; set; }
            public int Course4 { get; set; }
            public int Course5 { get; set; }
        }
    }
  5. Access the AcademicsController.cs tab and change the document as follows:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using System.Threading.Tasks;
    
    namespace RedOakHighSchool102.Controllers
    {
        public class AcademicsController : Controller
        {
            int iCourse1Sem1NumericGrade = -1;
            int iCourse2Sem1NumericGrade = -1;
            int iCourse3Sem1NumericGrade = -1;
            int iCourse4Sem1NumericGrade = -1;
            int iCourse5Sem1NumericGrade = -1;
    
            // GET: Academics
            public ActionResult Index()
            {
                return View();
            }
    
            // GET: Academics/GradeReportStartUp
            public ActionResult GradeReportStartUp()
            {
                return View();
            }
    
            // GET: Academics/GradeReportPreparation
            public ActionResult GradeReportPreparation(string CourseName1, string Course1Sem1NumericGrade, string Course1Sem2NumericGrade, string Course1Sem3NumericGrade,
                                                       string CourseName2, string Course2Sem1NumericGrade, string Course2Sem2NumericGrade, string Course2Sem3NumericGrade,
                                                       string CourseName3, string Course3Sem1NumericGrade, string Course3Sem2NumericGrade, string Course3Sem3NumericGrade,
                                                       string CourseName4, string Course4Sem1NumericGrade, string Course4Sem2NumericGrade, string Course4Sem3NumericGrade,
                                                       string CourseName5, string Course5Sem1NumericGrade, string Course5Sem2NumericGrade, string Course5Sem3NumericGrade)
            {
                iCourse1Sem1NumericGrade = int.Parse(Course1Sem1NumericGrade);
                iCourse2Sem1NumericGrade = int.Parse(Course2Sem1NumericGrade);
                iCourse3Sem1NumericGrade = int.Parse(Course3Sem1NumericGrade);
                iCourse4Sem1NumericGrade = int.Parse(Course4Sem1NumericGrade);
                iCourse5Sem1NumericGrade = int.Parse(Course5Sem1NumericGrade);
    
                Func<char> GetCourse2LetterGrade = () =>
                {
                    if (iCourse2Sem1NumericGrade >= 90)
                        return 'A';
                    else if (iCourse2Sem1NumericGrade >= 80)
                        return 'B';
                    else if (iCourse2Sem1NumericGrade >= 70)
                        return 'C';
                    else if (iCourse2Sem1NumericGrade >= 65)
                        return 'D';
    
                    return 'F';
                };
    
                Task<char> processCourse1Sem1NumericGrade = new Task<char>(GetCourse1LetterGrade);
                Task<char> processCourse2Sem1NumericGrade = new Task<char>(GetCourse2LetterGrade);
    
                Task<char> processCourse3Sem1NumericGrade = new Task<char>(() =>
                {
                    if (iCourse3Sem1NumericGrade >= 90)
                        return 'A';
                    else if (iCourse3Sem1NumericGrade >= 80)
                        return 'B';
                    else if (iCourse3Sem1NumericGrade >= 70)
                        return 'C';
                    else if (iCourse3Sem1NumericGrade >= 65)
                        return 'D';
    
                    return 'F';
                });
    
                processCourse1Sem1NumericGrade.Start();
                processCourse2Sem1NumericGrade.Start();
                processCourse3Sem1NumericGrade.Start();
    
                ViewBag.Course1Sem1LetterGrade = processCourse1Sem1NumericGrade.Result;
                ViewBag.Course2Sem1LetterGrade = processCourse2Sem1NumericGrade.Result;
                ViewBag.Course3Sem1LetterGrade = processCourse3Sem1NumericGrade.Result;
    
                Func<char> GetCourse4LetterGrade = () =>
                {
                    if (iCourse4Sem1NumericGrade >= 90)
                        return 'A';
                    else if (iCourse4Sem1NumericGrade >= 80)
                        return 'B';
                    else if (iCourse4Sem1NumericGrade >= 70)
                        return 'C';
                    else if (iCourse4Sem1NumericGrade >= 65)
                        return 'D';
    
                    return 'F';
                };
    
                Task<char> processCourse4Sem1NumericGrade = Task<char>.Run<char>(GetCourse4LetterGrade);
                Task<char> processCourse5Sem1NumericGrade = Task<char>.Run<char>(() =>
                {
                    if (iCourse5Sem1NumericGrade >= 90)
                        return 'A';
                    else if (iCourse5Sem1NumericGrade >= 80)
                        return 'B';
                    else if (iCourse5Sem1NumericGrade >= 70)
                        return 'C';
                    else if (iCourse5Sem1NumericGrade >= 65)
                        return 'D';
    
                    return 'F';
                });
    
                ViewBag.Course4Sem1LetterGrade = processCourse4Sem1NumericGrade.Result;
                ViewBag.Course5Sem1LetterGrade = processCourse5Sem1NumericGrade.Result;
    
                Task<Models.Semester> sem1Grades = GetSemesterGrades();
    
                sem1Grades.Start();
    
                double crs1GPA = (sem1Grades.Result.Course1 / 25.00);
                double crs2GPA = (sem1Grades.Result.Course2 / 25.00);
                double crs3GPA = (sem1Grades.Result.Course3 / 25.00);
                double crs4GPA = (sem1Grades.Result.Course4 / 25.00);
                double crs5GPA = (sem1Grades.Result.Course5 / 25.00);
    
                ViewBag.Semester1NumericGPA = ((crs1GPA + crs2GPA + crs3GPA + crs4GPA + crs5GPA) / 5).ToString();
    
                double semester1Average = (iCourse1Sem1NumericGrade + iCourse2Sem1NumericGrade + iCourse3Sem1NumericGrade + iCourse4Sem1NumericGrade + iCourse5Sem1NumericGrade) / 5.00;
    
                Task<char> semester1LetterGPA = Task<char>.Run<char>(() =>
                {
                    if (semester1Average >= 90)
                        return 'A';
                    else if (semester1Average >= 80)
                        return 'B';
                    else if (semester1Average >= 70)
                        return 'C';
                    else if (semester1Average >= 65)
                        return 'D';
    
                    return 'F';
                });
    
                ViewBag.Semester1LetterGPA = semester1LetterGPA.Result;
                
                return View();
            }
    
            public char GetCourse1LetterGrade()
            {
                if (iCourse1Sem1NumericGrade >= 90)
                    return 'A';
                else if (iCourse1Sem1NumericGrade >= 80)
                    return 'B';
                else if (iCourse1Sem1NumericGrade >= 70)
                    return 'C';
                else if (iCourse1Sem1NumericGrade >= 65)
                    return 'D';
    
                return 'F';
            }
    
            public Models.Semester RegisterSemester1()
            {
                Models.Semester sem = new Models.Semester() { Course1 = iCourse1Sem1NumericGrade, Course2 = iCourse2Sem1NumericGrade, Course3 = iCourse3Sem1NumericGrade, Course4 = iCourse4Sem1NumericGrade, Course5 = iCourse5Sem1NumericGrade };
    
                return sem;
            }
    
            public Task<Models.Semester> GetSemesterGrades()
            {
                Task<Models.Semester> grades = new Task<Models.Semester>(RegisterSemester1);
    
                return grades;
            }
        }
    }
  6. Access the GradeReportPreparation.cshtml tab and change the document as follows:
    @{
        ViewBag.Title = "Grade Report Start-Up";
    }
    
    <h1>Red Oak High School</h1>
    <h2>Grade Report Start-Up</h2>
    
    @using (Html.BeginForm("GradeReportPreparation", "Academics", FormMethod.Post))
    {
        <table border="6">
            <tr>
                <td style="font-weight: 600;">Course Name</td>
                <td style="text-align: center; font-weight: bold"><b>Numeric Grade</b></td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName1", "Math")</td>
                <td style="text-align: center">@Html.TextBox("Course1Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName2", "English")</td>
                <td style="text-align: center">@Html.TextBox("Course2Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName3", "Social Science")</td>
                <td style="text-align: center">@Html.TextBox("Course3Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName4", "Physical Science")</td>
                <td style="text-align: center">@Html.TextBox("Course4Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
            <tr>
                <td>@Html.TextBox("CourseName5", "History/Geography")</td>
                <td style="text-align: center">@Html.TextBox("Course5Sem1NumericGrade", "0", new { style = "width: 60px;" })</td>
            </tr>
        </table>
        <hr />
        <p style="width: 600px;"><input type="submit" name="btnPrepareGradeReport" value="Prepare Grade Report" style="width: 300px" /></p>
    }
  7. Click the GradeReportStartUp.cshtml tab to activate it
  8. To execute the project, on the main menu, click Debug -> Start Without Debugging
  9. On the form, replace English with English Litterature
  10. Change the grades as follows:
    Course Name	Numeric Grade
    Math			    95
    English Litterature			77
    Social Science	84
    Chemistry		    79
    History/Geography	68

    Introducing Tasks and Classes

  11. Click the Prepare Grade Report button

    Introducing Tasks and Classes

  12. Close the browser and return to your programming environment

Asynchrony in ASP.NET MVC

Introduction

In our introduction to synchronous operations, we saw how important it is to think about threads (and processes) competing for the same resources. An example is about two sources (such as two people) trying to access the same bank account, on purpose or by mistake, at the same time. Another example is when a certain operation needs to use many resources at the same time. One more example is for an operation that must take a long time to complete. In these and other situations, you as a programmer should write code that performs operations that do not interfere with other operations. Such operations are referred to as asynchronous operations. The code that takes care of this can be written for a method, a lambda expression, or in exception handling.

We saw that, when anticipating one or more oprations that must be performed asynchronously, you can (should) create a method that returns a Task<> object. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ArraysOperations1.Controllers
{
    public class StudiesController : Controller
    {
        // This number represents the numeric grade of a student.
        int number = -1;

        // GET: Studies
        public ActionResult Index()
        {
            /* In a typical application (or a Web app for a school, the students grades 
             * may come from different sources, sometimes from computers in different locations... */
            number = 82;

            return View();
        }

        public char GetLetterGrade()
        {
            if (number >= 90)
                return 'A';
            else if (number >= 80)
                return 'B';
            else if (number >= 70)
                return 'C';
            else if (number >= 65)
                return 'D';

            return 'F';
        }

        private Task<char> GetCourseGrade()
        {
            Task<char> grade = new Task<char>(GetLetterGrade);

            return grade;
        }
    }
}

Introduction to Asynchronous Methods

As you may know by now, the primary section of code that performs an assignment is the method of a class. Therefore, if you want to take care of a(n) asynchronous operation(s), the primary place to do this is the method.

To let you create a method that addresses concernes for one or more asynchronous operations, the C# language provides the async keyword. To start the method, precede its return type with the async keyword. The formula to follow is:

public async data-type method-name(parameter(s))
{
}

The primary job of an asynchronous method is to avoid interferring with other operations. We saw that, to make this possible, you can create a method that returns a task. Such a method can (must) return a Task<> object. If the operation must produce a regular value (a number, a character, or a Boolean value) or a string, specify the desired type between < and >. In this case, pass the data type as the parameter type. Here is an example:

public async Task<string> StudentComments()
{
}

If the method must produce an object, specify the class name as the parameter type of Task<>. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ArraysOperations1.Controllers
{
    public class StudiesController : Controller
    {
        // This number represents the numeric grade of a student.
        int number = -1;

        // GET: Studies
        public ActionResult Index()
        {
            number = 82;

            return View();
        }

        public char GetLetterGrade()
        {
            if (number >= 90)
                return 'A';
            else if (number >= 80)
                return 'B';
            else if (number >= 70)
                return 'C';
            else if (number >= 65)
                return 'D';

            return 'F';
        }

        private Task<char> GetCourseGrade()
        {
            Task<char> grade = new Task<char>(GetLetterGrade);

            return grade;
        }

        private async Task<Semester> GradeReport()
        {

        }
    }

    public class Semester
    {
        public int Course1 { get; set; }
        public int Course2 { get; set; }
        public int Course3 { get; set; }
        public int Course4 { get; set; }
        public int Course5 { get; set; }
    }
}

In both cases, the method may or may not use parameters, it is up to you. Other than that, if you are not planning to use the return value of the method, you can return null. Here are examples:

public async Task<string> StudentComments()
{
    return null;
}

private async Task<Semester> GradeReport()
{
    return null;
}

You can also return an object of the parameter type. Here are two examples:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ArraysOperations1.Controllers
{
    public class StudiesController : Controller
    {
        public async Task<string> StudentComments()
	{
	    return "Nothing";
	}

	private async Task<Semester> GradeReport()
        {
            return new Semester();
        }

        private async Task<Semester> GradeSummary()
        {
            return new Semester("SPRING 2018");
        }
    }

    public class Semester
    {
        private string sName;

        public Semester()
        {

        }

        public Semester(string semName)
        {
            sName = semName;
        }
    }
}

Depending on what is going on, you can also return an object of a class derived from the parameter type.

In the method that anticipates an asynchronous operation, which is the async method, you must indicate where the long operation is performed. This is done by calling the method that performs the task.

To let you indicate the method that performs the arduous operation, the C# language provides the await keyword. When calling the method that performs the long operation, precede it with that keyword. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ArraysOperations1.Controllers
{
    public class StudiesController : Controller
    {
        int number = -1;

        public ActionResult Index()
        {
            number = 82;

            return View();
        }

        public char GetLetterGrade()
        {
            return 'F';
        }

        private Task<char> GetCourseGrade()
        {
            Task<char> grade = new Task<char>(GetLetterGrade);

            return grade;
        }

        private async Task<Semester> GradeReport()
        {
            await GetCourseGrade();

            return null;
        }
    }

    public class Semester
    {
    }
}

Most of the time, you will need to get the return value of the called method and use that value or object as you see fit. To get that value, you can declare a local variable and initialize it with the await calling method. Here is an example:

private async Task<Semester> GradeReport()
{
    var summary = await GetCourseGrade();

    return null;
}

You can then use the value as you see fit. For example, if necessary, you can use the returned value when initializing a variable. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ArraysOperations1.Controllers
{
    public class StudiesController : Controller
    {
        // This number represents the numeric grade of a student.
        int number = -1;

        // GET: Studies
        public ActionResult Index()
        {
            number = 82;

            return View();
        }

        public char GetLetterGrade()
        {
            if (number >= 90)
                return 'A';
            else if (number >= 80)
                return 'B';
            else if (number >= 70)
                return 'C';
            else if (number >= 65)
                return 'D';

            return 'F';
        }

        private Task<char> GetCourseGrade()
        {
            Task<char> grade = new Task<char>(GetLetterGrade);

            return grade;
        }

        private async Task<Semester> GradeReport()
        {
            var summary = await GetCourseGrade();

            Student pupil = new Student()
            {
                StudentNumber = 939485,
                LetterGrade = summary
            };

            return null;
        }
    }

    public class Student
    {
        public long StudentNumber { get; set; }
        public char LetterGrade   { get; set; }
    }

    public class Semester
    {
        public int Course1 { get; set; }
        public int Course2 { get; set; }
        public int Course3 { get; set; }
        public int Course4 { get; set; }
        public int Course5 { get; set; }
    }
}

As always, if you are not planning to use the value many times, you don't have to first declare a variable. You can call the method where it is needed. Here is an example:

private async Task<Semester> GradeReport()
{
    Student pupil = new Student()
    {
        StudentNumber = 939485,
        LetterGrade = await GetCourseGrade()
    };

    return null;
}

Asynchrony and Web Pages

Some webpages involve intensive work. The work may include many visitors trying to access one resource, such as a video, on the webserver. Another example is about a user who must log in to a webpage to access a bank account. In some cases, you want the visitor to access the account from only one location, such as to withdraw money from only one machine or to perform only one transaction on the account at one particular moment.

To address web-based issues related to asynchrony, when creating the action method of a view, you should handle its operations asynchronously. To do this, specify its return type as ActionResult but make it an asynchronous Task<>. This means that you must specify the parameter type as ActionResult, as in async Task<ActionResult>. Here is an example:

public async Task<ActionResult> GradeReport()
{
}

As done so far for our views, you can call a method that returns an ActionResult object or returns an object of a class derived from ActionResult, and return that method call. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ArraysOperations1.Controllers
{
    public class OperationsController : Controller
    {
        public async Task<ActionResult> StudentReport()
        {
            return View();
        }
    }
}

As mentioned previously, when you create an asynchronous method, in the body of the method, you must use the await keyword to call the method that handles the complex operation(s). If necessary, you can get the returned value of the method and use it as you want. Here is an example:

using System.Web.Mvc;
using System.Threading.Tasks;

namespace ArraysOperations1.Controllers
{
    public class AccountabilityController : Controller
    {
        private string GetCourseGrade()
        {
            return "Excellent";
        }

        public Task<string> Conclusion()
        {
            return new Task<string>(GetCourseGrade);
        }

        public async Task<ActionResult> ReportPreparation()
        {
            var ss = await Conclusion();

            ss.ToUpper();

            return View();
        }
    }
}

Introduction to Promising Objects

Introduction to Synchronous Operations

As we reviewed already, when two operations must be performed on a machine, a synchronous operation is one that must be completed before the next operation starts (or executes). In most cases, the first operation must complete successfully before the next operation starts, in which case the next operation may not execute if the first did not complete successfully.

Synchrony is important in various scenarios. In one case, an operation B needs the result(s) produced by another operation A. Another case is when, even if operation B doesn't depend on operation A (and sometimes they are not related, at all), for one reason or another (maybe there is a risk that operation B will intefer with the way operation A behaves), operation B must wait for operation A to complete.

Introduction to Asynchronous Operations

When various operations must be performed on a machine, asynchrony is the fact that two or more operations can run (or execute) at the time without a major concern. This too is possible and important in various cases. In one scenario, maybe operation A complements operation B while both are running. In another case, operations A and B don't interfer with each other's work.

When planning the operations (and transactions) for your web app, you should plan for synchronous and asynchronous operations. Keep in mind that synchronous operations may lead the user to wait when one operation is going in order to start another operation. In most cases, a synchronous operation means that your application may have to refresh (or re-load) the whole webpage to make some general changes on either a section of a webpage or the whole document. Asynchronous operations allow you to make change on a section of a webpage without refreshing the whole webpage. This is where Ajax intervenes.

Introduction to Promises

A promise is an object used to perform an aynchronous opration that must consider two possibilities: success and failure. In case you think that this is the same as a regular statement that includes a conditional statement, it is not. In such a conditional statement, you can either just create a statement and stop there, or you can create an if condition.

To support promises, the JavaScript language provides a built-in object named Promise. The object has one constructor that takes a function as argument. The formula to it is:

new Promise( function(resolve, reject) { ... } );

To start a promise, create a function that takes two arguments for two possible outcomes. The basic way to get a promise is to create a function and pass two arguments to it. Each argument is a callback function. The primary formula to follow is:

action-to-complete(success-function, failure-function);

As an alternative, create an object and assign a two-parameter-based function to it as follows:

const promise = action-to-complete();

The Promise object is equipped with a method named then. You must call that method and pass the two callback functions to it. The formula to follow is:

const promise = action-to-complete();

promise.then(success-function, failure-function);

As an alternative, you can call the then() method directly on the action-to-complete() method call. The formula to follow is:

action-to-complete().then(success-function, failure-function);

This is called an asynchronous function call.

In all three cases, you can define a function separately and pass its name as argument to the action-to-complete() function. This would be done as follows:

function success-function() {
}

function failure-function() {
}

action-to-complete(success-function, failure-function);

Or it can be done as follows:

function success-function() {
}

function failure-function() {
}

const promise = action-to-complete();
promise.then(success-function, failure-function);

Or it can be done as follows:

action-to-complete().then(success-function, failure-function);

This time too, you can separately define the functions and then pass their names as argument, or you can define them directly in the parentheses of the then() method:

action-to-complete().then(function(){

}, function(){

});

Practical LearningPractical Learning: Ending the Lesson


Previous Copyright © 2014-2019, FunctionX Home