【问题标题】:How to route EVERYTHING other than Web API to /index.html如何将 Web API 以外的所有内容路由到 /index.html
【发布时间】:2013-11-07 17:01:53
【问题描述】:

我一直在使用 Web API 在 ASP.NET MVC 内部开发一个 AngularJS 项目。除非您尝试直接转到有角度的路由 URL 或刷新页面,否则它工作得很好。我认为我可以使用 MVC 的路由引擎来处理这件事,而不是胡闹服务器配置。

当前的 WebAPIConfig:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints: new { id = @"^[0-9]+$" }
        );

        config.Routes.MapHttpRoute(
            name: "ApiWithActionAndName",
            routeTemplate: "api/{controller}/{action}/{name}",
            defaults: null,
            constraints: new { name = @"^[a-z]+$" }
        );

        config.Routes.MapHttpRoute(
            name: "ApiWithAction",
            routeTemplate: "api/{controller}/{action}",
            defaults: new { action = "Get" }
        );
    }
}

当前路由配置:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.IgnoreRoute(""); //Allow index.html to load
        routes.IgnoreRoute("partials/*"); 
        routes.IgnoreRoute("assets/*");
    }
}

当前 Global.asax.cs:

public class WebApiApplication : HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        GlobalConfiguration.Configure(WebApiConfig.Register);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        var formatters = GlobalConfiguration.Configuration.Formatters;
        formatters.Remove(formatters.XmlFormatter);
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings
        {
            Formatting = Formatting.Indented,
            PreserveReferencesHandling = PreserveReferencesHandling.None,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
        };
    }
}

目标:

/api/* 继续转到 WebAPI,/partials/ 和 /assets/ 都转到文件系统,绝对其他任何东西都被路由到 /index.html,这是我的 Angular 单曲页面应用程序。

--编辑--

我似乎已经让它工作了。将此添加到 BOTTOM OF RouteConfig.cs:

 routes.MapPageRoute("Default", "{*anything}", "~/index.html");

而对根 web.config 的更改:

<system.web>
...
  <compilation debug="true" targetFramework="4.5.1">
    <buildProviders>
      ...
      <add extension=".html" type="System.Web.Compilation.PageBuildProvider" /> <!-- Allows for routing everything to ~/index.html -->
      ...
    </buildProviders>
  </compilation>
...
</system.web>

但是,它闻起来像黑客。有更好的方法吗?

【问题讨论】:

  • 作为对那些尝试的人(并且对于他们下面的答案并不理想)的说明,这个问题中列出的黑客有效,但如果用户输入的路径也恰好是一个文件夹,则不是。因此,例如,如果您将所有内容路由到 ~/index.html,那么只有在您的应用程序中没有名为 /whatever/ 的文件夹路径时,路径 /whatever/ 才会路由到那里。
  • 任何想法如何解决这个警告?
  • 感谢一个不得不将 Angular 塞进旧版 MVC 应用程序的人

标签: c# asp.net asp.net-mvc asp.net-mvc-4 angularjs


【解决方案1】:

几天前我一直在使用 OWIN Self-Host 和 React Router,并且遇到了可能类似的问题。这是我的解决方案。

我的解决方法很简单;检查它是否是系统中的文件;否则返回 index.html。因为如果请求其他一些静态文件,您并不总是希望返回 index.html。

在您的 Web API 配置文件中:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

config.Routes.MapHttpRoute(
    name: "Default",
    routeTemplate: "{*anything}",
    defaults: new { controller = "Home", action = "Index" }
);

然后创建一个 HomeController 如下...

public class HomeController: ApiController
{
    [HttpGet]
    [ActionName("Index")]
    public HttpResponseMessage Index()
    {
        var requestPath = Request.RequestUri.AbsolutePath;
        var filepath = "/path/to/your/directory" + requestPath;

        // if the requested file exists in the system
        if (File.Exists(filepath))
        {
            var mime = MimeMapping.GetMimeMapping(filepath);
            var response = new HttpResponseMessage();
            response.Content = new ByteArrayContent(File.ReadAllBytes(filepath));
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(mime);
            return response;
        }
        else
        {
            var path = "/path/to/your/directory/index.html";
            var response = new HttpResponseMessage();
            response.Content = new StringContent(File.ReadAllText(path));
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
            return response;
        }
    }
}

【讨论】:

  • 评论希望如果有人正在寻找VueJS Router 的解决方案,它将有助于搜索引擎索引。这对于我在带有 ApiController 的 C# 中实现它的方式绝对完美。
【解决方案2】:

我有一个与前几个答案类似的方法,但缺点是如果有人错误地调用 API,他们最终会返回那个索引页面,而不是更有用的东西。

所以我更新了我的,这样它就会为任何不以 /api 开头的请求返回我的索引页面:

        //Web Api
        GlobalConfiguration.Configure(config =>
        {
            config.MapHttpAttributeRoutes();
        });

        //MVC
        RouteTable.Routes.Ignore("api/{*anything}");
        RouteTable.Routes.MapPageRoute("AnythingNonApi", "{*url}", "~/wwwroot/index.html");

【讨论】:

  • 这个答案对我有用。在 web api 配置之后,我将 2x RouteTable 配置添加到我的 global.asax 中,并且我注册了 .html PageBuilderProvider 并且它起作用了。除了默认的 /api 路由之外,不需要注册任何额外的 web api 路由。我部署在应用程序根目录中的 Angular 4 应用程序与路由完美配合,所有包、图像和其他文件也按预期运行。竖起大拇指!
【解决方案3】:

就我而言,这些方法都不起作用。我被困在 2 个错误消息地狱中。 不提供此类页面或某种 404。

url 重写成功:

<system.webServer>
    <rewrite>
      <rules>
        <rule name="AngularJS" stopProcessing="true">
          <match url="[a-zA-Z]*" />

          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
    ...

注意我在 [a-zA-Z] 上匹配,因为我不想重写任何 .js .map 等 url。

这在 VS 中开箱即用,但在 IIS 中您可能需要安装 url-rewrite 模块 https://www.iis.net/downloads/microsoft/url-rewrite

【讨论】:

  • 对我来说,这行得通,但我不得不将模式更改为 .*(api)
【解决方案4】:

好吧,我刚刚删除了 Global.asax.cs 中的 RouteConfig.RegisterRoutes(RouteTable.Routes); 调用,现在无论我输入什么 url,如果资源存在,它将被提供。甚至 API 帮助页面仍然有效。

【讨论】:

  • 您描述的行为是预期的,但不是问题所要求的。当然,您可以提供静态资源。问题是,如何将任意路由映射到特定的静态资源(index.html)。
  • 抱歉修改了错误的答案,现在删除了:)
【解决方案5】:

建议更多原生方法

<system.webServer>
    <httpErrors errorMode="Custom">
        <remove statusCode="404" subStatusCode="-1"/>
        <error statusCode="404" prefixLanguageFilePath="" path="/index.cshtml" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

【讨论】:

  • 工作完美,更符合其他 Web 服务器的配置方式。谢谢!
  • 不确定这是否是“正确的方法”,但在寻找其他方法后,我又回到了这个。迄今为止最好的。
  • 也为我工作,因为我只使用 ASP.NET API,我没有可用的路由配置,因为它只在 System.Web.Mvc 中可用。这完美地工作。谢谢!
  • 使用此方法后,我收到“未提供此类页面”错误
【解决方案6】:

使用通配符段:

routes.MapRoute(
    name: "Default",
    url: "{*anything}",
    defaults: new { controller = "Home", action = "Index" }
);

【讨论】:

  • 通配符可能会起作用,我可以让它转到平面文件而不是 MVC 控制器吗?或者,我将如何制作一个带有 Index 操作的 Home 控制器,该操作将执行传递给 index.html,同时保持他们输入的任何内容作为 URL(例如 /something/edit/123)?
  • 在 ASP.NET MVC 中,请求总是发送到控制器,控制器使用视图引擎生成视图。这可以是一个没有什么特别之处的简单 HTML 文件,请参阅Controller.View。只需将文件重命名为 .cshtml,将其放在 Views/Home 文件夹中,然后在文件顶部将 Layout 设置为 null。
  • 我的答案中的路由将保留用户请求的任何 URL。
  • 这不是 web api...是吗?
猜你喜欢
  • 2021-10-29
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
  • 2019-07-17
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2014-12-08
相关资源
最近更新 更多