Web Front End to Back End Integration
I started my journey into the world of web development in 2013. Back then, I was working with Perl, Apache, and Unix at an ad serving company, Valueclick. The stack was ancient, due to the fact the company was founded back in the 90’s, when one of the cutting-edge ways to serve a web page was to use the text processing dynamic language Perl (PHP, which was specifically designed for the web, hadn’t gained widespread adoption as it has today).
One of the decisions that was made, before I came to the company, was
whether to have the page rendering done on the server side or client
side. Since this web serving management application only had to work
with account managers in a desktop environment, and there were some
developers experienced with javascript, the decision was made to have
the rendering engine be in the front end and do a single page
application. Frameworks such as Knockout.js, Angular.js, and React.js
were not considered, because they were just coming about and the team
did not have experience with them. Therefore, we simply used jQuery and
vanilla.js to parse metadata about the page when it was served from the
back end in json. This was done to render tables, selections, or
standard form submission. An alternative to this method that was
considered was the Perl library Mason, which allowed for the pages to be
rendered on the backend, but it was not used.
The implementation worked well, as the application gained
responsiveness. After some time on the project, however, I wondered
whether there was a way to make the back end more tightly integrated
with the front end. Every change made, no matter how small, required
changes on both the front end and the back end, which were coded in
vastly different technologies (that is part of the reason node.js has
been so popular recently, to have the same language run on both the
front and back ends). It turns out there was a way to have the front
and back end more integrated, but it was not in the Unix/Open source
world that I was currently in. It was in the proprietary world of
Microsoft in the form of Microsoft web forms. Admittedly, I discovered
web forms rather late, since they had been created by Microsoft in the
early 2000’s, and I looked into them in 2013! They had already been
superceded by ASP.NET MVC, which was more testable and scalable.
Some people may think that by adopting MVC, that the tight integration between the back end and front end that the Web Forms framework provides was lost, and that it is true to some extent. You cannot, for example, bind a front end element to an SQL data table in Microsoft MVC as you can do with MS Webforms using the datagrid construct. However, the front end/back end coupling is not completely lost. Sure, you could use straight HTML in a view in MVC, but there is also the ability to use MVC helper functions to bind elements to ViewModel data structures in your services, and to add data attributes in the back end to have validation on the front end. Let’s start with an example. Here is a view (the comments section of this blog, hopefully posting this isn’t too much of a security risk ):
@model List<CommentSectionForBlog.Models.BlogComment> @if (@ViewBag.CanComment == true) { <div class="row"> <div class="col-xs-12"> <h1>Comments</h1> </div> </div> <div class="row"> @foreach (var comment in Model.ToList()) { <div class="col-xs-12"> <p>@comment.Body</p> <p>-- by @comment.AuthorName on @comment.DateAdded</p> </div> } </div> using (Html.BeginForm("Execute", "Comments", FormMethod.Post, new {id="commentform"})) { @Html.ValidationSummary(true) <input type="hidden" name="BlogEntry.Title" value="@ViewBag.PageName"/> <div class="row"> <div class="col-sm-2" > <label for="Body">Comment:</label> </div> <div class="col-sm-10"> <textarea type="text" style="width: 500px; height: 200px; margin-bottom: 10px;"form="commentform" name="Body"></textarea> </div> </div> <div class="row"> <div class="col-sm-2"> <label for="Name">Name:</label> </div> <div class="col-sm-10" > <input type="text" style="width: 500px; margin-bottom:10px" name="AuthorName"/> </div> </div> <input type="submit" value="Submit"/> } }
As you can see from the code above, standard html tags are used. This
is due to the flexibility of the MVC razor view framework: it is
comfortable with contructs that enable simple,straight html web
development. On the back end, when a post is made, the data is passed
to a function with many arguments. And whenever you add to the input,
you have to add a parameter to the function. This is a place where
additional errors can be introduced.
If you want greater coupling between the front end and the back end, however, Microsoft MVC has HTML helper methods should be used. Here is the refactored code utilizing these MVC helper methods:
Index.cshtml:
@using CommentSectionForBlog.Models @model List<CommentSectionForBlog.Models.BlogComment> @if (@ViewBag.CanComment == true) { <div class="row"> <div class="col-xs-12"> <h1>Comments</h1> </div> </div> <div class="row"> @foreach (var comment in Model.ToList()) { <div class="col-xs-12"> @Html.DisplayTextFor(model => comment.Body) <p>-- by @Html.DisplayTextFor(model => comment.AuthorName) on @Html.DisplayTextFor(model => comment.DateAdded) </p> </div> } </div> @(Html.Partial("_NewComment", new BlogComment())) }
And _NewComment.cshtml::
@using CommentSectionForBlog.Models @model CommentSectionForBlog.Models.BlogComment @using (Html.BeginForm("Execute", "Comments", FormMethod.Post, new { id = "commentform" })) { @Html.ValidationSummary(true) <input type="hidden" name="BlogEntry.Title" value="@ViewBag.PageName"/> <div class="row"> <div class="col-sm-2" > @Html.LabelFor(model => model.Body) </div> <div class="col-sm-10"> @Html.TextAreaFor(model => model.Body, new { @style = "width: 500px; height: 200px; margin-bottom: 10px;" }) </div> </div> <div class="row"> <div class="col-sm-2"> @Html.LabelFor(model => model.AuthorName) </div> <div class="col-sm-10"> @Html.TextBoxFor(model => model.AuthorName, new { @style = "width: 500px; margin-bottom: 10px" }) </div> </div> <input type="submit" value="Submit"/> }
As you can see, the helper methods, @Html.LabelFor & @Html.TextBoxFor, have been added. The page is split page into two sections, the first which includes an .cshtml partial. This improves the clarity and re-usability of sections of the view. And on the back end:
[HttpPost] public ActionResult Execute(BlogComment blogCommentViewModel) { var comentService = new CommentService(); comentService.SaveBlogComment(blogCommentViewModel.Body, blogCommentViewModel.AuthorName, blogCommentViewModel.BlogEntry.Title); return RedirectToAction("Index",new {pageName = blogCommentViewModel.BlogEntry.Title }); }
We utilize the BlogComment view model, which is automatically bound to the .cshtml view using Microsoft MVC helper methods @Html.TextAreaFor and @Html.TextBoxFor.
In our view model, we can also decorate attributes with validation constructs so we have unobstrusive front end validation with back end code. The following is an example:
[Required(ErrorMessageResourceType = typeof(Common), ErrorMessageResourceName = "RequiredField")] [Display(Name = "Author Name", Prompt = "Author Name")] public string AuthorName { get; set; }
The data annotations indicate that the FirstName attribute is required prior to form submission, as well as information to display in the error message (“First Name”) when the field is not given.
So there you have it. An example of how front-end back-end integration is still alive and well in the Microsoft stack using MVC.