ASP. net mvc interceptor

Source: Internet
Author: User

This article will add the log and exception handling functions to the announcement function of the MVC announcement publishing system, so as to discuss how to use the interceptor in ASP. net mvc.

A small problem

We continue to improve the "MVC announcement publishing system". This time, we need to add logging for the announcement publishing function. Capability That is, before the announcement is published, record it once, and record it again after the announcement is published successfully. Then, you need to handle exceptions. That is, when a service component encounters a problem, the system jumps to the corresponding error page and displays the corresponding prompt.

Some people may have laughed. What is the problem? The corresponding log function was added to the beginning and end of the dorelease action soon. For Exception Handling, try... catch directly. Done .

Yes, the above method works, but there are two problems:

1. duplicate code. A lot of log processing code is very similar to the Exception Processing code, which leads to a lot of repeated code in each action.

2. Responsibility is damaged. Don't forget that our controller is just a controller. It should only represent the logic, and should not be surrounded by a lot of log processing code and try... catch blocks. The action we need should be clean, neat, and contain only actions that represent logic.

The above two points cause bad code in our system. So how can we solve this problem?

From chef to AOP

Imagine a scenario: How do senior chefs work in a restaurant? We know that he doesn't need to wash vegetables, cut vegetables, or serve dishes with dishes. If he finds that the beef in his hand has deteriorated, he doesn't need to take the beef to the meat shop owner. Theory He has a single job: cooking.

After the raw materials are sent, a special food slicer will wash and cut the food, and then send the processed food to the cook. The cook will just fry the food in the pan. Naturally, you do not have to worry about the food after it is fried, because there are dedicated waiters responsible for this. If it finds that the beef has deteriorated, it just needs to say that there will naturally be people who will handle it.

This scenario is typical AOP (for Aspect-Oriented Programming ). A cook can be regarded as a business component. One method is "Cooking". However, before cooking, you have to cut the food and someone else needs to deliver the food. This is not a concern of the cook! As a result, our cut-off workers and waiters are equivalent to interceptions. The cut-off workers intercept and cut the dishes before cooking. The cut-off workers intercept the dishes after cooking and are responsible for delivering the dishes. Of course, we also have an exception Interceptor: the person who handles the problem is the one who will handle the problem when the cook finds that the meat has deteriorated and shouted.

Based on this scenario, let's take a look at the benefits. First, the cook has a single responsibility, so he can focus on his own Work : Cooking without worrying about your own concerns. In addition, "interceptors" can be reused. For example, a stingy boss can find three chefs, but only recruit one waiter. In this way, a waiter can serve three chefs, the reuse of the interceptor makes the code repeated disappear!

Back

Now, let's go back to our "MVC announcement publishing system ". I believe that after reading the above scenario, your inspiration must come: Right, action is not Chef If we can make the log function into an interceptor, we can intercept the log function once before the dorelock is executed, and record the log again after the dorelock is executed. It is better to have an interceptor that can be intercepted when an action exception occurs (like the person who handled the bad beef above ). Done .

But how can we intercept an action? Fortunately, this mechanism is built into the ASP. net mvc framework! Haha, let's do it now!

Implement interceptor

ASP. net mvc has three interceptors: Action interceptor, result interceptor, and exception interceptor. I want to use the first and third types. In fact, the so-called ASP. net mvc interceptor is nothing mysterious, just a common class. Only the filterattribute base class must be inherited. The action interceptor must implement the iactionfilter interface, while the exception interceptor must implement the iexceptionfilter interface.

Let's first look at the implementation: Let's create a new filters directory under the controllers directory, and then create two classes under filters, one is loggerfilter and the other is predictionfilter. The first is the loggerfilter code.

Loggerfilter. CS:

1 using system;
2 using system. Collections. Generic;
3 using system. LINQ;
4 using system. Web;
5 using system. Web. MVC;
6 using system. Web. MVC. Ajax;
7
8 namespace mvcdemo. controllers. Filters
9 {
10 public class loggerfilter: filterattribute, iactionfilter
11 {
12 Void iactionfilter. onactionexecuting (actionexecutingcontext filtercontext)
13 {
14 filtercontext. Controller. viewdata ["executinglogger"] = "you are about to add an announcement. The announcement has been written to the log! Time: "+ datetime. now;
15}
16
17 void iactionfilter. onactionexecuted (actionexecutedcontext filtercontext)
18 {
19 filtercontext. Controller. viewdata ["executedlogger"] = "The announcement has been added and logs have been written! Time: "+ datetime. now;
20}
21}
22}

 

As you can see, this class inherits filterattribute and implements iactionfilter. The key is iactionfilter, which has two methods: onactionexecuting is executed before the intercepted action, and onactionexecuted is executed after the intercepted action. Both methods have a parameter, which has different types, but is actually a role: Context of the intercepted action.

In this case, I have to explain that your interceptor intercepts the action and will inevitably use the action-related content during processing. For example, in our example, you need to add content to the viewdata of the controller where the intercepted action is located. Therefore, the interceptor method has a parameter that indicates that the context of the intercepted action is a logical task.

Next, let's look at the exceptionfilter interceptor, which plays a role when an action exception occurs.

Exceptionfilter. CS:

1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.Mvc;
6using System.Web.Mvc.Ajax;
7
8namespace MVCDemo.Controllers.Filters
9{
10  public class ExceptionFilter : FilterAttribute,IExceptionFilter
11  {
12    void IExceptionFilter.OnException(ExceptionContext filterContext)
13    {
14      filterContext.Controller.ViewData["ErrorMessage"] = filterContext.Exception.Message;
15      filterContext.Result = new ViewResult()
16      {
17        ViewName = "Error",
18        ViewData = filterContext.Controller.ViewData,
19      };
20      filterContext.ExceptionHandled = true;
21    }
22  }
23}

 

The exception interceptor also needs to inherit filterattribute, but does not implement iactionfilter. Instead, it needs to implement the iexceptionfilter interface. This interface has only one method: onexception, which is called when an exception occurs. Let's take a look at what I asked it to do: first, the exception information (exceptioncontext is also the context, and its member exception is an exception type instance, that is, the thrown exception) record it to the corresponding key value of viewdata, and then we will display the error view.

Note! This is not a controller, but another class, so you cannot call the view method to return the viewresult instance. We had to create a new viewresult instance and set its view name to error. We passed the dataview in the context.

The last line of filtercontext. effecitonhandled = true; is very important. This line tells the system that the exception has been handled and should not be processed again.

Application interceptor

Okay. After the interceptor is created, how can it be applied to the corresponding action? If you have used spring, you must be deeply touched by the trouble of Implementing AOP. If you hate writing XML as much as you do, you are so happy. In ASP. net mvc, the application interceptor is easy and pleasant. You only need to write the interceptor as an attribute on the action to apply the interceptor. Check the code.

Announcecontroller. CS:

1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.Mvc;
6using System.Web.Mvc.Ajax;
7using MVCDemo.Models;
8using MVCDemo.Models.Interfaces;
9using MVCDemo.Models.Entities;
10using MVCDemo.Controllers.Filters;
11
12namespace MVCDemo.Controllers
13{
14  public class AnnounceController : Controller
15  {
16    public ActionResult Release()
17    {
18      ICategoryService cServ = ServiceBuilder.BuildCategoryService();
19      List<CategoryInfo> categories = cServ.GetAll();
20      ViewData["Categories"] = new SelectList(categories, "ID", "Name");
21      return View("Release");
22    }
23
24    [LoggerFilter()]
25    [ExceptionFilter()]
26    public ActionResult DoRelease()
27    {
28      AnnounceInfo announce = new AnnounceInfo()
29      {
30        ID = 1,
31        Title = Request.Form["Title"],
32        Category = Int32.Parse(Request.Form["Category"]),
33        Content = Request.Form["Content"],
34      };
35
36      IAnnounceService aServ = ServiceBuilder.BuildAnnounceService();
37      aServ.Release(announce);
38
39      ViewData["Announce"] = announce;
40
41      System.Threading.Thread.Sleep(2000);
42      ViewData["Time"] = DateTime.Now;
43      System.Threading.Thread.Sleep(2000);
44
45      return View("ReleaseSucceed");
46    }
47  }
48}

 

No. As long as you write these two attributes on dorelease, everything is done. The framework will help you to call the interceptor at any time. Note: To show the sequence of the interceptor, we add a viewdata ["time"] To dorelease, which records the execution time of this action, because the log interceptor records the time before and after, we can see the execution sequence by comparing the time. As for the two sleep, the effect is more obvious. This line of code means that the program will be delayed for 2 seconds here.

To execute this program, we need to modify the releasesucceed. aspx view to add a few places to display the corresponding data in viewdata.

Releasesucceed. aspx:

1 <% @ page Language = "C #" autoeventwireup = "true" codebehind = "releasesucceed. aspx. cs" inherits = "mvcdemo. Views. Announce. releasesucceed" %>
2 <% @ import namespace = "mvcdemo. Models. Entities" %>
3
4 <! Doctype HTML public "-// W3C // dtd xhtml 1.0 transitional // en" "http://tech.ddvip.com/%22http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd/%22">
5
6 <HTML xmlns = "http://tech.ddvip.com/%22http://www.w3.org/1999/xhtml/%22">
7 8 <title> </title>
9 10 <body>
11 <% announceinfo announce = viewdata ["announce"] As announceinfo; %>
12 <div>
13 14 <DL>
15 <DT> ID: </DT>
16 <DD> <% = announce. ID %> </DD>
17 <DT> title: </DT>
18 <DD> <% = announce. Title %> </DD>
19 <DT> category ID: </DT>
20 <DD> <% = announce. Category %> </DD>
21 <DT> content: </DT>
22 <DD> <% = announce. Content %> </DD>
23 <DT> Release Date: </DT>
24 <DD> <% = viewdata ["time"] %> </DD>
25 </dl>
26 <p> <% = viewdata ["executinglogger"] %> </P>
27 <p> <% = viewdata ["executedlogger"] %> </P>
28 </div>
29 </body>
30

 

No problem. interceptor Method It can be seen from the time that onactionexecuting is executed first, action is executed, and onactionexecuted is executed.

Let's take a look at the effect of the exception blocker. To trigger an exception interceptor, you must first throw an exception. Therefore, we have some hands and feet on the business logic component. Change the release method of mockannounceservices to the following:

1/** // <summary>
2 // publish an announcement
3 /// </Summary>
4 /// <Param name = "announce"> </param>
5 Public void release (announceinfo announce)
6 {
7 throw new exception ("announcement failed! Why? No reason! I am a business component. If I say it fails, it will fail! ");
8 return;
9}

In addition, we need to implement an error. aspx view, which is the error view defined in the exception interceptor. We can create it in views/shared. By the way, shared views are generally placed under shared, because ASP. Net MVC's view search mechanism is that when the directory with the same name as the controller does not exist, you can go to shared to see if there is any such view.

Error. aspx:

1 <% @ page Language = "C #" autoeventwireup = "true" codebehind = "error. aspx. cs" inherits = "mvcdemo. Views. Shared. error" %>
2
3 <! Doctype HTML public "-// W3C // dtd xhtml 1.0 transitional // en" "http://tech.ddvip.com/%22http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd/%22">
4
5 <HTML xmlns = "http://tech.ddvip.com/%22http://www.w3.org/1999/xhtml/%22">
6 7 <title> </title>
8 9 <body>
10 <div>
11 12 <% = viewdata ["errormessage"] %>
13 </div>
14 </body>
15

 

Obviously, the service component throws an exception, but we didn't use try... catch in the Action method, but the exception interceptor successfully intercepts the exception and handles it accordingly.

Let's look back and see if the code is clear after the interceptor is used.

Summary

Through this article, you should be able to master the basic use of the interceptor and use it to implement AOP in the presentation layer. As the final part of this series, the next article will give a comprehensive discussion of ASP. net mvc and compare it with the web form model, so that friends can see their advantages and disadvantages to better Learning Use this framework.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.