ASP.NET-自定义HttpModule与HttpHandler

在之前的ASP.NET是如何在IIS下工作的这篇文章中介绍了ASP.NET与IIS配合工作的机制,在http请求经过一系列处理后,最后到达ASP.NET管道中,这时,就是Http Modules和HttpHandler出场的时候了。

再来摆出管道工作时序图来一看:

HttpModule

HttpModule是类似于过滤器的作用,可以没有,也可以有任意个,每一个都可以订阅管道事件中的任意个事件,在每个订阅的事件中可自定义功能实现。

HttpModule是实现IHttpModule接口的类。接口如下:

public interface IHttpModule
    {
        // 摘要: 
        //     处置由实现 System.Web.IHttpModule 的模块使用的资源(内存除外)。
        void Dispose();
        //
        // 摘要: 
        //     初始化模块,并使其为处理请求做好准备。
        //
        // 参数: 
        //  context:
        //  一个 System.Web.HttpApplication,它提供对 ASP.NET 应用程序内所有应用程序对象的公用的方法、属性和事件的访问
        void Init(HttpApplication context);
    }

下面实现一个HttpModule,并订阅管道中的一系列事件,订阅事件就是在Init方法中绑定EventHandler的过程:

代码有点长,因为我把每一个事件都订阅了,这样一来可以清楚的看出哪些事件执行了,这些事件执行的先后顺序是什么。代码如下:

public class MyModule : IHttpModule
    {
        #region IHttpModule Members

        public void Dispose()
        {
            //此处放置清除代码。
        }

        public void Init(HttpApplication context)
        {
            // 下面是如何处理 LogRequest 事件并为其 
            // 提供自定义日志记录实现的示例
            context.LogRequest += new EventHandler(OnLogRequest);
            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
            context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
            context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest);
            context.Disposed += new EventHandler(context_Disposed);
            context.Error += new EventHandler(context_Error);
            context.EndRequest += new EventHandler(context_EndRequest);
            context.MapRequestHandler += new EventHandler(context_MapRequestHandler);
            context.PostAcquireRequestState += new EventHandler(context_PostAcquireRequestState);
            context.PostAuthenticateRequest += new EventHandler(context_PostAuthenticateRequest);
            context.PostAuthorizeRequest += new EventHandler(context_PostAuthorizeRequest);
            context.PostLogRequest += new EventHandler(context_PostLogRequest);
            context.PostReleaseRequestState += new EventHandler(context_PostReleaseRequestState);
            context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute);
            context.PostResolveRequestCache += new EventHandler(context_PostResolveRequestCache);
            context.PostUpdateRequestCache += new EventHandler(context_PostUpdateRequestCache);
            context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState);
            context.RequestCompleted += new EventHandler(context_RequestCompleted);
            context.ResolveRequestCache += new EventHandler(context_ResolveRequestCache);
            context.UpdateRequestCache += new EventHandler(context_UpdateRequestCache);
            context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
            context.PreSendRequestContent += new EventHandler(context_PreSendRequestContent);
            context.PreSendRequestHeaders += new EventHandler(context_PreSendRequestHeaders);
            context.PostMapRequestHandler += new EventHandler(context_PostMapRequestHandler);


        }

        void context_Error(object sender, EventArgs e)
        {
            WriteLog("Error");
            //HttpContext.Current.Response.Write("Error<br />");
        }

        void context_UpdateRequestCache(object sender, EventArgs e)
        {
            WriteLog("UpdateRequestCache");
            //HttpContext.Current.Response.Write("UpdateRequestCache<br />");
        }

        void context_ResolveRequestCache(object sender, EventArgs e)
        {
            WriteLog("ResolveRequestCache");
            // HttpContext.Current.Response.Write("ResolveRequestCache<br />");
        }

        void context_RequestCompleted(object sender, EventArgs e)
        {
            WriteLog("RequestCompleted");
            // HttpContext.Current.Response.Write("RequestCompleted<br />");
        }

        void context_ReleaseRequestState(object sender, EventArgs e)
        {
            WriteLog("ReleaseRequestState");
            //HttpContext.Current.Response.Write("ReleaseRequestState<br />");
        }

        void context_PostUpdateRequestCache(object sender, EventArgs e)
        {
            WriteLog("PostUpdateRequestCache");
            //HttpContext.Current.Response.Write("PostUpdateRequestCache<br />");
        }

        void context_PostResolveRequestCache(object sender, EventArgs e)
        {
            WriteLog("PostResolveRequestCache");
            //HttpContext.Current.Response.Write("PostResolveRequestCache<br />");
        }

        void context_PostRequestHandlerExecute(object sender, EventArgs e)
        {
            WriteLog("PostRequestHandlerExecute");
            //HttpContext.Current.Response.Write("PostRequestHandlerExecute<br />");
        }

        void context_PostReleaseRequestState(object sender, EventArgs e)
        {
            WriteLog("PostReleaseRequestState");
            //HttpContext.Current.Response.Write("PostReleaseRequestState<br />");
        }

        void context_PostLogRequest(object sender, EventArgs e)
        {
            WriteLog("PostLogRequest");
            //HttpContext.Current.Response.Write("PostLogRequest<br />");
        }

        void context_PostAuthorizeRequest(object sender, EventArgs e)
        {
            WriteLog("PostAuthorizeRequest");
            //HttpContext.Current.Response.Write("PostAuthorizeRequest<br />");
        }

        void context_PostAuthenticateRequest(object sender, EventArgs e)
        {
            WriteLog("PostAuthenticateRequest");
            //HttpContext.Current.Response.Write("PostAuthenticateRequest<br />");
        }

        void context_PostAcquireRequestState(object sender, EventArgs e)
        {
            WriteLog("PostAcquireRequestState");
            //HttpContext.Current.Response.Write("PostAcquireRequestState<br />");
        }

        void context_MapRequestHandler(object sender, EventArgs e)
        {
            WriteLog("MapRequestHandler");
            //HttpContext.Current.Response.Write("MapRequestHandler<br />");
        }

        void context_Disposed(object sender, EventArgs e)
        {
            WriteLog("Disposed");
            //HttpContext.Current.Response.Write("Disposed<br />");
        }

        void context_AuthorizeRequest(object sender, EventArgs e)
        {
            WriteLog("AuthorizeRequest");
            //HttpContext.Current.Response.Write("AuthorizeRequest<br />");
        }

        void context_AcquireRequestState(object sender, EventArgs e)
        {
            WriteLog("AcquireRequestState");
            //HttpContext.Current.Response.Write("AcquireRequestState<br />");
        }


        void context_PreSendRequestHeaders(object sender, EventArgs e)
        {
            WriteLog("PreSendRequestHeaders");
            //HttpContext.Current.Response.Write("PreSendRequestHeaders<br />");
        }

        void context_PreSendRequestContent(object sender, EventArgs e)
        {
            WriteLog("PreSendRequestContent");
            //HttpContext.Current.Response.Write("PreSendRequestContent<br />");
        }

        void context_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            WriteLog("PreRequestHandlerExecute");
            //HttpContext.Current.Response.Write("PreRequestHandlerExecute<br />");
        }

        void context_EndRequest(object sender, EventArgs e)
        {
            WriteLog("EndRequest");
            //HttpContext.Current.Response.Write("EndRequest<br />");
        }

        void context_BeginRequest(object sender, EventArgs e)
        {
            WriteLog("*******************************************************************************");
            HttpApplication app = sender as HttpApplication;
            WriteLog(app.Context.Request.Path);
            WriteLog("BeginRequest");
            //HttpContext.Current.Response.Write("BeginRequest<br />");
        }

        void context_AuthenticateRequest(object sender, EventArgs e)
        {
            WriteLog("AuthenticateRequest");
            //HttpContext.Current.Response.Write("AuthenticateRequest<br />");
        }
        #endregion

        public void OnLogRequest(Object source, EventArgs e)
        {
            //可以在此处放置自定义日志记录逻辑
            WriteLog("OnLogRequest");
            //HttpContext.Current.Response.Write("OnLogRequest<br />");
        }

        public void context_PostMapRequestHandler(object sender, EventArgs e)
        {
            WriteLog("PostMapRequestHandler");
            //HttpContext.Current.Response.Write("PostMapRequestHandler<br />");
        }

        public void WriteLog(string message)
        {
            string path = @"d:\aspnet\httpmodule.txt";
            StreamWriter writer = null;
            if (!File.Exists(path))
            {
                writer = File.CreateText(path);
            }
            else
            {
                FileInfo info = new FileInfo(path);
                writer = info.AppendText();

            }
            writer.WriteLine(message);

            writer.Flush();
            writer.Close();
        }
    }

订阅的事件实现中,将事件名称保存到我本地D盘的一个文本文件中。

代码实现完毕了,下一步就是要代码起作用了,很简单,只需要在web.config中简单配置就可以了。配置中注意IIS7集成模式和IIS7经典模式(包括IIS6)的区别,配置如下:

<!--IIS6或者IIS7经典模式-->
<system.web>
    <httpModules>
      <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/>
    </httpModules>
  </system.web>
<!--IIS7集成模式-->
<system.webServer>
    <modules>
      <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/>
    </modules>
</system.webServer>

如此一来,一个HttpModule及其配置工作就完成了,接下来,发布网站到IIS或者直接在VS中运行,随便访问项目中的一个文件(任何文件类型都可以),我的项目中有一个WebForm2.aspx的页面,我在浏览器中访问这个页面,发现页面是空白的,因为页面中我什么都没写,上面的Module实现中,我把输出全部放到本地D盘的一个文本文件中了,ok,打开那个文本文件。如图:

我们看到输出内容,第2行是访问的页面地址,下面依次为订阅的事件输出,我们清楚的看到了事件的执行顺序。

BeginRequest          		#发出信号表示创建任何给定的新请求。 此事件始终被引发,并且始终是请求处理期间发生的第一个事件
AuthenticateRequest         #发出信号表示配置的身份验证机制已对当前请求进行了身份验证。 订阅 AuthenticateRequest 事件可确保在处理附加模块或事件处理程序之前对请求进行身份验证
PostAuthenticateRequest     #预订 PostAuthenticateRequest 事件的功能可以访问由 PostAuthenticateRequest 处理的任何数据
AuthorizeRequest			#发出信号表示 ASP.NET 已对当前请求进行了授权。 订阅 AuthorizeRequest 事件可确保在处理附加的模块或事件处理程序之前对请求进行身份验证和授权
PostAuthorizeRequest		#发出信号表示 ASP.NET 已对当前请求进行了授权。 订阅 PostAuthorizeRequest 事件可确保在处理附加的模块或处理程序之前对请求进行身份验证和授权
ResolveRequestCache			#引发这个事件来决定是否可以使用从输出缓冲返回的内容来结束请求。这依赖于Web应用程序的输出缓冲时怎样设置的
PostResolveRequestCache		#在 ASP.NET 跳过当前事件处理程序的执行并允许缓存模块满足来自缓存的请求时发生
MapRequestHandler			#ASP.NET 基础结构使用 MapRequestHandler 事件来确定用于当前请求的请求处理程序
PostMapRequestHandler		#在 ASP.NET 已将当前请求映射到相应的事件处理程序时发生
AcquireRequestState			#当 ASP.NET 获取与当前请求关联的当前状态(如会话状态)时发生
PostAcquireRequestState		#预订 AcquireRequestState 事件的功能可以访问由 PostAcquireRequestState 处理的任何数据
PreRequestHandlerExecute	#在ASP.NET开始执行HTTP请求的处理程序之前引发这个事件。在这个事件之后,ASP.NET 把该请求转发给适当的HTTP处理程序
PostRequestHandlerExecute   #在 ASP.NET 事件处理程序(例如,某页或某个 XML Web service)执行完毕时发生
ReleaseRequestState			#在 ASP.NET 执行完所有请求事件处理程序后发生。 该事件将使状态模块保存当前状态数据
PostReleaseRequestState		#在 ASP.NET 已完成所有请求事件处理程序的执行并且请求状态数据已存储时发生
UpdateRequestCache			#当 ASP.NET 执行完事件处理程序以使缓存模块存储将用于从缓存为后续请求提供服务的响应时发生
PostUpdateRequestCache		#在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件
OnLogRequest				#恰好在 ASP.NET 为当前请求执行任何记录之前发生,即使发生错误,也会引发 LogRequest 事件
PostLogRequest				#在 ASP.NET 处理完 LogRequest 事件的所有事件处理程序后发生
EndRequest					#在 ASP.NET 响应请求时作为 HTTP 执行管线链中的最后一个事件发生
PreSendRequestContent		#恰好在 ASP.NET 向客户端发送内容之前发生,可能发生多次
PreSendRequestHeaders		#恰好在 ASP.NET 向客户端发送 HTTP 标头之前发生
RequestCompleted			#在任何托管模块和处理程序执行后,它使模块清理资源

访问一个页面的过程中,依次触发了23个事件,而HttpModule可订阅的事件个数为25个,观察发现,Error和Disposed这两个事件没有触发。Error事件在发生错误的情况下执行,而Disposed事件,当我们关闭刚才打开的页面,再到文本文件里查看,发现Disposed事件出现了,所以Disposed在会话结束后触发。

由于HttpModule的个数可以有多个,我们可以按照上面的方式定义HttpModule实现类,然后再web.config中增加配置项,就可以实现多个HttpModule同时订阅管道事件了。

介绍完HttpModule,那么HttpHandler又是什么呢,它又在什么什么时候执行呢?接下来看一下HttpHandler。

HttpHandler

HttpHandler是HTTP请求的处理中心,真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。  HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。

HttpHandler是实IHttpHandler接口的类,IHttpHandler接口定义如下:

    public interface IHttpHandler
    {
        // 摘要: 
        //     获取一个值,该值指示其他请求是否可以使用 System.Web.IHttpHandler 实例。
        //
        // 返回结果: 
        //     如果 System.Web.IHttpHandler 实例可再次使用,则为 true;否则为 false。
        bool IsReusable { get; }

        // 摘要: 
        //     通过实现 System.Web.IHttpHandler 接口的自定义 HttpHandler 启用 HTTP Web 请求的处理。
        //
        // 参数: 
        //   context:
        //     System.Web.HttpContext 对象,它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session
        //     和 Server)的引用。
        void ProcessRequest(HttpContext context);
    }

接口中只有一个属性和一个方法,所以实现一个HttpHandler也很简单,下面实现一个简单的HttpHandler,代码如下:

public class MyIISHandler : IHttpHandler
    {
        /// <summary>
        /// 您将需要在网站的 Web.config 文件中配置此处理程序 
        /// 并向 IIS 注册它,然后才能使用它。有关详细信息,
        /// 请参见下面的链接: http://go.microsoft.com/?linkid=8101007
        /// </summary>
        #region IHttpHandler Members

        public bool IsReusable
        {
            // 如果无法为其他请求重用托管处理程序,则返回 false。
            // 如果按请求保留某些状态信息,则通常这将为 false。
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            //在此处写入您的处理程序实现。
            WriteLog("请求一个asox页面");
        }

        #endregion
    }

上面我实现了一个很简单的HttpHandler类,在ProcessRequest方法中,调用上面的HttpModule类中写文本文件的方法,在文本文件中写入“请求一个asox页面”,没错,是一个asox页面,我自己定义的文件格式,下面我会在web.config中添加配置项:

<!--IIS6或者IIS7经典模式-->
  <system.web>
    <httpHandlers>
      <add name="mycustomhandler" path="*.asox" verb="*" type="fengzheng.MyIISHandler,handler_modules"/>
    </httpHandlers>
  </system.web>
 
<!--IIS7集成模式-->
  <system.webServer>
    <handlers>
       <add name="mycustomhandler" path="*.asox" verb="*" type="fengzheng.MyIISHandler,handler_modules"/>
    </handlers>
  </system.webServer>

配置项属性的解释:

path:指定了需要调用处理程序的路径和文件名(可以包含通配符)。“*”、“*.aspx”、“booklist.aspx”、“test1.aspx,test2.aspx”、“*.asox”、“*.txt”。

verb:指定了处理程序支持的HTTP动作。*-支持所有的HTTP动作;“GET”-支持Get操作;“POST”-支持Post操作;“GET, POST”-支持两种操作。

type:用名字空间、类名称和程序集名称的组合形式指定处理程序或处理程序工厂的实际类型。ASP.NET运行时首先搜索bin目录中的DLL,接着在GAC中搜索。

接着,发布站点到IIS。打开IIS,找到当前站点的“处理程序映射”,会发现多了刚刚配置的HttpHandler,如图:

没错,关于对*.asox这种类型的文件,就可以映射到上面创建的HttpHandler来进行处理,观察其它条目发现,像*.aspx、*.ashx的处理程序是System.Web.UI.PageHandlerFactory和System.Web.UI.SimpleHandlerFactory这样的工厂类型。没错,可以指定处理程序为一个HttpHandler,也可以指定为一个抽象工厂类型。先不说工厂类型的事儿,访问一下网站中的asox页面,看一下文本文件的记录情况。

起作用了,在HttpModule输出的一堆信息中,夹杂着HttpHandler的输出,当然这仅限于访问asox类型的页面,因为我只对路径为*.asox的文件格式做了设置,修改下配置文件,例如将path=”*.asox”改为path=”*.aspx”,那么ASP.NET对*.aspx页面原有的解析机制将被我们设置的处理程序所覆盖。

回到上面的输出内容,我们观察HttpHandler输出内容所在的位置,位于PreRequestHandlerExecute和PostRequestHandlerExecute这两个事件之间,这与HttpApplication类中的管道事件的创建过程有关。

前面说到了,处理处理程序可以指定为一个工厂类型,下面,我就创建一个工厂类型的处理程序。

这里所说的工厂类型的处理程序,就是实现了IHttpHandlerFactory接口的类,IHttpHandlerFactory接口定义如下:

public interface IHttpHandlerFactory
    {
        // 摘要: 
        //     返回实现 System.Web.IHttpHandler 接口的类的实例。
        //
        // 参数: 
        //   context:
        //     System.Web.HttpContext 类的实例,它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session
        //     和 Server)的引用。
        //
        //   requestType:
        //     客户端使用的 HTTP 数据传输方法(GET 或 POST)。
        //
        //   url:
        //     所请求资源的 System.Web.HttpRequest.RawUrl。
        //
        //   pathTranslated:
        //     所请求资源的 System.Web.HttpRequest.PhysicalApplicationPath。
        //
        // 返回结果: 
        //     处理请求的新的 System.Web.IHttpHandler 对象。
        IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);
        //
        // 摘要: 
        //     使工厂可以重用现有的处理程序实例。
        //
        // 参数: 
        //   handler:
        //     要重用的 System.Web.IHttpHandler 对象。
        void ReleaseHandler(IHttpHandler handler);
    }

同样很简单,也是只有两个接口方法,下面是实现这个接口的工厂,代码如下:

public class MyHttpHandlerFactory:IHttpHandlerFactory
{
        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
			//写日志
            WriteLog(string.Format("requestType:{0}|url:{1}|pathTranslated:{2}", requestType, url, pathTranslated));
            
			//生成一个IHttpHandler
			Type t = typeof(MyIISHandler);
            IHttpHandler handler =  Activator.CreateInstance(t) as IHttpHandler;
            return handler;
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
        }
}

方法中,返回了前面创建的那个HttpHander类,依然调用记录文本文件的方法输出内容,方便观察执行的实际和具体内容。配置文件改改为这个工厂类。

<add name="mycustomFactoryHandler" path="*.asox" verb="*" type="fengzheng.MyHttpHandlerFactory,handler_modules"/>

配置完毕后,访问网站中的asox页面,打开文本文件,内容如下:

我们发现,工厂类中构造IHttpHandler接口的方法发生在HttpModule的MapRequestHandler之后,这同样与HttpApplication类中构造管道事件有关。

说了这么多,那么,HttpModule和HttpHandler究竟能干什么呢?

HttpModule很常用的一个作用就是Url重写,URLRewriter就是基于HttpModule实现的。

另外,有通过HttpHandler对图片加水印,防止盗链的。

具体的可以参考这篇文章

部署网站注意事项:

网站采用.net 4.0集成模式部署,集成模式是一种统一的请求处理管道,它将ASP.NET请求管道与IIS核心管道组合在一起,这种模式能够提供更好的性能,能够实现配置和治理的模块化,而且增加了使用托管代码模块扩展IIS时的灵活性。IIS经典模式与集成模式的区别

集成模式和经典模式的配置文件稍有不同,部署时需要注意针对不同的部署模式,修改配置文件。在vs2013中新建的web应用程序,默认的web.config内容如下:

<?xml version="1.0" encoding="utf-8"?>
<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
</configuration>
  • 按照经典模式部署,配置文件应该如下:
<?xml version="1.0" encoding="utf-8"?>
<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <httpModules>
      <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/>
    </httpModules>
    <httpHandlers>
      <add name="mycustomhandler" path="*.asox" verb="*" type="fengzheng.MyIISHandler,handler_modules"/>
    </httpHandlers>
  </system.web>
</configuration>

经典模式经测试总是出现如下错误,500.21 - 模块无法识别:

HTTP 错误 500.21 - Internal Server Error
处理程序“PageHandlerFactory-ISAPI-4.0_64bit”在其模块列表中有一个错误模块“IsapiModule”

至于错误原因:目前还不是很清楚。

  • 按照集成模式部署,配置文件应该如下,将配置信息放到system.webServer节点之下:
<?xml version="1.0" encoding="utf-8"?>
<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.webServer>
    <modules>
      <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/>
    </modules>
    <handlers>
      <add name="mycustomhandler" path="*" verb="*" type="fengzheng.MyIISHandler,handler_modules"/>
    </handlers>
  </system.webServer>
</configuration>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

img标签的src=""会引起的Page_Load多次执行

今天看见园子里有人因img的src为空导致session丢失,详情见http://www.cnblogs.com/kyneblog/archive/2009/0...

231100
来自专栏王磊的博客

缓存通用管理类 + 缓存 HttpContext.Current.Cache 和 HttpRuntime.Cache 的区别

  以前写asp.net时用HttpContext.Current.Cache存缓存很好用,今天写了一个windows服务程序,HttpContext.Curr...

39670
来自专栏林德熙的博客

C# 获取 PC 序列号

在 C++ 需要使用 GetSystemFirmwareTable 的方法来获得 PC 的序列号,需要写的代码很多,但是在 C# 可以使用 WMI 来拿到序列号

28910
来自专栏C# 编程

[C#]使用ILMerge将源DLL合并到目标EXE(.NET4.6.2)

本文为原创文章,如转载,请在网页明显位置标明原文名称、作者及网址,谢谢! 本文主要是使用微软的ILMerge工具将源DLL合并到目标EXE,因此,需要下载以下工...

1.4K00
来自专栏.net core新时代

分布式中使用Redis实现Session共享(二)

  上一篇介绍了一些redis的安装及使用步骤,本篇开始将介绍redis的实际应用场景,先从最常见的session开始,刚好也重新学习一遍session的实现原...

33060
来自专栏跟着阿笨一起玩NET

System.Threading.Tasks.Task引起的IIS应用程序池崩溃

2. 从服务器端看(Windows Server 2008 + IIS 7.0),在事件日志中会出现Event ID为5010的错误:

34320
来自专栏技术小讲堂

使用Donut Caching和Donut Hole Caching在ASP.NET MVC应用中缓存页面何时使用Donut CachingDonut Caching 的Nuget 包Donut Ho

Donut Caching是缓存除了部分内容以外的整个页面的最好的方式,在它出现之前,我们使用“输出缓存”来缓存整个页面。 何时使用Donut Caching ...

31350
来自专栏ZKEASOFT

纸壳CMS的插件加载机制

纸壳CMS是基于插件化设计的,可以通过扩展插件来实现不同的功能。如何通过插件来扩展,可以参考这篇文章:

13720
来自专栏林德熙的博客

win10 uwp HttpClient post错误

进行HttpClient post参数错误 从“Windows.Web.Http.HttpStringContent”转换为“System.Net.Http.H...

11110
来自专栏码农分享

定时从列表中爬今日通知信息,打包成windows服务

每天8点爬取今日发布的新闻和通知公告,将爬取后的信息保存到Excel文件中,将程序发布成windows服务,开机即可自动启动。

13820

扫码关注云+社区

领取腾讯云代金券