1

In my MVC project I pass list of currencies to the view within the drop down list. However, once I try to post the view I get the following exception:

The ViewData item that has the key 'FromCurrencyId' is of type 'System.Int32' but must be of type 'IEnumerable'.

Currency Controller

namespace Project.Controllers
{
    public class CurrencyController : Controller
    {
      [HttpGet]
        // GET: Currency
        public ActionResult Index()
        {

            CurrenciesClient Cur = new CurrenciesClient();
            var listCurrency = Cur.findAll().ToList();

            Currencies model = new Currencies();
            model.FromCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
            model.ToCurrencies = new SelectList(listCurrency, "Id",  "CurrencyName");

            return View(model);

        }

        [HttpPost]
        public ActionResult Index(Currencies cur)
        {


            if (ModelState.IsValid)
            {
                if (cur.FromCurrencyId == cur.ToCurrencyId)
                {
                    //do something if same currecnies and return.
                    ModelState.AddModelError("CurrencyCountry", "Can't make the conversion for the same value");
                }
                else
                {
                   some code .....
                }
            }

            return View(cur);

        }
    }
}

Currencies VM

namespace Project.ViewModels
{
    public class Currencies
    {
        public int Id { get; set; }
        [Required]
        public int FromCurrencyId { get; set; }
        public SelectList FromCurrencies { get; set; }

        [Required]
        public int ToCurrencyId { get; set; }
        public SelectList ToCurrencies { get; set; }

        public string CurrencyName { get; set; }

        public string CurrencyCountry { get; set; }


        [Required]
        public decimal ConversionRate { get; set; }

        public decimal Value { get; set; }

        public SelectList AvailableCurrencies { get; set; }


    }
}

CurrencyClient web service VM

namespace Project.ViewModels
{
    public class CurrenciesClient 
    {
        private string base_Url = "http://localhost:51646/api/";

        public IEnumerable<Currencies> findAll()
        {
            try
            {
                HttpClient client = new HttpClient();
                client.BaseAddress = new Uri(base_Url);
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpResponseMessage response = client.GetAsync("currencies").Result;
                if (response.IsSuccessStatusCode)
                {
                    var resposeData = response.Content.ReadAsStringAsync().Result;
                    var Currency = JsonConvert.DeserializeObject<List<Currencies>>(resposeData);
                    return Currency;


                }
                return null;

            }
            catch
            {
                return null;
            }
        }
    }
}

Index View

model Project.ViewModels.Currencies

@{
    ViewBag.Title = "Index";
}


@using (Html.BeginForm("Index", "Currency", FormMethod.Post))
{
    @Html.TextBoxFor(m => m.ConversionRate, new { @size = "5" })
    @Html.DropDownListFor(m => m.FromCurrencyId, Model.FromCurrencies as IEnumerable<SelectListItem>)
      @Html.DropDownListFor(m => m.ToCurrencyId, Model.ToCurrencies as IEnumerable<SelectListItem>)
        <button type="submit" class="btn btn-primary">Convert</button>
}
Dodi
  • 111
  • 4
  • 14

3 Answers3

1

This problem is becuase you are passing null value from your dropdown.Means you are not selecting any value. Check that if you will pass some value from dropdown it will work fine.To solve this problem you need to add the same code

Currencies model = new Currencies();
            model.FromCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
            model.ToCurrencies = new SelectList(listCurrency, "Id",  "CurrencyName");

in your controller index post method.Because if selectListitem would be null the following code will be executed

 IEnumerable<SelectListItem> selectList = o as IEnumerable<SelectListItem>;
if (selectList == null)
{
    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 
        MvcResources.HtmlHelper_WrongSelectDataType,
        name, o.GetType().FullName, "IEnumerable<SelectListItem>"));
}

Which will throw exception. (It would be better if you will use

ViewBag.FromCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");

like this.)

The better description is given here:

The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'

The whole explanation is also given in this link like how does this code work.

Community
  • 1
  • 1
Rajput
  • 2,597
  • 16
  • 29
  • Thank you for your reply. I really want to show you my new edit for the code but don't know if I need to update my question? – Dodi Dec 18 '16 at 18:47
  • Still the same problem @Dodi82 – Rajput Dec 18 '16 at 18:49
  • Yes, but I altered my code in the post action method and now I get an exception with the get action method of a null value in ths line var listCurrency = Cur.findAll().ToList(); ! Can I edit my code and you probably will be able to figure out the problem – Dodi Dec 18 '16 at 19:11
  • What is currencyClient Class Can you show us the implementation of this class and before adding this to your code that was running fine? Check it out again adding this to your post method has no effect on get method.If you have not altered anything in get method. – Rajput Dec 18 '16 at 19:20
  • So again same problem or now it is fixed. @Dodi82 – Rajput Dec 18 '16 at 20:17
  • Hiya, Thank you for your help. I tried to pass the value to the LINQ from the Currencies.cs to the post action method but has no luck as I kept getting a Null value in the result. However, I managed to fix the partial view using the Unobtrusive library the minified version script within the Index View! – Dodi Dec 19 '16 at 17:47
  • take refernce of my project that will help you – Rajput Dec 19 '16 at 20:43
  • you have shared with yourself. right click on folder or file and click on get sharable link , an dsend that link to me what you have shared this is provate link make sure you are making access to public – Rajput Dec 20 '16 at 22:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/131103/discussion-between-dodi82-and-rajput). – Dodi Dec 21 '16 at 00:25
  • show me code come to teamviewer – Rajput Dec 22 '16 at 19:13
0

you will have to set the Dropdown data in the post controller as well, otherwise it will not be able to find the ViewBag values, as a result when after post action it calls the Index view, the ViewBag.FromCurrencies and ViewBag.ToCurrencies will be null which is obviously that we don't want.

For fixing the error, you will have to change you post action to be like:

[HttpPost]
public ActionResult Index(Currencies cur)
{


        if (ModelState.IsValid)
        {
            if (cur.FromCurrencyId == cur.ToCurrencyId)
            {
                //do something if same currecnies and return.
                ModelState.AddModelError("CurrencyCountry", "Can't make the conversion for the same value");
            }
            else
            {
               some code .....
            }
        }

        CurrenciesClient Cur = new CurrenciesClient();
        var listCurrency = Cur.findAll().ToList();

        Currencies model = new Currencies();
        model.FromCurrencies = new SelectList(listCurrency, "Id", "CurrencyName");
        model.ToCurrencies = new SelectList(listCurrency, "Id",  "CurrencyName");

        return View(cur);

    }
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
0

You should not return the view from your POST action or you will run into many issues. Here is the problem with that:

  1. When you submit the form the URL is pointing to your Index. The body of your http post will have a bunch of Currencies items in it. Therefore, MVC, will submit the form to your Index method with Currencies cur parameter.
  2. If all is well you return the same view.
  3. If you refresh the page, your browser will simply reissue the last request and guess what, it will submit the form again. But this is not what you intended by refreshing. You wanted to get the form as it was originally presented not resubmit it.

Therefore instead of returning a view from a POST, you should always, except if AJAX was used, return a redirect.

In this case if all goes well, you may want to send the user to a success page or some other page so you should do this:

return RedirectToAction("YourActionName", "YourControllerName");

This pattern is called the PRG pattern. What this does is this:

  1. user submits a form
  2. If all goes well on the server side, you tell the browser to issue another request and get another page.
  3. The browser gets the other page which may be a success page.
  4. Now the user is on the success page. If they hit refresh they will get the success page again. They will not be submitting the same form over and over.
CodingYoshi
  • 25,467
  • 4
  • 62
  • 64
  • Thank you very much for your answer. Would it be good if I use a partial view to return once the process is success? – Dodi Dec 18 '16 at 18:24
  • No because the browser will still have the same URL. You can try it, return a partial and then refresh the browser and see what happens. If you use AJAX, you can show a message to the user "Success" but then you need to issue a request to another page so it gets another page. Right now you are showing the same view to the user, how would they know if things went well? You see the issue is not simply refresh of the browser but also other issues. – CodingYoshi Dec 18 '16 at 18:29
  • I am working to use the Unobtrusive library Ajax which will post the partial view with the result rather than posting back the whole page! I want to display a result for the user after performing the conversion than redirecting to another page. However, the challenge will be resetting the page after showing the result! – Dodi Dec 19 '16 at 10:29