ASP.NET MVC中CSS文件中的URL自动解析

27

在普通的WebForms场景下,任何位于CSS文件内内部的根相对URL(例如:~/folder/file.txt)

.form { background-image: url(~/Content/Images/form_bg.gif); }

如果我指定,这些将在运行时自动解析。

<head runat="server">

在引用页中。

然而,在ASP.NET MVC Beta1网站上已不再发生这种情况。

是否有一种方法可以启用此功能,而不需要使用黑客技巧或CSS加载器文件?可能使用HttpModules或其他东西吗?

还是我的网站设计不正确?什么才是良好的设计?

由于原始的ASP.NET WebForms已经具有此功能,如果可能的话,我希望利用任何现有的功能。但我并不是很清楚。

这个Web应用程序将部署在几个环境中,其中~根文件夹可能不明显。


编辑: 我指的是文件内容中的URL,而不是文件本身的URL。

6个回答

46

我建议您不要使用自动根查找字符~。我理解您希望在不同的部署中根目录不同时仍然可以使用相同的解决方案,但在CSS文档中,使用相对路径不会有任何问题。无论加载该CSS文件的页面的路径如何,CSS文档中的路径(例如图像URL)将始终相对于CSS文件的位置。因此,如果您的图像位于~/Content/Images,而样式表位于~/Content/Stylesheets,则始终可以使用background-image: url(../Images/form_bg.gif);,无论加载样式表的页面的位置如何,都可以正常工作。

这种方法有什么问题吗?


啊...我又犯傻了。这应该可以工作。我习惯于在Web表单中的CSS中使用波浪号(~)相对路径。它总是有效的,所以我期望MVC也是一样的,但是... - chakrit
它在旧的Mac浏览器上存在一些问题...但我认为现在没有人再支持它们了。 - chakrit
它还存在一些问题,旧版的Netscape解析背景图像样式规则的方式不是标准的,这也是我最近遇到这个问题的最后一次,因此我建议使用IHttpModule。然而,最终,也许这并不需要考虑Netscape,因为它可能已经很久以前就消失了。 - David Alpert
1
这个问题被提出并且我阅读它已经有一段时间了。时间足够长,以至于我忘记了答案,并且很高兴能够再次找到它。谢谢。 - Jeff Siver
1
只是提醒一下,如果你被迫使用像IE6这样的老旧浏览器并且使用AlphaImageLoader,这将无法正常工作。AIL相对于浏览器URL加载内容,因此使用的任何路径都必须来自根目录。 - Thomas W Tupper

5

过去我使用过的一个技巧是,将我的CSS文件命名为.ASPX扩展名,并在页面签名中设置ContentType属性:

<%@ Page Language="C#" ContentType="text/css" %>

body {
    margin: 0;
    padding: 0;
    background: #C32605 url(<%= ResolveUrl("~/Content/themes/base/images/BodyBackground.png") %>) repeat-x;
    font-family: Verdana, Arial, sans-serif;
    font-size: small;
    color: #d7f9ff;
}

这将确保CSS文件通过ASP.NET框架,并用相对路径替换服务器端代码。

4

这里这里这里这里是一些关于实现IHttpModule来拦截Web请求的资源...

编写/适配一个用于检查文件类型的模块(例如伪代码:if(request以“.css”结尾)...)

然后使用正则表达式将所有“~/”的实例替换为System.Web.VirtualPathUtility.ToAbsolute(“~/”)

我不知道这样做对性能会有什么影响,因为需要通过这种过滤器运行每个请求,但您可以在web.config文件和/或MVC URL路由方面进行调整,使所有.css请求通过此类过滤器进行处理,而跳过其他文件。

想想看,您可能可以在ASP.NET MVC应用程序中通过将所有CSS引用指向执行此预处理的特殊控制器操作来实现相同的效果。但我怀疑这不如IHttpModule高效。


1
如果您想解析任何文件(包括文本文件、JavaScript等)中的~/,可以编写一个处理程序为其分配过滤器,并使用该过滤器搜索这些路径...例如...
public class StringParsingFilter : MemoryStream {

    public Stream OriginalStream {
        get { return this.m_OriginalStream; }
        set { this.m_OriginalStream = value; }
    }
    private System.IO.Stream m_OriginalStream;

    public StringParsingFilter() : base() {
        this.m_OriginalStream = null;
    }

    public override void Flush() {
        this.m_OriginalStream.Flush();
    }

    public override void Write(byte[] buffer, int offset, int count) {

        //otherwise, parse for the correct content
        string value = System.Text.Encoding.Default.GetString(buffer);
        string contentType = HttpContext.Current.Response.ContentType;

        //Do any parsing here
        ...

        //write the new bytes to the stream
        byte[] bytes = System.Text.Encoding.Default.GetBytes(value);
        this.m_OriginalStream.Write(bytes, offset, count + (bytes.Length - buffer.Length));

    }

}

你需要编写一个自定义处理程序来确定何时分配此过滤器,例如以下内容...

 public class FilterControlModule : IHttpModule {

    public void Init(HttpApplication context) {
        HttpApplication oAppContext = context;
        oAppContext.BeginRequest += new EventHandler(_HandleSettingFilter);                        
    }

    private void _HandleSettingFilter(object sender, EventArgs e) {

        //You might check the file at this part to make sure
        //it is a file type you want to parse
        //if (!CurrentFile.isStyleSheet()) { return; }
        ...

        //assign the new filter
        StringParsingFilter filter = new StringParsingFilter();
        filter.OriginalStream = HttpContext.Current.Response.Filter;
        HttpContext.Current.Response.Filter = (Stream)filter;

    }

}

其实只需要说“查找IHttpModules”可能会更容易,但这是我用来解析路径不是ASP.net文件的一些代码。

您还需要更改IIS设置中的一些内容,以允许通过将ASP.net ISAPI设置为所有处理的文件的通配符来解析文件。如果您使用的是IIS6,可以在此网站上了解更多信息...

您还可以使用此方法修改任何文件类型,因此可以为图像分配一些过滤器,为JavaScript或样式表分配一些过滤器,或者...真正的任何东西...


谢谢!我已经完成了通配符映射。我知道Http模块,但由于ASP.NET Web Form 已经有这个功能,所以我认为必须有一种更简单的方法……比如链接一些已从MVC剥离的现有ASP.NET Web Form模块。不管怎样,还是谢谢你,我可以使用你的代码。 - chakrit

0
我创建了一个PathHelper工具类,它为我提供了所有我需要的路径。例如:
<link href="<%=PathHelper.CssUrl("FormulaIndex.css")%>" rel="Stylesheet" type="text/css"/>

通过使用System.Web.VirtualPathUtility.ToAbsolute()和我的约定(content/css/yourFile.css),为我提供了正确的完整URL。

我对js、xml、t9n、图片等也做了同样的处理...它是集中的、可重用的,现在我只需要更改一行代码就可以捕获所有网站和页面中从content/js到Scripts的脚本文件夹移动。

如果你问我,这是一个愚蠢的举动,但这是当前测试版的现实 :(


我的意思是文件内容中的URL,而不是文件本身的URL。 - chakrit

0
你可以使用URL重写器来在请求进入时修复URL,但我不确定在这种情况下它是否像黑客那样优雅。

啊,好主意!我可以使用路由框架来实现。让我试试看。 - chakrit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接