Asp.NET MVC3 And LinQ Based Sample Web Application


 Asp.NET MVC3 And LinQ Based Sample Web Application  
 

In this tutorial, my goal is to assist you through an very simple web application development that utilizes asp.net mvc framework(more specifically version 3.0), linq to sql, and razor template engine, so that you can have complete idea of developing a database driven application with these technologies. We will be using Asp.NET MVC 3 and .NET Framework 4 for this sample application.

I have already discussed basics about Asp.NET MVC3 basics already, so I won’t go much far today. If you are very new to asp.net mvc framework and/or need a more basic walk through, go ahead and read about how you can get started with asp.net mvc and razor template engine .
Also, if a complete beginner to LinQ, you should consider reading linq to sql tutorial as well.

To Do Of This Tutorial:

In this tutorial, our goal is to become familiar with the fantastic ready made solution of asp.net mvc for show,insert,edit and delete data. Lets assume, we want to build a poll application. so, we will have to prepare a set of questions and their answers. In this tutorial, we will only see how to show, add, insert and delete questions.

Database Structure:

See the simple dbml structure to get the idea of this table. Although you can put the dbml file anywhere you want, its best to put that in the models directory,
LinQ To SQL DBML Sample

Creating The model:

In the model directory, create a new model named ‘QuestionModel’. This will contains all our model implementation code block. Create and interface named ‘IQuestionService’ , which will be base and define the methods to be implemented.

public interface IQuestionService
        {
            bool ValidateQuestion(Question poll);
            bool CreateQuestion(Question poll);
            List<Question> GetAllQuestions();
            Question GetQuestion(int id);
            bool DeleteQuestion(int id);
            bool SaveQuestion(Question poll);
        }

Now create a new class named ‘QuestionService’ which implement the interface ‘IQuestionService’. Besides, this class should contain the declaration of an object of ‘MyDataContext’ type(according to dbml file). Also, we can implement the first part, which list all existing questions that means the ‘GetAllQuestions’ method. So, the constructor and this method should look like as follows:

 private MPDataContext qDB; 

 public QuestionService()
 {
      qDB = new MPDataContext();
 }
 public List<Question> GetAllQuestions()
 {
      return qDB.Questions.ToList();
 }

Create New Page And Controller:

First create a new mvc application and select razor as the template engine as i described on my previous basic mvc 3 tutorial
Lets create a new page and its controller, that we will be using through out the tutorial. Open ‘Views’=>’Shared’=>’_Layout.chtml’ and add a new menu link Like as follows:

<ul id="menu">
       <li>@Html.ActionLink("Home", "Index", "Home")</li>
       <li>@Html.ActionLink("About", "About", "Home")</li>
       <li>@Html.ActionLink("Questions", "Index", "Question")</li>
</ul>

Notice the structure @Html.ActionLink(“Questions”, “Index”, “Question”) . First parameter is the text of the anchor link, second is the method name that will be called for the associated controller and third one the name of the controller. Save it. And create a new controller named “QuestionController.cs” and check the option for automatically creating action methods for create/update/delete.

Now, Create an instance of our model class here in the constructor and implement the ‘index’ method to send the question lists to view.

    private QuestionModels.IQuestionService qService;

    public QuestionController()
    {
          qService = new QuestionModels.QuestionService();
    }

         //
        // GET: /Question/

        public ActionResult Index()
        {
            List<Question> questions;
            try
            {
                questions = qService.GetAllQuestions();
            }
            catch
            {
                questions = new List<Question>();
            }
            return View(questions);
        }

Creating The View:

Lets create the view for this index method. Instead of creating it manually, we can create it easily just by give some commands(I have already explain how to do it in my previous basic mvc 3 tutorial). Don’t forget to select the ‘Scaffold Template’ as ‘List’ while creating the view.Now please build the application and run it. Navigate to the ‘Questions’ Menu. You should See something like as follows:

New Controller Index Page

As We have no data in database yet, we get this empty list. However, ‘create’ option won’t work also as we haven’t implement the controller method for that yet.

Implement Create Method:

You will see, among the automatically generated methods, there are two methods named ‘Create’, one is with ‘ [HttpPost]’ and parameter another is without attribute and parameter. Without one will be called when we show the create template to user. when user fills up the form and submits, with the ‘[HtttpPost]’ one will be called. withe the corresponding ‘Question’ object as parameter.

//
        // GET: /Question/Create

        public ActionResult Create()
        {
            //Question question = new Question();
            return View();
        } 

        //
        // POST: /Question/Create

        [HttpPost]
        public ActionResult Create(Question question)
        {
            try
            {
                // TODO: Add insert logic here
                qService.CreateQuestion(question);
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

In the model section, now we need to implement the ‘CreateQuestion’ method as follows, of course using Linq :)

public bool CreateQuestion(Question tQestion)
            {
                try
                {
                    qDB.Questions.InsertOnSubmit(tQestion);
                    qDB.SubmitChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }

OK, now lets rebuild and run the the application again. We should be able to create question now which will be saved to database and then we should see this in the main list.

Create New Page

List Page

Create Details Page:

Details page are called with the id or the record as parameter. We can implement the controller in the following way:

//
        // GET: /Question/Details/5

        public ActionResult Details(int id)
        {
            Question question;
            try
            {
                question = qService.GetQuestion(id);
            }
            catch
            {
                question = new Question();
            }
            return View(question);
        }

Also, implement the model’s method for return the record details in linq to sql, which is very simple to implement :) :

public Question GetQuestion(int id)
{
    return qDB.Questions.Single(q => q.Id == id);
}

Besides, we will also have to create the view with scaffold template as ‘Details’. And now we should be done to see the details page:

Details Page

Edit Page:

Similar to create page, there are 2 methods for edit option also, one is with ‘HttpPost’ attributes. Here is the controller code for this option:

//
        // GET: /Question/Edit/5
 
        public ActionResult Edit(int id)
        {

            Question question;
            try
            {
                question = qService.GetQuestion(id);
            }
            catch
            {
                question = new Question();
            }
            return View(question);
        }

        //
        // POST: /Question/Edit/5

        [HttpPost]
        public ActionResult Edit(int id, Question question)
        {
            try
            {
                // TODO: Add update logic here
                question.Id = id;
                qService.SaveQuestion(question);
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

Also, implement the ‘SaveQuestion’ method on the model section which will retrieve the corresponding record, change it and then save it :

public bool SaveQuestion(Question tQestion)
            {
                try
                {
                    Question question = qDB.Questions.Single(q => q.Id == tQestion.Id);
                    question.Details = tQestion.Details;
                    question.Title = tQestion.Title;
                    qDB.SubmitChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }

So, we should be able to edit and save a record from now on:

Edit Record

Implement ‘Delete’ Functionality:

Delete option also include 2 methods. It have a basic scaffold template also, which simply ask for confirmation from the user whether he really want’s to delete or not. Here is the code sample for the controller part of delete action:

//
        // GET: /Question/Delete/5
 
        public ActionResult Delete(int id)
        {
            Question question;
            try
            {
                question = qService.GetQuestion(id);
            }
            catch
            {
                question = new Question();
            }
            return View(question);
        }

        //
        // POST: /Question/Delete/5

        [HttpPost]
        public ActionResult Delete(int id, FormCollection collection)
        {
            try
            {
                // TODO: Add delete logic here
                qService.DeleteQuestion(id);
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

Also, we need to implement the model class’s ‘DeleteQuestion’ method on models section using linq to sql as follows:

public bool DeleteQuestion(int id)
            {
                try
                {
                    Question question = qDB.Questions.Single(q => q.Id == id);
                    qDB.Questions.DeleteOnSubmit(question);
                    qDB.SubmitChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }

So, if we rebuild and run the application again. We should be able to delete now:

Delete Record

Adding Validation On Forms:

Till now, we haven’t added any kind of validation to our application, neither client nor server. Asp.NET MVC 3 comes with a very nice feature of binding a model class to be validated nicely in both client and server end. We don’t have to even write any java-script code for client validation, they will be automatically generated. To add validations to the entity classes in dbml files, open the dbml in design mode, right click and select ‘view code’ option. On the code file, add the following code snippet:

        [MetadataType(typeof(QuestionValidation))]
        public partial class Question
       {        
       }

        [Bind(Exclude="Id")]
        public class QuestionValidation
        {
            [Required(ErrorMessage="Title Required")]
            public string Title { get; set; }
            [Required(ErrorMessage = "Description Required")]
            public string Details { get; set; }
        }

Complete Code Reference:

To make it more easier, I am going to share the both model and controller codes together here. As we didn’t had to touch the view part at all(all were generated automatically except the layout part that i have already given above), I am not going put their code here.

Controller :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyMvcApplication.Models;

namespace MyMvcApplication.Controllers
{
    public class QuestionController : Controller
    {

        private QuestionModels.IQuestionService qService;

        public QuestionController()
        {
            qService = new QuestionModels.QuestionService();
        }

        //
        // GET: /Question/

        public ActionResult Index()
        {
            List<Question> questions;
            try
            {
                questions = qService.GetAllQuestions();
            }
            catch
            {
                questions = new List<Question>();
            }
            return View(questions);
        }

        //
        // GET: /Question/Details/5

        public ActionResult Details(int id)
        {
            Question question;
            try
            {
                question = qService.GetQuestion(id);
            }
            catch
            {
                question = new Question();
            }
            return View(question);
        }

        //
        // GET: /Question/Create

        public ActionResult Create()
        {
            //Question question = new Question();
            return View();
        } 

        //
        // POST: /Question/Create

        [HttpPost]
        public ActionResult Create(Question question)
        {
            try
            {
                // TODO: Add insert logic here
                qService.CreateQuestion(question);
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
        
        //
        // GET: /Question/Edit/5
 
        public ActionResult Edit(int id)
        {

            Question question;
            try
            {
                question = qService.GetQuestion(id);
            }
            catch
            {
                question = new Question();
            }
            return View(question);
        }

        //
        // POST: /Question/Edit/5

        [HttpPost]
        public ActionResult Edit(int id, Question question)
        {
            try
            {
                // TODO: Add update logic here
                question.Id = id;
                qService.SaveQuestion(question);
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        //
        // GET: /Question/Delete/5
 
        public ActionResult Delete(int id)
        {
            Question question;
            try
            {
                question = qService.GetQuestion(id);
            }
            catch
            {
                question = new Question();
            }
            return View(question);
        }

        //
        // POST: /Question/Delete/5

        [HttpPost]
        public ActionResult Delete(int id, FormCollection collection)
        {
            try
            {
                // TODO: Add delete logic here
                qService.DeleteQuestion(id);
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
    }
}

Model :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;

namespace MyMvcApplication.Models
{

    public class QuestionModels
    {

        #region Services
        public interface IQuestionService
        {
            bool ValidateQuestion(Question poll);
            bool CreateQuestion(Question poll);
            List<Question> GetAllQuestions();
            Question GetQuestion(int id);
            bool DeleteQuestion(int id);
            bool SaveQuestion(Question poll);
        }

        public class QuestionService:IQuestionService
        {

            private MPDataContext qDB; 

            public QuestionService()
            {
                qDB = new MPDataContext();
            }

            #region IQuestionService Members

            public bool ValidateQuestion(Question tQuestion)
            {
                if (tQuestion.Title.Length <= 0)
                {
                    return false;
                }
                if (tQuestion.Details.Length <= 0)
                {
                    return false;
                }
                return true;
            }

            public bool CreateQuestion(Question tQestion)
            {
                try
                {
                    qDB.Questions.InsertOnSubmit(tQestion);
                    qDB.SubmitChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }

            public List<Question> GetAllQuestions()
            {
                return qDB.Questions.ToList();
            }

            public Question GetQuestion(int id)
            {
                return qDB.Questions.Single(q => q.Id == id);
            }

            public bool DeleteQuestion(int id)
            {
                try
                {
                    Question question = qDB.Questions.Single(q => q.Id == id);
                    qDB.Questions.DeleteOnSubmit(question);
                    qDB.SubmitChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }

            public bool SaveQuestion(Question tQestion)
            {
                try
                {
                    Question question = qDB.Questions.Single(q => q.Id == tQestion.Id);
                    question.Details = tQestion.Details;
                    question.Title = tQestion.Title;
                    qDB.SubmitChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }

            #endregion
        }

        #endregion

        #region ValidationClasses
        [Bind(Exclude="Id")]
        public class QuestionValidation
        {
            [Required(ErrorMessage="Title Required")]
            public string Title { get; set; }
            [Required(ErrorMessage = "Description Required")]
            public string Details { get; set; }
        }
        #endregion
    }
}

Hope this tutorial on asp.net mvc3 and linq with razor template easier is helpful to you and now easy for you to do as your home practice :D . Let me know if anything isn’t clear enough by commenting below. Happy coding :)

Comments

  1. Bruce says

    How about a boolean field to represent a checkbox in your Model? This must map to an int in the database, since there is no bool datatype in SQL Server?

  2. Dharmik says

    What is need to make method “QuestionService()” in Model…..????
    coz we can directly define like this…
    private MPDataContext qDB=new MPDataContext();

  3. Dharmik says

    I got an error when i write this code…..
    Error is …”Return type must be declared”..

    private MPDataContext qDB;

    public QuestionService()
    {
    qDB = new MPDataContext();
    }
    public List GetAllQuestions()
    {
    return qDB.Questions.ToList();
    }

  4. says

    If i add one more column QuestionType to the given model and there is a seperate table that stores the QuestionType, how can i use a dropdown list, that contains all the QuestionTypes while creating new Question and while Editting existing Question?

    Is there any samples or tutorials that discus this using LINQ_SQL model or can you help me to do the same

  5. Jimmy says

    When put file *.dbml in models directory then drag table database then auto create class Question but when buil project show error class Quesion has exits and not store in IQuestionService!!!!!!!! Please show me source samples list. tks. i begin with asp.net mvc… :)

Leave a Reply