ASP.NET 5 + Angular 2 маршрутизации (страница шаблона без загрузки)
Angular 2 beta использует html5 маршрутизацию по умолчанию.
Однако при переходе к компоненту и изменению маршрута (например, http://localhost:5000/aboutus) и вы перезагружаете/обновляете страницу, ничего не происходит загружен.
Проблема была поднята в этом сообщении.
Большинство ответов говорят о том, что если мы будем проводить маршрутизацию HTML5 в angular 2, то эту проблему маршрутизации следует заботиться на стороне сервера. Подробнее обсуждение здесь.
Я не уверен, как справиться с этой проблемой, используя среду сервера asp.net.
Любой angular 2 разработчик, который также использует asp.net и сталкивается с этой проблемой?
PS. Я использую ASP.NET 5. Мои маршруты angular 2 используют маршруты MVC.
Ответы
Ответ 1
Проблема, которую вы видите, связана с разницей между маршрутизацией 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()
добавьте маршрут "спа-спад" к существующим маршрутам:
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-адресам, которые сервер не обрабатывает, чтобы их передавать на клиент для правильной маршрутизации.
Ответ 2
В вашем 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();
}
});
Ответ 3
Вам нужна эта маршрутизация в ASP.NET MVC
app.UseMvc(routes =>
{
routes.MapRoute("Default", "{*url}", new { @controller = "App", @action = "Index" });
});
Затем вам нужно настроить SystemJS с параметрами basePath
Ответ 4
Мое любимое решение - добавить следующий код в 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);
}
Ответ 5
Функция, которую вы ищете, это переписать URL. Есть два возможных способа справиться с этим. Классический способ - позволить IIS выполнять работу, как описано здесь:
fooobar.com/questions/295334/...
Если вы не хотите зависеть от IIS, вы можете обрабатывать это в промежуточном программном обеспечении ASP.NET 5, как показано в моем ответе здесь:
fooobar.com/questions/295335/...
Ответ 6
Вот еще два варианта решения этой проблемы. Вы можете добавить стратегию размещения хешей в свой модуль приложения.
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
@NgModule({
imports: [.... ],
declarations: [...],
bootstrap: [AppComponent],
providers: [
{
provide: LocationStrategy,
useClass: HashLocationStrategy
}
]
})
export class AppModule { }
Этот параметр будет работать только для частей вашего приложения Angular2, которые живут на домашнем ASP-контроллере
Второй вариант - добавить маршруты к вашему ASP-контроллеру, которые соответствуют вашим маршрутам приложений Angular 2 и вернуть представление "Index"
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[ActionName("Angular-Route1")]
public IActionResult AngularRoute1()
{
return View("Index");
}
public IActionResult Route2()
{
return View("Index");
}
}
Ответ 7
Мне не повезло получить
routes.MapRoute("Default", "{*url}",
new { @controller = "App", @action = "RedirectIndex" });
работать. Я все еще получаю 404 с любым маршрутом на стороне клиента.
Update:
Выяснил, почему весь маршрут не работает: у меня был определенный маршрут атрибута ([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"));
});
Это в основном заканчивается тем самым маршрутом catch-all, который просто отправляет index.html через существующий запрос URL, если не было другого обработчика, который взял запрос.
Это прекрасно работает даже в сочетании с Правила перезаписи IIS (и в этом случае вышеуказанное просто не будет срабатывать.
Написал сообщение в блоге по этой теме:
Ответ 8
Вы использовали:
: [RouterOutlet, RouterLink] в компоненте.
Ответ 9
примените решение @ZOXEXIVO, тогда в вашем _Layout.cshtml добавьте следующее:
<head>
<base href="/"/>
.....
</had>
Ответ 10
Вы можете использовать как маршрутизацию
когда вы вызываете Home/Index из маршрутизации angular.
написать
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-адреса, чтобы он загружал компонент панели инструментов.