web-dev-qa-db-de.com

ASP.NET 5 + Angular 2 Routing (Vorlagenseite nicht erneut geladen)

Angular 2 beta verwendet standardmäßig html5-Routing. Wenn Sie jedoch zu einer Komponente wechseln und die Route geändert wird (z. B. http: // localhost: 5000/aboutus ) und Sie die Seite neu laden/aktualisieren, nichts ist geladen

Das Problem wurde in diesem post also .. .. Die meisten Antworten besagen, dass, wenn wir HTML5-Routing in Winkel 2 verfolgen wollen, dieses Problem des Routing in erledigt werden sollte serverseitig. Weitere Diskussion hier.

Ich bin nicht sicher, wie Sie dieses Problem in der asp.net-Serverumgebung behandeln.

Irgendwelche ewigen Entwickler, die ebenfalls asp.net verwenden und auf dieses Problem stoßen?

PS. Ich verwende ASP.NET 5. Meine Angular 2-Routen verwenden MVC-Routen.

21
raberana

Das Problem, das Sie sehen, hat mit dem Unterschied zwischen dem Routing von Angular auf dem Client und dem serverseitigen MVC-Routing zu tun. Sie erhalten tatsächlich einen 404 Page Not Found-Fehler, da der Server keinen Controller und keine Aktion für diese Route hat. Ich vermute, Sie behandeln keine Fehler, weshalb es so aussieht, als ob nichts passiert.

Wenn Sie http://localhost:5000/aboutus neu laden oder versuchen, eine Verknüpfung zu dieser URL direkt aus einer Verknüpfung oder durch Eingabe in die Adressleiste (Deep Linking) herzustellen, sendet es eine Anfrage an den Server. ASP.NET MVC versucht, diese Route aufzulösen. In Ihrem Fall wird versucht, die Variable aboutusController zu laden und die Aktion Index auszuführen. Natürlich wollen Sie das nicht, denn Ihre aboutus-Route ist eine Angular -Komponente.

Was Sie tun sollten, ist eine Möglichkeit für den ASP.NET MVC-Router zu schaffen, URLs, die von Angular aufgelöst werden sollen, an den Client zurückzuleiten.

Fügen Sie in Ihrer Startup.cs-Datei in der Configure()-Methode eine Route "Spa-Fallback" zu den vorhandenen Routen hinzu:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

    // when the user types in a link handled by client side routing to the address bar 
    // or refreshes the page, that triggers the server routing. The server should pass 
    // that onto the client, so Angular can handle the route
    routes.MapRoute(
        name: "spa-fallback",
        template: "{*url}",
        defaults: new { controller = "Home", action = "Index" }
    );
});

Durch das Erstellen einer Catch-All-Route, die auf den Controller und die View verweist, die schließlich Ihre App Angular laden, können URLs, die der Server nicht verarbeitet, zur ordnungsgemäßen Weiterleitung an den Client übergeben werden.

16
Brad Rem

Fügen Sie dies in Ihrem Startup.cs der Configure-Methode hinzu. Dies muss vor anderen app-Anweisungen stehen.

app.Use(async (context, next) => {
    await next();

    if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) {
        context.Request.Path = "/index.html"; // Put your Angular root page here 
        await next();
    }
});
8
Jaanus

Meine Lieblingslösung ist, den folgenden Code zu Global.asax.cs hinzuzufügen, der das Problem sehr reibungslos und zuverlässig erledigt:

     private const string RootUrl = "~/Home/Index";
     // You can replace "~Home/Index" with whatever holds your app selector (<my-app></my-app>)
     // such as RootUrl="index.html" or any controller action or browsable route

     protected void Application_BeginRequest(Object sender, EventArgs e)
        {
            // Gets incoming request path
            var path = Request.Url.AbsolutePath;

            // To allow access to api via url during testing (if you're using api controllers) - you may want to remove this in production unless you wish to grant direct access to api calls from client...
            var isApi = path.StartsWith("/api", StringComparison.InvariantCultureIgnoreCase);
            // To allow access to my .net MVCController for login
            var isAccount = path.StartsWith("/account", StringComparison.InvariantCultureIgnoreCase);
            if (isApi || isAccount)
            {
                return;
            }

            // Redirects to the RootUrl you specified above if the server can't find anything else
            if (!System.IO.File.Exists(Context.Server.MapPath(path)))
                Context.RewritePath(RootUrl);
        }
6
Methodician

Sie müssen dieses Routing in ASP.NET MVC verwenden

app.UseMvc(routes =>
{
     routes.MapRoute("Default", "{*url}",  new { @controller = "App", @action = "Index" });
});

Dann müssen Sie SystemJS mit basePath-Optionen einrichten

5
ZOXEXIVO

Ich habe kein Glück bekommen 

 routes.MapRoute("Default", "{*url}",  
                  new { @controller = "App", @action = "RedirectIndex" });

arbeiten. Ich bekomme immer noch eine 404 mit einer clientseitigen Route.

Update:
Ich habe herausgefunden, warum die Catch-All-Route nicht funktionierte: Ich hatte eine definierte Attribut-Route ([Route("api/RedirectIndex")]) und die ebene Route kann direkt mit der Fallback-Route aufgerufen werden, die jedoch nicht ausgelöst wurde. Das Entfernen der Attributroute hat funktioniert.

Eine andere Lösung, die genauso einfach zu funktionieren scheint wie der catch-all-Routenhandler, ist das Erstellen eines benutzerdefinierten Handlers, der am Ende der Middleware-Pipeline in Configure() ausgelöst wird:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

});

//handle client side routes
app.Run( async (context) =>
{
        context.Response.ContentType = "text/html";
        await context.Response.SendFileAsync(Path.Combine(env.WebRootPath,"index.html"));

});

Dies ist im Wesentlichen die Catch-All-Route, die einfach index.html über die vorhandene URL-Anforderung aussendet, wenn kein anderer Handler die Anforderung abgerufen hat.

Dies funktioniert auch in Kombination mit IIS Rewrite-Regeln (in diesem Fall werden die oben genannten Informationen einfach nicht gefeuert.

Schreibe einen Blogbeitrag zu diesem Thema:

2
Rick Strahl

Die Funktion, nach der Sie suchen, ist die URL-Umschreibung. Es gibt zwei Möglichkeiten, damit umzugehen. Die klassische Methode besteht darin, IIS die Arbeit machen zu lassen, wie hier beschrieben:

https://stackoverflow.com/a/25955654/3207433

Wenn Sie sich nicht auf IIS verlassen wollen, können Sie dies in der ASP.NET 5-Middleware tun, wie in meiner Antwort hier gezeigt:

https://stackoverflow.com/a/34882405/3207433

2
Bill

Hier sind zwei weitere Möglichkeiten, dieses Problem zu lösen. Sie können entweder die Hash-Standortstrategie zu Ihrem App-Modul hinzufügen.

import { LocationStrategy, HashLocationStrategy } from '@angular/common';

@NgModule({
imports: [.... ],
declarations: [...],
bootstrap: [AppComponent],
providers: [
{
  provide: LocationStrategy,
  useClass: HashLocationStrategy
}
]
})
export class AppModule { }

Diese Option funktioniert nur für die Teile Ihrer Angular2-App, die sich auf dem Home ASP -Controller befinden

Die zweite Option ist das Hinzufügen von Routen zu Ihrem ASP -Controller, die mit den App-Routen von Angular 2 übereinstimmen, und die Ansicht "Index" zurückgeben

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [ActionName("Angular-Route1")]
    public IActionResult AngularRoute1()
    {
        return View("Index");
    }

    public IActionResult Route2()
    {
        return View("Index");
    }
}
1
Allen Rufolo

Sie können das Routing Verwenden, wenn Sie Home/Index aus dem Winkelrouting aufrufen.

schreiben 

Home/Index.cshtml
<my-app></my-app>

app.routing.ts
    const routes: Routes = [
        { path: '', redirectTo: '/Home/Index', pathMatch: 'full' },
        { path: 'Home/Index', component: DashboardComponent }
    ]

Wenn also die URL Home/Index ist lädt die Komponente der aktiven URL, sodass die Dashboard-Komponente geladen wird.

0
Engineer

Die oben ausgewählte Lösung hat bei mir nicht funktioniert. Ich habe auch 404 erhalten, nachdem ich alle Kommentare zu T gelesen habe. Ich verwende eine angle5-App in einer MVC5-App. Ich verwende die Standard-Index-Landing-Page als Start für das angle5. Meine winkelige App befindet sich in einem Ordner mit dem Namen mvcroot/ClientApp /, aber beim Erstellen werden die verteilten Dateien in mvcroot/Dist/gespeichert, indem eine Einstellung in der .angular-cli.json-Datei mit "outDir" geändert wird: "../Dist".

Diese Lösung hat jedoch funktioniert. 

Auf diese Weise werden nur Routen im Dist-Verzeichnis überschrieben. Sie können jetzt jedes Mal auf "Aktualisieren" klicken und die genaue Route für das Laden der angle5-App bestimmen, während Sie sich auf die richtige Komponente beschränken. Stellen Sie sicher, dass Sie den Fang zuerst setzen. Wenn Sie einen Token-Auth in Ihrem angle5 verwenden, speichern Sie das Token in window.localStorage (oder einem anderen Mechanismus außerhalb der angle5-App), da beim Aktualisieren der gesamte Speicher gelöscht wird, in dem Sie Ihr Token möglicherweise in einer globalen Variablen speichern . Dies verhindert, dass sich der Benutzer erneut anmelden muss, wenn er aktualisiert wird.

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Catch All",
                "dist/{*url}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional });

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }


            );
0
RandallTo

Hast du benutzt: 

anweisungen: [RouterOutlet, RouterLink] in der Komponente. 

0
Sachin

wenden Sie die Lösung von @ ZOXEXIVO an und fügen Sie in Ihrer _Layout.cshtml Folgendes hinzu:

<head>
    <base href="/"/>
    .....
</had>
0
jcmordan