Too many times we implement these kinds of similar logic and structures in our MVC controllers as shown in Figure 1.

  1. try .. catch block
  2. Process data, and return some kind of ID back. In this case, student number.
  3. return a JSON object back to indicate whether it is success or not, and related information
Figure 1.    
 
     [HttpPost]
     public JsonResult CreateStudent(Student student)
     {
            string message = "";
            bool isSuccess = false;
            string studentNumber = "";

            try
            {
                // business logic here ....
                studentNumber = StudentRepository.CreateStudent(student);

                isSuccess = true;
                message = "";
            }
            catch (Exception ex)
            {
                message = ex.Message;
            }

            return Json(new
            {
                IsSuccess = isSuccess,
                ID = studentNumber,
                ErrorMessage = message
            });
      }

 

We then copy and paste to other methods such as CreateXYZ, UpdateXYZ, and DeleteXYZ, etc, to the same controller and to many other controllers. Needless to say, it is NOT the best practice.

However, we can abstract the similar logic and structure out, and put it directly into Controller class in Figure 2. We can create much better clean code this way.

Figure 2.

FuncExtensionMvcController

Here are the recaps of codes above:

Line 11 – 12: An extension method to add this method ‘DoWorkAndReturnJsonResult’ to MVC Controller so that any child controllers in the same assembly can use the feature.

Line 13: We use Func<T> func to abstract the processing logic

Line 14: A Func<object, JsonResult> jsonFormatter to format the object in JSON

Line 20 – 30: try … catch block

Line 40 – 49: An overloaded method ‘DoWorkAndReturnJsonResult’ with the 2nd paramter in Line 42 is Action action.

Line 51 – 58: Another extension method to convert Action to Func<T> to support the overloaded method ‘DoWorkAndReturnJsonResult’ in Line 40 – 49 seamlessly.

Here is how it is being called in MVC Controller using the first overloaded method of ‘DoWorkAndReturnJsonResult’ with Func<T>.

Figure 3.

1    public class StudentController : Controller
2    {
3        [HttpPost]
4        public JsonResult CreateStudent(Student student)
5        {
6            return this.DoWorkAndReturnJsonResult<string>(
7            () =>
8            {
9                 // business logic here. Func<string> is used below
10                string studentNumber = StudentRepository.CreateStudent(student);
11                return studentNumber;
12            },
13            Json);
14        }
15    }

 

Here is another caller method in MVC Controller using the second overloaded method of ‘DoWorkAndReturnJsonResult’ with Action.

Figure 4.

1    public class StudentController : Controller
2    {
3        [HttpPost]
4        public JsonResult UpdateStudent(Student student)
5        {
6            return this.DoWorkAndReturnJsonResult<string>(
7            () =>
8            {
9                 // business logic here. Action is used below
10                StudentRepository.UpdateStudent(student);
12            },
13            Json);
14        }
15    }

Notes:

  1. student is passed in the lambda expression using closure.
  2. Json is a built-in object in controller, and can format an object into JSON.

 

Compare with Figure 1, Figure 3 and Figure 4 is much shorter, cleaner, and easier to understand and maintain.

In this exercise, to simplify the explanation, we only demonstrate how to abstract the business logic that returns JsonResult to MVC controller using the techniques of extension method, Func, Action, lambda, and closure, and to achieve the goal of cleaner code base.

Advertisements