.Netcore 2.0 and Virtual Directory - asp.net-core

I have a .netcore 2.0 project running on IIS windows 2012.
There is an issue as I can't seem to get virtual directories working that exist outside of the root of the application. This works fine when the files are in the solution:
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), #"wwwroot", "images")),
RequestPath = new PathString("/MyImages")
});
The below does not however when outside of the root folder -
app.UseDirectoryBrowser(new DirectoryBrowserOptions()
{
FileProvider = new PhysicalFileProvider(Configuration["Keys:UploadFolder"]),
RequestPath = new PathString("/upload")
});
The reason for doing this is I have setup CI with octopus deploy. Each time I do a deployment the uploaded files are no longer there without using a virtual directory or creating some powershell script in octopus to copy them all over from last deployment.
Any recommendations or ways of resolving this in IIS with virtual directories in .netcore 2.0?

Related

IIS ASP.NET 6 startup throws System.IO.DirectoryNotFoundException: D:\agent\_work\38\s\IdentityServer\wwwroot\

We are updating one of our applications, in this case IdentityServer, from .NET 5 to .NET 6. It is being hosted by IIS and deployed by Azure Devops Services. The issue we are seeing is that on our development environment the website fails to load but on our staging environment it runs just fine. The error we are seeing on development is
12:45:37.519|Fatal|1||Host terminated unexpectedly.||
System.IO.DirectoryNotFoundException: D:\agent\_work\38\s\IdentityServer\wwwroot\
at Microsoft.Extensions.FileProviders.PhysicalFileProvider..ctor(String root, ExclusionFilters filters)
at Microsoft.Extensions.FileProviders.PhysicalFileProvider..ctor(String root)
at Microsoft.AspNetCore.Hosting.StaticWebAssets.StaticWebAssetsLoader.<>c.<UseStaticWebAssetsCore>b__1_0(String contentRoot)
at Microsoft.AspNetCore.StaticWebAssets.ManifestStaticWebAssetFileProvider..ctor(StaticWebAssetManifest manifest, Func`2 fileProviderFactory)
at Microsoft.AspNetCore.Hosting.StaticWebAssets.StaticWebAssetsLoader.UseStaticWebAssetsCore(IWebHostEnvironment environment, Stream manifest)
at Microsoft.AspNetCore.Hosting.StaticWebAssets.StaticWebAssetsLoader.UseStaticWebAssets(IWebHostEnvironment environment, IConfiguration configuration)
at Microsoft.AspNetCore.WebHost.<>c.<ConfigureWebDefaults>b__9_0(WebHostBuilderContext ctx, IConfigurationBuilder cb)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass9_0.<ConfigureAppConfiguration>b__0(HostBuilderContext context, IConfigurationBuilder builder)
at Microsoft.Extensions.Hosting.HostBuilder.BuildAppConfiguration()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at IdentityServer.Program.Main(String[] args) in D:\agent\_work\38\s\IdentityServer\Program.cs:line 23
The path it reports, D:\agent\_work\38\s\IdentityServer\wwwroot\ is interesting because that path is the same as the path from the DevOps build machine. We don't see this error if we revert back to .NET 5 and we don't see the problem on our staging machine.
The Program.cs class is defined as
using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using NewRelic.LogEnrichers.Serilog;
using Serilog;
using Serilog.Events;
namespace IdentityServer
{
public class Program
{
public static int Main(string[] args)
{
try
{
CreateLogger();
Log.Information("Starting host...");
CreateHostBuilder(args).Build().Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly.");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
public static void CreateLogger()
{
var configuration = GetConfiguration();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.Enrich.FromLogContext() // allows logging middleware to inject output values
.Enrich.WithThreadId()
.Enrich.WithNewRelicLogsInContext()
.CreateLogger();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var configuration = GetConfiguration();
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(
webBuilder =>
{
webBuilder.UseConfiguration(configuration);
webBuilder.UseSerilog();
webBuilder.UseIIS();
webBuilder.CaptureStartupErrors(true);
webBuilder.UseStartup<Startup>();
});
}
private static IConfiguration GetConfiguration()
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{environment}.json", true, true);
var configuration = builder.Build();
return configuration;
}
}
}
We do have other .NET 6 web applications running just fine on this instance of IIS. I was thinking that the problem might be in our release pipelines but they are identical in their task configurations between the environments. Tried looking for the directory path in the code or configuration but don't see it anywhere. Have tried manually setting the WebRoot and ContentRoot paths via .UseWebRoot("path to folder") and .UseContentRoot("path to folder") in the Program.cs but didn't see any change in the logs or the app starting.
Even updated the web.config file to have the exact path for executing the project dll in the aspNetCore element but still no change.
Update 10 Feb 2022
Added debug output to the startup to verify file and folder paths. Everything in the environment variables and execution file path look correct.
ASPNETCORE_IIS_PHYSICAL_PATH - C:\inetpub\webapps\IdentityServer\
Executable Path: C:\inetpub\webapps\IdentityServer\IdentityServer.dll
The problem ended up being how we were pushing our updates out to the servers from DevOps. Our pipelines were built to copy over files out of the Release directory of the build folder. One of the problems with this approach is that files not needed for a site to run but generated during a build are also copied to the release server. In this case, a new file which is generated in .NET 6, .staticwebassets.runtime.json, was getting copied to our servers.
The way .NET 6 seems to behave is that if the environment is set to Development then it will look for this file to figure out where the static web assets are located. If the file doesn't exist then it will assume the files are in a wwwroot sub-directory of the site. This makes sense for instances where you are running the project from your local Visual Studio. More details about this file are available in another SO post with links to the source code in GitHub. To fix our problem we changed our release pipeline to use the publish.zip file that is generated when you run the publish command on a solution. The archive only contains the files needed to run the site, so none of the extraneous files like .staticwebassets.runtime.json are included. We should have been doing this the whole time... lesson learned.
We now unzip the publish.zip file, apply any file transformations, then copy the unzipped files to the web server.

Using virtual directory with ASP.NET Core 3.1

In ASP.NET framework 4.8 and below version the web application use IIS for processing and show data. And when we need to work with other resource like folders and network resource we can easily create Virtual Directory in IIS and map to physical path and my application work theme like normal folder.
but in Net Core we use Kestrel and IIS work as a proxy and Virtual Directory not recognized by Kestrel. I use this code but not work in function. Write this section in Configure Function
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(#"E:\\MyFiles"),
RequestPath = new PathString("/PFiles"),
EnableDirectoryBrowsing = true
});
and this is my code :
var folder = Path.Combine(environment.WebRootPath, "temp");
var fileName = Path.Combine(environment.WebRootPath, "temp\\test.jpeg");
var basePath = Path.Combine(environment.WebRootPath, "PFiles");
var yearPath = Path.Combine(basePath, "2020");
var monthpath = Path.Combine(basePath, "2020", "06");
if (!Directory.Exists(yearPath))
{
Directory.CreateDirectory(yearPath);
}
if (!Directory.Exists(monthpath))
{
Directory.CreateDirectory(monthpath);
}
var dpath = Path.Combine(basePath, "2020", "06");
var destinationPath = Path.Combine(environment.WebRootPath, dpath);
System.IO.File.Move(fileName, destinationPath);
but I receive Access denied Error or create directory inside of wwwroot folder. So, what must I do?
you get this error because iis default account does not have enough permission to access the folder.
you could try to assign the iis_iusrs , iusr, or IIS AppPool<myappoolname> permission to the folder where you want to create directory.

ASP.NET Core can't see images when acceding by browser

I've created an ASP.NET Core 3.1 Web API project, on IIS Express it works perfectly with the controllers. I've created a folder called images and copied some .jpg files there.
My idea was get those images from my Xamarin app using the url, like
http://192.168.0.185:52493/img/lucas.PNG
but nothing is being returned. Then I've tried writing the url directly into Internet Explorer, but nothing happens, the image is not shown in the browser either.
Any idea what it can be?
If you would like to access your file from your own folder img located in the root of the project instead of the default wwwroot folder ,you need to configure the Static File Middleware in startup.cs Configure method like below:
app.UseStaticFiles();// For the wwwroot folder
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "img")),
RequestPath = "/img"
});
app.UseRouting();
//other middlewares
Refer to https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-2.2#serve-files-outside-of-web-root

.net core how to access shared folder on server outside project

I'm building a small app and want to access files (images) from a directory outside the project but on the same server the app will be running.
How can I access the directory I want?
I used this in Startup.cs inside Configure:
app.UseFileServer(new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(env.ContentRootPath + "/Albums"),
RequestPath = new PathString("/Albums"),
EnableDirectoryBrowsing = true
});
And from Model that should be using it:
Initialize(_environment.WebRootPath + "/Albums");

How can you use multiple directories for static files in an aspnet core app?

By default, the wwwroot directory can host static files. However, in some scenarios, it might be ideal to have two directories for static files. (For example, having webpack dump a build into one gitignored directory, and keeping some image files, favicon and such in a not-gitignored directory). Technically, this could be achieved by having two folders within the wwwroot, but it might organizationally preferable to have these folders at the root level. Is there a way to configure an aspnet core app to use two separate directories for static files?
Just register UseStaticFiles twice:
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "static"))
});
Now files will be found from wwwroot and static folders.
Registering UseStaticFiles twice won't solve it for MapFallbackToFile
An alternative approach.
// Build the different providers you need
var webRootProvider =
new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider =
new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, #"Other"));
// Create the Composite Provider
var compositeProvider =
new CompositeFileProvider(webRootProvider, newPathProvider);
// Replace the default provider with the new one
app.Environment.WebRootFileProvider = compositeProvider;
https://wildermuth.com/2022/04/25/multiple-directories-for-static-files-in-aspnetcore/