繁体   English   中英

如何修改 ASP.NET MVC static 文件根目录

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM