简体   繁体   English

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

[英]How to modify ASP.NET MVC static file root

I want to be able to reorganize my ASP.NET MVC site structure to more closely match the way Rails does it (We do both rails and ASP.net at my company).我希望能够重组我的 ASP.NET MVC 站点结构,以更接近 Rails 的方式(我们在我的公司同时使用 rails 和 ASP.net)。

In Rails, there is a "public" folder that behaves as the root of the site.在 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. 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.

In asp.net MVC there is a "Content" folder that I want to behave as the root.在 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 . So instead of accessing http://domain.com/content/myfile.html , i want to be able to do http://domain.com/myfile.html .

I know I can just drop the file in the root of the project, but i need to do this with many files including css, js, html, images, etc and want to share some standardized assets across rails and aspnetmvc.我知道我可以将文件放在项目的根目录中,但我需要对许多文件执行此操作,包括 css、js、html、图像等,并且希望跨 rails 和 aspnetmvc 共享一些标准化资产。

Is there a way to do this?有没有办法做到这一点?

There is another possible solution.还有另一种可能的解决方案。 Instead of using code, you can use a rewrite rule to handle this for you.您可以使用重写规则来为您处理此问题,而不是使用代码。 If you are using IIS 7 or above, you can use Microsoft's URL Rewrite Module.如果您使用的是 IIS 7 或更高版本,则可以使用微软的 URL Rewrite Module。

A rule like the following would probably do it:像下面这样的规则可能会做到这一点:

<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>

The rule checks for a request to a css or js file off the root of the site.该规则检查对 css 或站点根目录下的 js 文件的请求。 Then it checks to see if the file exists in the content folder.然后它检查文件是否存在于内容文件夹中。 If it exists, then the rewrite will return the file in the content folder.如果存在,则重写将返回内容文件夹中的文件。 I've only tested this a little bit, but it seems to work.我只测试了一点,但它似乎工作。 It certainly needs more testing, and possible refinement.它当然需要更多的测试和可能的改进。

The only solution I can think of, is to use a custom controller and route to do this for you.我能想到的唯一解决方案是使用自定义 controller 和路由为您执行此操作。 But it isn't a clean solution.但这不是一个干净的解决方案。

First you need a PublicController class with a GetFile action method.首先,您需要一个带有 GetFile 操作方法的 PublicController class。 This assumes that all files are in the public/content folder directly.这假定所有文件都直接位于 public/content 文件夹中。 Handling folders makes things more complicated.处理文件夹会使事情变得更加复杂。

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);
    }
}

Now, you just need a route near the bottom of your list of routes that looks like this:现在,您只需要一条靠近路线列表底部的路线,如下所示:

routes.MapRoute("PublicContent", "{file}", new {controller = "Public", action = "GetFile"});

The problem is, now when you just put in a controller name like 'Home' instead of defaulting to the Index action method on the HomeController, it assumes you want to download a file called "Home" from the content directory.问题是,现在当您只输入 controller 名称(如“Home”)而不是默认为 HomeController 上的 Index 操作方法时,它假定您要从内容目录下载一个名为“Home”的文件。 So, above the file route, you would need to add a route for each controller so it knows to get the Index action instead.因此,在文件路径上方,您需要为每个 controller 添加一个路径,以便它知道获取索引操作。

routes.MapRoute("HomeIndex", "Home", new { controller = "Home", action = "Index" });

So, one way around that is to change the route to this:因此,解决此问题的一种方法是将路线更改为:

routes.MapRoute("PublicContent", "{file}.{extension}", new {controller = "Public", action = "GetFile"});

And the action method to this:以及对此的操作方法:

    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);
    }

Like I said, this assumes that all files are in the content directory, and not in subfolders.就像我说的,这假设所有文件都在内容目录中,而不是在子文件夹中。 But if you wanted to do subfolders like Content/css/site.css you could add your routes like this:但是,如果您想做 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"});

Now the action method has to change too.现在动作方法也必须改变。

    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);
    }

If you start getting multiple levels deep in the folder structure, this gets uglier and uglier.如果您开始在文件夹结构中深入多个级别,这将变得越来越丑陋。 But maybe this will work for you.但也许这对你有用。 I'm sure you were hoping for a checkbox in the project properties, but if there is one, I don't know about it.我确定您希望项目属性中有一个复选框,但如果有,我不知道。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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