Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

WCF RESTful service and WebGrid in ASP.NET MVC 5 - Part 2

4.88/5 (21 votes)
22 Jun 2014CPOL7 min read 64.8K   2.4K  
In this article we will learn how to create WCF RESTful services and consume those services in ASP.NET MVC 5 application using WebGrid Control.

Note: To work with the code attached here, WCF service created in first part should be up and running.

Introduction

This is second part of the article which is having two parts. In first part we have created WCF RESTful service which we will be consuming in this part. In this second part we will create an ASP.NET MVC web application with WebGrid control and will do CRUD operations.

If you have not gone through first part, I recommend you to have a visit there because it will give you better context and help you while going through this article. Following is outlines for this second part of the article:

  • Creating ASP.NET MVC 5 application
  • Displaying Data into WebGrid control
  • Adding inline Edit operation
  • Adding inline Delete operation
  • Adding Create operation

Creating ASP.NET MVC 5 application

Along with this article we will create a demo MVC application which will perform CRUD operations on customers data. Customers data will be displayed in a WebGrid where user will be doing Create, Read, Update (Edit) and Delete operations. When user does any operations at client side (browser) call goes to a particular Action method of Controller of MVC application. Then Action method will call to WFC RESTful web service created in first part of this article. Finally WCF web service calls repository to perform appropriate operation on database to persist the change.

Please follow below steps to create the demo application:

  1. Let's get started by creating a sample application by selecting ASP.NET Web Application template, naming project as DemoMVCApp and click ok.

    Project Template
     
  2. Now select MVC template as shown below and click ok.

    MVC Selected

    Visual Studio will create a ASP.NET MVC project structure for us. We will modify it in next steps to implement required functionalities.
     
  3. Under Models folder, add a class called as Customer and write following code in it as shown below:
       public class Customer
       {
           public int CustomerId { get; set; }
           [Required]
           [DisplayName("Name")]
           public string CustomerName { get; set; }
    
           [Required]
           [DisplayName("Address")]
           public string CustomerAddress { get; set; }
       }
    }
    
  4. Under Controller folder, Add a controller named as CustomerController. This controller will have action methods for Get, Post, Put and Delete action for Customer model. In CustomerController class write the code as shown below:
    readonly string customerServiceUri = "http://localhost:1750/CustomerService.svc/";
    // customerServiceUri is a global variable for this customercontroller, having the path of CustomerService. 
    // Please change URI path if service is hosed at some different URI in your case. 
            public ActionResult Index()
            {
                List<Customer> customerList = new List<Customer>();
                using (WebClient webClient = new WebClient())
                {
                    string dwml;
                    dwml = webClient.DownloadString(customerUri + "GetAllCustomers");
                    customerList = JsonConvert.DeserializeObjectAsync<List<Customer>>(dwml).Result;
                }
                return View(customerList);
            }
    We just implemented a action method called Index which makes call to WCF services, deserialize the recieved data and returns the list of customers.
     

Displaying Data into WebGrid control

  1. Add a view by right clicking on Index method in CustomerController and naming it as Index. It will add a Index.cshtml file inside Views > Customer folder. Write the following code in Index view. This code will create a WebGrid and data will be binded to this grid. We are giving references to script and css files directly. (we are not focusing on bundling and minifications feature here.)

    Note: All custom css is written in index.css under Content folder and custom script is written in index.js file under Scripts folder, Please create those files in corresponding folders, code accordingly and give the reference in Index page. Caution: Put reference to index.js at the end of the page.
    @model  IEnumerable<DemoMVCWebApp.Models.Customer>
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <link href="~/Content/index.css" rel="stylesheet" />
    @{
        var grid = new WebGrid(Model, canPage: true, rowsPerPage: 5,
        selectionFieldName: "selectedRow");
        grid.Pager(WebGridPagerModes.NextPrevious);}
    <div id="gridContent">
        @grid.GetHtml(tableStyle: "webGrid",
                headerStyle: "header",
                alternatingRowStyle: "alt",
                selectedRowStyle: "select",
                rowStyle: "webgrid-row-style",
                columns: grid.Columns(
                grid.Column("CustomerId", "Customer Id", @<text> <span id="spnCustomerId">@item.CustomerId</span></text>,
                           canSort: false),
                grid.Column("CustomerName", "Customer Name", format: @<text>
                                     <span id="spnCustomerName" class="display-mode">@item.CustomerName</span>
                                     <input type="text" id="CustomerName" value="@item.CustomerName" class="edit-mode"/></text>,
                           canSort: false),
                           
                grid.Column("CustomerAddress", "Customer Address", format: @<text>
                                     <span id="spnCustomerAddress" class="display-mode">@item.CustomerAddress</span>
                                     <input type="text" id="CustomerAddress" value="@item.CustomerAddress" class="edit-mode"/></text>,
                           canSort: false),
                grid.Column("Action", format: @<text>
                                    <img src="~/Content/images/edit.jpg" title="Edit Customer" id="btnEdit" class="edit-button"/>
                                    <img src="~/Content/images/delete.jpg" title="Delete Customer" class="delete-customer"/>
                                     </text>, style: "width:220px", canSort: false)
                          ))
    </div>
  2. Under App_Start folder, in RoutConfig.cs file, set default route as shown below
    defaults: new { controller = "Customer", action = "Index", id = UrlParameter.Optional }
  3. Run the application, hope you will get all customers in WebGrid as shown below:

    Output for Customer page
     

Adding inline Edit operation

For editing any customer, we will use inline editing into WebGrid. As you have seen in fourth column of WebGrid, we are using images - one for edit and another for delete operation.

In this section, we will write some code so that on edit image click, data in corresponding row will be editable. Along with that, instead of edit image, save image will appear at same place with appropriate tool tip. So edit functionality looks like:

Project Template

while clicking on save image, edited customer object will go to EditCustomer action method of CustomerController. Then that action method will call WCF service and service will save update customer in database using repository.

Programmatically, in WebGrid each row is having span tag and an input tag with different CSS classes. On page load all text boxes which are having CSS class “edit-mode” will be hidden. Another thing we are considering is that, at a time only one row should be editable. To enable inline editing, on edit button click we are toggling the CSS classes because now span tag should be hidden and textboxe should appear in corresponding row.

If the edit fuctionality is not clear yet, please run the application and see the behaviour of edit button then look into JavaScript code written in index.js file. Or you just keep following the steps below, things will be obivious as you type and understand the code.

  1. Open index.js file under Scripts folder and write following code. This code hides the input boxes (having CSS class "edit-mode") while page load which are not needed in viewing mode.
    $(document).ready(function () {
    $('.edit-mode').hide();
    });
  2. Further we need to write JavaScript to handle click on Edit button. Write following code in index.js. Hope the comments written with code are enough to expain it.
                $('.edit-button').on("click", function () {
    // allEditableRow : will have all rows which are editable (where save button is visible).
    var allEditableRow = $("[src='/Content/images/save.jpg']");
    
    // make row editable only if no other row is editable as of now by toggle
    // otherwise go to else and save data of editable row first or alert to save that"
    if (allEditableRow.length == 0) {
        var tr = $(this).parents('tr:first');
        tr.find('.edit-mode,.display-mode').toggle();
        var imageSource = $(this).attr('src');
        if (imageSource == '/Content/images/edit.jpg') {
            $(this).attr('src', '/Content/images/save.jpg');
            $(this).attr('title', 'Save Customer');
        }
    }
    else {
        // making sure that only one row is editable and save button of editable row is clicked
        if (allEditableRow.length == 1 && $(this).attr('src') == '/Content/images/save.jpg')
        {
    
            var selectedId = $(this).parents('tr').find('td:nth-child(1)').text().trim();
            var selectedName = $(this).parents('tr').find('#CustomerName').val();
            var selectedAddless = $(this).parents('tr').find('#CustomerAddress').val();
            // create object with updated values
            var customerModel =
                {
                    "CustomerId": selectedId,
                    "CustomerName": selectedName,
                    "CustomerAddress": selectedAddless
                };
            $.ajax({
                url: '/Customer/EditCustomer',
                type: 'POST',
                contentType: 'application/json; charset=utf-8',
                data: JSON.stringify(customerModel)
            });
            alert("Your data is saved");
            window.location.reload(true);
            $(this).attr('src', '/Content/images/edit.jpg');
        }
        else {
            alert("Please finish the editing of current editable row. Save first");
        }
    }
    
  3. In CustomerController, we need to implement EditCustomer action method as shown below.
    public void EditCustomer(Customer customer)
            {
                using (WebClient wc = new WebClient())
                {
                    MemoryStream ms = new MemoryStream();
                    DataContractJsonSerializer serializerToUplaod = new DataContractJsonSerializer(typeof(Customer));
                    serializerToUplaod.WriteObject(ms, customer);
                    wc.Headers["Content-type"] = "application/json";
                    wc.UploadData(customerServiceUri + "EditCustomer", "PUT", ms.ToArray());
                }
            }
  4. Run the application, edit any customer then save it, updated data will be saved into database and reflected back in WebGrid.

Adding inline Delete operation

To delete a record, user will click on delete image in corresponding row. User will get a confirmation popup. If user confirms to delete, corresponding row data would be deleted. The confirmation popup (on delete button click) is shown in below screen shot.

Delete Operation

we will write the code for delete fuctioanlity:

  1. Open index.js file in Scripts folder and write following code:
    $('.delete-customer').click(function () {
        var selectedId = $(this).parents('tr').find('td:nth-child(1)').text().trim();
        var selectedName = $(this).parents('tr').find('#CustomerName').val();
        var message = "Please confirm delete for Customer ID " + selectedId + ", and Name: " + selectedName + " ? \nClick 'OK' to delete otherwise 'Cancel'.";
        if (confirm(message) == true) {
            selectedId = $(this).parents('tr:first').children('td:first').text();
            $.ajax({
                url: '/Customer/DeleteCustomer',
                data: { id: selectedId },
                type: 'POST',
                success: function () {
                    window.location.reload();
                },
                error: function (xhr) {
                    alert("something seems wrong");
                }
            });
        }
        else
        {
            alert("Delete is Canceled!");
        }
    });
  2. In CustomerController class write following code. This action method will fire for delete operation.
    public void DeleteCustomer(int id)
            {
                using (WebClient wc = new WebClient())
                {
                    MemoryStream ms = new MemoryStream();
                    DataContractJsonSerializer serializerToUplaod = new DataContractJsonSerializer(typeof(Customer));
                    serializerToUplaod.WriteObject(ms, id);
                    wc.Headers["Content-type"] = "application/json";
                    wc.UploadData(customerServiceUri + "DeleteCustomer", "DELETE", ms.ToArray());
                }
            }
  3. Run the application, try to delete any record from webgrid, it should work as expected.

Adding Create operation

To implement this functionality, we will use partial view. While user click on New Customer button, ajax call goes to GetCustomerPV action method of CustomerController and gets the partial view. A form will apprear and user will fill data and click Save button inside that form. Then call will go to CreateCustomer action method of CustomerController to save new customer. We are not using extensive validation here but both fields are mandatory to fill. If you click on save button without filling any data, error meesage will appear as shown in below screen show:

HTML Layout of Views

Let's follow below steps to implement this functionality:

  1. Write following line of code in CustomerController.
    public ActionResult GetCustomerPV()
            {
                return PartialView("CreateCustomerPV");
            }
  2. Create a partial view by right clicking on GetCustomerPV action method and naming it as CreateCustomerPV. Open newly created CreateCustomerPV partial view and write following code:
    @model DemoMVCWebApp.Models.Customer
    @*Below scripts files are used to provide the client side validation*@
    <script src="~/Scripts/jquery.validate.min.js"></script>
    <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
    <div class="createDiv">
        <h4>Please fill below Customer Form:</h4>
        <br />
        @using (Html.BeginForm("CreateCustomer", "Customer"))
        {
            @Html.AntiForgeryToken()
            <div class="form-horizontal">
                @Html.ValidationSummary(true)
                <div class="form-group">
                    @Html.LabelFor(model => model.CustomerName, new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.CustomerName)
                        @Html.ValidationMessageFor(model => model.CustomerName)
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.CustomerAddress, new { @class = "control-label col-md-2" })
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.CustomerAddress)
                        @Html.ValidationMessageFor(model => model.CustomerAddress)
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <input type="submit" value="Save" class="btnCustomerPV" />
                    </div>
                </div>
            </div>
        }
    </div>
  3. Now we need to add a button called New Customer on main page and on click that button partial view will be called. Add following code just below the div tag in Index.cshtm file (Index View). We are adding a "div" tag where the partial view will be added.
    <input type="button" value="New Customer" class="btnCustomerPV" />
    <div id="placeHolderCustomerPV">
    </div>
    Now open index.js file, add following lines of code which will call to GetCustomerPV action method.
    $('.btnCustomerPV').click(function () {
        $('.btnCustomerPV').hide();
        $.ajax({
            // Call CreatePartialView action method
            url: '/Customer/GetCustomerPV',
            type: 'Get',
            success: function (data) {
                $("#placeHolderCustomerPV").empty().append(data);
            },
            error: function () {
                alert("something seems wrong");
            }
        });
    });
  4. In partial view we have written following code, so on submit button of partial view, call will go to CreateCustomer action method of CustomerController.
    @using (Html.BeginForm("CreateCustomer", "Customer"))
    In the controller write following lines of code to add CreateCustomer action method:
    public ActionResult CreateCustomer(Customer customer)
            {
                using (WebClient wc = new WebClient())
                {
                    MemoryStream ms = new MemoryStream();
                    DataContractJsonSerializer serializerToUplaod = new DataContractJsonSerializer(typeof(Customer));
                    serializerToUplaod.WriteObject(ms, customer);
                    wc.Headers["Content-type"] = "application/json";
                    wc.UploadData(customerServiceUri + "AddCustomer", "POST", ms.ToArray());
                }
                int pageToShow;
                int totalCustomers;
                List<Customer> customerList = new List<Customer>();
                using (WebClient webClient = new WebClient())
                {
                    string customerCount;
                    customerCount = webClient.DownloadString(customerServiceUri + "GetCustomersCount");
                    totalCustomers = Convert.ToInt32(customerCount);
                }
                if (totalCustomers % 5 != 0)
                    pageToShow = (totalCustomers / 5) + 1;
                else pageToShow = totalCustomers / 5;
              
                return Redirect(HttpRuntime.AppDomainAppVirtualPath + "?page=" + pageToShow);
            }
    Here after saving new the customer, we are redirecting to appropriate index to show the recently added data.
     
  5. Now run the application and click on New Customer button fill data into form then click on save button. Data will be saved and as we have written the logic for redirection, it will be displayed in the last row in WebGrid control.

Conclusion

Hope you have enjoyed the demo we created in both articles and learned how to create WCF RESTful service and consume it in ASP.NET MVC application using WebGrid control. Your comments and suggestions are most welcome. Thanks.

License

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