I have following Web.Config, which works fine for IIS. However its not working for self hosted like in Windows Service.
<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>
So that the UI won't treat /api as part of html url.
However I hosted this application in windows service and this web.config file is no longer works. The index.html file is being returned.
Is there a way I could add this rule to .net core, so that same rule is applied when I host it in Windows Service rather than IIS.
Startup 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");
}
});
}
Program Class:
Added following logic to run as Windows Service
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 Core URL Rewriting Middleware was created specifically for this purpose. Per the documentation: Use URL Rewriting Middleware when you're unable to use the following approaches:
The first step is to establish URL rewrite and redirect rules by creating an instance of the RewriteOptions class with extension methods for any of your rewrite rules. An example of this is defined below:
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/$1")
.AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
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}"));
}
Regex Matching
If you specifically want to use rewrites utilizing regex matching then you can use AddRedirect to redirect requests. The first parameter contains your regex for matching on the path of the incoming URL. The second parameter is the replacement string. The third parameter, if present, specifies the status code. If you don't specify the status code, the status code defaults to 302 - Found, which indicates that the resource is temporarily moved or replaced.
Example:
AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
skipRemainingRules: true)
For your specific request
For your specific request you would use something akin to the following in your Configure method:
var options = new RewriteOptions().AddRewrite(@"\/(api)\/(.*)", "\/$2",true);
Keep in mind you may have to adjust the regex values to suit a specific purpose depending on your application configuration. app.UseRewriter(rewrite);