I am using Visual Studio Code version 1.42 on my Ubuntu 18.04. I just successfully installed sudo dotnet add package Google.Apis.Drive.v3 via terminal but I can't find a way to install System.Web on my C# project.
I tried many different ways:
1) sudo dotnet add package Microsoft.AspNet.WebApi
2) sudo dotnet add package Microsoft.AspNet.Mvc -Version 5.2.7
3) sudo dotnet add package Microsoft.AspNet.Mvc
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
//using System.Web;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
namespace IHostingEnvironmentExample.Controllers
{
public class HomeController : Controller
{
private IHostingEnvironment _env;
public HomeController(IHostingEnvironment env)
{
_env = env;
}
public IActionResult Index()
{
var webRoot = _env.WebRootPath;
var file = System.IO.Path.Combine(webRoot, "test.txt");
System.IO.File.WriteAllText(file, "Hello World!");
return View();
}
}
}
namespace WebApi2.Models
{
public class GoogleDriveFilesRepository
{
//defined scope.
public static string[] Scopes = { DriveService.Scope.Drive };
// Operations....
//create Drive API service.
public static DriveService GetService()
{
//Operations....
public static List<GoogleDriveFiles> GetDriveFiles()
{
// Other operations....
}
//file Upload to the Google Drive.
public static void FileUpload(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
{
DriveService service = GetService();
string path = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"),
Path.GetFileName(file.FileName));
file.SaveAs(path);
var FileMetaData = new Google.Apis.Drive.v3.Data.File();
FileMetaData.Name = Path.GetFileName(file.FileName);
FileMetaData.MimeType = MimeMapping.GetMimeMapping(path);
FilesResource.CreateMediaUpload request;
using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open))
{
request = service.Files.Create(FileMetaData, stream, FileMetaData.MimeType);
request.Fields = "id";
request.Upload();
}
}
}
//Download file from Google Drive by fileId.
public static string DownloadGoogleFile(string fileId)
{
DriveService service = GetService();
string FolderPath = System.Web.HttpContext.Current.Server.MapPath("/GoogleDriveFiles/");
FilesResource.GetRequest request = service.Files.Get(fileId);
string FileName = request.Execute().Name;
string FilePath = System.IO.Path.Combine(FolderPath, FileName);
MemoryStream stream1 = new MemoryStream();
request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
{
switch (progress.Status)
{
case DownloadStatus.Downloading:
{
Console.WriteLine(progress.BytesDownloaded);
break;
}
case DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
SaveStream(stream1, FilePath);
break;
}
case DownloadStatus.Failed:
{
Console.WriteLine("Download failed.");
break;
}
}
};
request.Download(stream1);
return FilePath;
}
}
}
Post that I consulted to find a solution to this problem were this one, this, also this one.
I came across this too which seemed to be related but no luck.
Also this last one was useful, however I am confused about which type of package to install.
thanks for providing guidance on how to solve this problem.
As per the code you showed, you are trying to use System.Web.HttpContext.Current.Server.MapPath, which indeed does not exist in .NET Core.
There is no more HttpContext static usable in ASP.NET Core, along with System.Web entirely.
To replace the "Server.MapPath", you can follow some guidance here : https://www.mikesdotnetting.com/Article/302/server-mappath-equivalent-in-asp-net-core
Basically, you need to access a IHostingEnvironment env object, that ASP.NET Core will happily inject.
I'd recommend not using static methods to leverage the constructor dependency injection that is performed in controller constructor automatically.
Otherwise you can also call the dependency service to get the instance (all the details of how to use the dependency service is a bit out of scope here, but feel free to comment if this is not clear)
From this, you should be able to get the path of the server :
public class HomeController : Controller
{
private IHostingEnvironment _env;
// Injection of IHostingEnvironment dependency through constructor
public HomeController(IHostingEnvironment env)
{
_env = env;
}
public void MyMethod()
{
// here you get your replacement of "Server.MapPath" :
var serverPath = _env.WebRootPath;
// ...
}
}
See also this related Q&A : How to use IHostingEnvironment
Related
I am using Visual Studio Code version 1.42 on my Ubuntu 18.04. I just successfully installed sudo dotnet add package Google.Apis.Drive.v3 via terminal but I can't find a way to install System.Web on my C# project.
After doing some research I came across this which explains that basically, I need to access a IHostingEnvironment env object, that ASP.NET Core will take care of.
The problem I'm having trouble resolving local file paths. I have is that I am not familiar with this type of approach and wanted to ask if, given the code below, someone could show me how to modify it to use a IHostingEnvironment env object.
The problem appears in the lines that contain :
HttpContext.Current.Server.MapPath("~/GoogleDriveFiles")
This is the rest of the code :
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
//using System.Web;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
namespace WebApi2.Models
{
public class GoogleDriveFilesRepository
{
//defined scope.
public static string[] Scopes = { DriveService.Scope.Drive };
// Operations....
//create Drive API service.
public static DriveService GetService()
{
//Operations....
public static List<GoogleDriveFiles> GetDriveFiles()
{
// Other operations....
}
//file Upload to the Google Drive.
public static void FileUpload(HttpPostedFileBase file) // <-- Error here
{
if (file != null && file.ContentLength > 0)
{
DriveService service = GetService();
string path = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"), // <-- Error here
Path.GetFileName(file.FileName));
file.SaveAs(path);
var FileMetaData = new Google.Apis.Drive.v3.Data.File();
FileMetaData.Name = Path.GetFileName(file.FileName);
FileMetaData.MimeType = MimeMapping.GetMimeMapping(path); // <-- Error here
FilesResource.CreateMediaUpload request;
using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open))
{
request = service.Files.Create(FileMetaData, stream, FileMetaData.MimeType);
request.Fields = "id";
request.Upload();
}
}
}
//Download file from Google Drive by fileId.
public static string DownloadGoogleFile(string fileId)
{
DriveService service = GetService();
string FolderPath = System.Web.HttpContext.Current.Server.MapPath("/GoogleDriveFiles/"); // <-- Error here
FilesResource.GetRequest request = service.Files.Get(fileId);
string FileName = request.Execute().Name;
string FilePath = System.IO.Path.Combine(FolderPath, FileName);
MemoryStream stream1 = new MemoryStream();
request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
{
switch (progress.Status)
{
case DownloadStatus.Downloading:
{
Console.WriteLine(progress.BytesDownloaded);
break;
}
case DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
SaveStream(stream1, FilePath);
break;
}
case DownloadStatus.Failed:
{
Console.WriteLine("Download failed.");
break;
}
}
};
request.Download(stream1);
return FilePath;
}
}
}
What I have done so far:
1) I went through this post as basic explanation but that didn't resolve the issue I have.
2) This post too was somehow useful as basic approach. Useful but still can't figure out what I am missing.
3) I dug more into the problem and arrived here but still no luck.
Thank you very much for pointing to the right direction.
You don't need System.Web or HttpContext. You can read the web app's root path from IHostingEnvironment.WebRootPath in ASP.NET Core 2.x, or IWebHostEnvironment.WebPath in ASP.NET Core 3.x.
The dependency injection mechanism knows about that interface which means you can add it as a dependency to your controllers or services, eg :
public class MyController : Controller
{
private IWebHostEnvironment _hostingEnvironment;
public MyController(IWebHostEnvironment environment) {
_hostingEnvironment = environment;
}
[HttpGet]
public IActionResult Get() {
var path = Path.Combine(_hostingEnvironment.WebRootPath, "GoogleDriveFiles");
...
}
You can pass the root path to your class's constructor. After all, a class named GoogleDriveFilesRepository only cares about its local folder, not whether it's hosted on a web or console application. For that to work, the methods should not be static:
public class GoogleDriveFilesRepository
{
public GoogleDriveFilesRepository (string rootPath)
{
_rootPath=rootPath;
}
public DriveService GetService()
{
//Operations....
public List<GoogleDriveFiles> GetDriveFiles()
{
// Other operations....
}
}
You can register that class as a service in Startup.cs :
public class Startup
{
private readonly IWebHostEnvironment _env;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
_env = env;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSignleton<GoogleDriveFilesRepository>(_ =>{
var gdriveRoot=Path.Combine(_env.WebRootPath,"GoogleDriveFiles");
return new GoogleDriveFilesRepository(gdrivePath);
});
...
}
}
This class can now be used as a dependency on a controller. It's no longer necessary to use IWebHostEnvironment in the controller :
public class MyController : Controller
{
private GoogleDriveFilesRepository _gdrive;
public MyController(GoogleDriveFilesRepository gdrive) {
_gdrive=gdrive;
}
}
The nice thing with dependency injection is that if done right, the classes themselves don't need to know that DI is used. MyContainer and GoogleDriveFilesRepository can be used in eg a unit test without having to setup DI :
[Fact]
public void Just_A_Test()
{
var repository=new GoogleDriveFilesRepository("sometestpath");
var myController=new MyController(repository);
myController.DoTheUpload(...);
}
If the issue is......... "I'm trying to get a static file on MY hosted web site"...then you'll want to look at this article:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-3.1
The key is this:
public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles(); // For the wwwroot folder
//OR
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
}
The default is 'wwwroot', of you can overload it with a custom value.
I want to create a web service with ASP.NET Core 2.1 which checks on application startup if the connection to the database works and then prepares some data in the database.
The check runs in a loop till the connection was successful or the users presses Ctrl + C (IApplicationLifetime). It is important that no HTTP call is processed before the database was initialized. My question is: where to put this code?
I need a the dependency injection system to be fully initialized, so the earliest i can think of would be at the end of my Startup.Configure method, but the cancellation tokens on IApplicationLifetime do not seem to work there (properly because asp isn't fully started)
Is there a official place where can put this startup logic?
You can build an extension method off of IWebHost which will allow you to run code before Startup.cs. Furthermore, you can use the ServiceScopeFactory to initialize any services you have (e.g. DbContext).
public static IWebHost CheckDatabase(this IWebHost webHost)
{
var serviceScopeFactory = (IServiceScopeFactory)webHost.Services.GetService(typeof(IServiceScopeFactory));
using (var scope = serviceScopeFactory.CreateScope())
{
var services = scope.ServiceProvider;
var dbContext = services.GetRequiredService<YourDbContext>();
while(true)
{
if(dbContext.Database.Exists())
{
break;
}
}
}
return webHost;
}
Then you can consume the method.
public static void Main(string[] args)
{
BuildWebHost(args)
.CheckDatabase()
.Run();
}
where to put this code?
class Initializer
{
internal static SemaphoreSlim _semaphoreSlim;
static SemaphoreSlim Slim
{
get
{
return LazyInitializer.EnsureInitialized(ref _semaphoreSlim, () => new SemaphoreSlim(1, 1));
}
}
public static void WaitOnAction(Action initializer)
{
Initializer.Slim.Wait();
initializer();
Initializer.Slim.Release();
}
}
is there a official place where can put this startup logic?
Startup.cs is good place to start...
Initializer.WaitOnAction(()=> /* ensure db is initialized here */);
/* check https://dotnetfiddle.net/gfTyTL */
I want to create a web service with ASP.NET Core 2.1 which checks on application startup
So for example I had a scenario to check for the folder structure if not create one as soon as the application starts.
The method to create folder structure is in FileService.cs which has to be initiated via DI as soon as the application starts up before any http request.
appsettings.json conatins keys and values which contains the structure to create folder structure.
"FolderStructure": {
"Download": {
"English": {
"*": "*"
},
"Hindi": {
"*": "*"
}
},
"Upload": {
"*": "*"
}
}
And used below interface and service
Interface
namespace MyApp.Services
{
public interface IFileService
{
void CreateDirectoryStructure(string path = "");
void CreateFolder(string name, string path = "");
void CreateFile(string name, string path = "");
bool CheckFileExists(string path);
bool CheckFolderExists(string path);
}
}
Service
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Configuration.Binder;
using System.IO;
using Microsoft.Extensions.Logging;
namespace MyApp.Services
{
public class FileService : IFileService
{
private readonly IFileProvider _fileProvider;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IConfiguration _config;
private readonly ILogger<FileService> _logger;
string defaultfolderPath = ConfigurationManager.AppSetting["DefaultDrivePath"];
public FileService(IFileProvider fileProvider, IHostingEnvironment hostingEnvironment, IConfiguration config, ILogger<FileService> logger)
{
_fileProvider = fileProvider;
_hostingEnvironment = hostingEnvironment;
_config = config;
_logger = logger;
}
public void CreateDirectoryStructure(string drivePath = "")
{
if (drivePath.Equals(""))
{
drivePath = ConfigurationManager.AppSetting["DefaultDrivePath"];
_logger.LogInformation($"Default folder path will be picked {drivePath}");
}
foreach (var item in _config.GetSection("FolderStructure").GetChildren())
{
CreateFolder(item.Key, drivePath);
foreach (var i in _config.GetSection(item.Path).GetChildren())
{
if (i.Key != "*")
CreateFolder(i.Key, $"{drivePath}/{item.Key}");
}
}
}
public void CreateFolder(string name, string path = "")
{
string fullPath = string.IsNullOrEmpty(path) ? $"{defaultfolderPath}/{name}" : $"{path}/{name}";
if (!Directory.Exists(fullPath))
{
Directory.CreateDirectory(fullPath);
_logger.LogInformation($"Directory created at {fullPath} on {DateTime.Now}");
}
}
public void CreateFile(string name, string path = "")
{
string fullPath = string.IsNullOrEmpty(path) ? $"{defaultfolderPath}/{name}" : $"{path}/{name}";
if (!File.Exists(fullPath))
{
File.Create(fullPath);
_logger.LogInformation($"File created at {fullPath} on {DateTime.Now}");
}
}
public bool CheckFolderExists(string path)
{
string fullPath = string.IsNullOrEmpty(path) ? defaultfolderPath : path;
return Directory.Exists(fullPath);
}
public bool CheckFileExists(string path)
{
string fullPath = string.IsNullOrEmpty(path) ? defaultfolderPath : path;
return File.Exists(fullPath);
}
}
}
Now the challenge is to call the folder service method as soon as the application starts but we need to initialize fileservice via DI
services.AddSingleton<IFileService, FileService>();
And in Configure method you can call the required service.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IFileService FileService)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
//dont change the below order as middleware exception need to be registered before UseMvc method register
app.ConfigureCustomMiddleware();
// app.UseHttpsRedirection();
app.UseMvc();
FileService.CreateDirectoryStructure();
}
I am building a website using asp.net core mvc, and for the login i added dependency for enc.dll file, which just encrypt/decrypt user information.
I made a Seeder class with enc.dll file, which has a key property and en/decrypt with the key. Then I added it to my service to use dependency injection feature.
services.AddSingleton<ISeeder, Seeder>();
While it works well when i call enc, dec function of seeder class, it does not return any error. Below is the example code.
private readonly ISeeder seed;
public AccountController(ISeeder seed)
{
this.seed = seed;
}
[HttpGet]
public IActionResult test()
{
string s = seed.Enc("testEncode");
return Json(s);
}
So it works when i return string s that is created by seed instance.
but it is not working when i try to return a view without using seed instance and throwing an error, where Enc is the dll library i am using.
InvalidOperationException: Cannot find compilation library location for package 'Enc'
Microsoft.Extensions.DependencyModel.CompilationLibrary.ResolveReferencePaths(ICompilationAssemblyResolver resolver, List<string> assemblies)
And below is my Seeder code.
private Enc enc;
private readonly EncKey key;
public Seeder(IOptions<EncKey> options)
{
enc = new Enc();
key = options.Value;
}
public string Dec(string toDec)
{
return enc.Dec(toDec, key.EncryptKey);
}
public string Enc(string toEnc)
{
return enc.Enc(toEnc, key.EncryptKey);
}
Could anyone help? I am working on .net core 2.0 environment
UPDATE
This issue was fixed in 2.0.3, for apply need to update VS(or manualy
dotnet SDK and Runtime) and project packages via nuget(in particular
Microsoft.AspNetCore.All to 2.0.3)
It's known issue of .Net Core 2.0 https://github.com/dotnet/core-setup/issues/2981
Razor view precompilation can not resolve lib path
Here workaround to get this work:
add this (it's fixing release publish error)
using Microsoft.AspNetCore.Mvc;
using Microsoft.DotNet.PlatformAbstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.DependencyModel.Resolution;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace somenamespace
{
public class MvcConfiguration : IDesignTimeMvcBuilderConfiguration
{
private class DirectReferenceAssemblyResolver : ICompilationAssemblyResolver
{
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
{
if (!string.Equals(library.Type, "reference", StringComparison.OrdinalIgnoreCase))
{
return false;
}
var paths = new List<string>();
foreach (var assembly in library.Assemblies)
{
var path = Path.Combine(ApplicationEnvironment.ApplicationBasePath, assembly);
if (!File.Exists(path))
{
return false;
}
paths.Add(path);
}
assemblies.AddRange(paths);
return true;
}
}
public void ConfigureMvc(IMvcBuilder builder)
{
// .NET Core SDK v1 does not pick up reference assemblies so
// they have to be added for Razor manually. Resolved for
// SDK v2 by https://github.com/dotnet/sdk/pull/876 OR SO WE THOUGHT
/*builder.AddRazorOptions(razor =>
{
razor.AdditionalCompilationReferences.Add(
MetadataReference.CreateFromFile(
typeof(PdfHttpHandler).Assembly.Location));
});*/
// .NET Core SDK v2 does not resolve reference assemblies' paths
// at all, so we have to hack around with reflection
typeof(CompilationLibrary)
.GetTypeInfo()
.GetDeclaredField("<DefaultResolver>k__BackingField")
.SetValue(null, new CompositeCompilationAssemblyResolver(new ICompilationAssemblyResolver[]
{
new DirectReferenceAssemblyResolver(),
new AppBaseCompilationAssemblyResolver(),
new ReferenceAssemblyPathResolver(),
new PackageCompilationAssemblyResolver(),
}));
}
}
}
and this (it's fixing compilation errors)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.DependencyModel;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
namespace somenamespace
{
public class ReferencesMetadataReferenceFeatureProvider : IApplicationFeatureProvider<MetadataReferenceFeature>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, MetadataReferenceFeature feature)
{
var libraryPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var assemblyPart in parts.OfType<AssemblyPart>())
{
var dependencyContext = DependencyContext.Load(assemblyPart.Assembly);
if (dependencyContext != null)
{
foreach (var library in dependencyContext.CompileLibraries)
{
if (string.Equals("reference", library.Type, StringComparison.OrdinalIgnoreCase))
{
foreach (var libraryAssembly in library.Assemblies)
{
libraryPaths.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, libraryAssembly));
}
}
else
{
foreach (var path in library.ResolveReferencePaths())
{
libraryPaths.Add(path);
}
}
}
}
else
{
libraryPaths.Add(assemblyPart.Assembly.Location);
}
}
foreach (var path in libraryPaths)
{
feature.MetadataReferences.Add(CreateMetadataReference(path));
}
}
private static MetadataReference CreateMetadataReference(string path)
{
using (var stream = File.OpenRead(path))
{
var moduleMetadata = ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata);
var assemblyMetadata = AssemblyMetadata.Create(moduleMetadata);
return assemblyMetadata.GetReference(filePath: path);
}
}
}
}
also change addMVC to this
//workaround https://github.com/dotnet/core-setup/issues/2981 will be fixed in 2.0.1
services.AddMvc().ConfigureApplicationPartManager(manager =>
{
var oldMetadataReferenceFeatureProvider = manager.FeatureProviders.First(f => f is MetadataReferenceFeatureProvider);
manager.FeatureProviders.Remove(oldMetadataReferenceFeatureProvider);
manager.FeatureProviders.Add(new ReferencesMetadataReferenceFeatureProvider());
});
and you will able to use dll in your view
also you have second way is disable razor precompilation here example
Deleting PrecompiledViews.dll from ASP.Net Core 2 API
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.
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>();
.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"));
.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.
* 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.
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.
If you are accessing it from Startup/Program routines, it is available under WebApplicationBuilder.Environment e.g.
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var webRootPath = builder.Environment.WebRootPath;
ConfigureServices(builder);
...
}
I'm using Visual Studio 2013 MVC, and I installed "Hangfire" to perform scheduled tasks. (http://hangfire.io/)
How can I protect the Web Monitoring UI page (http://localhost/Hangfire) with a password?
Thanks
Please take a look to the documentation
In short.
You can use already created authorization filters or implement your own
using Hangfire.Dashboard;
public class MyRestrictiveAuthorizationFilter : IAuthorizationFilter
{
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
// In case you need an OWIN context, use the next line.
var context = new OwinContext(owinEnvironment);
return false;
}
}
Additional information:
Also you can take a look to the special package Hangfire.Dashboard.Authorization which contains the logic which you needed
Let me give the entire code for a RestrictiveAuthorizationFilter:
This way you can handle authorization however you desire.
Assuming you have the OWINStartup class added.
OWINStartup.cs
using Owin;
using Hangfire;
using Hangfire.Dashboard;
public class OWINStartup
{
public void Configuration(IAppBuilder app)
{
GlobalConfiguration.Configuration.UseSqlServerStorage("String");
DashboardOptions options = new DashboardOptions()
{
AuthorizationFilters = new IAuthorizationFilter[]
{
new MyRestrictiveAuthorizationFilter()
}
};
app.UseHangfireDashboard("/hangfire", options);
}
}
RestrictiveAuthorizationFilter.cs
using Hangfire.Dashboard;
using System.Collections.Generic;
using Microsoft.Owin;
public class MyRestrictiveAuthorizationFilter : IAuthorizationFilter
{
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
var context = new OwinContext(owinEnvironment);
return context.Authentication.User.Identity.IsAuthenticated;
}
}
Notice: using System.Collections.Generic;
References:
https://github.com/HangfireIO/Hangfire/issues/202
https://media.readthedocs.org/pdf/hangfire/latest/hangfire.pdf (page 20)
Hangfire.Dashboard.Authorization version: 2.1.0
Set this up in your Startup.Cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//TODO
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new MyAuthorizationFilter() }
});
app.UseHangfireDashboard();
var options = new BackgroundJobServerOptions { WorkerCount = 1 };
app.UseHangfireServer(options); }
Create this class, it allows authenticated users to see the Dashboard
public class MyAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
{
var httpContext = context.GetHttpContext();
// Allow all authenticated users to see the Dashboard (potentially dangerous).
return httpContext.User.Identity.IsAuthenticated;
}
}