ASP.NET MVC5写.php路由匹配时的问题 ASP.NET MVC 4 在 .NET 4.0 与.NET 4.5 的專案範本差異
由于外包公司结束合作,所以考虑把其APP服务替换过来,因原后台是用php写的,在不影响员客户端使用的情况下在MVC下重写路由配置实现处理原php链接地址的请求,但实现时发现怎么也匹配不到自己写的路由,度娘上找到一博文,解决了当时问题,应该是台湾wili保哥写的吧,记得以前看过保哥大神写的《ASP.NET MVC 4开发指南》,不知道是不是同一个,转帖如下:
ASP.NET MVC 4 在 .NET 4.0 與 .NET 4.5 的專案範本差異
昨天在【ASP.NET MVC 4 開發實戰】課程中,學員們發現了一個問題,就是在實作與測試 ASP.NET MVC 的 Routing (路由) 機制的過程中,發現有個功能有些人做得出來,有些人卻做不出來,當我前去查看時也沒立即發現問題癥結,中午休息的空檔終於找到的這個細微的差異之處,所以還是寫篇文章提醒正準備開始使用 .NET Framework 4.5 的 ASP.NET MVC 開發人員。
在此我們先建立一個以 .NET Framework 4.0 為主的 ASP.NET MVC 4 專案:
專案範本則以「網際網路應用程式」為主要範本:
接著我們開啟專案下 App_Start\RouteConfig.cs 檔案,試圖修改預設路由的 url 參數定義:
我們試著將 {action} 修改成 {action}.aspx
這時,我們可以測試該專案,連接以下網址
http://localhost:26618/Home/Index.aspx
你會看到網頁是可以正常顯示的,如下圖示:
接著,我們試著將 {action} 修改成 {action}.{ext},把 .aspx 修改成一個路由變數
我們定義了 .{ext} 這個路由變數,代表我們可以在 {action} 後面加上任意 "副檔名”,然而事實上這不是個 “副檔名”,而是一個路由值而已!
這時,我們可以測試該專案,連接以下網址
http://localhost:26618/Home/Index.php
( 備註:這是為了示範路由與網址的對應而設計的一個範例,你就算把 .php 改成 .jsp 都能執行 )
你會看到網頁是可以正常顯示的,如下圖示:
接下來,我們建立一個以 .NET Framework 4.5 為主的 ASP.NET MVC 4 專案:
然後完全使用上述的範例執行一次,但練習到最後,你卻會發現,使用以下網址可行:
http://localhost:26636/Home/Index.aspx
但使用以下網址卻會引發 HTTP 錯誤 404.0 – Not Found 的錯誤 ( 而且該錯誤是從 IIS 傳來的 )
http://localhost:26636/Home/Index.php
但是如果我在 .php 後面加上一條斜線 ( / ),問題竟然可以解決,例如:
http://localhost:26636/Home/Index.php/
後來我用 WinMerge 工具比對兩個 ASP.NET MVC 專案資料夾的差異,這才發現,雖然兩個都是 ASP.NET MVC 4 專案,但是 web.config 的預設內容卻改變了,是在 <system.webServer> 區段下的 <modules> 區段,原本在 .NET 4.0 專案範本中有下圖這段runAllManagedModulesForAllRequests 設定,但是在 .NET 4.5 卻被移除,進而導致此差異:
然而,這段設定最主要是針對 IIS7+ ( 含 IIS 7.5, IIS 8.0 ) 的 整合 (Integrated) 模式下進行設定,如果你不加上 <modules runAllManagedModulesForAllRequests="true" /> 的話,在預設的情況下,透過 .NET 撰寫的 HttpModules 只能針對 Managed 要求進行處裡 (也就是那些透過 .NET 執行的程式),那些透過原生模組 (native modules) 處裡的檔案,例如 JPEG, CSS, JavaScript 等靜態檔案,就不會流經這些 HttpModules 進行處裡,在這種情況下,如果你沒有明確註冊 HttpHandler 在 IIS 裡面的話,將會導致 IIS 無法判定明確的 MIME Type 而導致找不到網頁的情況,也就是我們這次遇到的問題。
當然,最簡單的應變措施就是直接把這段設定加回去,不過,加回去之前請三思,這條設定被拿掉是有原因的,而原因就出在:效能衝擊 ( Performance Impact )!
在 IIS6 以前,IIS 在處理 HTTP 要求的過程中,只能透過 原生模組 (native modules) 處裡所有要求,並且預設透過副檔名來決定如何對應不同的原生模組,以 ASP.NET 為例,就會有一個 .aspx 對應到 c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll 的設定,相關設定畫面可參考如下圖示,你可以發現,所有 HTTP 要求都必須透過「對應」的方式,才能得知正確的 Handler,接下來才能將 HTTP 要求委派給對應的 Handler 進行處理:
以下是從聖哥的【Windows Server 2008 應用程式新平台 - IIS 7.0】簡報中擷取的一段圖示,你可以從這裡看出 IIS 6.0 在處理要求的流程。
這裡你將會發現到,如果我們要透過「身分驗證」模組處裡本次要求,他是 IIS 內建的一個原生模組,雖然我們也可以在 ASP.NET 撰寫 HttpHandler 或 HttpModules 做到相同的事情,但是這些由 ASP.NET 撰寫的程式預設只能處理所有與 ASP.NET 相關的要求而已,也就是那些副檔名註冊在 IIS 裡面,並且設定到 aspnet_isapi.dll 的那些副檔名,才真正能執行到這段程式碼。反之,如果今天從用戶端傳來的 HTTP 要求是 *.htm 副檔名,他所對應到的只要不是 aspnet_isapi.dll 的話,就執行不到這段由 ASP.NET 開發框架下撰寫的 HttpHandler 或 HttpModules。我在 2007 年曾經寫過的一篇文章,就是試圖解決這個問題,參見:如何讓 ASP.NET 的表單驗證功能保護 .htm 的檔案
從 IIS7 開始,這個所謂的 IIS Request Pipeline (要求管線) 做了一次重大個改進,一個名為「整合」模式的新式要求管線,把整個模組執行的過程做出了改善,他允許你用 .NET 撰寫 Managed Modules,並且可以套用在任何 HTTP 要求上面,徹底打破架構上的限制,以下是 IIS7+ 新式要求管線示意圖:
( 註:若想深入研究的人,建議可閱讀 Introduction to IIS Architectures 文章。)
回到本文提出的問題,當我們沒有 <modules runAllManagedModulesForAllRequests="true" /> 這項預設設定的話 ( 預設為 false ),代表的是,我們在 ASP.NET 定義的模組 (modules),只想處理 Managed 要求 (就是那些註冊為 .NET 相關的要求) 而已,而非 所有 HTTP 要求 (AllRequests),所以當你試圖要求 *.php 等尚未註冊的 handler 時,自然就會引發 HTTP 錯誤 404.0 – Not Found的錯誤!
不過,可能會有人想問,為什麼我在 .php 後面加上一條斜線 ( / ),問題竟然可以解決呢?
因為從 ASP.NET 4.0 開始,新增了一個 ExtensionlessUrlHandler 要求處理器 (handler),這是一個專門用來處理那些「沒有副檔名的 HTTP 要求」。因為我們在撰寫 ASP.NET MVC 的時候,通常不會在網址加上所謂的「副檔名」,對於這些要求,IIS 會不知道應該將要求如何派送給那個 handler 處理,所以才衍生出這樣的需求,可以說是為了 ASP.NET MVC 量身打造的!
像是 ExtensionlessUrlHandler 這樣的處理器,如果要在 IIS6 實現,必須要註冊所謂的萬用字元應用程式對應才有可能 (設定了這個會影響 IIS6 的執行效能),最主要還是 IIS 架構上的差異使然。
你可以從下圖看到 ASP.NET MVC 專案範本中,預設就會載入所謂的 ExtensionlessUrlHandler 處理器!
文字版本如下:
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness32"
responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness64"
responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
如果你想註冊 *.php 並且讓 ASP.NET MVC 路由可以辨識的話,可以參考以下設定:
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness32"
responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness64"
responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
<add name="(PHP) ExtensionlessUrlHandler-ISAPI-4.0_32bit"
path="*.php"
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness32"
responseBufferLimit="0" />
<add name="(PHP) ExtensionlessUrlHandler-ISAPI-4.0_64bit"
path="*.php"
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness64"
responseBufferLimit="0" />
<add name="(PHP) ExtensionlessUrlHandler-Integrated-4.0"
path="*.php"
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
最後想要補充說明的是,如果你自行開發 HTTP 模組 ( HttpModules ) 的話,就算你手動加上<modules runAllManagedModulesForAllRequests="false" /> 設定,可能會認為「任何原生模組相關的 HTTP 要求」( 例如: *.htm, *.css 之類的 ) 都不會再流經你自行開發的 HTTP 模組,然而,這是個錯誤觀念!
使用這個 runAllManagedModulesForAllRequests 設定,最主要的差異在於:
- 當設定為 true 的時候,所有 HTTP 要求,包含已註冊的、未註冊的附檔名對應,都會流經你自己撰寫的 HTTP 模組。
- 當設定為 false 的時候,所有 HTTP 要求,所有已註冊的附檔名對應,還是會流經你自己撰寫的 HTTP 模組。
這個小細節對於寫 HTTP 模組的開發人員來說非常重要!
ASP.NET MVC5写.php路由匹配时的问题 ASP.NET MVC 4 在 .NET 4.0 与.NET 4.5 的專案範本差異的更多相关文章
- ASP.NET MVC5 :Attribute路由使用详解
1.什么是Attribute路由?怎么样启用Attribute路由? 微软在 ASP.NET MVC5 中引入了一种新型路由:Attribute路由,顾名思义,Attribute路由是通过Attrib ...
- 通过阅读ASP.NET MVC5 框架解密 路由的一点心得
路由: 1.在ASP.NET中路由不专属与ASP.NET MVC,因为路由(Route)是在system.web 命名空间下的,所以传统的WebForm也可以使用路由. 2.什么叫做路由 采用某种机制 ...
- 在ASP.NET MVC5中使用特性路由
首先在RegisterRoutes时开启特性路由功能: routes.MapMvcAttributeRoutes(); 然后,就可以使用了. [Route("{productId:int}/ ...
- ASP.NET MVC5(一)—— URL路由
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- ASP.NET MVC5使用Area区域
转载:http://www.lanhusoft.com/Article/217.html 在大型的ASP.NET mvc5项目中一般都有许多个功能模块,这些功能模块可以用Area(中文翻译为区域)把它 ...
- Asp.net MVC]Asp.net MVC5系列——Routing特性
目录 概述 路由特性 使用路由 可选参数和参数的默认值 路由前缀 默认路由 路由约束 自定义路由约束 路由名 区域(Area) 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列— ...
- 《ASP.NET MVC 5 破境之道》:第一境 ASP.Net MVC5项目初探 — 第三节:View层简单改造
第一境 ASP.Net MVC5项目初探 — 第三节:View层简单改造 MVC默认模板的视觉设计从MVC1到MVC3都没有改变,比较陈旧了:在MVC4中做了升级,好看些,在不同的分辨率下,也能工作得 ...
- ASP.NET MVC3中的路由系统 Routes
MVC中,用户访问的地址并不映射到服务器中对应的文件,而是映射到对应Control里对应的ActionMethod,由ActionMethod来决定返回用户什么样的信息.而把用户访问的地址对应到对应的 ...
- ASP.NET MVC3中的路由系统(Routes) .
MVC中,用户访问的地址并不映射到服务器中对应的文件,而是映射到对应Control里对应的ActionMethod,由ActionMethod来决定返回用户什么样的信息.而把用户访问的地址对应到对应的 ...
随机推荐
- js继承之Object.create()
通过 Object.create() 方法,使用一个指定的原型对象和一个额外的属性对象创建一个新对象.这是一个用于对象创建.继承和重用的强大的新接口.说直白点,就是一个新的对象可以继承一个对象的属性, ...
- Ambari安装之部署本地库(镜像服务器)(二)
部署本地库(镜像服务器) (1)下载HortWorks官网上的3个库到本地(也可以在线下载,但是速度会很慢) 我们先把hortworks官网上需要下载的3个库下载到本地(这个还是需要很长时间的,当然你 ...
- 使用travis-ci自动部署github上的项目
travis-ci是什么? 一个使用yaml格式配置用于持续集成完成自动化测试部署的开源项目 官网:https://travis-ci.org/ 使用travis-ci集成vue.js项目 首先,您需 ...
- 【无旋式treap】例题
[bzoj3223]文艺平衡树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[ ...
- tensorflow elu函数应用
1.elu函数 图像: 2.tensorflow elu应用 import tensorflow as tf input=tf.constant([0,-1,2,-3],dtype=tf.float3 ...
- Laravel 中使用子域名(一个框架多项目)
1.本地虚拟域名为:www.test.com,子域名为admin.test.com 2.apache环境中,配置apache的httpd-vhost.conf文件 <VirtualHost *: ...
- (转)Linux下增加交换分区的大小
场景:最近在Linux环境安装ELK相关软件时候发现机器特别的卡,所以就查看了Linux机器的内存使用情况,发现是内存和交换分区空间太小了. 对于虚拟机中的内存问题,可以直接通过更改虚拟机的硬件进行解 ...
- (转)JAVA反射机制理解
JAVA反射机制: 通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们. 理论的东东太多也没 ...
- iOS 使用 socket 即时通信(非第三方库)
其实写这个socket一开始我是拒绝的. 因为大家学C 语言和linux基础时肯定都有接触,客户端和服务端的通信也都了解过,加上现在很多开放的第三方库都不需要我们来操作底层的通信. 但是来了!!! 但 ...
- 【CSS】font样式简写(转)- 不是很建议简写
一.字体属性主要包括下面几个 font-family,font-style,font-variant,font-weight,font-size,font font-family(字体族): “Ari ...