9

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.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
Emanuele
  • 2,194
  • 6
  • 32
  • 71
  • Here are some helpfuls. https://andrewlock.net/ihostingenvironment-vs-ihost-environment-obsolete-types-in-net-core-3/ – granadaCoder Feb 28 '20 at 16:17
  • 3
    You *don't* need `System.Web` or `IHostingEnvironment` to use Google Drive. What are you trying to do? PS: Edit your question and make *clear* what the problem is. Right now those `Error here` comments are completely hidden -3 pages down and too far to the right – Panagiotis Kanavos Feb 28 '20 at 16:18
  • Your *real* question is how to resolve local file paths, not how to use `System.Web` or `IHostingEnvironment`. – Panagiotis Kanavos Feb 28 '20 at 16:20
  • https://bytenota.com/asp-net-core-getting-project-root-directory-path/ and https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-3.1 – granadaCoder Feb 28 '20 at 16:20
  • Is there a static file you're trying to "get" in your code..hosted on YOUR site? Is that the issue? – granadaCoder Feb 28 '20 at 16:22
  • All, thanks for reading the question. Yes, basically I am trying to resolve a local path. I have a Google Drive folder and I am trying download/upload files on it. Final goal (now only on localhost), would be that the user is able to upload/download files from google drive via `HTML` button on a user interface – Emanuele Feb 28 '20 at 16:25
  • @Emanuele you need to use `IHostingEnvironment.WebPath` for this in ASP.NET Core 2.x, IWebHostEnvironment.WebPath in ASP.NET Core 3.x. YOu need to *pass* that interface to your class, eg as a dependency in the constructor. The DI already knows about those interfaces. That's how controllers get them – Panagiotis Kanavos Feb 28 '20 at 16:27

2 Answers2

16

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(...);
}
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
1

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.

granadaCoder
  • 26,328
  • 10
  • 113
  • 146