.NET Core 3.1 - HostingEnvironment does not contain a definition for MapPath

1.6k views Asked by At

I am using .NET Core 3.1 and I am trying to connect to the Google's Indexing API by presenting a private key. I have looked at things like: Example of Google Indexing API Batch Request using .NET and https://hamidmosalla.com/2019/12/07/using-google-indexing-api-with-google-api-client-library-for-net/

Here is my code:

using Google.Apis.Auth.OAuth2;
using Google.Apis.Requests;
using Google.Apis.Services;
using Google.Apis.Indexing.v3;
using Google.Apis.Indexing.v3.Data;
using Microsoft.Extensions.Hosting.Internal;

public static class MyClassDownloader {
    public static GoogleCredential GetGoogleCredential()
    {    
        string path = HostingEnvironment.MapPath("/PrivateKey/myprivatekey.json");
        GoogleCredential credential;
    
        using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            credential = GoogleCredential.FromStream(stream).CreateScoped(new[] { "https://www.googleapis.com/auth/indexing" });
        }
    
        return credential;
    }
}

However, I am getting an error on the line regarding MapPath:

'HostingEnvironment' does not contain a definition for 'MapPath'

I have tried looking into IHostingEnvironment, after which I learned it was deprecated for IWebHostEnvironment. How do I get the proper physical path for my JSON file regardless of if I am in development or production?

1

There are 1 answers

0
Christian On

I'd change MyClassDownloader to not be static and add a constructor that takes IWebHostEnvironment as a parameter which would be saved in a variable inside MyClassDownloader. Then, MyClassDownloader needs to be registered in Startup.ConfigureServices(). Finally everywhere MyClassDownloader.GetGoogleCredential() is called (e.g. in controllers), an instance of MyClassDownloader needs to be available. This instance is made available through injecting it into the using class' (e.g. the controller) constructor.

Example (I did not test that code):

// MyClassDownloader.cs
// Make MyClassDownloader non static and add constructor
public class MyClassDownloader 
{
    private readonly IWebHostEnvironment webHostEnvironment;

    public MyClassDownloader(IWebHostEnvironment webHostEnvironment) 
    {
        this.webHostEnvironment = webHostEnvironment;
    }

    // Method not static any more
    public GoogleCredential GetGoogleCredential()
    {    
        // Depending on the hosting OS you might have to use backslash but I'm
        // not sure about that
        string path = System.IO.Path.Combine(
            webHostEnvironment.WebRootPath, 
            "/PrivateKey/myprivatekey.json");

        GoogleCredential credential;
    
        using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            credential = GoogleCredential.FromStream(stream).CreateScoped(new[] { "https://www.googleapis.com/auth/indexing" });
        }
    
        return credential;
    }
}

// Startup.cs
public class Startup 
{
    // ... some code

    public void ConfigureServices(IServiceCollection services)
    {
        // ... some code
        
        // Register newly non static MyClassDownloader so it can be injected
        // into classes that need it.
        services.AddTransient<MyClassDownloader>();

        // ... some more code
    }

    // ... some more code
}

// GoogleCredentialConsumer.cs
// Sample class that needs an instance of GoogleCredential. 
// To obtain the GoogleCredential instance, it needs a MyClassDownloader. 
// Might be a controller or another class
public class GoogleCredentialConsumer 
{
    private readonly MyClassDownloader myClassDownloader;

    public GoogleCredentialConsumer(MyClassDownloader myClassDownloader)
    {
        this.myClassDownloader = myClassDownloader;
    }

    public void MethodThatNeedsGoogleCredential()
    {
        var theGoogleCredential = myClassDownloader.GetGoogleCredential();
        // yay, finally I have it!
    }
}