web-dev-qa-db-fra.com

Comment router TOUT autre chose que l'API Web vers /index.html

J'ai travaillé sur un projet AngularJS, à l'intérieur d'ASP.NET MVC en utilisant l'API Web. Cela fonctionne très bien, sauf lorsque vous essayez d'aller directement à une URL routée angular ou d'actualiser la page. Plutôt que de créer une monkey avec la configuration du serveur, je pensais que ce serait quelque chose que je pourrais gérer avec Moteur de routage de MVC.

WebAPIConfig actuel:

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

RouteConfig actuelle:

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/*");
    }
}

Actuel 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,
        };
    }
}

OBJECTIF:

/ api/* continue d'aller vers WebAPI,/partials/ et/assets/ tous vont au système de fichiers, absolument tout le reste est routé vers/index .html, qui est mon Angular application d'une seule page.

- MODIFIER -

Il semble que je l'ai fait fonctionner. Ajouté ceci au BOTTOM OF RouteConfig.cs:

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

Et ce changement à la racine 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>

Cependant, ça sent comme un hack. Une meilleure façon de procéder?

53
Scott R. Frost

Utilisez un segment générique:

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

Suggérer une approche plus native

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

dans mon cas, aucune de ces approches n'a fonctionné. j'étais coincé dans 2 enfers de message d'erreur. soit ce type de page n'est pas servi ou une sorte de 404.

la réécriture d'url a fonctionné:

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

remarquez que j'ai fait une correspondance sur [a-zA-Z] parce que je ne veux pas réécrire les URLs .js .map etc.

cela fonctionnait dans VS out of hte box, mais dans IIS vous devrez peut-être installer un module de réécriture d'url https://www.iis.net/downloads/Microsoft/url -rewrite

5
Sonic Soul

J'ai eu une approche similaire à celle des quelques premières réponses, mais l'inconvénient est que si quelqu'un fait un appel d'API de manière incorrecte, il finira par récupérer cette page d'index au lieu de quelque chose de plus utile.

J'ai donc mis à jour le mien de telle sorte qu'il renverra ma page d'index pour toute demande ne commençant pas par/api:

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

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

Eh bien, je viens de supprimer l'appel RouteConfig.RegisterRoutes(RouteTable.Routes); dans Global.asax.cs et maintenant quelle que soit l'URL que j'entre, si la ressource existe, elle sera servie. Même les pages d'aide de l'API fonctionnent toujours.

0
Andreas