How to work with Transactions in ASP.NET MVC ?

Sheonarayan
Posted by in ASP.NET MVC category on for Intermediate level | Points: 250 | Views : 32513 red flag
Rating: 5 out of 5  
 2 vote(s)

In this article, we are going to learn how Transactions work in ASP.NET MVC.
Recommendation
Read Consuming Restful Web API in ASP.NET MVC? before this article.

Introduction

We all know the benefit of Transactions in ASP.NET Web Form. Transaction is used to insert data into more than one database tables. To do this in ASP.NET MVC, we can take help of view models and TransactionScope. In this example, we are going to insert data into PersonalDetails and the Files tables.


Using the code

To explain, how transaction works in ASP.NET MVC, we have a sample ViewModel  below.
using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations.Schema;
 using System.Linq; using System.Web;  

namespace 
MVCTraining5.Models
 {    
 public class PersonaldetailsFilesViewModel 
    {
        [DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOpt ion.Identity)]  
      public int AutoId { get; set; }  
        public string FirstName { get; set; }  
        public string LastName { get; set; }  
        public int Age { get; set; }  
        public bool Active { get; set; }  

        public string FileName { get; set; }   
    }
 } 
Above ViewModel code is pretty simple, it has one primary key that is also marked as Database generated (auto increment). First 5 columns are form PersonalDetail entity and last one is from Files entity.

Controller Action method

Here is the sample code for Controller action method
public ActionResult InsertWithViewModel()   
      {           
  PersonaldetailsFilesViewModel model = new 
PersonaldetailsFilesViewModel();     
        return View(model);     
    } 
The first InsertWithViewModel() method simply returns the  PersonaldetailsFilesViewModel view model instance to the view. 

Now, right click this method and create a  View corresponding to this action method. 


In the above Add View dialog box, we have selected Template as Create, Model class to our View model class. Clicking Add button creates a View. 

NOTE: This How to is the part of my ASP.NET MVC How to Tips & Tricks eBook.


View code

In the view code , we should notice the Html.BeginForm helper method where we are passing our action method, controller name, form action method and the enctype to “multipart/form-data” so that we will be able to upload an image for the FileName field
@model MVCTraining5.Models.PersonaldetailsFilesViewModel  
@{  
   ViewBag.Title = "Insert With View Model";
 }  
<h2>Insert With View Model</h2> 
<p class="label-success">@ViewBag.ResultMessage</p>  
@using (Html.BeginForm("InsertWithViewModel", "PersonalDetail", FormMethod.Post, new { enctype = "multipart/form-data" })) 
{    
 @Html.AntiForgeryToken()     
     <div class="form-horizontal">     
    <h4>PersonaldetailsFilesViewModel</h4> 
        <hr />        
 @Html.ValidationSummary(true, "", new { @class = "text-danger" })    
     <div class="form-group">    
         @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })    
         <div class="col-md-10">    
             @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })     
            @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" }) 
            </div>    
   </div>  
        <div class="form-group">   
          @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })   
          <div class="col-md-10">    
             @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })   
              @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })     
        </div>
         </div>  
        <div class="form-group">    
         @Html.LabelFor(model => model.Age, htmlAttributes: new { @class = "control-label col-md-2" }) 
            <div class="col-md-10"> 
              @Html.EditorFor(model => model.Age, new { htmlAttributes = new { @class = "form-control" } })     
            @Html.ValidationMessageFor(model => model.Age, "", new { @class = "text-danger" })                </div>  
       </div>  
        <div class="form-group"> 
            @Html.LabelFor(model => model.Active, htmlAttributes: new { @class = "control-label col-md-2" })
             <div class="col-md-10"> 
                <div class="checkbox">   
                  @Html.EditorFor(model => model.Active) 
                    @Html.ValidationMessageFor(model => model.Active, "", new { @class = "text-danger" })         
        </div>     
        </div>    
     </div>  
        <div class="form-group">   
          @Html.LabelFor(model => model.FileName, htmlAttributes: new { @class = "control-label col-md-2" }) 
            <div class="col-md-10"> 
                <input type="file" name="FileName"  class="form-control" />                 @Html.ValidationMessageFor(model => model.FileName, "", new { @class = "text-danger" })                         </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> 
}
We have also replaced the typical @Html.EditFor of FileName property to the input type=”file”, so that for FileName field, file upload element appears instead of a normal TextBox in the browser.



Controller Action method-post


Following code is the part of controller action method that gets executed when the Create button is clicked on the view. The "db" object is basically the instance of the ApplicationDbContext that gets created automatically when we add a controller from the Model and choose option to scaffold view.
[HttpPost]  
       [ValidateAntiForgeryToken]      
   public ActionResult InsertWithViewModel(PersonaldetailsFilesViewModel model, HttpPostedFileBase FileName) 
        {  
            if (!ModelState.IsValid)   
          {          
       return View(model); 

 }  
            using (var transaction = db.Database.BeginTransaction()) 
            {              
   try               
  {               
      // try to enter personal details first     
                PersonalDetail pd = new PersonalDetail()    
                 {                     
    Active = model.Active,      
                   Age = model.Age,       
                  FirstName = model.FirstName,  
                       LastName = model.LastName   
                  };     
                db.PersonalDetails.Add(pd);  
                   db.SaveChanges();  
                    // try to enter Files detials now  
                   // upload  the file first       
              string path = Server.MapPath("~/UserData/");      
               //string selectedFileName = System.IO.Path.GetFileName(FileName.FileName);  
                    // get extension name of the selcted file  
                   string extensionName = System.IO.Path.GetExtension(FileName.FileName);                     // generate a random file name and appende extension name    
                   string finalFileName = DateTime.Now.Ticks.ToString() + extensionName;    
                 // now save the selected file with new name  
                   FileName.SaveAs(path + finalFileName);  
                    Files file = new Files()              
       {                  
       Active = true,         
                FileName = finalFileName,   
                      PersonalDetailsId = pd.AutoId         
            };          
           db.Files.Add(file);      
               db.SaveChanges();  
                    // Oh we are here, looks like everything is fine - save all the data permanently                     transaction.Commit();  

                    ViewBag.ResultMessage = "Record inserted into both tables successfully !";    
             }               
  catch (Exception)       
          {             
        // roll back all database operations, if any thing goes wrong      
               transaction.Rollback();          
           ViewBag.ResultMessage = "Error occured, records rolledback."; 
           }        
      }  
            return View();   
      }  
Notice the 2nd InsertWithViewModel method that accepts 1st parameter as the PersonaldetailsFilesViewModel andn 2nd parameter as HttpPostedFileBase (the parameter name for this must match with the name of the html file upload element).       

First, we are checking for the ModelState. If not valid we are returning to the View again with the model (In this case, we do not have validation in the View model attributes so this doesn't make much sense). 

In this case, we have to insert one record each into PersonalDetials and Files database table and if any error occurs while inserting record into anyone of these tables, all changes made if any must be rolled. Let’s take an example – if there is no error while inserting record into PersonalDetail table and an error occurs while inserting record into Files table, even the PersonalDetail table record should be rolled back. To achieve this functionality, we will use transaction. 

We are beginning the transaction by calling db.Database.BeginTransaction() method and under this scope, we are using Try block and trying to insert a record into PersonalDetail, uploading the user selected file on the server and inserting a record into Files table. If all three steps goes well, we are calling transaction.Commit() method and writing success message into ViewBag. If any error occurs, the program moves into catch block in which we are calling the transaction.Rollback() method that undo any activity done on the database and then writing the error message in the ViewBag.


Conclusion


You can see that how easy it is now to work with transaction in ASP.NET MVC. We can take help of view models and transactions in the process.

Thanks for reading, do write your comments or suggestions about this article by responding it. For more ASP.NET Real time problem solutions, click here.


Recommendation
Read Quickly listing records in Grid in ASP.NET MVC after this article.
Page copy protected against web site content infringement by Copyscape

About the Author

Sheonarayan
Full Name: Sheo Narayan
Member Level: HonoraryPlatinum
Member Status: Administrator
Member Since: 7/8/2008 6:32:14 PM
Country: India
Regards, Sheo Narayan http://www.dotnetfunda.com

Ex-Microsoft MVP, Author, Writer, Mentor & architecting applications since year 2001. Connect me on http://www.facebook.com/sheo.narayan | https://twitter.com/sheonarayan | http://www.linkedin.com/in/sheonarayan

Login to vote for this post.

Comments or Responses

Posted by: Jayakumars on: 3/27/2015 | Points: 25
Hi
sheo

In This Article where is db declaration? How to create this, This is EDMX ? this is possibke for vs 2012 version?

db.PersonalDetails.Add(pd);
Posted by: Sheonarayan on: 3/27/2015 | Points: 25
Hi Jaya...

The article was written assuming that the reader would have basic knowledge of ASP.NET MVC.

The db declaration is as simple as creating the instance of the ApplicationDbContext that normally gets written when you create controller and views with scaffolding.
  public class PersonalDetailController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();

// your action method follows that use db object to save or retrieve data
}

This also comes in ASP.NET MVC 4 when you add a controller and select scaffolding template as " .... read/write .... using Entity Framework" and select a model for which controller action method and views to generate.

For more details, I would encourage you to read my previous articles on ASP.NET MVC from the beginning to get enough knowledge about ASP.NET MVC.

Thanks

Login to post response

Comment using Facebook(Author doesn't get notification)