Home > OS >  Best practices for passing in API key in ASP.NET Core MVC
Best practices for passing in API key in ASP.NET Core MVC

Time:09-25

I am working on a simple weather dashboard in ASP.NET core with MVC. I have figured out how to pass the URI base address for the weather API call from the appsettings to the configuration settings and then to the interface which calls the weather API:

appsettings:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      //Here:
      "openWeatherAPI": "https://api.openweathermap.org/",
    }
  

startup configuration:

   

 public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            //Here
            string uri = Configuration.GetValue<string>("openWeatherAPI");

            services.AddControllersWithViews();

            services.AddHttpClient<IForecastRepository, ForecastRepository>(c =>  
                {
                    //And Here:
                    c.BaseAddress = new Uri(uri);
                }
                );

Forecast Interface:

 

    public interface IForecastRepository
        {
            Task<CityModel> GetMovieDetailsAsync(string cityName);
        }
    
        public class ForecastRepository : IForecastRepository
        {     
                private readonly HttpClient _httpClient;
    
            public ForecastRepository(HttpClient httpClient)
                {
                    _httpClient = httpClient;       
            }
    
    
            public async Task<CityModel> GetMovieDetailsAsync(string cityName)
            {
                string IDOWeather = "/*my api key is hardcoded in here*/";
                var queryString = $"data/2.5/weather?q={cityName}&units=imperial&APPID={IDOWeather}";
                var response = await _httpClient.GetStringAsync(queryString);
    
             //...code conitnues

Is there a similar way I can pass in the API key? It's my understanding that it is not considered best practice to have it written into the app where I do.

For discussion of HttpClientFactory:

WeatherController:

    public class WeatherController : Controller
    {


        private readonly IForecastRepository _forecastRepository;
        
        public WeatherController(IForecastRepository forecastRepository)
        {
            _forecastRepository = forecastRepository;
        }

        public IActionResult SearchCity()
        {
            var viewModel = new CityModel();
            return View(viewModel);
        }

        public IActionResult City()
        {
            var viewModel = new CityModel();
            return View(viewModel);
        }


        [HttpPost]
        public async Task<IActionResult> SearchResults(CityModel titleFromView)
        {

            var movieDetail = await _forecastRepository.GetMovieDetailsAsync(titleFromView.Name);
            return View("City", movieDetail);
      

CodePudding user response:

try this code

 public class ForecastRepository : IForecastRepository
{     
   private readonly HttpClient _httpClient;
   private readonly string _apiKey;

 public ForecastRepository(HttpClient httpClient, IConfiguration configuration)
 {
     _httpClient = httpClient;   
     _apiKey  = configuration.GetValue<string>("idoWeather");
      //or
     _apiKey  = configuration["idoWeather"];
}
    
 public async Task<CityModel> GetMovieDetailsAsync(string cityName)
  {
    string IDOWeather = _apiKey;

    var queryString = $"data/2.5/weather?q={cityName}&units=imperial&APPID={IDOWeather}";
   var response = await _httpClient.GetStringAsync(queryString);
    
             //...code conitnues
    }

appsettings:

   {
      ....
      "idoWeather": "apikey",
      "openWeatherAPI": "https://api.openweathermap.org/",
    }

and by the way I highly recommend you to use HttpClientFactory. if you need httpClient with different url you will have to change baseUrl some way. You can create a set of typed or named http clients in startup, but since you usually will not need all of them, it is better to create when it is needed. For more info you can read my another answer https://stackoverflow.com/a/69054959/11392290

private readonly IHttpClientFactory _clientFactory
private readonly IConfiguration _configuration;

 public ForecastRepository(IHttpClientFactory clientFactory, IConfiguration configuration)
 {
    _configuration=configuration;
    _clientFactory = clientFactory;
  
}
 
public async Task<CityModel> GetMovieDetailsAsync(string cityName)
  {
 
 var baseAddress = _configuration.GetValue<string>("openWeatherAPI");
   var  IDOWeather = _configuration.GetValue<string>("idoWeather");
      //or
     var baseAddress = _configuration["openWeatherAPI"];
      var  IDOWeather  = _configuration["idoWeather"];

var queryString = $"data/2.5/weather?q={cityName}&units=imperial&APPID={IDOWeather}";

var httpClient = _clientFactory.CreateClient();
httpClient.BaseAddress = new Uri(baseAddress);
 var response = await httpClient.GetStringAsync(queryString);

to use factory replace

 services.AddHttpClient<IForecastRepository, ForecastRepository>(c =>  
 {
     //And Here:
                    c.BaseAddress = new Uri(uri);
   }
);

with

services.AddHttpClient();

and since you are using a repository you have to add it to services for DI

services.AddScoped<IForecastRepository , ForecastRepository>();
  • Related