[英]How to modify ASP.NET MVC static file root
我希望能够重组我的 ASP.NET MVC 站点结构,以更接近 Rails 的方式(我们在我的公司同时使用 rails 和 ASP.net)。
在 Rails 中,有一个充当站点根目录的“公共”文件夹。 For example, I could drop in a "test.html" and access the file with the url http://domain.com/test.html which would serve up the static html file.
在 asp.net MVC 中有一个“内容”文件夹,我想作为根文件夹。 So instead of accessing http://domain.com/content/myfile.html , i want to be able to do http://domain.com/myfile.html .
我知道我可以将文件放在项目的根目录中,但我需要对许多文件执行此操作,包括 css、js、html、图像等,并且希望跨 rails 和 aspnetmvc 共享一些标准化资产。
有没有办法做到这一点?
还有另一种可能的解决方案。 您可以使用重写规则来为您处理此问题,而不是使用代码。 如果您使用的是 IIS 7 或更高版本,则可以使用微软的 URL Rewrite Module。
像下面这样的规则可能会做到这一点:
<rule name="Rewrite static files to content" stopProcessing="true">
<match url="^([^/]+(?:\.css|\.js))$" />
<conditions>
<add input="{APPL_PHYSICAL_PATH}content{SCRIPT_NAME}" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="/content/{R:1}" />
</rule>
该规则检查对 css 或站点根目录下的 js 文件的请求。 然后它检查文件是否存在于内容文件夹中。 如果存在,则重写将返回内容文件夹中的文件。 我只测试了一点,但它似乎工作。 它当然需要更多的测试和可能的改进。
我能想到的唯一解决方案是使用自定义 controller 和路由为您执行此操作。 但这不是一个干净的解决方案。
首先,您需要一个带有 GetFile 操作方法的 PublicController class。 这假定所有文件都直接位于 public/content 文件夹中。 处理文件夹会使事情变得更加复杂。
public class PublicController : Controller
{
private IDictionary<String, String> mimeTypes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{{"css", "text/css"}, {"jpg", "image/jpg"}};
public ActionResult GetFile(string file)
{
var path = Path.Combine(Server.MapPath("~/Content"), file);
if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found");
var extension = GetExtension(file); // psuedocode
var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain";
return File(path, mimetype);
}
}
现在,您只需要一条靠近路线列表底部的路线,如下所示:
routes.MapRoute("PublicContent", "{file}", new {controller = "Public", action = "GetFile"});
问题是,现在当您只输入 controller 名称(如“Home”)而不是默认为 HomeController 上的 Index 操作方法时,它假定您要从内容目录下载一个名为“Home”的文件。 因此,在文件路径上方,您需要为每个 controller 添加一个路径,以便它知道获取索引操作。
routes.MapRoute("HomeIndex", "Home", new { controller = "Home", action = "Index" });
因此,解决此问题的一种方法是将路线更改为:
routes.MapRoute("PublicContent", "{file}.{extension}", new {controller = "Public", action = "GetFile"});
以及对此的操作方法:
public ActionResult GetFile(string file, string extension)
{
var path = Path.Combine(Server.MapPath("~/Content"), file + "." + extension);
if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found");
var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain";
return File(path, mimetype);
}
就像我说的,这假设所有文件都在内容目录中,而不是在子文件夹中。 但是,如果您想做 Content/css/site.css 之类的子文件夹,您可以像这样添加您的路线:
routes.MapRoute("PublicContent_sub", "{subfolder}/{file}.{extension}", new { controller = "Public", action = "GetFileInFolder" });
routes.MapRoute("PublicContent", "{file}.{extension}", new { controller = "Public", action = "GetFile"});
现在动作方法也必须改变。
public ActionResult GetFile(string file, string extension)
{
return GetFileInFolder("", file, extension);
}
public ActionResult GetFileInFolder(string subfolder, string file, string extension)
{
var path = Path.Combine(Server.MapPath("~/Content"), subfolder, file + "." + extension);
if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found");
var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain";
return File(path, mimetype);
}
如果您开始在文件夹结构中深入多个级别,这将变得越来越丑陋。 但也许这对你有用。 我确定您希望项目属性中有一个复选框,但如果有,我不知道。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.