背景:
项目架构是webservice做服务端,通过json来传递数据。前端有安卓、IOS、PHP几个团队。前端团队经常反馈遇到服务调用失败的情况,但是我们查看代码发现服务并没什么问题,所以经常会发生扯皮的情况,基于这个前提下,做一个记录前端请求的模块,记录前端请求的参数是否正确。
需求:
记录某些重要的请求的WebMethod及其请求的信息。
方案:
1.直接在每个WebMethod里修改,添加记录日志的代码
2.重写IHttpModule记录请求,自定义HttpApplication的BeginRequest事件记录日志。
3.添加全局应用程序记录请求,在Application_BeginRequest里记录日志。
4.使用特性,新增中间层继承ContextBoundObject,通过传递上下文来记录日志。
分析:
1.第1种需要改动现有的WebMethod,破坏原有结构。
2.第2种和第3种其实是一样的,都可以接收到所有的请求。
3.第4种非常灵活,可以在想要的WebMethod上添加,且不会修改到原有的逻辑。但是新增中间层传递上下文无疑是增加了结构发复杂性,考虑到现有项目已经比较大了,不想牵一发而动全身。
选择:
先定义一个用于标记是否需要写日志的特性,重写IHttpMoudule,拿到请求的文件及方法,通过反射判断该方法是否包含需要写日志的特性。
实现:
新增一个类RequestLogAttribute.cs继承Attribute,并且设置应用级别为方法。
[AttributeUsage(AttributeTargets.Method)] public class RequestLogAttribute : Attribute { }
新增一个类RequestLoggerHttpModule.cs继承IHttpModule,并实现Init方法。在Init方法中添加自定义事件HttpApplication.BeginRequest,可以拿到我们熟悉的HttpRequest、HttpContext、HttpResponse。
public class RequestLoggerHttpModule : IHttpModule { public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(Application_BeginRequest); } void Application_BeginRequest(object sender, EventArgs e) { HttpApplication application = sender as HttpApplication; HttpContext context = application.Context; HttpRequest request = application.Request; HttpResponse response = application.Response; } public void Dispose(){} }
同时,在Web.Config里添加节点
<system.webServer> <modules> <add name="RequestLoggerHttpModule" type="命名空间.RequestLoggerHttpModule,程序集名"></add> </modules> </system.webServer>
有了HttpRequest之后,用反射拿到请求的方法,并且判断是否不是存在我们定义的特性。
#region 是否存在记录日志的特性 /// <summary> /// 是否存在记录日志的特性 /// </summary> /// <param name="request"></param> /// <returns></returns> bool LogAttribute(HttpRequest request) { string extension = request.CurrentExecutionFilePathExtension; if (string.IsNullOrEmpty(extension)) return false; string filePath = request.FilePath.Replace(extension, string.Empty); int last = filePath.LastIndexOf('/');//取最后一个/ filePath = filePath.Substring(last, filePath.Length - last); string className = filePath.Replace("/", string.Empty); string methodName = request.PathInfo.Replace("/", string.Empty); Type t = Type.GetType(className); if (t == null || string.IsNullOrEmpty(methodName)) return false; MethodInfo method = t.GetMethod(methodName); if (method == null) return false; object[] attributes = method.GetCustomAttributes(typeof(RequestLogAttribute), false); if (attributes == null || attributes.Length <= 0) return false; return true; } #endregion
所有请求的信息都包含在HttpRequest中,这个不再赘述。如有疑问可以参考:HttpRequest
使用方法也很简单
[WebMethod] [RequestLog] public void Test() { }