4

I want to pass a parameter (string) to my Controller from my View. The value should be that which is selected from a dropdown list in the view. The method is called after a button-click, but in the Controller, the parameter is always null.

In the View:

    @using (Html.BeginForm("Send", "Overview", FormMethod.Get))
    {
        <p>Email: @Html.DropDownList("Emails", Model.GetEmails())
        <input type="submit" value="Send" />
        </p>

    }

In the Controller:

    public ActionResult Send(string email)
    {
        // email is always null!
        return null;
    }

In the Overview model:

    private List<SelectListItem> emails;
    ...
    public Overview()
    {
        emails = new List<SelectListItem>();
        emails.Add(new SelectListItem() { Text = "[email protected]", Value = "[email protected]", Selected = true });
        emails.Add(new SelectListItem() { Text = "[email protected]", Value = "[email protected]", Selected = false });
        emails.Add(new SelectListItem() { Text = "[email protected]", Value = "[email protected]", Selected = false });
    }
    ...
    public List<SelectListItem> GetEmails()
    {
        return emails;
    }

Could you please help me get this work? What am I missing? (Btw, never mind the Controller returning null for now please :)).

2
  • This seemed to fix it, in the Controller: string email2 = Request.Form["Emails"]; Commented Jan 12, 2014 at 14:32
  • Why is GetEmails() public and why return a List<>? both of these look suspiciously like anti patterns Commented Jan 12, 2014 at 20:00

2 Answers 2

7

From your terminology I'm guessing you're confused about what's going on. You never send anything from the view to the controller. Instead the view is something that assembles Html to send to the web browser. So what's actually happening is this:

  • Your browser requests /MyApp/Overview from your server (IIS)
  • IIS picks it up and sends that to Asp.Net
  • Asp.Net Mvc sees the request and through routing figures out that you want to call the Overview method on the MyAppController class
  • The method runs and produces a Model
  • Asp.Net Mvc passes the model to the view engine which runs your view to produce html
  • The html is returned to IIS which sends it to your browser
  • Your browser displays the html as a select control.
  • The user makes a selection and clicks "submit" on the form
  • The browser encodes their submission and sends it to the url in the form's action attribute (eg <form method=POST action="/MyApp/Send>)
  • IIS picks that up and sends that to Asp.Net
  • Asp.Net Mvc sees the request and through routing figures out that you want to call the Send method on the MyAppController class
  • Asp.Net Mvc sees that your method expects a string parameter named email and tries to find this information in the submitted form data using model binding
  • Asp.Net Mvc invokes the Send method with the found parameter value (if available)
  • ...

You do not provide quite enough context for me to be able to analyze what is wrong but my guess is that @Html.DropDownList("Emails", Model.GetEmails()) is generating something like <select name="Emails"> ....</select>. This means that when model binding is happening it is looking for submitted "email" input but finds nothing. Instead try something like @Html.DropDownList("email", Model.GetEmails()) to get it to work.

Semantically this is more correct anyways, because while the control displays emails (plural), a user actually interacts with it by selecting an email (singular). Think of it as if it was just a text box, you wouldn't name that in the plural.

I should note by the way, that you have several HUGE security holes here. By taking the email address as input into your method it seems like anyone can open up the developer tools in their browser and use your service to send emails to any email address! Spammers love to find unsecured services like this. A much better solution would be to have the value in the generated select list be an id for the user you want emailed, and in the Send method take the id as input. Also, Send should definitely not be accessible via Http GET (so put an [HttpPost] attribute on there!). If it allows GET, even if this is behind a login page, I can trick users who are logged in into visiting a form with an <img src="http://yoursite.com/MyApp/Send/[email protected]" /> and every time they visit the page someone will receive a spam email.

Sign up to request clarification or add additional context in comments.

1 Comment

Nice. And yes, int are better to pass than a string email.
5

You could just use a string in your model,

public string emails { get; set; };

then Use a DropDownListFor on your view,

@Html.DropDownListFor(x => x.emails, Model.GetEmails())

and get the value directly from the model on the POST.

[HttpPost]
public ActionResult Send(OverviewViewModel overviewModel)
{
    //here is the value from the drop down
    var theEmail = overviewModel.emails;
}

2 Comments

what if you have 2 dropdownlists and you have to check which one user has selected a choice in and which one not?
The same concept still applies there, just set a "default" value within your List<SelectListItem> before sending it to your view. You can do that by setting the item's Selected property to true (the OP does this above). If your default value is still selected on the model by the time you POST, you can assume the user has not selected anything from that particular drop down.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.