简体   繁体   中英

Simple ASP.NET Core Web API - cannot implicitly convert type system.threading.tasks.task<microsoft.aspnetcore.mvc.IAction>

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; }
}

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);
}

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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM