您的位置:首页 > 理论基础 > 计算机网络

Asp.net Web Applicatoin实现自定义HttpModule拦截异常处理

2011-11-12 16:55 756 查看
Asp.net的NamePipe机制给我们提供了很多扩展性.使用HttpModule我们可能实现的有:

强制站点范围的Cookie策略
集中化监控与日志
编写设置与删除HTTP头
控制response输出,如删除多余空白字符
Session管理
认证与受权
下面我们来看如何实现自定义异常处理:

publicclassErrorModule:IHttpModule
{
#regionIHttpModuleMembers
///<summary>
///Disposesoftheresources(otherthanmemory)usedbythemodulethatimplements<seecref="T:System.Web.IHttpModule"/>.
///</summary>
publicvoidDispose()
{
//donothing
}
///<summary>
///Initializesamoduleandpreparesittohandlerequests.
///</summary>
///<paramname="context">An<seecref="T:System.Web.HttpApplication"/>thatprovidesaccesstothemethods,properties,andeventscommontoallapplicationobjectswithinanASP.NETapplication</param>
publicvoidInit(HttpApplicationcontext)
{
context.Error+=newEventHandler(customcontext_Error);
}
privatevoidcustomcontext_Error(objectsender,EventArgse)
{
HttpContextctx=HttpContext.Current;
HttpResponseresponse=ctx.Response;
HttpRequestrequest=ctx.Request;
Exceptionexception=ctx.Server.GetLastError();
varsboutput=newStringBuilder();
sboutput.Append("Querystring:<p/>");
//Getoutthequerystring
intcount=request.QueryString.Count;
for(inti=0;i<count;i++)
{
sboutput.AppendFormat("<br/>{0}:--{1}",request.QueryString.Keys[i],request.QueryString[i]);
}
//Getouttheformcollectioninfo
sboutput.Append("<p>-------------------------<p/>Form:<p/>");
count=request.Form.Count;
for(inti=0;i<count;i++)
{
sboutput.AppendFormat("<br/>{0}:--{1}--<br/>",request.Form.Keys[i],request.Form[i]);
}
sboutput.Append("<p>-------------------------<p/>ErrorInfo:<p/>");
sboutput.AppendFormat(@"Yourrequestcouldnotprocessed.Pleasepressthebackbuttononyourbrowserandtryagain.<br/>
Iftheproblempersists,pleasecontacttechnicalsupport<p/>
Informationbelowisfortechnicalsupport:<p/>
<p/>URL:{0}<p/>Stacktrace:---<br/>{1}<p/>InnerException:<br/>{2}"
,ctx.Request.Url,exception.InnerException.StackTrace,exception.InnerException);
response.Write(sboutput.ToString());
//Toletthepagefinishrunningwecleartheerror
ctx.Server.ClearError();
}
#endregion
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

上面的代码实现了IHttpModule接口,实现基于HttpApplication.Error事件,接着我们自定义输出了一些信息,包括Form,QueryString.最后把原来的Error信息清除了,这样你看到以前那个黄页了.这个自定义的Module可以用于调试Web应用程序使用.

Web.config中配置:

<httpModules>
<addname="ErrorLoggingModule"type="MyWeb.ErrorModule"/>
</httpModules>

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

实际开发中,我们可以做的事儿很多,对这些信息记日志,发邮件.如下,我们演示使用EnterpriseLibrary做异常处理并日志记录,部分代码如下:

///<summary>
///HandlestheErroreventoftheEntLibLoggingcontrol.
///</summary>
///<paramname="sender">Thesourceoftheevent.</param>
///<paramname="e">The<seecref="System.EventArgs"/>instancecontainingtheeventdata.</param>
///<remarks>authorPetterLiu
'target='_blank'>http://wintersun.cnblogs.com</remarks>
privatevoidEntLibLogging_Error(objectsender,EventArgse)
{
varbuilder=newConfigurationSourceBuilder();
builder.ConfigureInstrumentation()
.ForApplicationInstance("MyApp")
.EnableLogging()
.EnablePerformanceCounters();
//asingleexceptionhandlingpolicynamedMyPolicyforexceptionsoftypeArgumentNullException.
//ThehandlerforthisexceptionpolicywilllogtheexceptiontotheGeneralcategory(definedintheLoggingApplicationBlockconfiguration)
//asawarningwitheventID9000,wraptheArgumentNullExceptionwithanInvalidOperationException,setthenewexceptionmessagetoMyMessage,andthenre-throwtheexception.
builder.ConfigureExceptionHandling()
.GivenPolicyWithName("MyPolicy")
.ForExceptionType<ArgumentNullException>()
.LogToCategory("Exception")
.WithSeverity(System.Diagnostics.TraceEventType.Warning)
.UsingEventId(9000)
.WrapWith<InvalidOperationException>()
.UsingMessage("MyMessage")
.ThenNotifyRethrow();
//loggingapplication
builder.ConfigureLogging()
.WithOptions
.DoNotRevertImpersonation()
.LogToCategoryNamed("Exception")
.SendTo.FlatFile("ExceptionLoggingFile")
.FormatWith(newFormatterBuilder()
.TextFormatterNamed("TextFormatter")
.UsingTemplate("Timestamp:{timestamp}{newline}Message:{message}{newline}Category:{category}{newline}"))
.ToFile("d:\\logs\\ExceptionsLog.log")
.SendTo.RollingFile("RollingLogfiles")
.RollAfterSize(1024)
.ToFile("d:\\logs\\Rollinglog.log")
.LogToCategoryNamed("General")
.WithOptions.SetAsDefaultCategory()
.SendTo.SharedListenerNamed("ExceptionLoggingFile");
varconfigSource=newDictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace(configSource);
EnterpriseLibraryContainer.Current=EnterpriseLibraryContainer.CreateDefaultContainer(configSource);
varex=HttpContext.Current.Server.GetLastError();
varem=EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();
em.HandleException(ex.InnerException,"MyPolicy");
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

注意上面的代码,为了运行代码您需要引用以下程序集


EnterpriseLibraryShareCommonLibrary
Microsoft.Practices.ServiceLocation
LoggingApplicationBlock
ExceptionHandlingApplicationBlock
ExceptionHandlingLoggingProvider


这里我们使用FluentAPI配置,因此没有配置XML文件.所以不需要Web.Config中配置任何信息.代码中有注释.为了测试我们使用一个PAGE故意Throw一个ArgumentNullException.通过Server.GetLastError()获取Exception,这时由名为MyPolicy策略处理异常.对于ArgumentNullException把它们记录日志到名为Exception分类中,这个日志文件位于d:\\logs\\
ExceptionLog.log.实际开发你完全按照你的需要来自定义策略.

然后这个日志文件中写出的内容是这样的:

----------------------------------------
Timestamp:2011-11-125:57:08
Message:HandlingInstanceID:a99d005d-5f8d-4613-9522-2d60efb089aa
Anexceptionoftype'System.ArgumentNullException'occurredandwascaught.
----------------------------------------------------------------------------
11/12/201113:57:08
Type:System.ArgumentNullException,mscorlib,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089
Message:Valuecannotbenull.
Parametername:Demoerror
Source:MyWeb
Helplink:
ParamName:Demoerror
Data:System.Collections.ListDictionaryInternal
TargetSite:VoidPage_Load(System.Object,System.EventArgs)
StackTrace:atMyWeb.About.Page_Load(Objectsender,EventArgse)inH:\MyProject\DotNet40\TDD2010\WebHost\MyWeb\About.aspx.cs:line14
atSystem.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtrfp,Objecto,Objectt,EventArgse)
atSystem.Web.Util.CalliEventHandlerDelegateProxy.Callback(Objectsender,EventArgse)
atSystem.Web.UI.Control.OnLoad(EventArgse)
atSystem.Web.UI.Control.LoadRecursive()
atSystem.Web.UI.Page.ProcessRequestMain(BooleanincludeStagesBeforeAsyncPoint,BooleanincludeStagesAfterAsyncPoint)

AdditionalInfo:

MachineName:USER
TimeStamp:2011-11-125:57:08
FullName:Microsoft.Practices.EnterpriseLibrary.ExceptionHandling,Version=5.0.414.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35
AppDomainName:3e5cb21e-3-129655510216406250
ThreadIdentity:
WindowsIdentity:USER\Petter

Category:Exception

由于我们日志模块我们配置还需要写Rollinglog.log文件,内容如下:

----------------------------------------
ExceptionWarning:9000:Timestamp:2011-11-125:57:08
Message:HandlingInstanceID:a99d005d-5f8d-4613-9522-2d60efb089aa
Anexceptionoftype'System.ArgumentNullException'occurredandwascaught.
----------------------------------------------------------------------------
11/12/201113:57:08
Type:System.ArgumentNullException,mscorlib,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089
Message:Valuecannotbenull.
Parametername:Demoerror
Source:MyWeb
Helplink:
ParamName:Demoerror
Data:System.Collections.ListDictionaryInternal
TargetSite:VoidPage_Load(System.Object,System.EventArgs)
StackTrace:atMyWeb.About.Page_Load(Objectsender,EventArgse)inH:\MyProject\DotNet40\TDD2010\WebHost\MyWeb\About.aspx.cs:line14
atSystem.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtrfp,Objecto,Objectt,EventArgse)
atSystem.Web.Util.CalliEventHandlerDelegateProxy.Callback(Objectsender,EventArgse)
atSystem.Web.UI.Control.OnLoad(EventArgse)
atSystem.Web.UI.Control.LoadRecursive()
atSystem.Web.UI.Page.ProcessRequestMain(BooleanincludeStagesBeforeAsyncPoint,BooleanincludeStagesAfterAsyncPoint)

AdditionalInfo:

MachineName:USER
TimeStamp:2011-11-125:57:08
FullName:Microsoft.Practices.EnterpriseLibrary.ExceptionHandling,Version=5.0.414.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35
AppDomainName:3e5cb21e-3-129655510216406250
ThreadIdentity:
WindowsIdentity:USER\Petter

Category:Exception
Priority:0
EventId:9000
Severity:Warning
Title:EnterpriseLibraryExceptionHandling
Machine:USER
AppDomain:3e5cb21e-3-129655510216406250
ProcessId:2444
ProcessName:C:\ProgramFiles\CommonFiles\MicrosoftShared\DevServer\10.0\WebDev.WebServer40.exe
ThreadName:
Win32ThreadId:2748
ExtendedProperties:
----------------------------------------
你可以看到上面的EventId=9000与我们之前在CODE中配置是相同的.
在开源社区有一个组件ELMAH(ErrorLoggingModulesandHandlersforASP.NET),已实现Error处理发邮件,写DB,发送到SNS等功能.我们随意来看下它的代码:
它就是基于IHttpModule的扩展,下面代码来ELMAH:

///<summary>
///Providesanabstractbaseclassfor<seecref="IHttpModule"/>that
///supportsdiscoveryfromwithinpartialtrustenvironments.
///</summary>
publicabstractclassHttpModuleBase:IHttpModule
{
voidIHttpModule.Init(HttpApplicationcontext)
{
if(context==null)
thrownewArgumentNullException("context");
if(SupportDiscoverability)
HttpModuleRegistry.RegisterInPartialTrust(context,this);
OnInit(context);
}
voidIHttpModule.Dispose()
{
OnDispose();
}
///<summary>
///Determineswhetherthemodulewillberegisteredfordiscovery
///inpartialtrustenvironmentsornot.
///</summary>
protectedvirtualboolSupportDiscoverability
{
get{returnfalse;}
}
///<summary>
///Initializesthemoduleandpreparesittohandlerequests.
///</summary>
protectedvirtualvoidOnInit(HttpApplicationapplication){}
///<summary>
///Disposesoftheresources(otherthanmemory)usedbythemodule.
///</summary>
protectedvirtualvoidOnDispose(){}
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

这是ErrorLogModule实现之前HttpModuleBase:

publicclassErrorLogModule:HttpModuleBase,IExceptionFiltering
{
publiceventExceptionFilterEventHandlerFiltering;
publiceventErrorLoggedEventHandlerLogged;
///<summary>
///Initializesthemoduleandpreparesittohandlerequests.
///</summary>
protectedoverridevoidOnInit(HttpApplicationapplication)
{
if(application==null)
thrownewArgumentNullException("application");
application.Error+=newEventHandler(OnError);
ErrorSignal.Get(application).Raised+=newErrorSignalEventHandler(OnErrorSignaled);
}
///<summary>
///Getsthe<seecref="ErrorLog"/>instancetowhichthemodule
///willlogexceptions.
///</summary>
protectedvirtualErrorLogGetErrorLog(HttpContextcontext)
{
returnErrorLog.GetDefault(context);
}
///<summary>
///Thehandlercalledwhenanunhandledexceptionbubblesupto
///themodule.
///</summary>
protectedvirtualvoidOnError(objectsender,EventArgsargs)
{
HttpApplicationapplication=(HttpApplication)sender;
LogException(application.Server.GetLastError(),application.Context);
}
///<summary>
///Thehandlercalledwhenanexceptionisexplicitlysignaled.
///</summary>
protectedvirtualvoidOnErrorSignaled(objectsender,ErrorSignalEventArgsargs)
{
LogException(args.Exception,args.Context);
}
///<summary>
///Logsanexceptionanditscontexttotheerrorlog.
///</summary>
protectedvirtualvoidLogException(Exceptione,HttpContextcontext)
{
if(e==null)
thrownewArgumentNullException("e");
//
//Fireaneventtocheckiflistenerswanttofilterout
//loggingoftheuncaughtexception.
//
ExceptionFilterEventArgsargs=newExceptionFilterEventArgs(e,context);
OnFiltering(args);
if(args.Dismissed)
return;
//
//Logaway...
//
ErrorLogEntryentry=null;
try
{
Errorerror=newError(e,context);
ErrorLoglog=GetErrorLog(context);
stringid=log.Log(error);
entry=newErrorLogEntry(log,id,error);
}
catch(ExceptionlocalException)
{
//
//IMPORTANT!Weswallowanyexceptionraisedduringthe
//loggingandsendthemouttothetrace.Theidea
//hereisthatloggingofexceptionsbyitselfshouldnot
//becriticaltotheoveralloperationoftheapplication.
//ThebadthingisthatwecatchANYkindofexception,
//evensystemonesandpotentiallyletthemslipby.
//
Trace.WriteLine(localException);
}
if(entry!=null)
OnLogged(newErrorLoggedEventArgs(entry));
}
///<summary>
///Raisesthe<seecref="Logged"/>event.
///</summary>
protectedvirtualvoidOnLogged(ErrorLoggedEventArgsargs)
{
ErrorLoggedEventHandlerhandler=Logged;
if(handler!=null)
handler(this,args);
}
///<summary>
///Raisesthe<seecref="Filtering"/>event.
///</summary>
protectedvirtualvoidOnFiltering(ExceptionFilterEventArgsargs)
{
ExceptionFilterEventHandlerhandler=Filtering;
if(handler!=null)
handler(this,args);
}
///<summary>
///Determineswhetherthemodulewillberegisteredfordiscovery
///inpartialtrustenvironmentsornot.
///</summary>
protectedoverrideboolSupportDiscoverability
{
get{returntrue;}
}
}

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

更多的功能等待您去挖掘,我们在实际开发中按需选择.希望这篇POST对您开发有帮助.

你可能感兴趣的文章:
在VS2010中配制Elmah邮件发送到Gmail
HttpModule应用:
使用HttpModules实现Asp.net离线应用程序
Asp.net使用HttpModule压缩并删除空白Html请求

Asp.net移除Server,X-Powered-By,和X-AspNet-Version头
EnterpriseLibrary:

使用Fluent配置API驱动EnterpriseLibrary5.0
EneterpriseLibrary5的Fluent配制API

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

作者:PetterLiu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-PetterLiuBlog。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐
章节导航