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.
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.
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.