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.NETは、この目的でStaticFileHandler
を使用します。残念ながら、このクラスは内部です。私はリフレクションを使用してハンドラーを作成しようとしましたが、実際に動作します:
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
を実装することですが、適切に実装する(範囲やetagなどのHTTPをサポートする)のは簡単ではありません。
ASP.NETの静的ファイルのルーティングにはどのようにアプローチすればよいですか?
この問題を数時間掘り下げた後、無視ルールを追加するだけで静的ファイルが提供されることがわかりました。
RegisterRoutes(RouteCollection routes)で、次の無視ルールを追加します。
routes.IgnoreRoute("{file}.js");
routes.IgnoreRoute("{file}.html");
なぜIISを使用してこれを行うのですか?リクエストがアプリケーションに到達する前に、最初のルートから2番目のルートへのリクエストをポイントするリダイレクトルールを作成することができます。リクエストをより迅速にリダイレクトする方法である。
あなたが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>
同様の問題がありました。最終的に 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));
}
}
}
内部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.
}
}
これはハックです。 IRouteHandler
はIHttpHandler
を返し、現在のリクエストを中止して転送することはありません。しかし、実際には私が望むものを達成します。
内部のStaticFileHandler
を使用することも、ハッキングです。アクセスするにはリフレクションが必要ですが、少なくともいくつかの MSDNのStaticFileHandler
に関するドキュメント もう少し「公式」なクラス。残念ながら、部分的な信頼環境で内部クラスを反映することは不可能だと思います。
近い将来、ASP.NETから削除されるとは思わないので、StaticFileHandler
の使用に固執します。
静的ファイルを処理するためにTransferRequestHandlerを追加する必要があります。次の回答を参照してください https://stackoverflow.com/a/21724783/22858