[翻译]运用文件解析器在任意文件中使用虚拟应用路径(~)
原文出处:http://www.codeproject.com
Using the FileResolver to allow virtual application paths ( ~ ) in any file
引言
如果不是很熟悉“~”在ASP.NET中的使用,你总是完全地忽略它。我们的开发环境经常是和成品的服务器是不同的。我们可以在开发的PC上使用一个虚拟路径来测试我们的应用程序,而使用一个单独的顶级网址来发布。
那么,当把image或者link加入到页面中的时候,你总是必须知道提供的路径的类型——相对、绝对等等。在ASP.NET中最好的技巧之一就是使用“~”。它实质上是HttpRuntime.AppDomainAppVirtual属性的一个快捷方式,引用的是虚拟应用程序的根,而不是web服务器的根。
“~”是快捷、简洁的,同时也十分受限制。比如,仅仅在设置那些Render之前知道怎么解析路径的控件的一些路径相关属性时,它是有用的。它只是在ASP.NET的预定义范围内有用,绝对不能使用在ASP.NET的控管外的文件中。至少目前还是这样。
我经常碰上的问题之一是:在非ASP.NET文件(如css文件)中设定一个路径。比如,我想在css文件中设定一个样式的背景(background-image)属性时,除非我使用一个相对路径,否则将是很头疼的事情。我通常的解决方法是直接增加背景属性到页面的标签里面而不是一个css文件里,我是首先承认这种做法是不令人满意的人。
两个解决办法在我的脑海中浮现。在结合它们之后,我构建了一个可靠的解决方案。我的思路包括使用一个HTTP处理机来截取任何资源请求,诸如css、js文件等等。该处理机负责分析上述的那些资源文件并且将解析后的文件返回给客户端。
基础
本文假定你对HTTP处理机有初步的了解。
代码的使用
针对本文,我打算用css文件来作为例子,当然这个技术也可以很容易的应用到任何其他需要处理的文件类型上。
假设当前有如下一个标签在a.aspx页面中来链接一个样式表。
<link rel="stylesheet" href="resources/stylesheet.css" />
一旦我实现了上面所述的解决方案,上面的标签将改成如下:
<link rel="stylesheet" href="~/resources/stylesheet.css.ashx" />
正如你所见到的,在文件路径上有一个小小的附加后缀“.ashx”,这是为了告诉文件解析器,需要解析css文件中任何的虚拟路径。
另外一个小小的变化是我们在css文件的路径上使用了“~”。一会你将看到HTTP处理机会自动地解析这个css文件路径。然而,它似乎不适用于ASP.NET1.1的场合,因此对于ASP.NET1.1,你可能必须使用一个真实的相对或绝对路径。
那么,让我们关注一下文件解析器的代码。
namespace FileResolverDemoWeb
{
public class FileResolver : IHttpHandler
{
/// <summary>
/// File cache item used to store file
/// content & date entered into cache
/// </summary>
internal class FileCacheItem
{
internal string Content;
internal DateTime DateEntered = DateTime.Now;
internal FileCacheItem(string content)
{
this.Content = content;
}
}
private FileCacheItem UpdateFileCache(HttpContext context,
string filePath)
{
string content;
using(FileStream fs = new FileStream(filePath,
FileMode.Open, FileAccess.Read))
{
using(StreamReader sr = new StreamReader(fs))
{
content = sr.ReadToEnd();
sr.Close();
}
fs.Close();
}
//Get absolute application path
string relAppPath = HttpRuntime.AppDomainAppVirtualPath;
if(!relAppPath.EndsWith("/"))
relAppPath += "/";
//Replace virtual paths w/ absolute path
content = content.Replace("~/", relAppPath);
FileCacheItem ci = new FileCacheItem(content);
//Store the FileCacheItem in cache
//w/ a dependency on the file changing
CacheDependency cd = new CacheDependency(filePath);
context.Cache.Insert(filePath, ci, cd);
return ci;
}
public void ProcessRequest(HttpContext context)
{
string absFilePath =
context.Request.PhysicalPath.Replace(".ashx", "");
//If a tilde was used in the page
//to this file, replace it w/ the app path
if(absFilePath.IndexOf("~\\") > -1)
absFilePath = absFilePath.Replace("~",
"").Replace("\\\\", "\\");
if(!File.Exists(absFilePath))
{
context.Response.StatusCode = 404;
return;
}
FileCacheItem ci = (FileCacheItem)context.Cache[absFilePath];
if(ci != null)
{
if(context.Request.Headers["If-Modified-Since"] != null)
{
try
{
DateTime date = DateTime.Parse(
context.Request.Headers["If-Modified-Since"]);
if(ci.DateEntered.ToString() == date.ToString())
{
//Don't do anything, nothing
//has changed since last request
context.Response.StatusCode = 304;
context.Response.StatusDescription =
"Not Modified";
context.Response.End();
return;
}
}
catch(Exception){}
}
else
{
//In the event that the browser doesn't
//automatically have this header, add it
context.Response.AddHeader("If-Modified-Since",
ci.DateEntered.ToString());
}
}
else
{
//Cache item not found, update cache
ci = UpdateFileCache(context, absFilePath);
}
context.Response.Cache.SetLastModified(ci.DateEntered);
context.Response.ContentType = "text/" +
GetContentType(Path.GetExtension(absFilePath));
context.Response.Write(ci.Content);
context.Response.End();
}
/// <summary>
/// Gets the appropriate content type for a specified extension
/// </summary>
private string GetContentType(string ext)
{
switch(ext.ToLower())
{
case ".css":
return "css";
break;
case ".xml":
return "xml";
break;
case ".js":
return "javascript";
break;
default:
return "plain";
break;
}
}
#region IHttpHandler Members
public bool IsReusable
{
get
{
return true;
}
}
#endregion
}
}
我们来分析一下上面的代码。
CacheItem是一个获取css文件中要解析内容的一个内部类。它有一个DateEntered属性,用于记录内容最后被更新的时间。它将决定我们是否需要提供一个新的css文件内容给客户端。
ProcessRequest是一个继承IHttpHander接口时必须实现的方法,方法里包含了大部分处理机的处理逻辑。在ProcessRequest方法中,我们从HttpContext.Request.PhysicalPath属性来获取要处理的文件。我们做个初步检查来确保文件路径已经被解析。一旦我们获得文件的映射实际路径,我们再检查一下确保文件在文件系统中是否存在。
string absFilePath = context.Request.PhysicalPath.Replace(".ashx", "");
//If a tilde was used in the page to this file, replace it w/ the app path
if(absFilePath.IndexOf("~\\") > -1)
absFilePath = absFilePath.Replace("~", "").Replace("\\\\", "\\");
if(!File.Exists(absFilePath))
{
context.Response.StatusCode = 404;
return;
}
一旦文件证实存在,我们需要检查页面缓存,看看是否有一个相关的CacheItem已经加入,如果这是这个css文件的首次请求,那么我们将创建并储存一个CacheItem。
如果CacheItem已经存在,我们比较DateEntered和来自请求头If-Modified-Since的值,如果日期匹配,那么我们知道客户端有着该文件最新的缓存,如果日期不是匹配的或者没有找到请求头,我们就试着加入请求头并且将新的内容返回给客户端。
FileCacheItem ci = (FileCacheItem)context.Cache[absFilePath];
if(ci != null)
{
if(context.Request.Headers["If-Modified-Since"] != null)
{
try
{
DateTime date = DateTime.Parse(
context.Request.Headers["If-Modified-Since"]);
if(ci.DateEntered.ToString() == date.ToString())
{
//Don't do anything, nothing has
//changed since last request
context.Response.StatusCode = 304;
context.Response.StatusDescription = "Not Modified";
context.Response.End();
return;
}
}
catch(Exception){}
}
else
{
//In the event that the browser doesn't
//automatically have this header, add it
context.Response.AddHeader("If-Modified-Since",
ci.DateEntered.ToString());
}
}
else
{
//Cache item not found, update cache
ci = UpdateFileCache(context, absFilePath);
}
context.Response.Cache.SetLastModified(ci.DateEntered);
context.Response.ContentType = "text/" +
GetContentType(Path.GetExtension(absFilePath));
context.Response.Write(ci.Content);
context.Response.End();
如果CacheItem没有找到,我们需要用一个新的CacheItem更新缓存。这包括从css文件中读取内容和用真实路径代替所有出现的“~”两个步骤。之后,我们将新的内容封装到一个CacheItem中并且储存它到页面缓存中。
private FileCacheItem UpdateFileCache(HttpContext context,
string filePath)
{
string content;
using(FileStream fs = new FileStream(filePath,
FileMode.Open, FileAccess.Read))
{
using(StreamReader sr = new StreamReader(fs))
{
content = sr.ReadToEnd();
sr.Close();
}
fs.Close();
}
//Get absolute application path
string relAppPath = HttpRuntime.AppDomainAppVirtualPath;
if(!relAppPath.EndsWith("/"))
relAppPath += "/";
//Replace virtual paths w/ absolute path
content = content.Replace("~/", relAppPath);
FileCacheItem ci = new FileCacheItem(content);
//Store the FileCacheItem in cache
//w/ a dependency on the file changing
CacheDependency cd = new CacheDependency(filePath);
context.Cache.Insert(filePath, ci, cd);
return ci;
}
至此,我们就基本完成了文件解析器。和所有处理机一样,它需要在你的web.config中加入一个附加的条目才能工作。不仅这个是必要的,而且我们还要做一些小小的设定来扩展文件解析器,使之支持任何我们所需的文件类型。
<configuration>
<system.web>
<httpHandlers>
<add verb="GET" path="*.css.ashx"
type="FileResolverDemoWeb.FileResolver,FileResolverDemoWeb" />
<add verb="GET" path="*.js.ashx"
type="FileResolverDemoWeb.FileResolver,FileResolverDemoWeb" />
</httpHandlers>
</system.web>
</configuration>
在这个场景里面,我解析了css和js文件。
(以下略,翻译水平有限,欢迎大家指正,如有需要请看原文)
tag: asp.net ~ 文件解析器 路径
转载于:https://www.cnblogs.com/luyuliang/archive/2006/09/23/512588.html
[翻译]运用文件解析器在任意文件中使用虚拟应用路径(~)相关推荐
- 使用springMVC提供的CommonsMultipartResolver文件解析器,实现文件轻松上传
springMVC提供的前端控制器,可以拦截所有请求,指挥调度所有后台逻辑资源. 使用传统方式进行文件上传,需要我们手动解析request对象,获取文件上传项,再进行文件的上传. springMVC框 ...
- XML - XML学习/XML文件解析器(C++)实现
XML - XML学习/XML文件解析器(C++)实现 XML概述 XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识.它也是元标记语言,用于定义其他与特定领域有关的, ...
- Glib学习(17) Key-value文件解析器 Key-value file parser
glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/ glib帮助文档:https://developer.gnome.org/glib/ 本节主 ...
- torrent文件解析器
第二步工作是解析torrent文件,有了bencoding编码解析器 解析torrent文件当然是易如反掌的任务了. 实现的封装类CTorrentParser,完成的主要任务有: 1.判断torren ...
- 【glib】Key-value文件解析器
1 头文件 2 描述 3 API 4 实例 4.1 本文Key-value文件解析器如下: 4.2 在准备一个Key-value文件示例文件 tt.txt 4.3 编译: 4.4 运行: 4.5 运行 ...
- 用友U8+ CRM任意文件上传、任意文件读取 实战
用友CRM系统,使用量非常广,这里存在任意文件读取漏洞.任意文件上传漏洞 任意文件读取 存在漏洞的文件为: /ajax/getemaildata.php 访问http://IP:端口/ajax/get ...
- 哪些服务器曾被发现文件解析漏洞,常见的文件解析漏洞总结
常见的文件解析漏洞总结 iis解析漏洞 解析漏洞主要是说一些特殊文件被iis,apache,nginx等web容器在特殊情况下被解释成脚本文件格式 ==iis5.x/6.0解析漏洞:== 1,目录解析 ...
- SAXReader解析器--xml字符串文件解析
输入为xml格式字符串 public static void main(String[] args) throws DocumentException {String xml="<?x ...
- Spring5利用视图解析器生成Excel文件
介绍 请求处理方法执行完成后,最终返回一个ModelAndView对象.对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 M ...
最新文章
- SIP协议和压力测试, SIP callflow图形生成
- CSS3的绝对定位与相对定位
- set 和select 的区别
- jquery cookie的用法
- 玩转Nodejs日志管理log4js
- Oracle 查询练习及答案
- 转载:认识自我,把握机遇 —— 谢恩伟 (二)
- Google 浏览器(2011)书签同步
- 易居IPO后首份成绩单透露了什么秘密?|一点财经
- php webqq登陆,Smart QQ——腾讯新一代网页版 WebQQ,更简洁纯粹的实用在线聊天工具!...
- 评职称自费出书多少钱
- office365安装后仍显示之前版本
- CITA环境搭建与运行
- iOS APP启动页更新失败
- Unity-解决报错Shader error in ‘EffectCore/alphaBlend_glow‘: ‘‘ : ‘UNITY_PASS_FORWARDBASE‘ already define
- 选择适合的Node js授权认证策略
- css scale()方法
- 解决Vue中重复点击相同路由控制台报错问题
- 权利的游戏 S0803
- 在vscode中安装python第三方库
热门文章
- 计算机网络段标试卷,计算机网络基础-段标-第2章.ppt
- win10配置mysql8.0_Win10下mysql 8.0.20 安装配置方法图文教程
- postgre管理员 无法访问表_postgresql – 授予用户对所有表的访问权限
- 香蜜台词共赴鸿蒙,香蜜台词斗法
- php 写一个大富翁游戏,C++大富翁代码 现在要设计一个类似“大富翁”的游戏:有一条由20个格子组成的 联合开发网 - pudn.com...
- java语言sql接口_Java语言SQL接口
- 数学建模学习笔记(二)——Topsis优劣解距离法
- java产生字符函数_java生成字符串md5函数类(javaSE)
- android progressbar 水平动画,Android ProgressBar 自定义样式(三),动画模式
- python习题week3