Академический Документы
Профессиональный Документы
Культура Документы
Model View Controller is an architecture or framework for building applications that separate the data (model) from the user interface (view) and the processing (controller). Providing a programming interface between the data and the processing has been a primary concept in information technology for decades. MVC is widely used in Web-based application frameworks, not just ASP.NET.
Views
This is a screenshot of the sidebar in the project showing all the existing Views.
HomeController
View Index, Profile, ContactUs Actions
public ActionResult Index() { return View(); }
This Action is used to directly display whatever is in the View page. Similar code is used to return the Profile and Contact Us pages.
View Events Action The following code is used to retrieve the records in the Events table and sort them in descending order of their start date. The sorted events are passed into the View to display them for the user.
public ActionResult Events() { var context = new ISDataClassesDataContext(); var events = from e in context.Events orderby e.StartDate descending select e; return View(events); }
This is the code written in the HomeController to access a specific Static Page, in other words this is an action to retrieve and display a specific record in the StaticPages table. The HomeController is the primary Controller which will be used to display pages that are accessible to users who are not logged in.
Firstly as in the codes that will be written to do similar functions; a new instace of the DataContext class is created. Working primarily with a single class called the DataContext, LINQ developers can:
y y y
Secondly, using a LINQ query, the required StaticPage record is selected based on its ID number. If the StaticPage record ID matches with the id parameter of this Action, it is chosen to be displayed. Then the View is returned, displaying the selected StaticPage record. Similar code is used to retrieve and display specific records in the Articles and Events tables. The Actions which are used to do so are called Article Details and Event Details respectively.
This is the code used to retrieve records from the Achievements table. Here, the years of achievements are chosen and sorted in descending order. Only distinct years are chosen i.e. even if the table contains multiple instances of the year 2002, the year 2002 will be chosen only once. This selection of years is passed into the View where it will be manipulated as needed. As already stated in the Design stage, the achievements records will first be sorted according to the Year of Achievement. Then those sorted records will be categorized by Competition Types.
So when displaying the achievements page, an additional (optional) parameter called year has to be passed. This year corresponds to the Year of Achievement. According to the next line of code, if this parameter is null, then by default, the first year from the selected years will be passed into the parameter. Then those achievements whose Year of Achievement is identical to the year parameter are selected. After that, the Competition Types are distinctively selected to be used in the View. Then, the selected achievements are finally passed into the View.
<div class="achievements"> <% if (ViewData["Years"] != null) { %> <table style="width: 950px" cellspacing="10px"> <tr> <td class="list" style="width: 110px"> <div> <ul> <% foreach (var y in ViewData["Years"] as IEnumerable<int>) {%> <li> <h3> <%: Html.ActionLink(y.ToString(), "Achievements", new { year = y.ToString() })%></h3> </li> <%} %> </ul> </div> </td> <% if (ViewData["Types"] != null) { %> <td class="list"> <div class="verticalline"> <ul> <% foreach (var t in ViewData["Types"] as IEnumerable<string>) { %> <li> <h3> <%: t%></h3> <ul> <% foreach (var item in Model) {%> <% if (item.CompetitionType.TypeName == t) {%> <li> <p> <%: item.AchievementName%> <%: item.CompetitionName%></p> </li> <%} %> <%} %> </ul> </li>
<%} %> </ul> </div> </td> <%} %> </tr> </table> <%} %> </div>
This is part of the HTML and C# code used in the View of the Achievements page. Here, a table of one row and two columns have been created. The first row contains a list of the years as selected in the Controller. The second row contains the achievements categorized according to their Competition Type.
View Staff and Articles Actions This is the code used in the HomeController to display the Staff page. Here as well there is an additional parameter called cat (short for category). It refers to the Staff Category that the staff member belongs to. If the parameter cat is null it is set to the first or default category name in the table. Then the StaffCategories table is selected to be used and manipulated in the View. After that the parameter cat is cast into a string and stored in the string Category, again to be used in the View. A LINQ query is then used to select the staff member(s) whose Staff Category matches the parameter cat. Similar code is used for the Articles action as well.
public ActionResult Staff(string cat) { var context = new ISDataClassesDataContext(); if (string.IsNullOrEmpty(cat)) cat = context.StaffCategories.FirstOrDefault().CategoryName; ViewData["Categories"] = context.StaffCategories; ViewData["Category"] = cat.ToString(); var staff = from s in context.Staff where s.StaffCategory.CategoryName == cat select s; return View(staff); }
ControlPanel Controller This Controller is be used for the Actions to display pages of the Content Management Interface section. It is used also to manage Actions like creating, deleting or editing records stored in the database. These Actions can be performed only by users who are logged in. The C #codes used for these Actions for all the tables are almost completely the same. The sample codes that Ill be in including here is the code for creating, editing, deleting and displaying Staff records.
This code is used to list and display all the staff records.
Staff Form
public PartialViewResult StaffForm() { return PartialView(); }
This code is used to display the Staff form, which is a Partial View. I used a Partial View for the form to avoid using two separate ones for creating and editing staff members.
<div class="editor-label"> <%: Html.LabelFor(model => model.StaffName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.StaffName) %> <%: Html.ValidationMessageFor(model => model.StaffName) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.PictureFilePath) %> </div> <div class="editor-field">
This is part of the Staff Form which shows code used to generate the text boxes and the file upload control. All the other forms are also similar to this.
ViewModels For the Create and Edit methods, an extra Model which I called the StaffViewModel is used. ViewModels are used to make validation of forms easier. The following is a part of the StaffViewModel.
namespace IrushaadhiyyaSchoolWebsite.ViewModels { public class StaffViewModel { [Required(ErrorMessage = "Please type in the name.")] [DisplayName("Name")] [StringLength(25, ErrorMessage="Name should not be longer than 25 characters")] public string StaffName { get; set; } [Required(ErrorMessage = "Please type in the job title.")] [DisplayName("Job Title")] public string JobTitle { get; set; } [DisplayName("Contact Number")] [StringLength(7)] [RegularExpression(@"\A[0-9]{7}\z", ErrorMessage="The contact number is invalid, it should be in the format nnnnnnn where n is a number.")] public string ContactNo { get; set; } [DisplayName("Email")] [RegularExpression(@"\A[a-zA-Z0-9\.\-_]+@{1}[A-Za-z0-9\.\-_]+(\.[a-zAZ]{2,3}){1,2}\z", ErrorMessage="The email address is invalid.")] public string Email { get; set; } [DisplayName("Picture (Optional)")] public HttpPostedFileBase PictureFilePath { get; set; } [Required(ErrorMessage = "Please select a category.")] [DisplayName("Staff Category")] public int? SelectedStaffCategory { get; set; } public IEnumerable<SelectListItem> StaffCategories { get; set; } } }
This is the StaffViewModel class with properties which are the same as the fields in the Staff table. Various Validation Attributes have been used for each property. Using the DisplayName attribute, I can change the name of the property that appears on the form. For the properties Contact Number and Email Address, custom made Regular Expressions have been used to validate the input. Regexes are used to make sure that the string entered is valid or not. It specifies the characters which can be used and which cannot. There are similar ViewModels for each editable table.
This is the GET method for creating a staff member. Here, the StaffViewModel along with the ISDataClassesDataContext has been used. A new instance of the StaffViewModel is created and passed into the View. The 5th line of code is used to populate the drop-down list in the Staff form.
} newStaff.ContactNo = model.ContactNo; newStaff.Email = model.Email; newStaff.JobTitle = model.JobTitle; newStaff.StaffName = model.StaffName; newStaff.StaffCategoryID = model.SelectedStaffCategory.Value; context.Staff.InsertOnSubmit(newStaff); context.SubmitChanges(); return RedirectToAction("Staff", "ControlPanel"); } model.StaffCategories = from s in context.StaffCategories select new SelectListItem { Text = s.CategoryName, Value = s.StaffCategoryID.ToString() }; return View(model); } catch { return View(); } }
This is the code written for the POST method of creating a new staff record. First of all, a trycatch statement is used to handle exceptions. After creating a new instance of the DataContext, the rest of the code is executed if the Model state is valid (no form errors). A new instance of the StaffModelView is created and then the Http HttpPostedFileBase (files uploaded by the user) PictureFilePath is checked to see if it is empty or null. If it isnt null, then a string called PictureFilePath is created and the file path and root path of where the picture is to be saved to is stored in the string. This file path of the uploaded image is then stored in the Staff Model (newStaff). If the PictureFilePath of the Model is not null, then the above steps do not take place. The data in the StaffViewModel (model) is then stored in the Staff Model (newStaff). Then the data is inserted into the Staff table and a new record is created. If the record has been successfully created, the user is directed to the Staff page in the CMI section which shows a list of the table records. If the Model State is invalid, then a new record isnt created, instead the drop-down list is populated to avoid any errors, and the Model is returned. The StaffViewModel (model) will contain the details that the user had entered before form submission. If there is an exception, it is handled by the try-catch statement and View is returned. Almost the same code is used in creating new records in all other tables using forms, as well.
This is the GET method of the EditStaff action which has a parameter called id, which will be identical to the ID number of the Staff record to be edited. Using a LINQ query, the Staff record which has and ID number that is the same as the id parameter is selected. This record is passed into the StaffViewModel and displayed in the form for the user to see and edit.
staff.JobTitle = model.JobTitle; staff.ContactNo = model.ContactNo; staff.Email = model.Email; staff.StaffCategoryID = model.SelectedStaffCategory.Value; staff.PictureFilePath = PictureFilePath; context.SubmitChanges(); return RedirectToAction("Staff", "ControlPanel"); } model.StaffCategories = from s in context.StaffCategories select new SelectListItem { Text = s.CategoryName, Value = s.StaffCategoryID.ToString() }; return View(model); } catch { return View(); } }
Almost the same thing happens here in the POST method for the EditStaff Action. The difference is that the data in the StaffViewModel (model) is stored in the selected Staff record. If the whole process is successful, the user is directed to the Staff page in the CMI section. If the Model State is invalid, the StaffViewModel (model) is returned, and if there is an internal error in the application, the Edit page is returned to the user.
For the delete Action, code in the Controller is not enough. Ajax will be code will be written directly in the View.
} }
This is the code in the Controller which simply selects the specified record according to its ID number and deletes it.
<%: Ajax.ActionLink("Delete", "DeleteStaff", "ControlPanel", new { id = item.StaffID }, new AjaxOptions { HttpMethod = "DELETE", Confirm = "Are you sure?", OnComplete = "refresh" })%>
This is the Ajax code used to direct the user to the delete action in the Controller after a confirmation message which appears when clicked on the link. The page will then be automatically refreshed showing an updated Staff page.
This is a snippet of code from the Achievements View page of the HomeController. This code checks whether there is any data in the Model, if there isnt any, that is, if the Model Count is 0, the user will be shown a message saying No achievements have been added yet. Else, if there is data in the Model, then the data is displayed as specified in the else statement.
This code snippet is repeated in all the pages except EventDetails and ArticleDetails. (The message shown may be a little different.)
This is a custom made Html Helper which truncates a given string (text) and shortens it to a given number of characters. If the texts length is greater than the integer number, then the text is truncated to that number of characters and returned with an additional string of ... at the end of the text.
Error Routing
protected void Application_Error() { var exception = Server.GetLastError(); var httpException = exception as HttpException; Response.Clear(); Server.ClearError(); var routeData = new RouteData(); routeData.Values["action"] = "Unknown"; routeData.Values["controller"] = "Error"; if (httpException != null) { Response.StatusCode = httpException.GetHttpCode(); switch (Response.StatusCode) { case 404: routeData.Values["action"] = "PageNotFound"; break;
default: routeData.Values["action"] = "Unknown"; break; } } Response.TrySkipIisCustomErrors = true; IController errorController = new ErrorController(); HttpContextWrapper wrapper = new HttpContextWrapper(Context); errorController.Execute(new RequestContext(wrapper, routeData)); }
This code has been used to route the user to an error page if one does occur. Using a switchcase statement, the error page to be displayed is decided. If it is a 404 error (page not found), then the Action to be referred to will be the PageNotFound Action. Otherwise, if any other error occurs, then the Unknown Action will be called. Miscellaneous Default picture for Staff Member records
<% if (!string.IsNullOrWhiteSpace(item.PictureFilePath)) {%> <img src="<%: Url.Content(item.PictureFilePath) %>" width="100px" height="100px" alt="<%: item.StaffName %>" /> <%} else {%> <img src="<%: Url.Content("~/content/siteimages/default.png") %>" width="100px" height="100px" alt="<%: item.StaffName %>" /> <%} %>
Each staff member has a picture, and the user (admin) has the choice to either upload an image or not. If the user has not uploaded any images, then the PictureFilePath will be empty. If it were to be displayed, but kept empty then an error would result. To solve this, using an if statement, the picture stored in the PictureFilePath would be displayed only if it wasnt empty. Otherwise, if it indeed was empty, then a default picture called default.jpg which is stored in the SiteImages folder will be set for that staff member.
This is a code snippet from the Master Page which first checks if the user is logged in or not. In other words, it checks whether the request to display the fifth menu block is authenticated or not. If the request is indeed authenticated, then the fifth menu block containing the Content Management Interface options is displayed. Otherwise, it is not.