如何从 web.config、API 调用返回 index.html 复制 .​​net 核心启动中的重写规则

How to replicate rewrite rule in .net core startup from web.config, API calls returning index.html

我有以下 Web.Config,它适用于 IIS。但是,它不适用于 Windows 服务中的自托管。

 <system.webServer>
  <rewrite>
    <rules>
      <rule name="Angular Routes" stopProcessing="true">
        <match url="./*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
        </conditions>
      </rule>
    </rules>
  </rewrite>
</system.webServer>

这样 UI 就不会将 /api 视为 html url 的一部分。

但是我在 windows 服务中托管了这个应用程序,这个 web.config 文件不再有效。正在返回 index.html 文件。

有什么方法可以将此规则添加到 .net 核心,以便在 Windows 服务而不是 IIS 中托管它时应用相同的规则。

启动class:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "publish/ClientApp/dist";
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();

            app.UseStaticFiles();

            if (!env.IsDevelopment())
            {
                app.UseSpaStaticFiles();
            }

            app.UseRouting();

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

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

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }

计划Class:

将以下逻辑添加到 运行 作为 Windows 服务

public static void Main(string[] args)
        {
            //Check for the Debugger is attached or not if attached then run the application in IIS or IISExpress
            var isService = false;

            //when the service start we need to pass the --service parameter while running the .exe
            if (Debugger.IsAttached == false && args.Contains("--service"))
            {
                isService = true;
            }

            if (isService)
            {
                //Get the Content Root Directory
                var pathToContentRoot = Directory.GetCurrentDirectory();

                string ConfigurationFile = "appsettings.json"; //Configuration file.
                string portNo = "5003"; //Port

                var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
                pathToContentRoot = Path.GetDirectoryName(pathToExe);

                //Get the json file and read the service port no if available in the json file.
                string AppJsonFilePath = Path.Combine(pathToContentRoot, ConfigurationFile);

                if (File.Exists(AppJsonFilePath))
                {
                    using (StreamReader sr = new StreamReader(AppJsonFilePath))
                    {
                        string jsonData = sr.ReadToEnd();
                        JObject jObject = JObject.Parse(jsonData);
                        if (jObject["ServicePort"] != null)
                            portNo = jObject["ServicePort"].ToString();

                    }
                }

                var host = WebHost.CreateDefaultBuilder(args)
                .UseContentRoot(pathToContentRoot)
                .UseStartup<Startup>()
                .UseUrls("http://localhost:" + portNo)
                .Build();

                host.RunAsService();
            }
            else
            {
                CreateHostBuilder(args).Build().Run();
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

ASP.NET 核心 URL 重写中间件就是专门为此目的创建的。 Per the documentation:当您无法使用以下方法时,请使用 URL 重写中间件:

  • URL 在 Windows 服务器
  • 上用 IIS 重写模块
  • Apache mod_rewrite Apache 服务器上的模块
  • URL 在 Nginx 上重写

第一步是建立 URL 重写和重定向规则,方法是创建 RewriteOptions class 实例,并为您的任何重写规则提供扩展方法。下面定义了一个例子:

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=&var2=", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

正则表达式匹配

如果您特别想使用正则表达式匹配进行重写,那么您可以使用 AddRedirect 来重定向请求。第一个参数包含用于匹配传入 URL 路径的正则表达式。第二个参数是替换字符串。第三个参数(如果存在)指定状态代码。如果不指定状态码,状态码默认为302 - Found,表示资源被临时移动或替换。

示例:

AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=&var2=", 
                skipRemainingRules: true)

根据您的具体要求

根据您的具体要求,您可以在 Configure 方法中使用类似于以下内容的内容:

var options = new RewriteOptions().AddRewrite(@"\/(api)\/(.*)", "\/",true);

请记住,您可能需要根据您的应用程序配置调整正则表达式值以适应特定目的。 app.UseRewriter(重写);

您需要 运行 和 RunAsCustomService

public static class WebHostServiceExtensions
{
    public static void RunAsCustomService(this IWebHost host)
    {
        var webHostService = new CustomWebHostService(host);
        ServiceBase.Run(webHostService);
    }
}

可能Here可以解决您的问题。