Error occurs on line
MyWeatherData = WeatherAPI.GetMyWeather();
Error:
Cannot implicitly convert type System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IAction>
I never used MVC before and I am getting confused on flow of MVC. Currently, from view
, I am calling HomeController
. Then from HomeController
, I am calling 2nd WeatherController
. I know this is wrong but now sure how to do this without creating so many controllers
What I am trying to do: I have a view (index), where I have a button. If button is clicked, I want to use the weather API to get the data, save in model class, and display the data in a view (index
).
Index.cshtml
file: this view has a button. if you click on it, it will send a post request to HomeController
<form asp-controller="Home" method="post">
<button type="submit" >Submit</button>
</form>
// Display weather data here on click
HomeController class
public WeatherModel MyWeatherData { get; set; } = default!;
public WeatherController WeatherAPI { get; set; }
public IActionResult Index()
{
MyWeatherData = WeatherAPI.GetMyWeather();
return View();
}
WeatherController class
[Route("api/[controller]")]
[ApiController]
public class WeatherController : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetMyWeather()
{
var latitude = 40.712776;
var longitude = -74.005974;
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("https://api.open-meteo.com");
var response = await client.GetAsync($"/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m");
response.EnsureSuccessStatusCode();
var stringResult = await response.Content.ReadAsStringAsync(); //get json data in string
var rawWeather = JsonConvert.DeserializeObject<WeatherModel>(stringResult);
WeatherModel WM = new WeatherModel();
WM.latitude = rawWeather.latitude;
WM.longitude = rawWeather.longitude;
WM.generationtime_ms = rawWeather.generationtime_ms;
WM.utc_offset_seconds = rawWeather.utc_offset_seconds;
WM.timezone = rawWeather.timezone;
WM.timezone_abbreviation = rawWeather.timezone_abbreviation;
WM.elevation = rawWeather.elevation;
return Ok(WM);
}
catch (HttpRequestException httpRequestException)
{
return BadRequest($"Error getting weather from OpenWeather: {httpRequestException.Message}");
}
}
} //end of method
Model class
public class WeatherModel
{
public long latitude { get; set; }
public long longitude { get; set; }
public long generationtime_ms { get; set; }
public long utc_offset_seconds { get; set; }
public string timezone { get; set; }
public string timezone_abbreviation { get; set; }
public string elevation { get; set; }
}
CodePudding user response:
You're asking a few different questions here but it seems like ultimately you want to know how to resolve the compilation issue.
As you can see in your WeatherController
action, it is async which is indicated by the async
keyword as well as the Task
type.
public async Task<IActionResult> GetMyWeather()
Task<IActionResult>
means that you must await the response in order to get the response of type IActionResult
. In order to do this, you should change your HomeController action to be async as well:
public async Task<IActionResult> Index()
{
MyWeatherData = await WeatherAPI.GetMyWeather();
return View();
}
CodePudding user response:
MyWeatherData
is type of WeatherModel
while the return type of GetMyWeather
is Task<IActionResult>
. That is why you get such compilation error.
Change your code like below:
HomeController
Note: you need initialize the WeatherController
, otherwise you will get the null exception when you run the code.
public WeatherModel MyWeatherData { get; set; } = default!;
public WeatherController WeatherAPI { get; set; } = new WeatherController(); //change here....
public async Task<IActionResult> Index()
{
MyWeatherData = await WeatherAPI.GetMyWeather(); //add await...
return View();
}
WeatherController
[Route("api/[controller]")]
[ApiController]
public class WeatherController : ControllerBase
{
[HttpGet]
public async Task<WeatherModel> GetMyWeather() //change the type to `Task<WeatherModel>`
{
var latitude = 40.712776;
var longitude = -74.005974;
using (var client = new HttpClient())
{
try
{
//...
return WM; //change here...
}
catch (HttpRequestException httpRequestException)
{
//also change here...
throw new Exception($"Error getting weather from OpenWeather: {httpRequestException.Message}");
}
}
}
}
Some suggestion
1.No need set the value for each property of the WeatherModel WM = new WeatherModel();
, the data rawWeather
you get is actually a type of WeatherModel
. Just change your code:
[HttpGet]
public async Task<WeatherModel> GetMyWeather()
{
var latitude = 40.712776;
var longitude = -74.005974;
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("https://api.open-meteo.com");
var response = await client.GetAsync($"/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m");
response.EnsureSuccessStatusCode();
var stringResult = await response.Content.ReadAsStringAsync(); //get json data in string
var rawWeather = JsonConvert.DeserializeObject<WeatherModel>(stringResult);
return rawWeather; //just return rawWeather....
}
catch (HttpRequestException httpRequestException)
{
throw new Exception($"Error getting weather from OpenWeather: {httpRequestException.Message}");
}
}
}
2.var latitude = 40.712776;
,var longitude = -74.005974;
are type of long
and hourly
is string type, be sure the api you called by HttpClient should contain parameter with (long latitude, long longitude, string hourly
). If the type does not match, you will get the 400 error.
For example:
[Route("/v1/forecast")]
public IActionResult Get(double latitude, double longitude,string hourly)
{
var model = new WeatherModel()
{
latitude = Convert.ToInt64(latitude),
longitude = Convert.ToInt64(longitude),
//...
};
return Json(model);
}