Asp.net的NamePipe机制给我们提供了很多扩展性. 使用HttpModule我们可能实现的有:
强制站点范围的Cookie策略
集中化监控与日志
编写设置与删除HTTP头
控制response输出,如删除多余空白字符
Session管理
认证与受权
下面我们来看如何实现自定义异常处理:
1 |
1: public class ErrorModule:IHttpModule |
1 |
2: { |
1 |
3: #region IHttpModule Members |
1 |
4: |
1 |
5: /// <summary> |
1 |
6: /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>. |
1 |
7: /// </summary> |
1 |
8: public void Dispose() |
1 |
9: { |
1 |
10: //do nothing |
1 |
11: } |
1 |
12: |
1 |
13: /// <summary> |
1 |
14: /// Initializes a module and prepares it to handle requests. |
1 |
15: /// </summary> |
1 |
16: /// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param> |
1 |
17: public void Init(HttpApplication context) |
1 |
18: { |
1 |
19: context.Error += new EventHandler(customcontext_Error); |
1 |
20: } |
1 |
21: |
1 |
22: private void customcontext_Error(object sender, EventArgs e) |
1 |
23: { |
1 |
24: HttpContext ctx = HttpContext.Current; |
1 |
25: HttpResponse response = ctx.Response; |
1 |
26: HttpRequest request = ctx.Request; |
1 |
27: |
1 |
28: Exception exception = ctx.Server.GetLastError(); |
1 |
29: |
1 |
30: var sboutput = new StringBuilder(); |
1 |
31: sboutput.Append("Querystring:<p/>"); |
1 |
32: //Get out the query string |
1 |
33: int count = request.QueryString.Count; |
1 |
34: for (int i = 0; i < count; i++) |
1 |
35: { |
1 |
36: sboutput.AppendFormat("<br/> {0}:-- {1} ", request.QueryString.Keys[i], request.QueryString[i]); |
1 |
37: } |
1 |
38: //Get out the form collection info |
1 |
39: sboutput.Append("<p>-------------------------<p/>Form:<p/>"); |
1 |
40: count = request.Form.Count; |
1 |
41: for (int i = 0; i < count; i++) |
1 |
42: { |
1 |
43: sboutput.AppendFormat("<br/> {0}:-- {1} -- <br/>", request.Form.Keys[i], request.Form[i]); |
1 |
44: } |
1 |
45: sboutput.Append("<p>-------------------------<p/>ErrorInfo:<p/>"); |
1 |
46: sboutput.AppendFormat(@"Your request could not processed. Please press the back button on your browser and try again.<br/> |
1 |
47: If the problem persists, please contact technical support<p/> |
1 |
48: Information below is for technical support:<p/> |
1 |
49: <p/>URL:{0}<p/>Stacktrace:---<br/>{1}<p/>InnerException:<br/>{2}" |
1 |
50: , ctx.Request.Url, exception.InnerException.StackTrace, exception.InnerException); |
1 |
51: |
1 |
52: response.Write(sboutput.ToString()); |
1 |
53: |
1 |
54: // To let the page finish running we clear the error |
1 |
55: ctx.Server.ClearError(); |
1 |
56: } |
1 |
57: |
1 |
58: #endregion |
1 |
59: |
1 |
60: } |
上面的代码实现了IHttpModule接口, 实现基于HttpApplication.Error事件, 接着我们自定义输出了一些信息,包括Form,QueryString. 最后把原来的Error信息清除了,这样你看到以前那个黄页了. 这个自定义的Module可以用于调试Web应用程序使用.
Web.config中配置:
1 |
<httpModules> |
1 |
<add name="ErrorLoggingModule" type="MyWeb.ErrorModule"/> |
1 |
</httpModules> |
实际开发中,我们可以做的事儿很多,对这些信息记日志,发邮件. 如下, 我们演示使用Enterprise Library 做异常处理并日志记录,部分代码如下:
1 |
1: /// <summary> |
1 |
2: /// Handles the Error event of the EntLibLogging control. |
1 |
3: /// </summary> |
1 |
4: /// <param name="sender">The source of the event.</param> |
1 |
5: /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> |
1 |
6: /// <remarks>author Petter Liu http://wintersun.cnblogs.com</remarks> |
1 |
7: private void EntLibLogging_Error(object sender, EventArgs e) |
1 |
8: { |
1 |
9: var builder = new ConfigurationSourceBuilder(); |
1 |
10: |
1 |
11: builder.ConfigureInstrumentation() |
1 |
12: .ForApplicationInstance("MyApp") |
1 |
13: .EnableLogging() |
1 |
14: .EnablePerformanceCounters(); |
1 |
15: |
1 |
16: //a single exception handling policy named MyPolicy for exceptions of type ArgumentNullException. |
1 |
17: //The handler for this exception policy will log the exception to the General category (defined in the Logging Application Block configuration) |
1 |
18: //as a warning with event ID 9000, wrap the ArgumentNullException with an InvalidOperationException, set the new exception message to MyMessage, and then re-throw the exception. |
1 |
19: builder.ConfigureExceptionHandling() |
1 |
20: .GivenPolicyWithName("MyPolicy") |
1 |
21: .ForExceptionType<ArgumentNullException>() |
1 |
22: .LogToCategory("Exception") |
1 |
23: .WithSeverity(System.Diagnostics.TraceEventType.Warning) |
1 |
24: .UsingEventId(9000) |
1 |
25: .WrapWith<InvalidOperationException>() |
1 |
26: .UsingMessage("MyMessage") |
1 |
27: .ThenNotifyRethrow(); |
1 |
28: |
1 |
29: //logging application |
1 |
30: builder.ConfigureLogging() |
1 |
31: .WithOptions |
1 |
32: .DoNotRevertImpersonation() |
1 |
33: .LogToCategoryNamed("Exception") |
1 |
34: .SendTo.FlatFile("Exception Logging File") |
1 |
35: .FormatWith(new FormatterBuilder() |
1 |
36: .TextFormatterNamed("Text Formatter") |
1 |
37: . UsingTemplate("Timestamp: {timestamp}{newline}Message: {message}{newline}Category: {category}{newline}")) |
1 |
38: .ToFile("d:\\logs\\ExceptionsLog.log") |
1 |
39: .SendTo.RollingFile("Rolling Log files") |
1 |
40: .RollAfterSize(1024) |
1 |
41: .ToFile("d:\\logs\\Rollinglog.log") |
1 |
42: .LogToCategoryNamed("General") |
1 |
43: .WithOptions.SetAsDefaultCategory() |
1 |
44: .SendTo.SharedListenerNamed("Exception Logging File"); |
1 |
45: |
1 |
46: var configSource = new DictionaryConfigurationSource(); |
1 |
47: builder.UpdateConfigurationWithReplace(configSource); |
1 |
48: EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource); |
1 |
49: |
1 |
50: var ex = HttpContext.Current.Server.GetLastError(); |
1 |
51: var em = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>(); |
1 |
52: em.HandleException(ex.InnerException, "MyPolicy"); |
1 |
53: } |
注意上面的代码, 为了运行代码您需要引用以下程序集
Enterprise Library Share Common Library
Microsoft.Practices.ServiceLocation
Logging Application Block
Exception Handling Application Block
Exception Handling Logging Provider
这里我们使用Fluent API配置, 因此没有配置XML文件. 所以不需要Web.Config中配置任何信息. 代码中有注释. 为了测试我们使用一个PAGE故意Throw 一个ArgumentNullException. 通过Server.GetLastError()获取Exception, 这时由名为MyPolicy策略处理异常. 对于ArgumentNullException把它们记录日志到名为Exception分类中,这个日志文件位于d:\\logs\\
ExceptionLog.log.实际开发你完全按照你的需要来自定义策略.
然后这个日志文件中写出的内容是这样的:
1 |
----------------------------------------Timestamp: 2011-11-12 5:57:08Message: HandlingInstanceID: a99d005d-5f8d-4613-9522-2d60efb089aaAn exception of type 'System.ArgumentNullException' occurred and was caught.----------------------------------------------------------------------------11/12/2011 13:57:08Type : System.ArgumentNullException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Message : Value cannot be null.Parameter name: Demo errorSource : MyWebHelp link : ParamName : Demo errorData : System.Collections.ListDictionaryInternalTargetSite : Void Page_Load(System.Object, System.EventArgs)Stack Trace : at MyWeb.About.Page_Load(Object sender, EventArgs e) in H:\My Project\DotNet40\TDD2010\WebHost\MyWeb\About.aspx.cs:line 14 at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)Additional Info:MachineName : USERTimeStamp : 2011-11-12 5:57:08FullName : Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35AppDomainName : 3e5cb21e-3-129655510216406250ThreadIdentity : WindowsIdentity : USER\PetterCategory: Exception |
由于我们日志模块我们配置还需要写Rollinglog.log文件,内容如下:
1 |
----------------------------------------Exception Warning: 9000 : Timestamp: 2011-11-12 5:57:08Message: HandlingInstanceID: a99d005d-5f8d-4613-9522-2d60efb089aaAn exception of type 'System.ArgumentNullException' occurred and was caught.----------------------------------------------------------------------------11/12/2011 13:57:08Type : System.ArgumentNullException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Message : Value cannot be null.Parameter name: Demo errorSource : MyWebHelp link : ParamName : Demo errorData : System.Collections.ListDictionaryInternalTargetSite : Void Page_Load(System.Object, System.EventArgs)Stack Trace : at MyWeb.About.Page_Load(Object sender, EventArgs e) in H:\My Project\DotNet40\TDD2010\WebHost\MyWeb\About.aspx.cs:line 14 at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)Additional Info:MachineName : USERTimeStamp : 2011-11-12 5:57:08FullName : Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35AppDomainName : 3e5cb21e-3-129655510216406250ThreadIdentity : WindowsIdentity : USER\PetterCategory: ExceptionPriority: 0EventId: 9000Severity: WarningTitle:Enterprise Library Exception HandlingMachine: USERApp Domain: 3e5cb21e-3-129655510216406250ProcessId: 2444Process Name: C:\Program Files\Common Files\Microsoft Shared\DevServer\10.0\WebDev.WebServer40.exeThread Name: Win32 ThreadId:2748Extended Properties: ---------------------------------------- |
1 |
你可以看到上面的EventId=9000与我们之前在CODE中配置是相同的. |
1 2 |
在开源社区有一个组件<a href="http://code.google.com/p/elmah/" target="_blank"><span style="color:#E3272D;">ELMAH</span></a>(Error Logging Modules and Handlers for ASP.NET),已实现Error处理发邮件,写DB,发送到SNS等功能. 我们随意来看下它的代码: 它就是基于IHttpModule的扩展,下面代码来ELMAH: |
1 |
1: /// <summary> |
1 |
2: /// Provides an abstract base class for <see cref="IHttpModule"/> that |
1 |
3: /// supports discovery from within partial trust environments. |
1 |
4: /// </summary> |
1 |
5: public abstract class HttpModuleBase : IHttpModule |
1 |
6: { |
1 |
7: void IHttpModule.Init(HttpApplication context) |
1 |
8: { |
1 |
9: if (context == null) |
1 |
10: throw new ArgumentNullException("context"); |
1 |
11: |
1 |
12: if (SupportDiscoverability) |
1 |
13: HttpModuleRegistry.RegisterInPartialTrust(context, this); |
1 |
14: |
1 |
15: OnInit(context); |
1 |
16: } |
1 |
17: |
1 |
18: void IHttpModule.Dispose() |
1 |
19: { |
1 |
20: OnDispose(); |
1 |
21: } |
1 |
22: |
1 |
23: /// <summary> |
1 |
24: /// Determines whether the module will be registered for discovery |
1 |
25: /// in partial trust environments or not. |
1 |
26: /// </summary> |
1 |
27: protected virtual bool SupportDiscoverability |
1 |
28: { |
1 |
29: get { return false; } |
1 |
30: } |
1 |
31: |
1 |
32: /// <summary> |
1 |
33: /// Initializes the module and prepares it to handle requests. |
1 |
34: /// </summary> |
1 |
35: protected virtual void OnInit(HttpApplication application) {} |
1 |
36: |
1 |
37: /// <summary> |
1 |
38: /// Disposes of the resources (other than memory) used by the module. |
1 |
39: /// </summary> |
1 |
40: protected virtual void OnDispose() {} |
1 |
41: } |
1 |
这是ErrorLogModule实现之前HttpModuleBase: |
1 |
1: public class ErrorLogModule : HttpModuleBase, IExceptionFiltering |
1 |
2: { |
1 |
3: public event ExceptionFilterEventHandler Filtering; |
1 |
4: public event ErrorLoggedEventHandler Logged; |
1 |
5: |
1 |
6: /// <summary> |
1 |
7: /// Initializes the module and prepares it to handle requests. |
1 |
8: /// </summary> |
1 |
9: |
1 |
10: protected override void OnInit(HttpApplication application) |
1 |
11: { |
1 |
12: if (application == null) |
1 |
13: throw new ArgumentNullException("application"); |
1 |
14: |
1 |
15: application.Error += new EventHandler(OnError); |
1 |
16: ErrorSignal.Get(application).Raised += new ErrorSignalEventHandler(OnErrorSignaled); |
1 |
17: } |
1 |
18: |
1 |
19: /// <summary> |
1 |
20: /// Gets the <see cref="ErrorLog"/> instance to which the module |
1 |
21: /// will log exceptions. |
1 |
22: /// </summary> |
1 |
23: protected virtual ErrorLog GetErrorLog(HttpContext context) |
1 |
24: { |
1 |
25: return ErrorLog.GetDefault(context); |
1 |
26: } |
1 |
27: |
1 |
28: /// <summary> |
1 |
29: /// The handler called when an unhandled exception bubbles up to |
1 |
30: /// the module. |
1 |
31: /// </summary> |
1 |
32: protected virtual void OnError(object sender, EventArgs args) |
1 |
33: { |
1 |
34: HttpApplication application = (HttpApplication) sender; |
1 |
35: LogException(application.Server.GetLastError(), application.Context); |
1 |
36: } |
1 |
37: |
1 |
38: /// <summary> |
1 |
39: /// The handler called when an exception is explicitly signaled. |
1 |
40: /// </summary> |
1 |
41: protected virtual void OnErrorSignaled(object sender, ErrorSignalEventArgs args) |
1 |
42: { |
1 |
43: LogException(args.Exception, args.Context); |
1 |
44: } |
1 |
45: |
1 |
46: /// <summary> |
1 |
47: /// Logs an exception and its context to the error log. |
1 |
48: /// </summary> |
1 |
49: protected virtual void LogException(Exception e, HttpContext context) |
1 |
50: { |
1 |
51: if (e == null) |
1 |
52: throw new ArgumentNullException("e"); |
1 |
53: |
1 |
54: // |
1 |
55: // Fire an event to check if listeners want to filter out |
1 |
56: // logging of the uncaught exception. |
1 |
57: // |
1 |
58: |
1 |
59: ExceptionFilterEventArgs args = new ExceptionFilterEventArgs(e, context); |
1 |
60: OnFiltering(args); |
1 |
61: |
1 |
62: if (args.Dismissed) |
1 |
63: return; |
1 |
64: |
1 |
65: // |
1 |
66: // Log away... |
1 |
67: // |
1 |
68: |
1 |
69: ErrorLogEntry entry = null; |
1 |
70: |
1 |
71: try |
1 |
72: { |
1 |
73: Error error = new Error(e, context); |
1 |
74: ErrorLog log = GetErrorLog(context); |
1 |
75: string id = log.Log(error); |
1 |
76: entry = new ErrorLogEntry(log, id, error); |
1 |
77: } |
1 |
78: catch (Exception localException) |
1 |
79: { |
1 |
80: // |
1 |
81: // IMPORTANT! We swallow any exception raised during the |
1 |
82: // logging and send them out to the trace . The idea |
1 |
83: // here is that logging of exceptions by itself should not |
1 |
84: // be critical to the overall operation of the application. |
1 |
85: // The bad thing is that we catch ANY kind of exception, |
1 |
86: // even system ones and potentially let them slip by. |
1 |
87: // |
1 |
88: |
1 |
89: Trace.WriteLine(localException); |
1 |
90: } |
1 |
91: |
1 |
92: if (entry != null) |
1 |
93: OnLogged(new ErrorLoggedEventArgs(entry)); |
1 |
94: } |
1 |
95: |
1 |
96: /// <summary> |
1 |
97: /// Raises the <see cref="Logged"/> event. |
1 |
98: /// </summary> |
1 |
99: protected virtual void OnLogged(ErrorLoggedEventArgs args) |
1 |
100: { |
1 |
101: ErrorLoggedEventHandler handler = Logged; |
1 |
102: |
1 |
103: if (handler != null) |
1 |
104: handler(this, args); |
1 |
105: } |
1 |
106: |
1 |
107: /// <summary> |
1 |
108: /// Raises the <see cref="Filtering"/> event. |
1 |
109: /// </summary> |
1 |
110: protected virtual void OnFiltering(ExceptionFilterEventArgs args) |
1 |
111: { |
1 |
112: ExceptionFilterEventHandler handler = Filtering; |
1 |
113: |
1 |
114: if (handler != null) |
1 |
115: handler(this, args); |
1 |
116: } |
1 |
117: |
1 |
118: /// <summary> |
1 |
119: /// Determines whether the module will be registered for discovery |
1 |
120: /// in partial trust environments or not. |
1 |
121: /// </summary> |
1 |
122: protected override bool SupportDiscoverability |
1 |
123: { |
1 |
124: get { return true; } |
1 |
125: } |
1 |
126: } |
1 |
更多的功能等待您去挖掘,我们在实际开发中按需选择.希望这篇POST对您开发有帮助. |
转自:http://www.cnblogs.com/wintersun/archive/2011/11/12/2246513.html