使用ASP.NET路由来提供静态文件


73

可以使用ASP.Net路由(不是MVC)来提供静态文件吗?

说我要路线

http://domain.tld/static/picture.jpg

http://domain.tld/a/b/c/picture.jpg

并且我想动态地执行它,因为重写的URL是动态计算的。我不能一劳永逸地建立静态路由。

无论如何,我可以创建这样的路线:

routes.Add(
  "StaticRoute", new Route("static/{file}", new FileRouteHandler())
);

在该FileRouteHandler.ProcessRequest方法中,我可以重写从/static/picture.jpg到的路径/a/b/c/picture.jpg。然后,我想为静态文件创建一个处理程序。ASP.NETStaticFileHandler为此使用了。不幸的是,该类是内部的。我试图使用反射创建处理程序,它实际上可以工作:

Assembly assembly = Assembly.GetAssembly(typeof(IHttpHandler));
Type staticFileHandlerType = assembly.GetType("System.Web.StaticFileHandler");
ConstructorInfo constructorInfo = staticFileHandlerType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
return (IHttpHandler) constructorInfo.Invoke(null);

但是使用内部类型似乎不是正确的解决方案。另一个选择是实现自己的实现StaticFileHandler,但是正确地做到这一点(支持范围和etags等HTTP东西)并非易事。

如何在ASP.NET中处理静态文件的路由?

Answers:


40

在研究了这个问题几个小时之后,我发现仅添加忽略规则将为您的静态文件提供服务。

在RegisterRoutes(RouteCollection路由)中,添加以下忽略规则:

routes.IgnoreRoute("{file}.js");
routes.IgnoreRoute("{file}.html");

对我来说,它可以工作,但是我无法解析区域的View文件夹中的JS文件,要解决此问题,我改用该区域的基本文件夹中的另一个文件夹,如/Areas/MyArea/ClientScripts/foo.js
eka808

26
我似乎以某种方式错过了难题中的一部分...忽略到静态文件的路由如何帮助路由/static/a/b/c(OP要求的)?您能否进一步说明您的答案,我真的很想了解这种解决方案。
奥利弗

20
与奥利弗(Oliver)同意,这不能解决操作问题,因此不应接受作为解决方案。
dhochee 2013年

如果您需要MVC控制器先检查用户是否在路由到那里之前登录,该怎么办?忽略路由与重定向到静态文件夹结构不同。
pilavdzice

添加robots.txt的最简单方法
joverall22

57

为什么不使用IIS来做到这一点?您可以只创建重定向规则,以将请求从第一个路由指向第二个路由,然后再将其发送到您的应用程序。因此,这将是一种更快的重定向请求的方法。

假设您拥有IIS7 +,则可以执行以下操作:

<rule name="Redirect Static Images" stopProcessing="true">
  <match url="^static/?(.*)$" />
  <action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" />
</rule>

或者,如果您不需要重定向,如@ ni5ni6所建议:

<rule name="Rewrite Static Images" stopProcessing="true">
  <match url="^static/?(.*)$" />
  <action type="Rewrite" url="/a/b/c/{R:1}" />
</rule>

为@RyanDawkins编辑2015-06-17

而且,如果您想知道重写规则的去向,这里是其在web.config文件中位置的映射。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <!-- rules go below -->
        <rule name="Redirect Static Images" stopProcessing="true">
          <match url="^static/?(.*)$" />
          <action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

我也更喜欢这种方法。我想,将其移到管道中并让IIS工作进程处理重定向比通过运行时实际循环处理路由的旋转周期更有效。即使服务器上的用户流失量大致相同,我也会选择不使用路由的路由(双关语),并将重定向保留在应用程序本身之外。
约瑟夫·弗里斯

从问题的最初版本来看,不清楚的是重写的URL是即时计算的(我在这里不关心性能)。我已经更新了问题以澄清这一点。无论如何,感谢您的答复。
Martin Liversage,2009年

(删除了我之前的评论,并使用未缩短的网址重新添加了它)。Martin,除了性能问题之外,为什么要在应用程序中处理此url,而在外部进行处理会更好呢?我想您可以创建一个处理该问题的控制器动作,但是您可以看一下:-geekswithblogs.net/sankarsan/archive/2009/01/18/…–
Dan Atkinson

1
@RyanDawkins在web.config中。请查看我的编辑以获取有关其确切位置的更多信息。
Dan Atkinson

1
很好的答案,第一次工作。现在,这种情况不会经常发生!
dahui

13

我有类似的问题。我最终使用了HttpContext.RewritePath

public class MyApplication : HttpApplication
{
    private readonly Regex r = new Regex("^/static/(.*)$", RegexOptions.IgnoreCase);

    public override void Init()
    {
        BeginRequest += OnBeginRequest;
    }

    protected void OnBeginRequest(object sender, EventArgs e)
    {
        var match = r.Match(Request.Url.AbsolutePath);
        if (match.Success)
        {
            var fileName = match.Groups[1].Value;
            Context.RewritePath(string.Format("/a/b/c/{0}", fileName));
        }
    }
}

1
非常感谢分享。在本地开发期间跑遍此寻找URL重写的解决方案,并意识到我可以在任何地方都可以这样做。我不是将其用于输入解析,而是用于JS和CSS文件版本管理。
布伦丹·摩尔

对于任何有兴趣的人,为了管理该表格的文件filename.v1234.js,我正在使用private readonly Regex regJS = new Regex("^(.*)([.]v[0-9]+)([.](js|css))$", RegexOptions.IgnoreCase);,然后Context.RewritePath(string.Format("{0}{1}", matchJS.Groups[1].Value, matchJS.Groups[3].Value));
在进行

7

我想出了一个替代使用internal的方法StaticFileHandler。在IRouteHandler我打电话HttpServerUtility.Transfer

public class FileRouteHandler : IRouteHandler {

  public IHttpHandler GetHttpHandler(RequestContext requestContext) {
    String fileName = (String) requestContext.RouteData.Values["file"];
    // Contrived example of mapping.
    String routedPath = String.Format("/a/b/c/{0}", fileName);
    HttpContext.Current.Server.Transfer(routedPath);
    return null; // Never reached.
  }

}

这是一个hack。本IRouteHandler应该返回的IHttpHandler,而不是中止和转移当前请求。但是,它确实实现了我想要的。

使用内部结构StaticFileHandler在某种程度上也是一种黑客,因为我需要进行反思才能访问它,但是至少在MSDNStaticFileHandler有一些文档使它成为一个稍微“正式”的类。不幸的是,我认为不可能在部分信任环境中反思内部类。

我会坚持使用,StaticFileHandler因为我认为在可预见的将来它不会从ASP.NET中删除。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.