Chupacabra
Chupacabra

Reputation: 45

.NET MVC Core Json / Async Task populating SelectList / IEnumerable

I can not find the answer nor can I fix my issue with grabbing Json data from a MVC WepApi and sending it to a drop down list.

I get the following error:

RuntimeBinderException: The best overloaded method match for 'Microsoft.AspNetCore.Mvc.Rendering.SelectList.SelectList(System.Collections.IEnumerable, string, string)' has some invalid arguments

I grab the Json data using the following code, this code is sitting in the Controlller right now:

    public async Task<IActionResult> GrabEmployees()
    {
        var item = new List<EmployeeViewModel>();

        using (var employee = new HttpClient())
        {
            employee.BaseAddress = new Uri("http://localhost:5050/");
            employee.DefaultRequestHeaders.Accept.Clear();
            employee.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            HttpResponseMessage response = await employee.GetAsync("api/employees");
            if (response.IsSuccessStatusCode)
            {
                item = await response.Content.ReadAsAsync<List<EmployeeViewModel>>();
            }
        }
        return ViewBag.Employees = item.Select(employee => new SelectListItem { Value = employee.EmployeeNumber, Text = (employee.FirstName + " " + employee.LastName) });
    }

So with the above code I tried setting the Task to a string, IEnumerable, JsonResult, all kinds of stuff it gives me the same error. It leads me to believe that the issue could be because it's async. I don't know though, I'm new to Json and MVC Core.

Here is how I pass the info into the View:

    public IActionResult Assignments()
    {
        ViewData["Title"] = "Assign Asset";
        ViewData["Message"] = "Use this section to assign assets to Employees.";
        ViewBag.Employees = GrabEmployees();
        ViewBag.Assets = AManger.GetAll();
        //Allows to assign assets to employees
        return View();
    }

Here is the View page code:

@model IEnumerable<Final.HRInventoryApp.Models.AssetViewModel>

<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>
@using (Html.BeginForm())
{
    @Html.DropDownList("Asset", new SelectList(ViewBag.Assets, "Id", "TagNumber"))
    @Html.DropDownList("EmployeeId", new SelectList(ViewBag.Employees, "Value", "Text"))
    <input type="submit" id="buttonsubmit" value="Submit" />

}

I am getting mixed results. When I first launch the application the page loads and the drop down is populated. If i click on another page and come back to said page it completely fails with that error. How can I fix this?

Upvotes: 1

Views: 3016

Answers (1)

Shyju
Shyju

Reputation: 218762

Looks like your GrabEmployees method is returning an IActionResult which you are setting to the viewbag in the other action method ! Also you have a statement return ViewBag.Employees; in that method!! That does not look correct. You should consider updating your GrabEmployees method to return the data you want (The collection of SelectListItem items)

public async Task<IEnumerable<SelectListItem>> GrabEmployees()
{
    var item = new List<SelectListItem>();

    using (var employee = new HttpClient())
    {
        employee.BaseAddress = new Uri("yourUrlForApiEndpointHere");
        employee.DefaultRequestHeaders.Accept.Clear();
        employee.DefaultRequestHeaders.Accept

                            .Add(new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = await employee.GetAsync("api/employees");
        if (response.IsSuccessStatusCode)
        {
            var data = await response.Content.ReadAsAsync<List<EmployeeViewModel>>();
            return data.Select(x => new SelectListItem { Value = x.EmployeeNumber,
                                           Text = (x.FirstName + " " + x.LastName) });
        }
    }
    return item;
}

And in your other action method,call this method and pass it to view.

public  async Task<IActionResult> Assignments()
{
    ViewData["Title"] = "Assign Asset";
    ViewData["Message"] = "Use this section to assign assets to Employees.";
    var d =  await GrabEmployees();
    ViewBag.Employees = d.ToList();
    // to do : Fix Assets the same way
    return View();
}

Now in the View,

@Html.DropDownList("EmployeeId", ViewBag.Employees as List<SelectListItem>)

Upvotes: 1

Related Questions