Фон
Сначала позвольте мне объяснить предысторию. Я работаю над проектом, который пытается объединить внутренний сервер, который использует веб-API, настроенный через OWIN, размещенный сейчас на IIS, но потенциально другие хосты с поддержкой OWIN в будущем, с интерфейсом, использующим AngularJS.
Интерфейс AngularJS - это полностью статический контент. Я полностью избегаю серверных технологий, таких как MVC / Razor, WebForms, Bundles, всего, что связано с интерфейсом и используемыми им активами, и вместо этого использую новейшие и лучшие методы с использованием Node.js, Grunt / Gulp и т. Д. . для обработки компиляции CSS, объединения, минификации и т. д. По причинам, которые я не буду здесь вдаваться, я храню проекты внешнего интерфейса и сервера в разных местах в одном проекте (вместо того, чтобы вставлять их все напрямую в проект хоста (см. диаграмму ниже).
MyProject.sln
server
MyProject.Host
MyProject.Host.csproj
Startup.cs
(etc.)
frontend
MyProjectApp
app.js
index.html
MyProjectApp.njproj
(etc.)
Итак, что касается внешнего интерфейса, все, что мне нужно сделать, это заставить мой хост обслуживать мой статический контент. В Express.js это тривиально. С OWIN я мог легко сделать это с помощью Microsoft.Owin.StaticFiles промежуточное ПО, и оно отлично работает (очень гладко).
Вот моя OwinStartup
конфигурация:
string dir = AppDomain.CurrentDomain.RelativeSearchPath; // get executing path
string contentPath = Path.GetFullPath(Path.Combine(dir, @"../../../frontend/MyProjectApp")); // resolve nearby frontend project directory
app.UseFileServer(new FileServerOptions
{
EnableDefaultFiles = true,
FileSystem = new PhysicalFileSystem(contentPath),
RequestPath = new PathString(string.Empty) // starts at the root of the host
});
// ensure the above occur before map handler to prevent native static content handler
app.UseStageMarker(PipelineStage.MapHandler);
Улов
По сути, он просто размещает все в frontend/MyProjectApp
, как если бы оно находилось прямо в корне MyProject.Host. Поэтому, естественно, если вы запрашиваете несуществующий файл, IIS генерирует ошибку 404.
Теперь, поскольку это приложение AngularJS и оно поддерживает html5mode
, я будут иметь некоторые маршруты, которые не являются физическими файлами на сервере, но обрабатываются как маршруты в приложении AngularJS. Если бы пользователь перешел на AngularJS (что-либо, кроме index.html
или файла, который физически существует, в этом примере), я бы получил 404, даже если этот маршрут мог бы быть действительным в приложении AngularJS. Поэтому мне нужно, чтобы мое промежуточное ПО OWIN возвращало файл index.html
в случае, если запрошенный файл не существует, и позволяло моему приложению AngularJS выяснить, действительно ли это 404.
Если вы знакомы с SPA и AngularJS, это нормальный и простой подход. Если бы я использовал маршрутизацию MVC или ASP.NET, я мог бы просто установить маршрут по умолчанию к контроллеру MVC, который возвращает мой index.html
или что-то в этом роде. Однако я уже заявлял, что не использую MVC, и я стараюсь сделать это как можно более простым и легким.
У этого пользователя была аналогичная дилемма, и он решил ее с помощью перезаписи IIS. В моем случае это не работает, потому что а) мой контент физически не существует там, где модуль перезаписи URL может его найти, поэтому он всегда возвращает index.html
и б) я хочу что-то, что не полагаются на IIS, но обрабатываются в промежуточном программном обеспечении OWIN, поэтому его можно использовать гибко.
TL; DNR меня, за то, что громко кричал.
Просто, как я могу перехватить 404 Not Found и вернуть содержимое (примечание: не перенаправления) моего FileServer
обслуживаемого index.html
с помощью промежуточного программного обеспечения OWIN?