WCF技術剖析之二:再談IIS與ASP.NET管道

原文: WCF技術剖析之二:再談IIS與ASP.NET管道

在2007年9月份,我曾經寫了三篇詳細介紹IIS架構和ASP.NET運行時管道的文章,深刻介紹了IIS 5.x與IIS 6.0HTTP請求的監聽與分發機制,以及ASP.NET運行時管道對HTTP請求的處理流程:php

[原創]ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI
[原創]ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline - Part I
[原創]ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline - Part II css

不少人留言爲什麼沒有IIS 7的介紹。在寫做《WCF深刻剖析》中,爲了剖析基於IIS的WCF服務寄宿(Hosting),再次對相關內容進行了研究,在這裏一併與你們分享。html

IIS 5.x與ASP.NETweb

咱們先來看看IIS 5.x是如何處理基於ASP.NET資源(好比.aspx,.asmx等)請求的,整個過程基本上能夠經過圖1體現。 數據庫

IIS 5.x運行在進程InetInfo.exe中,在該進程中一個最重要的服務就是名爲World Wide Web Publishing Service(簡稱W3SVC)的Windows Service。W3SVC的主要功能包括HTTP請求的監聽、工做進程的管理以及配置管理(經過從Metabase中加載相關配置信息)等。 編程

當檢測到某個HTTP Request後,先根據擴展名判斷請求的是不是靜態資源(好比.html,.img,.txt,.xml等),若是是則直接將文件內容以HTTP Response的形式返回。若是是動態資源(好比.aspx,asp,php等等),則經過擴展名從IIS的腳本影射(Script Map)找到相應的ISAPI Dll。 api

clip_image002
 

 圖1 IIS 5.x與ASP.NET 緩存

ISAPI是Internet服務器API(Internet Server Application Programming Interface)的縮寫,是一套本地的(Native)Win32 API,具備較高的執行性能,是IIS和其餘動態Web應用或者平臺之間的紐帶。好比ASP ISAPI橋接IIS與ASP,而ASP.NET ISAPI則鏈接着IIS與ASP.NET。ISPAI定義在一個Dll中,ASP.NET ISAPI對應的Dll爲Aspnet_isapi.dll,你能夠在目錄「%windir%\Microsoft.NET\Framework\{version no}\」中找到該Dll。 安全

ISAPI支持ISAPI擴展(ISAPI Extension)和ISAPI篩選(ISAPI Filter),前者是真正處理HTTP請求的接口,後者則能夠在HTTP請求真正被處理以前查看、修改、轉發或者拒絕請求,好比IIS能夠利用ISAPI篩選進行請求的驗證(Authentication)。 服務器

若是咱們請求的是一個基於ASP.NET的資源類型,好比:.aspx Web Page、 .asmx Web Service或者.svc WCF Service等,Aspnet_isapi.dll會被加載,ASP.NET ISAPI擴展會建立ASP.NET的工做進程(若是該進程還沒有啓動),對於IIS 5.x來講,該工做進程爲aspnet.exe。IIS進程與工做進程之間經過命名管道(Named Pipes)進程通訊,以得到最好的性能。

在工做進程初始化過程當中,.NET 運行時(CLR)被加載,從而構建了一個託管的環境。對於某個Web應用的初次請求,CLR會爲其建立一個AppDomain。在此AppDomain中,HTTP運行時(HTTP Runtime)被加載並用以建立相應的應用。對於寄宿於IIS 5.x的全部Web 應用都運行在同一個進程(工做進程Aspnet_wp.exe)的不一樣AppDomain中。

IIS 6與ASP.NET

經過上面的介紹,咱們能夠看出IIS 5.x至少存在着以下兩個方面的不足:

  • ISAPI Dll被加載到InetInfo.exe進程中,它和工做進程之間是一種典型的跨進程通訊方式,儘管採用性能最好的命名管道,可是仍然會帶來性能的瓶頸;
  • 全部的ASP.NET應用,運行在相同的進程(aspnet_wp.exe)中的不一樣的應用程序域(AppDomain)中,基於應用程序域的隔離級別不能從根本上解決一個應用程序對另外一個程序的影響,在更多的時候,咱們須要不一樣的Web應用運行在不一樣的進程中。

在IIS 6.0中,爲了解決第一個問題,ISAPI.dll被直接加載到工做進程中。爲了解決第2個問題,引入了應用程序池(Application Pool)的機制。咱們能夠爲一個或者多個Web應用建立應用程序池,每個應用程序池對應一個獨立的工做進程,從而爲運行在不一樣應用程序池中的Web應用提供基於進程的隔離級別。IIS 6.0的工做進程名稱爲w3wp.exe。

固然,除了上面兩點改進以外,IIS 6.0還有其餘一些值得稱道的地方,其中最重要的一點就是建立了一個新的HTTP監聽器:HTTP協議棧(HTTP Protocol Stack,HTTP.SYS)。HTTP.SYS運行在Windows的內核模式(Kernel Mode)下,做爲驅動程序而存在。它是Windows 2003的TCP/IP網絡子系統的一部分,從結構上,它屬於TCP之上的一個網絡驅動程序。嚴格地說,HTTP.SYS已經不屬於IIS的範疇了,因此HTTP.SYS的配置信息並不保存在IIS的元數據庫(Metabase),而是定義在註冊表中。HTTP.SYS的註冊表項位於下面的路徑中:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/HTTP。HTTP.SYS可以帶來以下的好處:

  • 持續監聽:因爲HTTP.SYS是一個網絡驅動程序,始終處於運行狀態,對於用戶的HTTP請求,可以及時做出反應;
  • 更好的穩定性:HTTP.SYS運行在操做系統內核模式下,並不執行任何用戶代碼,因此其自己不會受到Web應用、工做進程和IIS進程的影響;
  • 內核模式下數據緩存:若是某個資源被頻繁請求,HTTP.SYS會把響應的內容進行緩存,緩存的內容能夠直接響應後續的請求。因爲這是基於內核模式的緩存,不存在內核模式和用戶模式的切換,響應速度將獲得極大的改進。

圖2體現了IIS的結構和處理HTTP請求的流程。從中能夠看出,與IIS 5.x不一樣,W3SVC從InetInfo.exe進程脫離出來(對於IIS6.0來講,InetInfo.exe基本上能夠看做單純的IIS管理進程),運行在另外一個進程SvcHost.exe中。不過W3SVC的基本功能並無發生變化,只是在功能的實現上做了相應的改進。與IIS 5.x同樣,元數據庫(Metabase)依然存在於InetInfo.exe進程中。

clip_image004
 

 圖2 IIS 6與ASP.NET

當HTTP.SYS監聽到用戶的HTTP請求後,將其分發給W3SVC。W3SVC解析出請求的URL,並根據從Metabase獲取的URL與Web應用之間的映射關係獲得目標應用,並進一步獲得目標應用運行的應用程序池或者工做進程。若是工做進程不存在(還沒有建立或者被回收),則爲該請求建立新的工做進程,工做進程的這種建立方式被稱爲請求式建立。在工做進程的初始化過程當中,相應的ISAPI.dll被加載,對於ASP.NET應用來講,被加載的ISAPI.dll爲Aspnet_ispai.dll。ASP.NET ISAPI再負責進行CLR的加載、AppDomain建立、Web Application的初始化等。

IIS 7.0與ASP.NET

IIS 7.0對請求的監聽和分發機制上又進行了革新性的改進,主要體如今對於Windows進程激活服務(Windows Process Activation Service,WAS)的引入,將原來(IIS 6.0)W3SVC承載的部分功能分流給了WAS。具體來講,經過上面的介紹,咱們知道對於IIS 6.0來講,W3SVC主要承載着三大功能:

  • HTTP請求接收:接收HTTP.SYS監聽到的HTTP請求;
  • 配置管理:從元數據庫(Metabase)中加載配置信息對相關組件進行配置;
  • 進程管理:建立、回收、監控工做進程。

在IIS 7.0,後兩組功能被移入WAS中,接收HTTP請求的任務依然落在W3SVC頭上。WAS的引入爲IIS 7.0一項史無前例的特性:同時處理HTTP和非HTTP請求。在WAS中,經過一個重要的接口:監聽器適配器接口(Listener Adapter Interface)抽象出不一樣協議監聽器監聽到的請求。至於IIS下的監聽器,除了基於網絡驅動的HTTP.SYS提供HTTP請求監聽功能外,WCF提供了3種類型的監聽器:TCP監聽器、命名管道(Named Pipes)監聽器和MSMQ監聽器,分別提供了基於TCP、命名管道和MSMQ傳輸協議的監聽功能。與此3種監聽器相對的,是3種監聽器適配器(Adapter)提供監聽器與監聽器適配器接口之間的適配。從這個意義上講,IIS 7.0中的W3SVC更多地爲HTTP.SYS起着監聽適配器的功能。WCF提供的這3種監聽器和監聽適配器定義在程序集SMHost.exe中,你能夠經過下面的目錄找到該程序集:%windir%\Microsoft.NET\Framework\v3.0\Windows Communication Foundatio。

WCF提供的這3種監聽器和監聽適配器最終以Windows Service的形式體現,雖然它們定義在一個程序集中,咱們依然經過服務工做管理器(SCM,Service Control Manager)對其進行單獨的啓動、終止和配置。SMHost.exe提供了4個重要的Windows Service:

  • NetTcpPortSharing爲WCF提供TCP端口共享,關於端口共享;
  • NetTcpActivator爲WAS提供基於TCP的激活請求,包含TCP監聽器和對應的監聽適配器;
  • NetPipeActivator爲WAS提供基於命名管道的激活請求,包含命名管道監聽器和對應的監聽適配器;
  • NetMsmqActivator爲WAS提供基於MSMQ的激活請求,包含MSMQ監聽器和對應的監聽適配器。

圖3爲上述的4個Windows Service在服務控制管理器(SCM)中的呈現。

clip_image006 

圖3 定義在SMHost.exe中的Windows Service

圖4揭示了IIS 7.0的總體構架以及整個請求處理流程。不管是從W3SVC接收到的HTTP請求,仍是經過WCF提供的監聽適配器接收到的請求,最終都會傳遞到WAS。若是相應的工做進程(或者應用程序池)還沒有建立,其建立之;不然將請求分發給對應的工做進程進行後續的處理。WAS在進行請求處理過程當中,經過內置的配置管理模塊加載相關的配置信息對相關的組建進行配置,與IIS 5.x和IIS 6.0基於Metabase的配置信息存儲不一樣的是,IIS 7.0大都將配置信息存放於XML形式的配置文件中。基本的配置存放在applicationHost.cofig中。

clip_image008 
圖4 IIS 7與ASP.NET

 

ASP.NET集成

從上面對IIS 5.x和IIS 6.0的介紹中,咱們不難發現這一點,IIS與ASP.NET是兩個相互獨立的管道(Pipeline),在各自管轄範圍內,它們各自具備本身的一套機制對HTTP請求進行處理。兩個管道經過ISAPI實現「聯通」:IIS是第一道屏障,當對HTTP請求進行必要的前期處理(好比身份驗證等)後,經過ISAPI將請求分發給ASP.NET管道。當ASP.NET在自身管道範圍內完成對HTTP請求的處理後,處理後的結果再返回到IIS,IIS對其進行後期處理(好比日誌記錄、壓縮等),最終生成HTTP響應(HTTP Response)。從另外一個角度講,IIS運行在非託管的環境中,而ASP.NET管道則是託管的,從這個意義上講,ISAPI仍是鏈接非託管環境和託管環境的紐帶。圖5反映了IIS 6.0與ASP.NET之間的橋接關係。

clip_image012 

圖5 基於IIS 6.0與ASP.NET雙管道設計

IIS 5.x和IIS 6.0下把兩個管道進行隔離至少帶來了下面一些侷限與不足:

  • 相同操做的重複執行:IIS與ASP.NET之間具備一些重複的操做,好比身份驗證;
  • 動態文件與靜態文件處理的不一致:由於只有基於ASP.NET的動態文件(好比.aspx、.asmx、.svc等等)的HTTP請求才能經過ASP.NET ISAPI進入ASP.NET管道,而對於一些靜態文件(好比.html、.xml、.img等)的請求,則由IIS直接響應,那麼ASP.NET管道中的一些功能將不能用於這些基於靜態文件的請求,好比,咱們但願經過Forms認證應用於基於圖片文件的請求;
  • IIS難以擴展:對於IIS的擴展基本上就體如今自定義ISAPI,可是對於大部分人來講,這不是一件容易的事情。由於ISAPI是基於Win32的非託管的API,並不是一種面向應用的編程接口。一般咱們但願的是諸如定義ASP.NET的HttpModule和HttpHandler同樣,經過託管代碼的方式來擴展IIS。

對於Windows平臺下的IIS來說,ASP.NET無疑是一等公民,它們之間不該該是「井水不犯河水」的關係,而應該是「你中有我,我中有你」的關係。爲此,在IIS 7.0中,實現了二者的集成。對於集成模式下的IIS 7.0,咱們得到以下的好處。

  • 容許咱們經過本地代碼(Native Code)和託管代碼(Managed Code)兩種方式定義IIS Module,這些IIS Module註冊到IIS中造成一個通用的請求處理管道。由這些IIS Module組成的這個管道可以處理全部的請求,不論請求基於怎樣的資源類型。好比,能夠將FormsAuthenticationModule提供的Forms認證應用到基於.aspx,CGI和靜態文件的請求。
  • 將ASP.NET提供的一些強大的功能應用到原來難以企及的地方,好比將ASP.NET的URL重寫功能置於身份驗證以前;
  • 採用相同的方式去實現、配置、檢測和支持一些服務器特性(Feature),好比Module、Handler映射、錯誤定製配置(Custom Error Configuration)等。

clip_image014

 圖6 基於IIS 7.0與ASP.NET集成管道設計

圖6演示了在ASP.NET集成模式下,IIS整個請求處理管道的結構。咱們能夠看到,原來ASP.NET提供的託管組件能夠直接應用在IIS管道中。

ASP.NET管道

以IIS 6.0爲例,在工做進程w3wp.exe中,利用Aspnet_ispai.dll加載.NET運行時(若是.NET運行時還沒有加載)。IIS 6引入了應用程序池的概念,一個工做進程對應着一個應用程序池。一個應用程序池能夠承載一個或者多個Web應用,每一個Web應用映射到一個IIS虛擬目錄。與IIS 5.x同樣,每個Web應用運行在各自的應用程序域中。

若是HTTP.SYS接收到的HTTP請求是對該Web應用的第一次訪問,當成功加載了運行時後,會經過AppDomainFactory爲該Web應用建立一個應用程序域(AppDomain)。隨後,一個特殊的運行時IsapiRuntime被加載。IsapiRuntime定義在程序集System.Web中,對應的命名空間爲System.Web.Hosting。IsapiRuntime會接管該HTTP請求。

IsapiRuntime會首先建立一個IsapiWorkerRequest對象,用於封裝當前的HTTP請求,並將該IsapiWorkerRequest對象傳遞給ASP.NET運行時:HttpRuntime,今後時起,HTTP請求正式進入了ASP.NET管道。根據IsapiWorkerRequest對象,HttpRuntime會建立用於表示當前HTTP請求的上下文(Context)對象:HttpContext。

隨着HttpContext被成功建立,HttpRuntime會利用HttpApplicationFactory建立新的或者獲取現有的HttpApplication對象。實際上,ASP.NET維護着一個HttpApplication對象池,HttpApplicationFactory從池中選取可用的HttpApplication用戶處理HTTP請求,處理完畢後將其釋放到對象池中。HttpApplicationFactory負責處理當前的HTTP請求。

在HttpApplication初始化過程當中,會根據配置文件加載並初始化相應的HttpModule對象。對於HttpApplication來講,在它處理HTTP請求的不一樣的階段會觸發不一樣的事件(Event),而HttpModule的意義在於經過註冊HttpApplication的相應的事件,將所需的操做注入整個HTTP請求的處理流程。ASP.NET的不少功能,好比身份驗證、受權、緩存等,都是經過相應的HttpModule實現的。

而最終完成對HTTP請求的處理實如今另外一個重要的對象中:HttpHandler。對於不一樣的資源類型,具備不一樣的HttpHandler。好比.aspx頁對應的HttpHandler爲System.Web.UI.Page,WCF的.svc文件對應的HttpHandler爲System.ServiceModel.Activation.HttpHandler。上面整個處理流程如圖7所示。

clip_image016 

圖7 ASP.NET 處理管道

HttpApplication

HttpApplication是整個ASP.NET基礎架構的核心,它負責處理分發給它的HTTP請求。因爲一個HttpApplication對象在某個時刻只能處理一個請求,只有完成對某個請求的處理後,HttpApplication才能用於後續的請求的處理。因此,ASP.NET採用對象池的機制來建立或者獲取HttpApplication對象。具體來說,當第一個請求抵達的時候,ASP.NET會一次建立多個HttpApplication對象,並將其置於池中,選擇其中一個對象來處理該請求。當處理完畢,HttpApplication不會被回收,而是釋放到池中。對於後續的請求,空閒的HttpApplication對象會從池中取出,若是池中全部的HttpApplication對象都處於繁忙的狀態,ASP.NET會建立新的HttpApplication對象。

HttpApplication處理請求的整個生命週期是一個相對複雜的過程,在該過程的不一樣階段會觸發相應的事件。咱們能夠註冊相應的事件,將咱們的處理邏輯注入到HttpApplication處理請求的某個階段。咱們接下來介紹的HttpModule就是經過HttpApplication事件註冊的機制實現相應的功能的。表1按照實現的前後順利列出了HttpApplication在處理每個請求時觸發的事件名稱。

表1

名稱

描述

BeginRequest

HTTP管道開始處理請求時,會觸發BeginRequest事件

AuthenticateRequest,PostAuthenticateRequest

ASP.NET前後觸發這兩個事件,使安全模塊對請求進行身份驗證

AuthorizeRequest,PostAuthorizeRequest

ASP.NET前後觸發這兩個事件,使安全模塊對請求進程受權

ResolveRequestCache,PostResolveRequestCache

ASP.NET前後觸發這兩個事件,以使緩存模塊利用緩存的直接對請求直接進程響應(緩存模塊能夠將響應內容進程緩存,對於後續的請求,直接將緩存的內容返回,從而提升響應能力)。

PostMapRequestHandler

對於訪問不一樣的資源類型,ASP.NET具備不一樣的HttpHandler對其進程處理。對於每一個請求,ASP.NET會經過擴展名選擇匹配相應的HttpHandler類型,成功匹配後,該實現被觸發

AcquireRequestState,PostAcquireRequestState

ASP.NET前後觸發這兩個事件,使狀態管理模塊獲取基於當前請求相應的狀態,好比SessionState

PreRequestHandlerExecute,PostRequestHandlerExecute

ASP.NET最終經過一請求資源類型相對應的HttpHandler實現對請求的處理,在實行HttpHandler先後,這兩個實現被前後觸發

ReleaseRequestState,PostReleaseRequestState

ASP.NET前後觸發這兩個事件,使狀態管理模塊釋放基於當前請求相應的狀態

UpdateRequestCache,PostUpdateRequestCache

ASP.NET前後觸發這兩個事件,以使緩存模塊將HttpHandler處理請求獲得的相應保存到輸出緩存中

LogRequest,PostLogRequest

ASP.NET前後觸發這兩個事件爲當前請求進程日誌記錄

EndRequest

整個請求處理完成後,EndRequest事件被觸發

對於一個ASP.NET應用來講,HttpApplication派生於global.asax文件,咱們能夠經過建立global.asax文件對HttpApplication的請求處理行爲進行定製。global.asax採用一種很直接的方式實現了這樣的功能,這種方式既不是咱們經常使用的方法重寫(Method Overriding)或者事件註冊,而是直接採用方法名匹配。在global.asax中,咱們按照這樣的方法命名規則進行事件註冊:Application_{Event Name}。好比Application_BeginRequest方法用於處理HttpApplication的BeginRequest事件。若是經過VS建立一個global.asax文件,下面是默認的定義。

   1: <%@ Application Language="C#" %>
   2: <script runat="server">
   3: void Application_Start(object sender, EventArgs e) {}
   4: void Application_End(object sender, EventArgs e) {}
   5: void Application_Error(object sender, EventArgs e) {}
   6: void Session_Start(object sender, EventArgs e) {}
   7: void Session_End(object sender, EventArgs e) {}
   8: </script>

HttpModule

ASP.NET爲建立各類.NET Web應用提供了強大的平臺,它擁有一個具備高度可擴展性的引擎,而且可以處理對於不一樣資源類型的請求。那麼,是什麼成就了ASP.NET的高可擴展性呢? HttpModule功不可沒。

從功能上講,HttpModule之於ASP.NET,就比如ISAPI Filter之於IIS同樣。IIS將接收到的請求分發給相應的ISAPI Extension以前,註冊的ISAPI Filter會先截獲該請求。ISAPI Filter能夠獲取甚至修改請求的內容,完成一些額外的功能。與之類似地,當請求轉入ASP.NET管道後,最終負責處理該請求的是與請求資源類型相匹配的HttpHandler對象,可是在Handler正式工做以前,ASP.NET會先加載並初始化全部配置的HttpModule對象。HttpModule在初始化的過程當中,會將一些功能註冊到HttpApplication相應的事件中,那麼在HttpApplication整個請求處理生命週期中的某個階段,相應的事件會被觸發,經過HttpModule註冊的事件處理程序也得以執行。

全部的HttpModule都實現了IHttpModule接口,下面是IHttpModule的定義。其中Init方法用於實現HttpModule自身的初始化,該方法接受一個HttpApplication對象,有了這個對象,事件註冊就很容易了。

   1: public interface IHttpModule
   2: {
   3:      void Dispose();
   4:     void Init(HttpApplication context);
   5: }

ASP.NET提供的不少基礎構件(Infrastructure)功能都是經過相應的HttpModule實現的,下面類列出了一些典型的HttpModule:

  • OutputCacheModule:實現了輸出緩存(Output Caching)的功能;
  • SessionStateModule:在無狀態的HTTP協議上實現了基於會話(Session)的狀態;
  • WindowsAuthenticationModule + FormsAuthenticationModule + PassportAuthentication- Module:實現了3種典型的身份認證方式:Windows認證、Forms認證和Passport認證;
  • UrlAuthorizationModule + FileAuthorizationModule:實現了基於Uri和文件ACL(Access Control List)的受權。

而另一個重要的HttpModule與WCF相關,那麼就是System.ServiceModel. Activation.HttpModule。HttpModule定義在System.ServiceModel程序集中,在默認的狀況下,HttpModule完成了基於IIS的寄宿工做。

除了這些系統定義的HttpModule以外,咱們還能夠自定義HttpMoudle。經過Web.config,咱們能夠很容易地將其註冊到咱們的Web應用中。

HttpHandler

若是說HttpModule至關於IIS的ISAPI Filter的話,咱們能夠說HttpHandler則至關於IIS的ISAPI Extension,HttpHandler在ASP.NET中扮演請求的最終處理者的角色。對於不一樣資源類型的請求,ASP.NET會加載不一樣的Handler來處理,也就是說.aspx page與.asmx web service對應的Handler是不一樣的。

全部的HttpHandler都實現了接口IHttpHandler。下面是IHttpHandler的定義,方法ProcessRequest提供了處理請求的實現。

   1: public interface IHttpHandler
   2: {
   3:     void ProcessRequest(HttpContext context);
   4:     bool IsReusable { get; }
   5: }

對於某些HttpHandler,具備一個與之相關的HttpHandlerFactory,用於建立或者獲取相應的HttpHandler。HttpHandlerFactory實現接口IHttpHandlerFactory,方法GetHandler用於建立新的HttpHandler,或者獲取已經存在的HttpHandler。

   1: public interface IHttpHandlerFactory
   2: {
   3:     IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);
   4:     void ReleaseHandler(IHttpHandler handler);
   5: }

HttpHandler和HttpHandlerFactory的類型均可以經過相同的方式配置到Web.config中。下面一段配置包含對3種典型的資源類型的HttpHandler配置:.aspx,.asmx和.svc。能夠看到基於WCF Service的HttpHandler類型爲:System.ServiceModel.Activation.HttpHandler。

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3: <system.web>
   4: <httpHandlers>
   5: <add path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
   6: <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
   7: <add path="*.asmx" verb="*" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="False"/>
   8: </httpHandlers>
   9: </system.web>
  10: </configuration>
做者: Artech
出處: http://artech.cnblogs.com 本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。
相關文章
相關標籤/搜索