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来决定返回用户什么样的信息.而把用户访问的地址对应到对应的 ...
随机推荐
- Android6.0 中appcompat_v7 报错
更新了AndroidSDK以后 各种错误,新建一个项目会附赠一个appcompat_v7,你只要知道这个是一个兼容包就可以了,具体的特性可以看相关介绍,其实也没啥特别的就是为了兼容低版本的呗, 但是呢 ...
- docker~Dockerfile方式建立镜像HelloWorld
回到目录 Dockerfile可以便捷的建立一个image,它可以在一个镜像基础上,去构建另一个镜像,这也许就是它的特色,也是docker的本意! 我们下载一个mono的镜像 docker pull ...
- 关于shell脚本函数、数组、字符串截取、svn更新发布实例
#/bin/bash #功能:QA服根据模板创建区配置文件并提交到svn上. SOURCE_PATH=/data/source_code SVN_PATH=/code/psm #svn发布目录,要 ...
- Linux 显示文本指定行内容
主要采用sed.head和tail命令 如果文本中使用了 \n 这类符号,cat命令会把它当成换行符,结果会出错 $ sed -n "10p" move.sh # 显示第10行 ...
- Python爬取百度贴吧数据
本渣除了工作外,在生活上还是有些爱好,有些东西,一旦染上,就无法自拔,无法上岸,从此走上一条不归路.花鸟鱼虫便是我坚持了数十年的爱好. 本渣还是需要上班,才能支持我的业余爱好.上班时间还是尽量访问外网 ...
- (转)volatile关键字
Java线程:volatile关键字 Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量 ...
- HTML5 开发APP
近期在做app,现在项目进行了一段时间,我打算把自己的经验写出来,给自己总结一下也给会用小伙伴看一下.本人前端一枚.我们所以能选的技术就是CSS,HTML,JS了,经过准备我决定用HBuilder 准 ...
- HTTP学习
HTTP(HyperText Transfer Protocol)全称"超文本传输协议" HTTP是基于 TCP/IP 协议的应用层协议 现在日常使用版本 HTTP/1.1 一个H ...
- hdu 6059---Kanade's trio(字典树)
题目链接 Problem Description Give you an array A[1..n],you need to calculate how many tuples (i,j,k) sat ...
- Presto向分区表快速插入数据时出现'target directory already exists'的原因
因为项目使用Presto作为ETL使用,需要将关系库中的数据导入到Hive中.目前关系库中的数据每天导入一次,在Hive中以天为间隔创建新的分区.思路是正确的,但是在使用的过程中,发现将少量关系库中的 ...