MVC CRUD By wizard without writing a single line in 2 minute - Step 4

how to create controller and view by using wizard? how to use bootstrap to design the page in mvc? how to create insert update and delete action method in mvc? how to save record by using entity framework?

CRUD functionality is the basic of learning of any language which we will see in this article and we will see how easy it is with asp.net MVC. We already seen, how we created the listing page without writing a single line of HTML. Same we will do for insert, update and delete by using the wizard. We will not write a single line of code but use the wizard to create controller action methods and views for use.

Delete CategoryController in Controller folder and Category folder in Views because we will create all the insert, update, delete and detail by just clicking some buttons by using wizard without writing a single line of code. I want to show the power and magic of ASP.Net MVC and Entity Framework. Let's create all these features

  • Right click on the controller folder
  • Click Add => Controller
  • See the bellow image
  • select MVC 5 Controller with views, using Entity Framework
  • Click Add
  • It will open a new dialog, see the second image
  • Provide Model Class: Category
  • Provide Data context class: LearningContext
  • Don't check "Use async controller action", you can check it latter on
  • Check "Generate views"
  • Check "Reference script libraries"
  • Check "Use a layout page": navigate to the view to /views/shared/_layout.cshtml, it is the master page
  • Controller name: CategoriesController (automatically entered when you select the model), leave it as it is
  • Click Add

    Choose controller wizard

    Chose model and context type

    Take a deep breath, all the magic is done, time to enjoy it. Run the application and navigate to http://localhost:12345/categories and try to use all the features Create New, Edit, Detail and Delete, we will see every thing is working as it should be.

    Isn't it like a magic, have you written any line of code, no, but result is great. Much talked let's try to understand entire code generated by wizard part by part.

Category listing

Open the CategoriesController file see the very first line inside the class

private LearningContext db = new LearningContext();

Created an object of our LearningContext class to access the data from database.

// GET: Categories
public ActionResult Index()
{
   return View(db.Categories.ToList());
}

First action method Index, is used to show the list of categories which we created manually in our previous article but this time it is created by th wizard. It return a view with parameter list of categories. Right click inside this action and click on Go To View, we will see the html

@model IEnumerable<Advance.Learning.WebApp.Models.Category>
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>@Html.ActionLink("Create New", "Create")</p>
<table class="table">
    <tr>
        <th>@Html.DisplayNameFor(model => model.CategoryName)</th>
        <th>@Html.DisplayNameFor(model => model.IsActive)</th>
        <th></th>
    </tr>
    @foreach (var item in Model) {
    <tr>
        <td>@Html.DisplayFor(modelItem => item.CategoryName)</td>
        <td>@Html.DisplayFor(modelItem => item.IsActive)</td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.CategoryId }) |
            @Html.ActionLink("Details", "Details", new { id=item.CategoryId }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.CategoryId })
        </td>
    </tr>
    }
</table>

One thing we need to note that there is no code for paging and it is true, it don't have any paging option. Html.ActionLink is only the code which is new for us. It renders the anchor tag of html.

   // Code
   @Html.ActionLink("Edit", "Edit", new { id=item.CategoryId })
   // Finale result after rendering will be
   <a href="/categories/Edit/1">Edit</a>

It have 10 overloaded version so we need to check them what is the best fit for us in different situations.

Detail action method

// GET: Categories/Details/5
public ActionResult Details(int? id)
{
  if (id == null){
    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  }
  Category category = db.Categories.Find(id);
  if (category == null){
    return HttpNotFound();
  }
  return View(category);
}

It's simply expecting a parameter, if not pass returns bad request or if record for provided id not found returns not found otherwise returns the view with detail of that category id. Here is the HTML of the Detail page:

@model Advance.Learning.WebApp.Models.Category
@{
    ViewBag.Title = "Details";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Details</h2>
<div>
    <h4>Category</h4>
    <hr />
    <dl class="dl-horizontal">
      <dt>@Html.DisplayNameFor(model => model.CategoryName)</dt>
      <dd>@Html.DisplayFor(model => model.CategoryName)</dd>
      <dt>@Html.DisplayNameFor(model => model.IsActive)</dt>
      <dd>@Html.DisplayFor(model => model.IsActive)</dd>
    </dl>
</div>
<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.CategoryId }) |
    @Html.ActionLink("Back to List", "Index")
</p>

Create method:

  • Get: used to render the blank page
  • Post: used to post and save the data into database
  • ValidateAntiForgeryToken attribute is used to prevent cross-site request forgery attacks.

    MVC's anti-forgery support writes a unique value to an HTTP-only cookie and then the same value is written to the form. When the page is submitted, an error is raised if the cookie value doesn't match the form value.

It's important to note that the feature prevents cross site request forgeries. That is, a form from another site that posts to your site in an attempt to submit hidden content using an authenticated user's credentials. The attack involves tricking the logged in user into submitting a form.

// GET: Categories/Created
public ActionResult Create()
{
    return View();
}

// POST: Categories/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CategoryId,CategoryName,IsActive")] Category category)
{
    if (ModelState.IsValid)
    {
        db.Categories.Add(category);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(category);
}

The [Bind] attribute will let you specify a list of property names for which binding is allowed. Otherwise anyone can post some invalid values say IsDeleted=true and if he would be lucky to guess your model then it will save this value with IsDeleted true.

Is check ModelState.IsValid, if not then add all the errors and return back to the same page otherwise save the data into database and return back to the listing page.

Create page HTML:

@model Advance.Learning.WebApp.Models.Category
@{
    ViewBag.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()    
    <div class="form-horizontal">
        <h4>Category</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.CategoryName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.CategoryName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.CategoryName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.IsActive, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <div class="checkbox">
                    @Html.EditorFor(model => model.IsActive)
                    @Html.ValidationMessageFor(model => model.IsActive, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

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

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
  • First line of the html is @model .... is the model which we need to render the page
  • ViewBag.Title: is the page title to pass to layout page
  • Layout: which layout (master) page this view will use
  • @using (Html.BeginForm()): to render html form tag without any parameter for now
  • @Html.AntiForgeryToken(): which we already discussed
  • @Html.ValidationSummary: to show all the error as a list
  • @Html.LabelFor: to render the label from the model
  • @Html.EditorFor: to render the textbox from model, note how is added the class
  • @section Scripts: to add the script at the bottom of the layout page

Edit an existing record:

It need two action method one HttpGet to get the data by category Id and render the view with complete detail and other HttpPost to save the data back to database, it is very similar to our previous create action, see this

// GET: Categories/Edit/5
public ActionResult Edit(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Category category = db.Categories.Find(id);
    if (category == null)
    {
        return HttpNotFound();
    }
    return View(category);
}

// POST: Categories/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "CategoryId,CategoryName,IsActive")] Category category)
{
    if (ModelState.IsValid)
    {
        db.Entry(category).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(category);
} 

Do see any new code which need to explain, I don't think so. Even if there is any, just egnore it for now because our next page we will create manually and will explain every line of code.

Delete a record:

Delete action method (Delete) is same as our other action methods but if you will note the DeleteConfirmed, it have some extra attributes. Why we need two different name for delete, if you can see closely both Delete and DeleteConfirmed both have only one parameter and a class cannot have two methods with same number and type of parameters, that's why it created a different name for two methods but to post will try to past the data to Detelet so it added [HttpPost, ActionName("Delete")] as attribute.

// GET: Categories/Delete/5
public ActionResult Delete(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Category category = db.Categories.Find(id);
    if (category == null)
    {
        return HttpNotFound();
    }
    return View(category);
}

// POST: Categories/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
    Category category = db.Categories.Find(id);
    db.Categories.Remove(category);
    db.SaveChanges();
    return RedirectToAction("Index");
}

Delete page html:

@model Advance.Learning.WebApp.Models.Category

@{
    ViewBag.Title = "Delete";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Delete</h2>

<h3>Are you sure you want to delete this?</h3>
<div>
    <h4>Category</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.CategoryName)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.CategoryName)
        </dd>

        <dt>
            @Html.DisplayNameFor(model => model.IsActive)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.IsActive)
        </dd>

    </dl>

    @using (Html.BeginForm()) {
        @Html.AntiForgeryToken()

        <div class="form-actions no-color">
            <input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("Back to List", "Index")
        </div>
    }
</div>

That's it for now. We will try the same feature for products listing, create, edit, detail and delete and will create all the page by adding code line by line to understand every part of the code in detail.

Questions and suggestions are always welcome.



Ali Adravi Having 13+ years of experience in Microsoft Technologies (C#, ASP.Net, MVC and SQL Server). Worked with Metaoption LLC, for more than 9 years and still with the same company. Always ready to learn new technologies and tricks.
  • mvc
  • crud
  • bootstrap
By Ali Adravi On 21 Mar, 15  Viewed: 4,573

Other blogs you may like

mvc search page example with code

MVC Searh page with pagination: It’s very easy to create a search page in asp.net but when I try to create the same in MVC I faced many problems, how to create model, how to keep searched values in search controls, pagination, I found myself nowhere, so start searching for some good examples but... By Ali Adravi   On 25 Aug 2013  Viewed: 40,117

MVC insert update delete and select records

CRUD (Create, Retrieve, Update and Delete) in MVC. When we start to learn new language, first we try to run an application with “Hello World” and then CRUD functionality. So in this article we will see how to select records from database (with WebGrid, pagination and sort functionality), update a... By Ali Adravi   On 17 Aug 2013  Viewed: 105,947

How to create a single thanks page for entire controller in MVC

Sometimes we need a thanks page say we have user registration, change password, activate account functionality in our application then we need a thanks page after registering with our site, to say thanks for registering with us or showing confirmation that your password is successfully changed or... By Hamden   On 30 Jun 2013  Viewed: 3,738

MVC jquery autocomplete with value and text field

In MVC, autocomplete with jquery is the best way to pull data from database and render according to our requirements, so in this article we will use jquery to show the auto complete text box without any ajax controls. We need a method to get the data from database, a controller method to handle the... By Ali Adravi   On 29 Jun 2013  Viewed: 6,997

Upload files with model data in MVC

Upload multiple files with model data in MVC is really very easy, when I started to test by uploading some files, I though it would be more complicated but it is really not. In my previous post [ASP.Net MVC file upload][1], I promised to post soon about how to upload multiple files. When I was... By Ali Adravi   On 04 Jun 2013  Viewed: 25,493