First, the preface
Exception handling is an essential part of every system that allows our programs to be friendly to prompt for errors, log error messages, and, more importantly, not disrupt normal data and affect system operations. Exception handling should be a pointcut, the so-called pointcuts are all parts will be used to it, regardless of which layer in the hierarchy, or the specific business logic module, the concern is the same. So, crosscutting concerns we will be unified in one place for processing. Both MVC and WebForm provide this implementation so that we can focus on exceptions.
In MVC, in Filterconfig, the default has been to help us register a handleerrorattribute, which is a filter that inherits the FilterAttribute class and implements the Iexceptionfilter interface. When it comes to exception handling , you will immediately associate 500 error pages, log logs, etc., Handleerrorattribute can easily customize the error page, the default is the error page, and log logs we just need to inherit it, and replace it with registration to globalfiltercollection. About Handleerrorattribute Many people know how to use, here is not to do the introduction.
OK, get to the theme! Dealing with exceptions in MVC, it is believed that many people are beginning to inherit Handleerrorattribute, and then rewrite the Onexception method to add their own logic, such as writing exception information to log files. Of course, there is nothing wrong with this, but a good design should be scene driven, dynamic and configurable. For example, in one scenario, we want Exceptiona to display error page A, and in scene two, we want it to display error page B, where the scene may be a cross project or a different module in the same system. In addition, the exception may be the classification, for example, when exceptiona occurs, we simply need to restore the state, the program can continue to run, exceptionb occurs, we want to record it to the file or system log, and Exceptionc occurs, is a more serious error, We want the program to take place by email or SMS notification. Simply put, different scenarios have different needs, and our programs need to be better faced with change. Of course, the inheritance Handleerrorattribute can also fully achieve the above mentioned, but here I do not intend to expand it, but to rewrite a module, and can be used with the original Handleerrorattribute common use.
Second, design and implementation
2.1 Defining configuration information
From the above we can already know what we want to do, for different exceptions, we want to be able to configure its handlers, error pages, and so on. As Next configuration:
<!--Custom exception configuration-->
<settingException>
<exceptions>
<!--Add priority is higher than group-->
<add exception= "Exceptions.passworderrorexception"
view = "Passworderrorview"
handler= " Exceptionhandlers.passworderrorexceptionhandler "/>
<groups>
<!-- Group can configure an exception view and handler-->
<group view= "Emptyerrorview" handler= " Exceptionhandlers.emptyexceptionhandler ">
<add exception=" Exceptions.usernameemptyexception "/>
<add exception= "exceptions.emailemptyexception"/>
</group>
</groups>
</exceptions>
</settingException>
Where the Add node is used to add a specific exception, its exception attribute is required, and view represents the error page, handler represents the specific handler, if view and handler are not, The exception is given to the default Handleerrorattribute processing. The group node is used for grouping, for example, the usernameemptyexception and emailemptyexception above correspond to the same handler and view.
The program reflects the reading of this configuration information and creates the corresponding object. We put this configuration file into the web.config to make sure it is ready to be changed at any time.
2.2 Exception Information Wrapper object
Here we define an entity object that corresponds to the node above. As follows:
public class Exceptionconfig
{
///<summary>
///views
///</summary> public
string View {get;set;}
<summary>
///Exception Object
///</summary> public
Exception exception{get;set;}
<summary>
///Exception handler
///</summary> public
iexceptionhandler handler{get;set;}
2.3 Define Handler Interface
As we said above, different anomalies may require different processing methods. Here we design an interface as follows:
Public interface Iexceptionhandler
{
///<summary>
///Exception processing complete
///</summary>
bool Hashandled{get;set;}
<summary>
///Processing exception
///</summary>
///<param name= "ex" ></param>
void Handle (Exception ex);
}
All kinds of exception handlers can only implement this interface.
2.3 Implementation Iexceptionfilter
This is necessary. If you implement the Iexceptionfilter interface, Settingexceptionprovider gets the wrapper object from the configuration information (cache) based on the exception object type.
public class Settinghandleerrorfilter:iexceptionfilter {public void onexception (E Xceptioncontext filtercontext) {if (Filtercontext = null) {throw new ArgumentNullException ("Filtercontex
T ");
} exceptionconfig config = Settingexceptionprovider.container[filtercontext.exception.gettype ()];
if (config = = null) {return; } if (config. Handler!= null) {//execute Handle method CONFIG.
Handler.handle (filtercontext.exception); if (config.
handler.hashandled) {//exception handled, no follow-up action required filtercontext.exceptionhandled = true;
Return }//Otherwise, if there is a custom page, the IF (!string) is displayed. IsNullOrEmpty (config.
View) {//Here can also be extended to implement iview views Viewresult view = new Viewresult (); View. ViewName = config.
View;
Filtercontext.result = view;
Filtercontext.exceptionhandled = true;
Return //Otherwise the exception continues to be passed}}
2.4 Read configuration file, create exception information wrapper object
This part of the code is more, in fact, you just know it is reading Web.config custom configuration node. Settingexceptionprovider is used to provide container objects.
public class Settingexceptionprovider {public static dictionary<type, exceptionconfig> Container = new Dicti
Onary<type, exceptionconfig> ();
Static Settingexceptionprovider () {Initcontainer (); ///Read configuration information, initialize container private static void Initcontainer () {var section = webconfigurationmanager.getsection ("Setti
Ngexception ") as settingexceptionsection;
if (section = = null) {return; } initfromgroups (section.
Exceptions.groups); Initfromaddcollection (section.
Exceptions.addcollection); private static void Initfromgroups (GroupCollection groups) {foreach (var group in groups.
Cast<groupelement> ()) {exceptionconfig config = new Exceptionconfig (); Config. View = group.
View; Config. Handler = Createhandler (group.
Handler); foreach (var item in group.) Addcollection.cast<addelement> ()) {Exception ex = createexception (item.
Exception); Config. Exception = EX Container[ex.
GetType ()] = config; }} private static void Initfromaddcollection (Addcollection collection) {foreach (var item in collection .
Cast<addelement> ()) {exceptionconfig config = new Exceptionconfig (); Config. View = Item.
View; Config. Handler = Createhandler (item.
Handler); Config. Exception = CreateException (item.
Exception); Container[config.
Exception.gettype ()] = config; Create Iexceptionhandler object private static Iexceptionhandler Createhandler (string fullName) {I with fully qualified name F (String.
IsNullOrEmpty (FullName)) {return null;
Type type = Type.GetType (fullName);
return Activator.CreateInstance (type) as Iexceptionhandler; Create the Exception object private static Exception createexception (string fullName) {if (string) based on the fully qualified name.
IsNullOrEmpty (FullName)) {return null;
Type type = Type.GetType (fullName); return Activator.CreateInstance (type) asException;
}
}
The following are the information for each configuration node:
Settingexceptions node:
<summary>
///settingexceptions node
///</summary> Public
class Settingexceptionsection: ConfigurationSection
{
[ConfigurationProperty ("Exceptions", isrequired=true)]
public Exceptionselement exceptions
{
get
{return
(exceptionselement) base[' exceptions ']
}}
Exceptions node:
<summary>
///Exceptions node
///</summary> Public
class Exceptionselement: ConfigurationElement
{
private static readonly ConfigurationProperty _addproperty =
New ConfigurationProperty ("", typeof (Addcollection), NULL, configurationpropertyoptions.isdefaultcollection);
[ConfigurationProperty ("", Isdefaultcollection = True)]
Public addcollection addcollection
{
get
{return
(addcollection) base[_addproperty];
}
[ConfigurationProperty ("groups")] public
groupcollection groups
{get
{return
( groupcollection) base["groups"]
Group Node Set:
<summary>
///Group node set
///</summary>
[Configurationcollection (typeof (Groupelement), Additemname= "group")] public
class groupcollection:configurationelementcollection
{
/*override*/
protected override ConfigurationElement createnewelement ()
{return
new groupelement ();
}
protected override Object Getelementkey (configurationelement Element)
{return
element;
}
}
Group node:
<summary>
///Group node
///</summary> public
class Groupelement:configurationelement
{
private static readonly ConfigurationProperty _addproperty =
new ConfigurationProperty ("", typeof ( Addcollection), NULL, configurationpropertyoptions.isdefaultcollection);
[ConfigurationProperty ("View")]
public string View
{
get
{return
base["View"]. ToString ();
}
}
[ConfigurationProperty ("handler")]
public string Handler
{
get
{return
base["Handler"]. ToString ();
}
}
[ConfigurationProperty ("", Isdefaultcollection = True)]
Public addcollection addcollection
{
get
{return
(addcollection) base[_addproperty];
}
}
Add node Set:
<summary>
///Add node set
///</summary> public
class Addcollection: ConfigurationElementCollection
{
/*override*/
protected override ConfigurationElement Createnewelement ()
{return
new addelement ();
}
protected override Object Getelementkey (configurationelement Element)
{return
element;
}
}
Add node:
<summary>
///Add node
///</summary> public
class Addelement:configurationelement
{
[ConfigurationProperty (' View ']] public
string View
{get
{return
base[' View "As String;
}
}
[ConfigurationProperty ("handler")]
public string Handler
{
get
{return
base[' Handler ' As String;
}
}
[ConfigurationProperty ("exception", IsRequired = True)]
public string Exception
{
get
{return
base[' Exception ' As String;
}
}}
Third, testing
OK, the following test, first of all, in the Filterconfig Registerglobalfilters method in, Handlererrorattribute before registering our filter:
Filters. ADD (New Settinghandleerrorfilter ()).
3.1 Preparing Exception objects
Prepare a few simple exception objects:
public class passworderrorexception:exception{} public
class usernameemptyexception:exception{}
Public Class emailemptyexception:exception{}
3.2 Prepare Handler
For the above exception, we prepared two handler, one to handle the password error exception, and one to handle the null exception. There is no actual processing code, concrete how to deal with, should be combined with specific business. Such as:
public class Passworderrorexceptionhandler:iexceptionhandler
{public
bool Hashandled{get;set;}
public void Handle (Exception ex)
{
//Concrete processing logic ...
}
} public class Emptyexceptionhandler:iexceptionhandler
{public
bool hashandled {get; set;}
public void Handle (Exception ex)
{
//Concrete processing logic ...
}
}
3.3 Throwing an exception
According to the above configuration, we manually throw the exception in action
Public ActionResult Index ()
{
throw new passworderrorexception ();
}
Public ActionResult Index2 ()
{
throw new usernameemptyexception ();
}
Public ActionResult Index3 ()
{
throw new emailemptyexception ();
}
As you can see, the corresponding handler will be executed, and the browser will also appear with our configured error page.
Iv. Summary
In fact, this is just a relatively simple example, so I call it a simple module, but the framework, library and other words. Of course, we can expand and optimize it according to the actual situation. Microsoft Enterprise Library Depending on the integration of such modules, interested friends can understand.