Click here to Skip to main content
15,889,909 members
Articles / Web Development / HTML
Tip/Trick

Minimalistic Example of Sending and Receiving Data Between the Client (View) and Server (Controller) via AJAX in an ASP.NET MVC App

Rate me:
Please Sign up or sign in to vote.
4.71/5 (5 votes)
25 Apr 2016CPOL4 min read 18K   3  
Simplest possible step-by-step instructions on how to set up an ASP.NET MVC app to use AJAX from the client to call a Controller method, sending data from the client (jquery code on a View) to the server (C# code on a Controller), and then response data back from the server to the client.

Most Valuable Code (Isn't that what MVC stands for?)

Caveat: I am not a jQuery or ASP.NET MVC guru, or even an expert. What I show you in this tip is the result of implementing the answers from several different people to several different questions that I pos[t]ed on StackOverflow.

I won't go into the theory behind or the raison d'etre of MVC; I will just show you what you need to do to send some data from a couple of html elements on a page to a controller, and then some other data back again, from the controller to the page.

These are the basic steps (this assumes you already have a page with some HTML elements on it) you can follow (and tweak, as necessary):

Create a Model

A model is just a regular old C# class (right-click your Models folder and select Add > Class), and can be as simple as this:

C#
public class UnitReportPairModel
{
    public List<string> UnitReportPairEmailVals { get; set; }
}

So this model defines a single member, a generic list of string. You should create it in your project's Models folder (I named it UnitReportPairModel.cs).

Create a Controller

The Controller is a little more specialized, inheriting Controller, but can be rather short/simple/sweet:

C#
public class UnitReportPairController : Controller
{
    public JsonResult GetUnitReportPairEmailAddresses(string unit, string report)
    {
        UnitReportPairModel model = new UnitReportPairModel();
        try
        {
            int rptId = GetReportIDForName(report);

            DataTable UnitReportPairEmailValsDT = new DataTable();
            string qry = string.Format(SQL.UnitReportPairEmailQuery, unit, rptId);
            UnitReportPairEmailValsDT = SQL.ExecuteSQLReturnDataTable(
                qry,
                CommandType.Text,
                null
                );

            List<string> emailAddresses = UnitReportPairEmailValsDT
                     .AsEnumerable()
                     .Select(row => row.Field<string>("EmailAddr"))
                     .ToList();

            model.UnitReportPairEmailVals = emailAddresses;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        return Json(model, JsonRequestBehavior.AllowGet);
    }

    private int GetReportIDForName(string rpt)
    {
        string qry = string.Format(SQL.RptIDForRptNameQuery, rpt);
        return SQL.GetIntValForQuery(qry);
    }
}</string></string>

You should create this controller file (I named it UnitReportPairController.cs) in your project's Controllers folder. You can create one of these by right-clicking your project's Controller folder and selecting Add > Controller... > MVC 5 Controller - Empty. replace the default ActionResult Index() that returns View() with your custom code.

This controller is where the model's member[s] is/are inflated/populated. How you do that (with calls to a database or whatever) are, of course, completely up to you. In the case shown above, a call to a SQL Server database is made, then the results are saved to a generic list of string, which are assigned to the Model's member, and returned as json. But to who? That's where the VIEW part comes in. Note first, though, that your Controller can have standalone/utility methods such as GetReportIDForName().

Create a View

As already mentioned, it is assumed that you already have some html on a page. In the scenario I'm showing, I created a select element and a bunch of checkboxes, like this (the CSS classes are, for the most part, bootstrap), which I added to the existing Index.cshtml file in the Views\Home folder:

HTML
@* row 1: Create select element with "Unit" options *@
<div class="row">
    <div class="col-md-12">
        <label class="sectiontext">Select a Unit</label>
        <select class="form-control, dropdown" 
        id="unitsselect" name="unitsselect">
            <option disabled selected value="-1">Please choose a Unit</option>
            @foreach (var field in units)
            {
                <option id="selItem_@(field.unit)" 
                value="@field.unit">@field.unit</option>
            }
        </select>
    </div>
</div>

@* row 2: Create Report checkboxes *@
<div class="row">
    <div class="col-md-12" id="unitsCheckboxDiv">
        <div class="containerforplatypus">
            <label class="sectiontext">Select Report[s]</label>
            @foreach (var rpt in reports)
            {
                @* convert id to lowercase and no spaces *@
                var morphedRptName = @rpt.report.Replace(" ", string.Empty).ToLower();
                <input class="ckbx leftmargin8" 
                id="ckbx_@(morphedRptName)" type="checkbox" 
value="@rpt.report" />@rpt.report
            }
        </div>
    </div>
</div>

Wait, There's More

This is an additional piece of HTML that figures into the "receiving-data-back-in-the-AJAX-callback" part of this tip:

HTML
@* row 3: Email recipients input/text elements  *@
<div class="row">
    <div class="col-md-12">
        <div class="containerforplatypus">
            <h4 class="h4, sectiontext">Specify Recipients</h4>
            <label class="margin4horizontal">Email 1</label>
            <input type="text" name="email1" id="email1" />
            <label class="margin4horizontal">Email 2</label>
            <input type="text" name="email2" id="email2" />
            <label class="margin4horizontal">Email 3</label>
            <input type="text" name="email3" id="email3" />
            <button class="btn btn-primary" name="addlEmails" 
            id="addlEmails">Add Another Email</button>
        </div>
    </div>
</div>

Now the jQuery Part of It

I reckon it is considered better practice to break jquery code into separate files, storing them in a Scripts folder, but I just added a Script section at the bottom of the page, which you can do like so:

HTML
@section Scripts
{
    <script type="text/javascript">
        $(document).ready(function () {
		        // add "ready function" code
        });

        // Add other code
    </script>
};

I have a moderate amount of code in the Script section, but to avoid confusing the issue and to keep this tip as simple and focused as possible, I am just going to show the parts that pertain specifically to the interchange of data between the page (client/jquery code) and the server (controller/C# code):

JavaScript
$(".ckbx").change(function () {
    var unitval = $('#unitsselect').val();
    var rptval = $(this).val();

    var model = JSON.stringify({ unit: unitval, report: rptval });
    $.ajax({
        type: 'GET',
        url: '@Url.Action
        ("GetUnitReportPairEmailAddresses", "UnitReportPair")',
        data: { unit: unitval, report: rptval },
        contentType: 'application/json',
        cache: false,
        success: function (returneddata) {
            populateemails(returneddata);
        },
        error: function () {
            alert('hey, boo-boo!');
        }
    });
}); // $(".ckbx").change(function ()

For the AJAX call above to reach your control, the Control needs to be named UnitReportPairController (the first argument is the name of the method, the second is the name of the Controller sans the "controller" appendage).

So this AJAX call is sending two string values, such as "RED ROBIN" and "PRODUCE USAGE" to the Controller method. What it gets back from that method (a jsonified generic list of string, or an array of string) is dealt with in the success/error dual callback. If the call returns successfully, and the "success" block is reached, it calls the method populateemails, passing the returned data along to it. This method is:

JavaScript
function populateemails(trampdata) {
    // first, clear them all
    $("#email1").val('');
    $("#email2").val('');
    $("#email3").val('');
    // Now set those for which there are values
    if (trampdata.UnitReportPairEmailVals.length > 0) {
      $("#email1").val(trampdata.UnitReportPairEmailVals[0]);
    }
    if (trampdata.UnitReportPairEmailVals.length > 1) {
      $("#email2").val(trampdata.UnitReportPairEmailVals[1]);
    }
    if (trampdata.UnitReportPairEmailVals.length > 2) {
      $("#email3").val(trampdata.UnitReportPairEmailVals[2]);
    }
}

Note: This jquery is doubtless rude, crude, and unrefined; feel free to refactor and elegantize it.

Riding Off into the Sunset

And there you have it - selecting a unit and a report invokes the AJAX call, which gets the appropriate email addresses for that unit/report pair, and populates the input text emails with those values. If this tip saves you time, be sure to use that time doing something useful, such as coming up with an antidote for Duckbill Platypus venom (they have a poison toe, don't ya know).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder Across Time & Space
United States United States
I am in the process of morphing from a software developer into a portrayer of Mark Twain. My monologue (or one-man play, entitled "The Adventures of Mark Twain: As Told By Himself" and set in 1896) features Twain giving an overview of his life up till then. The performance includes the relating of interesting experiences and humorous anecdotes from Twain's boyhood and youth, his time as a riverboat pilot, his wild and woolly adventures in the Territory of Nevada and California, and experiences as a writer and world traveler, including recollections of meetings with many of the famous and powerful of the 19th century - royalty, business magnates, fellow authors, as well as intimate glimpses into his home life (his parents, siblings, wife, and children).

Peripatetic and picaresque, I have lived in eight states; specifically, besides my native California (where I was born and where I now again reside) in chronological order: New York, Montana, Alaska, Oklahoma, Wisconsin, Idaho, and Missouri.

I am also a writer of both fiction (for which I use a nom de plume, "Blackbird Crow Raven", as a nod to my Native American heritage - I am "½ Cowboy, ½ Indian") and nonfiction, including a two-volume social and cultural history of the U.S. which covers important events from 1620-2006: http://www.lulu.com/spotlight/blackbirdcraven

Comments and Discussions

 
-- There are no messages in this forum --