How to get absolute path in ASP.Net Core alternative way for Server.MapPath

C#asp.netasp.net Core.Net Coreasp.net Core-Mvc

C# Problem Overview


How to get absolute path in ASP net core alternative way for Server.MapPath

I have tried to use IHostingEnvironment but it doesn't give proper result.

IHostingEnvironment env = new HostingEnvironment();
var str1 = env.ContentRootPath; // Null
var str2 = env.WebRootPath; // Null, both doesn't give any result 

I have one image file (Sample.PNG) in wwwroot folder I need to get this absolute path.

C# Solutions


Solution 1 - C#

As of .Net Core v3.0, it should be IWebHostEnvironment to access the WebRootPath which has been moved to the web specific environment interface.

Inject IWebHostEnvironment as a dependency into the dependent class. The framework will populate it for you

public class HomeController : Controller {
    private IWebHostEnvironment _hostEnvironment;

    public HomeController(IWebHostEnvironment environment) {
        _hostEnvironment = environment;
    }

    [HttpGet]
    public IActionResult Get() {
        string path = Path.Combine(_hostEnvironment.WebRootPath, "Sample.PNG");
        return View();
    }
}

You could go one step further and create your own path provider service abstraction and implementation.

public interface IPathProvider {
    string MapPath(string path);
}

public class PathProvider : IPathProvider {
    private IWebHostEnvironment _hostEnvironment;

    public PathProvider(IWebHostEnvironment environment) {
        _hostEnvironment = environment;
    }

    public string MapPath(string path) {
        string filePath = Path.Combine(_hostEnvironment.WebRootPath, path);
        return filePath;
    }
}

And inject IPathProvider into dependent classes.

public class HomeController : Controller {
    private IPathProvider pathProvider;

    public HomeController(IPathProvider pathProvider) {
        this.pathProvider = pathProvider;
    }

    [HttpGet]
    public IActionResult Get() {
        string path = pathProvider.MapPath("Sample.PNG");
        return View();
    }
}

Make sure to register the service with the DI container

services.AddSingleton<IPathProvider, PathProvider>();

Solution 2 - C#

.NET Core 3.0

Var 1:

string path = System.IO.Directory.GetCurrentDirectory();

Var 2:

string path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, AppDomain.CurrentDomain.BaseDirectory.IndexOf("\\bin"));

Solution 3 - C#

*** Hack *** Not recommended, but FYI you can get an absolute path from a relative path with

var abs = Path.GetFullPath("~/Content/Images/Sample.PNG").Replace("~\\","");

Prefer the DI/Service approaches above, but if you are in a non-DI situation (e.g., a class instantiated with Activator) this will work.

Solution 4 - C#

.Net Core 3

For example I want to locate ~/wwwroot/CSS

public class YourController : Controller 
{
    private readonly IWebHostEnvironment _webHostEnvironment;

    public YourController (IWebHostEnvironment webHostEnvironment)
    {
        _webHostEnvironment= webHostEnvironment;
    }

    public IActionResult Index()
    {
        string webRootPath = _webHostEnvironment.WebRootPath;
        string contentRootPath = _webHostEnvironment.ContentRootPath;

        string path ="";
        path = Path.Combine(webRootPath , "CSS");
        //or path = Path.Combine(contentRootPath , "wwwroot" ,"CSS" );
        return View();
    }
}

Some Tricks

Also if you don't have a controller or service,follow last Part and register it's class as a singleton. Then, in Startup.ConfigureServices:

services.AddSingleton<your_class_Name>();

Finally, inject your_class_Name where you need it.


.Net Core 2

For example I want to locate ~/wwwroot/CSS

public class YourController : Controller
{
    private readonly IHostingEnvironment _HostEnvironment;

    public YourController (IHostingEnvironment HostEnvironment)
    {
        _HostEnvironment= HostEnvironment;
    }

    public ActionResult Index()
    {
        string webRootPath = _HostEnvironment.WebRootPath;
        string contentRootPath = _HostEnvironment.ContentRootPath;

        string path ="";
        path = Path.Combine(webRootPath , "CSS");
        //or path = Path.Combine(contentRootPath , "wwwroot" ,"CSS" );
        return View();
    }
}

MoreDetails

Thanks to @NKosi but IHostingEnvironment is obsoleted in MVC core 3!!

according to this :

Obsolete types (warning):

Microsoft.Extensions.Hosting.IHostingEnvironment
Microsoft.AspNetCore.Hosting.IHostingEnvironment
Microsoft.Extensions.Hosting.IApplicationLifetime
Microsoft.AspNetCore.Hosting.IApplicationLifetime
Microsoft.Extensions.Hosting.EnvironmentName
Microsoft.AspNetCore.Hosting.EnvironmentName

New types:

Microsoft.Extensions.Hosting.IHostEnvironment
Microsoft.AspNetCore.Hosting.IWebHostEnvironment : IHostEnvironment
Microsoft.Extensions.Hosting.IHostApplicationLifetime
Microsoft.Extensions.Hosting.Environments 

So you must use IWebHostEnvironment instead of IHostingEnvironment.

Solution 5 - C#

A better solution is to use the IFileProvider.GetFileInfo() method.

    public IActionResult ResizeCat([FromServices] IFileProvider fileProvider)
    {
        // get absolute path (equivalent to MapPath)
        string absolutePath = fileProvider.GetFileInfo("/assets/images/cat.jpg").PhysicalPath;  
        ... 
    }

You must register IFileProvider like this to be able to access it through DI:

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc();

        var physicalProvider = _hostingEnvironment.ContentRootFileProvider;
        var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
        var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);

        // choose one provider to use for the app and register it
        //services.AddSingleton<IFileProvider>(physicalProvider);
        //services.AddSingleton<IFileProvider>(embeddedProvider);
        services.AddSingleton<IFileProvider>(compositeProvider);
    }

As you can see this logic (for where a file comes from) can get quite complex, but your code won't break if it changes.

You can create a custom IFileProvider with new PhysicalFileProvider(root) if you have some special logic. I had a situation where I want to load an image in middleware, and resize or crop it. But it's an Angular project so the path is different for a deployed app. The middleware I wrote takes IFileProvider from startup.cs and then I could just use GetFileInfo() like I would have used MapPath in the past.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShanmu_92View Question on Stackoverflow
Solution 1 - C#NkosiView Answer on Stackoverflow
Solution 2 - C#Alexander S.View Answer on Stackoverflow
Solution 3 - C#Randy BuchholzView Answer on Stackoverflow
Solution 4 - C#Amir133View Answer on Stackoverflow
Solution 5 - C#Simon_WeaverView Answer on Stackoverflow