Search code examples
c#databaseasp.net-mvcdrop-down-menustrong-typing

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


I am trying to implement a MVC application that has a view, controller and view model in order to populate a dropdown list from a database and then use the data for the selected item in a [HttpPost]. Below is the data in each of the corresponding files:

MessageController.cs

public String send_url;
    private msg_cmsEntities smse = new msg_cmsEntities();
public ActionResult Message_Send_Get()
{

    var model = new MessageModel
    {
        MessagesList = smse.Messages
           .Select(c => new SelectListItem
           {
               Value = c.message1,
               Text = c.message1
           })
    };
    return View(model);            
}

[HttpPost]
    public ActionResult Message_Send_Get(String code, String password, String from, String Message_List, MessageModel message_to_send)
    {
        //If the Model is valid (no errors) then go into this statement
        if (ModelState.IsValid)
        {
            WebRequest wrGETURL;

        //This is a string that points to the location of the Web Service 
        string web_service_location = "http://www.google.com?";

        //This initates a new writeable instance of HttpValueCollection
        NameValueCollection query_string = System.Web.HttpUtility.ParseQueryString(string.Empty);
        //This builds up the query string that will be used for the redirect
        query_string["code"] = code;
        query_string["password"] = password;
        query_string["from"] = from;
        query_string["msg"] = Message_List;

        //This concatinates the web_service_location (String) and query_string (String)
        send_url = web_service_location + query_string.ToString();


        Debug.WriteLine(send_url);

        wrGETURL = WebRequest.Create(send_url);
    }
    var model = new MessageModel
    {
        MessagesList = smse.Messages
           .Select(c => new SelectListItem
           {
               Value = c.message1,
               Text = c.message1
           })
    };
    return View(message_to_send);
}

Message_Send_Get.aspx(The View):

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Message_Send.Models.MessageModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Message_Send_Get
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Message_Send_Get</h2>

    <% using (Html.BeginForm()) {%>
        <%: Html.ValidationSummary(true) %>

        <fieldset>
            <legend>Fields</legend>

            <div class="editor-label">
                <%: Html.LabelFor(model => model.code) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.code) %>
                <%: Html.ValidationMessageFor(model => model.code) %>
            </div>

            <div class="editor-label">
                <%: Html.LabelFor(model => model.password) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.password) %>
                <%: Html.ValidationMessageFor(model => model.password) %>
            </div>

            <div class="editor-label">
                <%: Html.LabelFor(model => model.from) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.from) %>
                <%: Html.ValidationMessageFor(model => model.from) %>
            </div>

            <div class="editor-label">
                <%: Html.LabelFor(model => model.message) %>
            </div>
            <div class="editor-field">
                <%= Html.DropDownListFor(model => model.message, Model.MessagesList)%>
                <%: Html.ValidationMessageFor(model => model.message) %>
            </div>               

            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% } %>

    <div>
        <%: Html.ActionLink("Back to List", "Index") %>
    </div>

</asp:Content>

MessageModels.cs

public class MessageModel
    {
        [Required(ErrorMessage = "You must enter a code for this service!!")]
        [DataType(DataType.Text)]
        [DisplayName("Code")]
        public string code { get; set; }

        [Required(ErrorMessage = "A password is required for the service!!")]
        [DataType(DataType.Text)]
        [DisplayName("Password")]
        public string password { get; set; }

        [Required(ErrorMessage = "You must enter the 'From' information!!")]
        [DataType(DataType.Text)]
        [DisplayName("Message From")]
        public string sms_from { get; set; }

        [Required]
        [DisplayName("Send Message")]
        public string message { get; set; }

        public IEnumerable<SelectListItem> MessagesList { get; set; }
    }

When using this I get the error in the title, can someone please help me with this?

Thanks


Solution

  • In your POST controller action you seem to be instantiating some model variable that you do nothing with it. You still return View(message_to_send); and of course this message_to_send variable doesn't have its MessagesList property assigned. Also why are you repeating all action arguments when they are already present in your view model?

    Here's how I would suggest you improve your code (I have put some Warnings as comments in the code):

    [HttpPost]
    public ActionResult Message_Send_Get(MessageModel message_to_send)
    {
        if (ModelState.IsValid)
        {
            WebRequest wrGETURL;
    
            //This is a string that points to the location of the Web Service 
            string web_service_location = "http://www.google.com?";
    
            //This initates a new writeable instance of HttpValueCollection
            NameValueCollection query_string = System.Web.HttpUtility.ParseQueryString(string.Empty);
            //This builds up the query string that will be used for the redirect
            query_string["code"] = message_to_send.code;
            query_string["password"] = message_to_send.password;
            query_string["from"] = message_to_send.sms_from;
    
            // Warning: you seem to have used some Message_List argument in your action
            // but there's no corresponding input field in the view or in the model
            // maybe you want to add some
            // query_string["msg"] = message_to_send.sms_from.msg;
    
            //This concatinates the web_service_location (String) and query_string (String)
            send_url = web_service_location + query_string.ToString();
    
            Debug.WriteLine(send_url);
    
            // Warning: Here you only created the request but never sent it
            // I guess you will have to complete the code .....
            wrGETURL = WebRequest.Create(send_url);
        }
    
        // since we want to redisplay the same view we need to reassign the
        // MessagesList property used by the dropdown because in HTML a dropdown
        // sends only the selected value when the form is submitted and not the entire
        // list of options
        message_to_send.MessagesList = smse.Messages
           .Select(c => new SelectListItem
           {
               Value = c.message1,
               Text = c.message1
           });
        return View(message_to_send);
    }
    

    Small remark: in your view you seem to be using some from property of your model: <%: Html.TextBoxFor(model => model.from) %> but such property doesn't exist in the model you have shown. Maybe you meant sms_from.