diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 9292309e..d7b1f3d1 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -8,7 +8,6 @@ name: Create and publish a Docker image on: workflow_dispatch: push: - branches: ['dev', 'staging', 'master'] env: REGISTRY: ghcr.io diff --git a/Data.Source/NLDAS.cs b/Data.Source/NLDAS.cs index 87d3318c..7b6fa336 100644 --- a/Data.Source/NLDAS.cs +++ b/Data.Source/NLDAS.cs @@ -1,11 +1,15 @@ -using System; +using Serilog; +using System; using System.Collections.Generic; -using System.Text; +using System.Globalization; +using System.Linq; using System.Net; -using System.Threading; -using Serilog; using System.Net.Http; +using System.Text; +using System.Threading; using System.Threading.Tasks; +using Utilities; + namespace Data.Source { @@ -21,6 +25,8 @@ public class NLDAS private double minLat = 25.0; // NLDAS spatial coverage min latitude private double maxLng = -63.0; // NLDAS spatial coverage max longitude private double minLng = -125.0; // NLDAS spatial coverage min longitude + private static object uriBuilder; + private string data; /// /// Get data function for nldas. @@ -29,7 +35,7 @@ public class NLDAS /// nldas dataset parameter /// /// - public string GetData(out string errorMsg, string dataset, ITimeSeriesInput componentInput, int retries = 0) + public string GetData(out string errorMsg, string dataset, ITimeSeriesInput componentInput, int retries = 0, string accessToken = null) { errorMsg = ""; @@ -51,18 +57,49 @@ public string GetData(out string errorMsg, string dataset, ITimeSeriesInput comp // Adjusts date/times by the timezone offset if timelocalized is set to true. componentInput.DateTimeSpan = AdjustForOffset(out errorMsg, componentInput) as DateTimeSpan; - + // Constructs the url for the NLDAS data request and it's query string. - string url = ConstructURL(out errorMsg, dataset, componentInput); + string url = ConstructURL(out errorMsg, dataset, componentInput, null, null, accessToken); if (errorMsg.Contains("ERROR")) { return null; } + if (componentInput.BaseURL[0].Contains("giovanni", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(accessToken)) + { + errorMsg = "ERROR: NLDAS EarthData access token is required for Giovanni data retrieval."; + return null; + } + // Uses the constructed url to download time series data. - string data = DownloadData(url, retries).Result; + string data = DownloadData(url, retries, accessToken).Result; + + if (errorMsg.Contains("ERROR") || data == null) { return null; } return data; } + private static string CallTimeSeries(string dataset, ITimeSeriesInput componentInput, string accessToken) + { + double[] coords = GetNldasGridCoordinate(componentInput.Geometry.Point); + string start = componentInput.DateTimeSpan.StartDate.ToString("yyyy-MM-ddTHH:mm:ss"); + string end = componentInput.DateTimeSpan.EndDate.ToString("yyyy-MM-ddTHH:mm:ss"); + string dataVariable = GetNldasDataVariable(dataset); + + using var gesDisc = new clsNLDAS_GES_DISC(); + return gesDisc.CallTimeSeries(coords[0], coords[1], start, end, dataVariable, accessToken); + } + + private static string GetNldasDataVariable(string dataset) + { + return dataset.Equals("PRECIP", StringComparison.OrdinalIgnoreCase) + ? "NLDAS_FORA0125_H_2_0_Rainf" + : dataset; + } + + private static string ConstructURL(out string errorMsg, string dataset, ITimeSeriesInput componentInput) + { + return ConstructURL(out errorMsg, dataset, componentInput, null, null, null); + } + private bool ValidateInput(out string errorMsg, ITimeSeriesInput input) { errorMsg = ""; @@ -171,25 +208,64 @@ public static string SetDateToLocal(double offset, string dateHour, string dateF /// /// /// - private static string ConstructURL(out string errorMsg, string dataset, ITimeSeriesInput cInput) + private static string ConstructURL(out string errorMsg, string dataset, ITimeSeriesInput cInput, string clsNldasGesDisc,string findOrCreateTokenUrl, string accessToken = null) { errorMsg = ""; + + if (cInput.BaseURL[0].Contains("giovanni", StringComparison.OrdinalIgnoreCase) && + string.IsNullOrWhiteSpace(accessToken)) + { + using var gesDisc = new clsNLDAS_GES_DISC(AppContext.BaseDirectory); + accessToken = gesDisc.GetAccessToken(); + } + { + double[] coords = GetNldasGridCoordinate(cInput.Geometry.Point); + + string start = cInput.DateTimeSpan.StartDate.ToString("yyyy-MM-ddTHH:mm:ss"); + string end = cInput.DateTimeSpan.EndDate.ToString("yyyy-MM-ddTHH:mm:ss"); + + string dataVariable = GetNldasDataVariable(dataset); + + string baseUrl = cInput.BaseURL[0].Split('?')[0]; + if (string.IsNullOrWhiteSpace(baseUrl)) + { + baseUrl = "https://api.giovanni.earthdata.nasa.gov/timeseries"; + } + + StringBuilder giovanniSb = new StringBuilder(); + giovanniSb.Append(clsNLDAS_GES_DISC.BuildTimeSeriesUrl(coords[0], coords[1], start, end, dataVariable, baseUrl)); + return giovanniSb.ToString(); + } + StringBuilder sb = new StringBuilder(); sb.Append(cInput.BaseURL[0]); - //Add X and Y coordinates - string[] xy = GetXYCoordinate(out errorMsg, cInput.Geometry.Point); // [0] = x, [1] = y + string[] xy = GetXYCoordinate(out errorMsg, cInput.Geometry.Point); if (errorMsg.Contains("ERROR")) { return null; } + sb.Append("X" + xy[0] + "-" + "Y" + xy[1]); - //Add Start and End Date string[] startDT = cInput.DateTimeSpan.StartDate.ToString("yyyy-MM-dd HH").Split(' '); string[] endDT = cInput.DateTimeSpan.EndDate.ToString("yyyy-MM-dd HH").Split(' '); - sb.Append(@"&startDate=" + startDT[0] + @"T" + startDT[1] + @"&endDate=" + endDT[0] + "T" + endDT[1] + @"&type=asc2"); + + sb.Append(@"&startDate=" + startDT[0] + @"T" + startDT[1] + + @"&endDate=" + endDT[0] + "T" + endDT[1] + + @"&type=asc2"); return sb.ToString(); - } + } + private static double[] GetNldasGridCoordinate(IPointCoordinate point) + { + double step = 0.125; + + double x = (point.Longitude + 124.9375) / step; + double longitude = (Math.Round(x, MidpointRounding.AwayFromZero) * step) - 124.9375; + + double y = (point.Latitude - 25.0625) / step; + double latitude = (Math.Round(y, MidpointRounding.AwayFromZero) * step) + 25.0625; + return new[] { latitude, longitude }; + } /// /// Downloads nldas data from nasa servers. If Http Request fails will retry up to 5 times. /// TODO: Add in start date and end date check prior to the download call (Probably add to Validators class) @@ -197,20 +273,32 @@ private static string ConstructURL(out string errorMsg, string dataset, ITimeSer /// /// /// - private async Task DownloadData(string url, int retries) + private async Task DownloadData(string url, int retries, string accessToken = null) { string data = ""; - HttpClient hc = new HttpClient(); - HttpResponseMessage wm = new HttpResponseMessage(); int maxRetries = 10; + if (string.IsNullOrWhiteSpace(accessToken) && + url.Contains("giovanni", StringComparison.OrdinalIgnoreCase)) + { + using var gesDisc = new clsNLDAS_GES_DISC(AppContext.BaseDirectory); + accessToken = gesDisc.GetAccessToken(); + } + + using HttpClient hc = new HttpClient(); + + if (!string.IsNullOrWhiteSpace(accessToken)) + { + hc.DefaultRequestHeaders.Authorization = + new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); + } try { string status = ""; while (retries < maxRetries && !status.Contains("OK")) { - wm = await hc.GetAsync(url); + using HttpResponseMessage wm = await hc.GetAsync(url); var response = wm.Content; status = wm.StatusCode.ToString(); data = await wm.Content.ReadAsStringAsync(); @@ -228,15 +316,11 @@ private async Task DownloadData(string url, int retries) Log.Warning("Error: Failed to download nldas data. Retry {0}:{1}, Url: {2}", retries, maxRetries, url); Random r = new Random(); Thread.Sleep(5000 + (r.Next(10) * 1000)); - return this.DownloadData(url, retries).Result; + return this.DownloadData(url, retries, accessToken).Result; } - wm.Dispose(); - hc.Dispose(); Log.Warning(ex, "Error: Failed to download nldas data."); return null; } - wm.Dispose(); - hc.Dispose(); return data; } @@ -304,10 +388,52 @@ public ITimeSeriesOutput SetDataToOutput(out string errorMsg, string dataset, st { splitData = data.Split(new string[] { "Data\r\n" }, StringSplitOptions.RemoveEmptyEntries); } + + if (splitData.Length <= 1) + { + return SetCsvDataToOutput(out errorMsg, dataset, data, output, input); + } + output.Dataset = dataset; output.DataSource = input.Source; output.Metadata = SetMetadata(out errorMsg, splitData[0], output); - output.Data = SetData(out errorMsg, splitData[1].Substring(0, splitData[1].IndexOf("MEAN")).Trim(), input.TimeLocalized, input.DateTimeSpan.DateTimeFormat, input.DataValueFormat, input.Geometry.Timezone); + output.Data = SetData(out errorMsg, splitData[1].Substring(0, splitData[1].IndexOf("mean")).Trim(), input.TimeLocalized, input.DateTimeSpan.DateTimeFormat, input.DataValueFormat, input.Geometry.Timezone); + return output; + } + + private ITimeSeriesOutput SetCsvDataToOutput(out string errorMsg, string dataset, string data, ITimeSeriesOutput output, ITimeSeriesInput input) + { + errorMsg = ""; + output.Dataset = dataset; + output.DataSource = input.Source; + + try + { + using var gesDisc = new clsNLDAS_GES_DISC(); + var parsedData = gesDisc.ParseCsv(data); + + foreach (var header in parsedData.headers) + { + output.Metadata[$"nldas_{header.Key}"] = header.Value; + } + + output.Data = new Dictionary>(); + foreach (var point in parsedData.dataPoints) + { + string date = SetDateToLocal( + input.TimeLocalized ? input.Geometry.Timezone.Offset : 0.0, + point.Timestamp.ToString("yyyy-MM-dd HH"), + input.DateTimeSpan.DateTimeFormat); + + output.Data[date] = new List { point.Value.ToString(input.DataValueFormat) }; + } + } + catch (Exception ex) + { + errorMsg = $"ERROR: Failed to parse NLDAS Giovanni CSV response. {ex.Message}"; + return null; + } + return output; } @@ -375,7 +501,7 @@ public static Dictionary CheckStatus(string dataset, ITimeSeries { try { - WebRequest wr = WebRequest.Create(ConstructURL(out string errorMsg, dataset, testInput)); + WebRequest wr = WebRequest.Create(ConstructURL(out string errorMsg, dataset, testInput, null, null, null)); HttpWebResponse response = (HttpWebResponse)wr.GetResponse(); string status = response.StatusCode.ToString(); string description = response.StatusDescription; diff --git a/Precipitation/NLDAS.cs b/Precipitation/NLDAS.cs index 61ef5f5d..292d3912 100644 --- a/Precipitation/NLDAS.cs +++ b/Precipitation/NLDAS.cs @@ -19,7 +19,7 @@ public class NLDAS /// /// /// - public ITimeSeriesOutput GetData(out string errorMsg, ITimeSeriesOutput output, ITimeSeriesInput input, int retries = 0) + public ITimeSeriesOutput GetData(out string errorMsg, ITimeSeriesOutput output, ITimeSeriesInput input, int retries = 0, string accessToken = null) { errorMsg = ""; @@ -27,7 +27,7 @@ public ITimeSeriesOutput GetData(out string errorMsg, ITimeSeriesOutput output, //bool validInputs = ValidateInputs(input, out errorMsg); //if (errorMsg.Contains("ERROR")) { return null; } //int t0 = DateTime.Now.Second; - string data = nldas.GetData(out errorMsg, "PRECIP", input, retries); + string data = nldas.GetData(out errorMsg, "PRECIP", input, retries, accessToken); //int t2 = DateTime.Now.Second; //Console.WriteLine("Data Request took " + (t2 - t0) + " seconds"); diff --git a/Precipitation/Precipitation.cs b/Precipitation/Precipitation.cs index fb4209d6..802a24a5 100644 --- a/Precipitation/Precipitation.cs +++ b/Precipitation/Precipitation.cs @@ -36,7 +36,7 @@ public Precipitation() { } /// /// /// - public ITimeSeriesOutput GetData(out string errorMsg, int retries = 0) + public ITimeSeriesOutput GetData(out string errorMsg, int retries = 0, string accessToken = null) { errorMsg = ""; ITimeSeriesOutputFactory iFactory = new TimeSeriesOutputFactory(); @@ -51,15 +51,15 @@ public ITimeSeriesOutput GetData(out string errorMsg, int retries = 0) // If the timezone information is not provided, the tz details are retrieved and set to the geometry.timezone varaible. if (this.Input.Geometry.Timezone.Offset == 0 && !this.Input.Source.Contains("ncei")) { - this.Input.Geometry.Timezone = Utilities.Time.GetTimezone(out errorMsg, this.Input.Geometry.Point) as Timezone; - if (errorMsg.Contains("ERROR")) { return null; } + //this.Input.Geometry.Timezone = Utilities.Time.GetTimezone(out errorMsg, this.Input.Geometry.Point) as Timezone; + //if (errorMsg.Contains("ERROR")) { return null; } } switch (this.Input.Source.ToLower()) { case "nldas": // NLDAS Precipitation Data call NLDAS nldas = new NLDAS(); - this.Output = nldas.GetData(out errorMsg, this.Output, this.Input, retries); + this.Output = nldas.GetData(out errorMsg, this.Output, this.Input, retries, accessToken); if (errorMsg.Contains("ERROR")) { return null; } break; case "gldas": diff --git a/Utilities/clsNLDAS_GES_DISC.cs b/Utilities/clsNLDAS_GES_DISC.cs new file mode 100644 index 00000000..2a45db63 --- /dev/null +++ b/Utilities/clsNLDAS_GES_DISC.cs @@ -0,0 +1,251 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Utilities +{ + public class clsNLDAS_GES_DISC : IDisposable + { + private readonly HttpClient _httpClient; + private readonly string _basePath; + //private const string TimeSeriesUrl = "https://api.giovanni.earthdata.nasa.gov/timeseries"; + private const string TimeSeriesUrl = "https://api.giovanni.earthdata.nasa.gov/proxy-timeseries?"; + private const string UserAgent = "GESDISC.Net v1.0"; + + public clsNLDAS_GES_DISC(string? basePath = null) + { + _basePath = basePath ?? AppContext.BaseDirectory; + + var handler = new HttpClientHandler() + { + UseCookies = true, + CookieContainer = new System.Net.CookieContainer() + }; + _httpClient = new HttpClient(handler); + _httpClient.DefaultRequestHeaders.Add("User-Agent", UserAgent); + } + + public (string username, string password) ReadNetrcCredentials() + { + string netrcPath = Path.Combine(_basePath, ".netrc"); + if (!File.Exists(netrcPath)) + throw new FileNotFoundException($"No .netrc file found at {netrcPath}. Please create one with your EarthData credentials."); + var lines = File.ReadAllLines(netrcPath); + string? username = null; + string? password = null; + + var tokens = lines + .SelectMany(line => line.Split('#')[0].Split((char[])null, StringSplitOptions.RemoveEmptyEntries)) + .ToArray(); + + bool foundMachine = false; + bool isEarthDataMachine = false; + + for (int i = 0; i < tokens.Length; i++) + { + if (tokens[i].Equals("machine", StringComparison.OrdinalIgnoreCase) && i + 1 < tokens.Length) + { + foundMachine = true; + isEarthDataMachine = tokens[i + 1].Contains("earthdata.nasa.gov", StringComparison.OrdinalIgnoreCase); + i++; + continue; + } + + if ((!foundMachine || isEarthDataMachine) && i + 1 < tokens.Length) + { + if (tokens[i].Equals("login", StringComparison.OrdinalIgnoreCase)) + { + username = tokens[++i]; + } + else if (tokens[i].Equals("password", StringComparison.OrdinalIgnoreCase)) + { + password = tokens[++i]; + } + } + } + + if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) + throw new InvalidOperationException("Could not find valid EarthData credentials in .netrc file."); + return (username, password); + } + + public string GetAccessToken() + { + try + { + var (username, password) = ReadNetrcCredentials(); + string? accessToken = FindOrCreateToken(username, password); + if (string.IsNullOrEmpty(accessToken)) + throw new InvalidOperationException("Failed to obtain access token"); + return accessToken; + } + catch (Exception ex) + { + throw new InvalidOperationException("Authentication with NASA EarthData failed. " + + "Please ensure that your .netrc file is stored and contains valid credentials. " + + $"Error: {ex.Message}", ex); + } + } + + public string? FindOrCreateToken(string username, string password) + { + try + { + var findOrCreateTokenUrl = "https://urs.earthdata.nasa.gov/api/users/find_or_create_token"; + var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")); + var request = new HttpRequestMessage(HttpMethod.Post, findOrCreateTokenUrl); + request.Headers.Authorization = + new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", credentials); + request.Headers.Accept.Add( + new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); + var response = _httpClient.Send(request); + if (response.IsSuccessStatusCode) + { + var responseContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + var tokenResponse = JObject.Parse(responseContent); + return tokenResponse["access_token"]?.ToString(); + } + else + { + var errorContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + throw new HttpRequestException($"Token request failed with status {response.StatusCode}: {errorContent}"); + } + } + catch (Exception ex) + { + throw new InvalidOperationException($"Failed to find or create token: {ex.Message}", ex); + } + } + + public string CallTimeSeries(double lat, double lon, string timeStart, string timeEnd, string dataVariable, string accessToken) + { + var requestUrl = BuildTimeSeriesUrl(lat, lon, timeStart, timeEnd, dataVariable); + var uriBuilder = new UriBuilder(requestUrl); + var request = new HttpRequestMessage(HttpMethod.Get, uriBuilder.Uri); + request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); + var response = _httpClient.Send(request); + if (!response.IsSuccessStatusCode) + { + var errorContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + throw new HttpRequestException($"API request failed with status {response.StatusCode}: {errorContent}"); + } + return response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + } + + public static string BuildTimeSeriesUrl(double lat, double lon, string timeStart, string timeEnd, string dataVariable, string? baseUrl = null) + { + var queryParams = new Dictionary + { + ["data"] = dataVariable, + ["location"] = $"[{lat.ToString(CultureInfo.InvariantCulture)},{lon.ToString(CultureInfo.InvariantCulture)}]", + ["time"] = $"{timeStart}/{timeEnd}" + }; + var uriBuilder = new UriBuilder(string.IsNullOrWhiteSpace(baseUrl) ? TimeSeriesUrl : baseUrl.Split('?')[0]); + var query = string.Join("&", queryParams.Select(kvp => $"{kvp.Key}={Uri.EscapeDataString(kvp.Value)}")); + uriBuilder.Query = query; + return uriBuilder.Uri.ToString(); + } + + public (Dictionary headers, List dataPoints) ParseCsv(string csvData) + { + var lines = csvData.Split('\n', StringSplitOptions.RemoveEmptyEntries); + var headers = new Dictionary(); + var dataPoints = new List(); + if (lines.Length < 15) + { + throw new InvalidOperationException( + "The returned CSV is empty or incomplete.\n" + + "Please ensure that your subsetting bounds are within the extent of your dataset\n" + + "or that your .netrc file is stored and contains valid credentials."); + } + for (int i = 0; i < 13 && i < lines.Length; i++) + { + var parts = lines[i].Split(',', 2); + if (parts.Length >= 2) + { + headers[parts[0]] = parts[1].Trim(); + } + } + for (int i = 15; i < lines.Length; i++) + { + var parts = lines[i].Split(','); + if (parts.Length >= 2) + { + if (DateTime.TryParse(parts[0], out var timestamp) && + double.TryParse(parts[1], out var value)) + { + dataPoints.Add(new TimeSeriesDataPoint + { + Timestamp = timestamp, + Value = value + }); + } + } + } + return (headers, dataPoints); + } + + public (Dictionary headers, List dataPoints) + GetTimeSeriesData(double lat, double lon, string timeStart, string timeEnd, + string dataVariable = "NLDAS_FORA0125_H_2_0_Rainf") + { + var accessToken = GetAccessToken(); + var csvData = CallTimeSeries(lat, lon, timeStart, timeEnd, dataVariable, accessToken); + return ParseCsv(csvData); + } + + public bool SaveToCsv(Dictionary headers, List dataPoints, string filePath) + { + bool success = false; + try + { + using var writer = new StreamWriter(filePath); + foreach (var header in headers) + { + writer.WriteLine($"{header.Key},{header.Value}"); + } + writer.WriteLine(); + writer.WriteLine("Timestamp,Value"); + foreach (var point in dataPoints) + { + writer.WriteLine($"{point.Timestamp:yyyy-MM-ddTHH:mm:ss},{point.Value}"); + } + success = true; + } + catch (Exception ex) + { + + } + return success; + } + + + public void Dispose() + { + _httpClient?.Dispose(); + } + + public static string GetUrlInfoValue() + { + throw new NotImplementedException(); + } + + public object FindOrCreateToken(string accessToken) + { + throw new NotImplementedException(); + } + } + + public class TimeSeriesDataPoint + { + public DateTime Timestamp { get; set; } + public double Value { get; set; } + } + +} diff --git a/Web.Services/App_Data/url_info.txt b/Web.Services/App_Data/url_info.txt index 9df1b189..3e7e3032 100644 --- a/Web.Services/App_Data/url_info.txt +++ b/Web.Services/App_Data/url_info.txt @@ -1,4 +1,4 @@ -nldas_precipitation_url http://hydro1.sci.gsfc.nasa.gov/daac-bin/access/timeseries.cgi?variable=NLDAS:NLDAS_FORA0125_H.002:APCPsfc&location=NLDAS: +nldas_precipitation_url https://api.giovanni.earthdata.nasa.gov/timeseries?data=NLDAS_FORA0125_H_2_0_Rainf gldas_precipitation_url https://hydro1.gesdisc.eosdis.nasa.gov/daac-bin/access/timeseries.cgi?variable=GLDAS2:GLDAS_NOAH025_3H_v2.1:Rainf_f_tavg&location=GEOM:POINT nldas_surfacerunoff_url http://hydro1.sci.gsfc.nasa.gov/daac-bin/access/timeseries.cgi?variable=NLDAS:NLDAS_NOAH0125_H.002:SSRUNsfc&location=NLDAS: gldas_surfacerunoff_url https://hydro1.gesdisc.eosdis.nasa.gov/daac-bin/access/timeseries.cgi?variable=GLDAS2:GLDAS_NOAH025_3H_v2.1:Qs_acc&location=GEOM:POINT diff --git a/Web.Services/Models/WSPrecipitation.cs b/Web.Services/Models/WSPrecipitation.cs index 53b5a6ab..952489a1 100644 --- a/Web.Services/Models/WSPrecipitation.cs +++ b/Web.Services/Models/WSPrecipitation.cs @@ -30,6 +30,8 @@ public async Task GetPrecipitation(PrecipitationInput input) errorMsg = (!Enum.TryParse(input.Source, true, out PrecipSources pSource)) ? "ERROR: 'Source' was not found or is invalid.": ""; if (errorMsg.Contains("ERROR")) { return err.ReturnError(errorMsg); } + string nldasAccessToken = null; + // Precipitation object Precipitation.Precipitation precip = new Precipitation.Precipitation(); @@ -45,13 +47,19 @@ public async Task GetPrecipitation(PrecipitationInput input) precip.Input.Geometry.GeometryMetadata["token"] = (precip.Input.Geometry.GeometryMetadata.ContainsKey("token")) ? precip.Input.Geometry.GeometryMetadata["token"] : "RUYNSTvfSvtosAoakBSpgxcHASBxazzP"; } + if (precip.Input.Source.Contains("nldas")) + { + using var gesDisc = new Utilities.clsNLDAS_GES_DISC(AppContext.BaseDirectory); + nldasAccessToken = gesDisc.GetAccessToken(); + } + // Gets the Precipitation data. - ITimeSeriesOutput result = precip.GetData(out errorMsg); + ITimeSeriesOutput result = precip.GetData(out errorMsg, accessToken: nldasAccessToken); if (errorMsg.Contains("ERROR")) { return err.ReturnError(errorMsg); } // Get generic statistics result = Utilities.Statistics.GetStatistics(out errorMsg, precip.Input, result); return result; - } + } } } \ No newline at end of file diff --git a/Web.Services/Properties/launchSettings.json b/Web.Services/Properties/launchSettings.json index c31b7302..e662adb1 100644 --- a/Web.Services/Properties/launchSettings.json +++ b/Web.Services/Properties/launchSettings.json @@ -3,7 +3,7 @@ "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:6055/", + "applicationUrl": "http://localhost:7777/", "sslPort": 0 } },