Бета-версия Angular 2 по умолчанию использует маршрутизацию html5. Однако, когда вы переходите к компоненту, и маршрут меняется (например, http: // localhost: 5000 / aboutus) и вы перезагружаете / обновляете страницу, ничего не загружается.

Проблема была поднята в этом сообщении тоже. В большинстве ответов говорится, что если мы собираемся продолжить маршрутизацию HTML5 в angular 2, то эту проблему маршрутизации следует решить на стороне сервера. Подробное обсуждение здесь .

Я не уверен, как решить эту проблему с помощью серверной среды asp.net.

Любые разработчики angular 2, которые также используют asp.net и сталкиваются с этой проблемой?

PS. Я использую ASP.NET 5. Мои маршруты Angular 2 используют маршруты MVC.

22
raberana 6 Янв 2016 в 11:23

11 ответов

Лучший ответ

Проблема, которую вы видите, связана с разницей между маршрутизацией Angular на клиенте и маршрутизацией на стороне сервера MVC. Фактически вы получаете ошибку 404 Page Not Found, потому что у сервера нет контроллера и действия для этого маршрута. Я подозреваю, что вы не обрабатываете ошибки, поэтому кажется, что ничего не происходит.

Когда вы перезагружаете http://localhost:5000/aboutus или пытаетесь установить ссылку на этот URL-адрес непосредственно с ярлыка или путем ввода его в адресную строку (глубокая ссылка), он отправляет запрос на сервер. ASP.NET MVC попытается разрешить этот маршрут, и в вашем случае он попытается загрузить aboutusController и запустить действие Index. Конечно, это не то, что вам нужно, потому что ваш маршрут aboutus является компонентом Angular.

Что вам нужно сделать, так это создать способ для маршрутизатора ASP.NET MVC передавать URL-адреса, которые должны быть разрешены Angular, обратно клиенту.

В вашем файле Startup.cs в методе Configure() добавьте резервный маршрут spa к существующим маршрутам:

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

Создавая всеобъемлющий маршрут, который указывает на контроллер и представление, которые в конечном итоге загружают ваше приложение Angular, это позволит передавать URL-адреса, которые сервер не обрабатывает, клиенту для правильной маршрутизации.

19
Brad Rem 16 Мар 2016 в 19:16

Вам нужно использовать эту маршрутизацию в ASP.NET MVC

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

Затем вам нужно настроить SystemJS с параметрами basePath

5
ZOXEXIVO 11 Мар 2016 в 15:07

В вашем Startup.cs добавьте это к методу Configure. Это должно быть перед другими операторами app.

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 10 Июн 2016 в 06:42

Выбранное выше решение не сработало для меня. Я также получил 404 после выполнения всех комментариев к T. Я использую приложение angular5 в приложении MVC5. Я использую целевую страницу индекса по умолчанию в качестве начальной для angular5. Мое приложение angular находится в папке с именем mvcroot / ClientApp /, но при сборке ng оно помещает распределенные файлы в mvcroot / Dist /, изменяя один параметр в файле .angular-cli.json с помощью "outDir": "../Dist"

Однако это решение сработало.

Таким образом, отключаются только маршруты в каталоге Dist. Теперь вы можете нажимать кнопку «Обновить» каждый раз и получать точный маршрут для перезагрузки приложения angular5, оставаясь при этом на правильном компоненте. Обязательно поставьте улов на первое место. С другой стороны, если вы используете аутентификацию токена в вашем angular5, сохраните токен в window.localStorage (или каком-либо другом механизме за пределами вашего приложения angular5), поскольку нажатие обновления уничтожит всю память, где вы, возможно, храните свой токен в глобальной переменной . Это избавляет пользователя от необходимости повторно входить в систему после обновления.

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 20 Апр 2018 в 21:32

Вы можете использовать оба маршрута при вызове Home / Index из угловой маршрутизации.

Записывать

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

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

Итак, когда URL-адрес будет Home / Index, будет загружен компонент активного URL-адреса, поэтому он загрузит компонент панели управления.

0
Engineer 25 Окт 2016 в 06:53

Примените решение @ ZOXEXIVO, затем добавьте в свой _Layout.cshtml следующее:

<head>
    <base href="/"/>
    .....
</had>
0
jcmordan 18 Апр 2016 в 14:43

Ты использовал:

Директивы: [RouterOutlet, RouterLink] в компоненте.

0
Sachin 6 Янв 2016 в 21:39

Вот еще два варианта решения этой проблемы. Вы можете добавить стратегию расположения хэша в свой модуль приложения.

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

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

Эта опция будет работать только для тех частей вашего приложения Angular2, которые находятся в Home ASP Controller.

Второй вариант - добавить в контроллер ASP маршруты, которые соответствуют маршрутам приложения Angular 2, и вернуть представление «Индекс».

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 2 Мар 2017 в 14:13

Мне не повезло с получением

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

Работать. Я все еще получаю 404 с любым маршрутом на стороне клиента.

Обновление:
Выяснили, почему маршрут для приема всей почты домена не работает: у меня был определен маршрут с атрибутом ([Route("api/RedirectIndex")]), и хотя к простому маршруту можно получить прямой доступ с помощью резервного маршрута, он не сработал. Удаление маршрута атрибута заставило его работать.

Еще одно решение, которое, кажется, работает так же просто, как и обработчик маршрута для приема всей почты домена, - это просто создать собственный обработчик, который запускается в конце конвейера промежуточного программного обеспечения в Configure():

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

});

По сути, это все-таки маршрут, который просто отправляет index.html по существующему URL-запросу, если не было другого обработчика, который принял запрос.

Это прекрасно работает даже в сочетании с Правила перезаписи IIS (в этом случае вышеуказанное просто никогда не будет запущено.

Написал сообщение в блоге по этой теме:

2
Rick Strahl 7 Авг 2017 в 19:00

Мое любимое решение - добавить в Global.asax.cs следующий код, который очень плавно и надежно решит проблему:

     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 4 Авг 2016 в 23:51

Функция, которую вы ищете, - это перезапись URL. Есть два возможных способа справиться с этим. Классический способ - позволить IIS выполнять работу, как описано здесь:

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

Если вы не хотите зависеть от IIS, вы можете вместо этого справиться с этим в промежуточном программном обеспечении ASP.NET 5, как показано в моем ответе здесь:

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

2
Community 23 Май 2017 в 12:26