Как маршрутизировать только определенные пути, иначе файлы по умолчанию / статические

#asp.net-core #.net-core #routes #asp.net-core-mvc

#asp.net-ядро #.net-ядро #маршруты #asp.net-core-mvc

Вопрос:

У меня есть CMS, работающая как ASP.NET Основное приложение MVC, и я хочу, чтобы:

  1. Для /api/ (или /api/* ) и / или /admin/ (или /admin/* ) он перехватывает ссылку и правильно маршрутизирует, используя свой контроллер MVC
  2. В противном случае используйте статический файл (которым я index.html управляю vue.js приложением и его внутренним маршрутом).

Основное использование: если я наберу /admin , запустите ASP.NET Основное приложение MVC, если я наберу / (или что-то еще, например /pages/text ), вызовет, index.html где vuejs будет действовать маршрутизация.

Как я могу это сделать?

Пробовал это:

 public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseDefaultFiles(); // load index.html as default page
    app.UseStaticFiles();
    app.UseOrchardCore();
}
  

Но это работает только с / , /api/* и /admin/* . Если я наберу /pages/text , это вызовет ASP.NET Основной контроллер MVC и, очевидно, возвращает ошибку (не vuejs app маршрутизацию).

Ответ №1:

Я сделал нечто подобное в размещенном на Blazor WebAssembly приложении с включенной аутентификацией. В моей ситуации, когда я звонил /api/{controller} в Postman, я получал html вместо json.

Я исправил это, добавив:

     app.UseEndpoints(endpoints =>
    {
        ...
        endpoints.Map("api/{**slug}", HandleApiFallback);
        endpoints.MapFallbackToFile("{**slug}", "index.html");
    });


    private Task HandleApiFallback(HttpContext context)
    {
        context.Response.StatusCode = StatusCodes.Status404NotFound;
        return Task.FromResult(0);
    }
  

Я думаю, что это также может быть адаптировано для вашей ситуации.

Другой способ, который может сработать, это:

         // In production, the Vue files will be served from this directory
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/dist";
        });




        app.UseSpaStaticFiles();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller}/{action=Index}/{id?}");

            if (env.IsDevelopment())
            {
                endpoints.MapToVueCliProxy(
                    "{*path}",
                    new SpaOptions { SourcePath = "ClientApp" },
                    npmScript: "serve",
                    regex: "Compiled successfully");
            }

            // Add MapRazorPages if the app uses Razor Pages. Since Endpoint Routing includes support for many frameworks, adding Razor Pages is now opt -in.
            endpoints.MapRazorPages();
        });

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";
        });
  

Ваше приложение Vue должно находиться внутри каталога с именем «ClientApp». Пожалуйста, взгляните на этот пример.

Ответ №2:

Вы могли бы написать промежуточное программное обеспечение, которое будет обрабатывать все 404 ответа, а затем переопределяет путь вашего запроса:

 public class ReturnDefaultMiddleware
{
    private readonly RequestDelegate _next;

    public ReturnDefaultMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        await _next(context);
        
        // If controller was found, return the actual response
        if(context.Response.HasStarted || context.Response.StatusCode != (int) HttpStatusCode.NotFound)
            return;

        // Rewrite the request to request index.html
        context.Request.Path = "/index.html";
        
        // Rerun the rest of the request pipeline
        await _next(context);
    }
}
  

Это выполнит ваш конвейер запросов как обычно. Если конвейер отвечает 404, потому что не был найден контроллер, который может обрабатывать маршрут, запрос будет переопределен.
Запустив await _next(context) снова весь процесс будут обработаны снова, но на новый index.html маршрут.

Просто добавьте новое промежуточное программное обеспечение перед запуском чего-либо еще:

 public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    // Add custom middleware here
    app.UseMiddleware<ReturnDefaultMiddleware>();

    app.UseDefaultFiles(); // load index.html as default page
    app.UseStaticFiles();
    app.UseOrchardCore();
}
  

Редактировать
Я не узнал, что существуют конкретные маршруты, на которые API должен отвечать. Если вы хотите запустить конвейер запросов MVC только на некоторых определенных маршрутах, вы можете переопределить путь для всех других маршрутов:

 app.UseWhen(ctx => !ctx.Request.Path.StartsWithSegments("/api") amp;amp; !ctx.Request.Path.StartsWithSegments("/admin"), builder =>
    {
        builder.UseMiddleware<ReturnDefaultMiddleware>();
    });
  

Это добавит промежуточное программное обеспечение ко всем запросам, которые не начинаются с path /admin или / api.
Промежуточное программное обеспечение будет таким же простым, как это:

 public class ReturnDefaultMiddleware
{
    private readonly RequestDelegate _next;
    public ReturnDefaultMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    public async Task Invoke(HttpContext context)
    {
        // Rewrite the request to request index.html
        context.Request.Path = "/index.html";
        // Rerun the request pipeline
        await _next(context);
    }
}
  

Обратите внимание, что относительные ссылки в вашем index.html не будет работать с этим решением. Вы могли бы рассмотреть возможность переопределения пути для определенных окончаний файлов или путей внутри промежуточного программного обеспечения.

Комментарии:

1. и что, когда происходит настоящий 404? Я потеряю его, перенаправив на «статические» файлы (что не так хорошо).

2. Если был найден соответствующий маршрут, context.Response.HasStarted будет true, поэтому запасной вариант использоваться не будет. Проверка была неправильной, и я исправил ее в своей правке.

3. Размышления об этом заставляют меня прийти к выводу, что проверки context.Response.HasStarted достаточно, чтобы увидеть, был ли соответствующий маршрут.

4. Пробовал ваш код, но не работает. Он просто возвращает 404

5. Смотрите мою правку в ответе. Если вы работаете с фиксированными маршрутами внутри вашего mvc, вы можете использовать UseWhen для переопределения пути на основе фактического префикса пути.

Ответ №3:

У меня была такая же проблема в ASP. NET 6 со сборкой моего приложения react, но я просто добавляю эту функцию, и это решило мою проблему (использует контроллеры, если их не найдено, использует навигацию моего приложения react, даже маршруты, которые не существуют, попадают на мою пользовательскую страницу 404 в react).

 app.Use(async (context, next) =>  
{  
    await next();  
    if (context.Response.StatusCode == 404 amp;amp; !Path.HasExtension(context.Request.Path.Value))  
    {  
        context.Request.Path = "/index.html";  
        context.Response.StatusCode = 200;  
        await next();  
    }  
}); 
  

Я думаю, что вы уже использовали эти методы, если нет, то я использовал их ПОСЛЕ функции для маршрутизации

 app.UseDefaultFiles();
app.UseStaticFiles();