Evolution of the User Interface

At this time I have demonstrated three iterations of the Artist web page in The World of Art Web App. The first iteration, simply called the Artist page, was designed with the ASP.Net Web Form model. In this example, I developed the user interface with three ASP.Net server side controls;

The ASP.Net Web Form model depends on the ASP.Net Engine, in the web server, to generate the actual HTML rendered by the client. The input to the ASP.Net engine is the XHTML elements and attributes defined in the .aspx web form file. This model supports a very rapid development process. However, it is a poor architectural design for a distributed web app, because the user interface and database access are tightly coupled. This tight coupling of architectural elements, makes long term maintenance and further development of the app more complicated, because the impact of change has a broad affect across the application. Here is the XHTML source code of the first iteration of the Artist page;

<%@ Page Title="World of Art Artist Web Form" Language="C#" MasterPageFile="~/Views/SiteMaster.Master" AutoEventWireup="true" CodeBehind="ArtistWebForm.aspx.cs" Inherits="WorldOfArtWebApp.Views.ArtistWebForm" %>
 
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
 
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <asp:HyperLink ID="HyperLinkBlog" runat="server"  CssClass="devbloglink"
      NavigateUrl="http://lexicon-software.com/the-artist-web-form/" Target="_blank">Developer&#39;s Blog</asp:HyperLink>
 
    <div  id="detailsArtist" class="artistdetaildiv">
    <asp:DetailsView ID="DetailsViewArtist" runat="server" Height="50px"  CssClass="artistview"
          Width="347px" AutoGenerateRows="False" DataSourceID="SqlDataSourceArtist" 
          AlternatingRowStyle-CssClass="altrowstyle" PagerStyle-CssClass="footerstyle" 
          CellPadding="4" RowStyle-CssClass="rowstyleartistviews"
         PagerStyle-ForeColor="#f9f9f9" AllowPaging="True">
          <AlternatingRowStyle CssClass="altrowstyle"></AlternatingRowStyle>
        <Fields>
            <asp:BoundField DataField="FirstName" HeaderText="First Name" SortExpression="Name" />
            <asp:BoundField DataField="LastName" HeaderText="Last Name" SortExpression="Name" />
 
           <asp:BoundField DataField="BirthDay" HeaderText="Birthday" 
                SortExpression="BirthDay" DataFormatString="{0:d}" />
            <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
            <asp:BoundField DataField="Country" HeaderText="Country" 
                SortExpression="Country" />
            <asp:BoundField DataField="TypeOfArtist" HeaderText="Type Of Artist" 
                SortExpression="TypeOfArtist" />
        </Fields>
         <PagerStyle CssClass="footerstyle" ForeColor="#F9F9F9"></PagerStyle>
         <RowStyle CssClass="rowstyleartistviews"></RowStyle>
    </asp:DetailsView>
   </div>
 
   <div id="gridArtist" class="artistgriddiv">
    <asp:GridView ID="GridViewArtist" runat="server" AllowPaging="True"  
           CssClass="artistview" AlternatingRowStyle-CssClass="altrowstyle" CellPadding="4"
           RowStyle-CssClass="rowstyleartistviews" HeaderStyle-CssClass="headerstyle" 
           HeaderStyle-ForeColor="#f9f9f9"  AllowSorting="True" 
           DataSourceID="SqlDataSourceArtist" AutoGenerateColumns="False">
        <AlternatingRowStyle CssClass="altrowstyle"></AlternatingRowStyle>
 
        <Columns>
            <asp:BoundField DataField="FirstName" HeaderText="First Name" 
                SortExpression="FirstName" />
            <asp:BoundField DataField="LastName" HeaderText="Last Name" 
                SortExpression="LastName" />
            <asp:BoundField DataField="BirthDay" DataFormatString="{0:d}" 
                HeaderText="Date of Birth" SortExpression="BirthDay" />
            <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
            <asp:BoundField DataField="Country" HeaderText="Country" 
                SortExpression="Country" />
        </Columns>
 
        <HeaderStyle CssClass="headerstyle" ForeColor="AntiqueWhite"></HeaderStyle>
 
        <RowStyle CssClass="rowstyleartistviews"></RowStyle>
    </asp:GridView>
 </div>
 
<asp:SqlDataSource ID="SqlDataSourceArtist" runat="server" 
    ConnectionString="<%$ ConnectionStrings:DB_38836_aspnetdbConnectionString %>" 
    SelectCommand="SELECT FirstName, LastName, BirthDay, City, Country, TypeOfArtist FROM aspnet_Artist">
</asp:SqlDataSource>
 
</asp:Content>

In the second iteration of the Artist page, which I called Art Entities, I eliminated the SqlDataSource web server control, and created a separation of concerns between the user interface and data access. This is where I introduced the concept of a layered architectural design, with the development of the Data Access Layer, and the Data Model Layer. In the Data Model Layer, I developed an Entity Relationship Model with the ADO.Net Entity Framework, which created a line of clear separation, and decoupling, between data access functions and the SQL Server database.

In this phase of development, the user interface evolved into an external layer of the overall web app design. However, the user interface is still based on server side ASP.Net web server controls. I simply exploited the data binding methods, built into these controls, to create an API to the data access layer. Here is the XHTML and C# source code used to render the Art Entities page of the World of Art Web App;

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/SiteMaster.Master" AutoEventWireup="true" CodeBehind="ArtistEntityWebForm.aspx.cs" Inherits="WorldOfArtWebApp.Views.ArtistEntityWebForm" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<div id="gridArtist" class="artistgriddiv">
    <asp:GridView ID="GridViewArtist" runat="server" AllowPaging="True"  
           CssClass="artistview" AlternatingRowStyle-CssClass="altrowstyle" CellPadding="4"
         RowStyle-CssClass="rowstyleartistviews" HeaderStyle-CssClass="headerstyle" 
           HeaderStyle-ForeColor="#f9f9f9"  AllowSorting="True" AutoGenerateColumns="False">
        <AlternatingRowStyle CssClass="altrowstyle"></AlternatingRowStyle>
 
        <Columns>
            <asp:BoundField DataField="Name" HeaderText="Artist Name" />
            <asp:BoundField DataField="DateOfBirth" DataFormatString="{0:d}" HeaderText="Date of Birth" />
            <asp:BoundField DataField="PlaceOfBirth" HeaderText="Place Of Birth" />
 
        </Columns>
 
      <HeaderStyle CssClass="headerstyle" ForeColor="AntiqueWhite"></HeaderStyle>
      <RowStyle CssClass="rowstyleartistviews"></RowStyle>
    </asp:GridView>
</div>
<div id="gridWorkOfArt" class="artistgriddiv">
   <asp:GridView ID="GridViewWorkOfArt" runat="server" AllowPaging="true"
    CssClass="artistview" AlternatingRowStyle-CssClass="altrowstyle" CellPadding="4"
         RowStyle-CssClass="rowstyleartistviews" HeaderStyle-CssClass="headerstyle" 
           HeaderStyle-ForeColor="#f9f9f9"  AllowSorting="True" AutoGenerateColumns="False">
        <AlternatingRowStyle CssClass="altrowstyle"></AlternatingRowStyle>
 
        <Columns>
           <asp:BoundField DataField="Title" HeaderText="Title" />
           <asp:BoundField DataField="ArtistName" HeaderText="Artist" />
 
        </Columns>
 
        <HeaderStyle CssClass="headerstyle" ForeColor="AntiqueWhite"></HeaderStyle>
        <RowStyle CssClass="rowstyleartistviews"></RowStyle>
   </asp:GridView>
</div>
 
 
   <div>
   <asp:Label runat="server" ID="labelException"></asp:Label>
   </div>
</asp:Content>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using ArtWorldObjects;
using WorldOfArtWebApp.DataAccess;
 
 
namespace WorldOfArtWebApp.Views
{
    public partial class ArtistEntityWebForm : System.Web.UI.Page
    {
        protected ArtWorldCollectionArtist artistData;
        protected ArtWorldCollectionArtPiece workOfArtData;
        protected TitleArtist titleArtist;
        protected List<TitleArtist> titleArtistList;
 
        protected void Page_Load(object sender, EventArgs e)
        {
            LoadArtistView();
            LoadWorkOfArtView();
        }
 
        protected void LoadArtistView()
        {
            try
            {
                artistData = new ArtWorldCollectionArtist();
 
                if (artistData.ArtWorldCollection.Count > 0 && artistData.ExceptionMessage == string.Empty)
                {
                    this.GridViewArtist.DataSource = artistData.GetListOfArtist();
                    this.GridViewArtist.DataBind();
                }
                else
                {
                    this.labelException.Text = "The artist information you requested is not available. " + artistData.ExceptionMessage;
                }
            }
            catch (Exception ex)
            {
                this.labelException.Text = "The artist information you requested is not available. " + ex.Message;
            }
        }
 
        protected void LoadWorkOfArtView()
        {
            try
            {
                workOfArtData = new ArtWorldCollectionArtPiece();
 
                if (workOfArtData.ArtWorldCollection.Count > 0 && workOfArtData.ExceptionMessage == string.Empty)
                {
                    titleArtistList = new List<TitleArtist>();
                    foreach (var workOfArtInList in workOfArtData.GetListOfArtPiece())
                    {
                        titleArtist = new TitleArtist(workOfArtInList.TheArtist, workOfArtInList);
                        titleArtistList.Add(titleArtist);
                    }
                    this.GridViewWorkOfArt.DataSource = titleArtistList;
                    this.GridViewWorkOfArt.DataBind();
                }
                else
                {
                    this.labelException.Text = "The art information you requested is not available. " + workOfArtData.ExceptionMessage;
                }
            }
            catch (Exception ex)
            {
                this.labelException.Text = "The art information you requested is not available. " + ex.Message;
            }
        }
    }
 
 
    /// <summary>
    /// Helper class for binding data to the Work of art gridview 
    /// </summary>
    public class TitleArtist
    {
        protected string m_artistName;
        protected string m_title;
 
        public TitleArtist()
        {
        }
 
        public TitleArtist(Artist artist, ArtPiece workOfArt)
        {
            m_artistName = artist.Name;
            m_title = workOfArt.Title;
        }
 
        public string ArtistName
        {
            get { return m_artistName; }
        }
 
        public string Title
        {
            get { return m_title; }
        }
    }
}

The ASP.Net Web server controls, used in the first two iterations of the user interface, is a suitable design solution for an enterprise level application, which is running internally to the enterprise. The number of users is limited to the employee and associates base, the application is supported by the internal IT infrastructure of the enterprise as an intranet appliation. The view state and post back model, supported by these web server controls, performs very well in this environment. However, if the application is to be distributed over a wide range of clients, and accessible from the world wide web, a much leaner and flexible architectural model is required. This is a requirement for the World of Art Web App. Therefore, in this latest iteration of the app, I added a web service layer to the architecture, based on the Microsoft Windows Communication Foundation (WCF). Accessing the service layer of the World of Art Web app, was a driving factor behind the design of the third iteration of the user interface.

Accessing the service layer, reverses the flow of content between the client and the server. In the previous versions, where server side controls were used, content was pushed from the server to the client. However, acquiring content from the service layer, requires the client to pull content from the server through an HTTP request.

The third iteration of the artists page, which I called Art Entities from Service, is a very minimal and efficient design, utilizing an HTTP GET Request to retrieve artist data from the web service, and JavaScript to render the artist result set in HTML. I also employed a CSS 3 cascading style sheet to complete the look and feel of the page.

Here is the XHTML source code of the ASP.net web form and the JavaScript source code used in the third iteration of the user interface;

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/SiteMaster.Master" AutoEventWireup="true" CodeBehind="ArtistEntityAjax.aspx.cs" Inherits="WorldOfArtWebApp.Views.ArtistEntityAjax" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<link href="Styles/Art.css" rel="Stylesheet" type="text/css" />
<h2>
    List of Artists From World of Art Web Service
</h2>
<p>
 
</p>
<div id="arts">
</div>
<script type="text/javascript" src="../Scripts/GetArtists.js"></script>
 
</asp:Content>
/*
* get the artist content of a JSON file using Ajax 
*
*/
 
$(document).ready(function () {
    getArtistsAjax();
 
});
 
function getArtistsAjax() {
    jQuery.ajax({
        type: 'GET',
        url: 'http://lexicon-software-apps.com/ArtService.svc/GetArtists',
        dataType: "jsonp",
        success: function (result) {
            updateArtists(result);
        },
        error: function (result) {
            requestFailed(result);
        }
    });
}
 
function updateArtists(artists) {
    if (artists.length == 0 || artists == null) {
        requestFailed(artists);
    }
    else {
        var artistDiv = document.getElementById("arts");
        for (var i = 0; i < artists.length; i++) {
            var artist = artists[i];
            var div = document.createElement("div");
            div.setAttribute("class", "artItem");
            div.innerHTML = artist.Name + " was born in " + artist.PlaceOfBirth + " on " + artist.DateOfBirthLongString;
            artistDiv.appendChild(div);
        }
    }
}
 
function requestFailed(results) {
    alert("The artist information you requested is not available");
}

Here is the cascading style sheet. You will notice some of the new CSS 3 attributes like “border-radius”, which is used to form the rounded corners of the artist grid in the Entities From Service page.

/* artists.css */
 
body {
	margin-left: 40px;
	margin-right: 40px;
}
div#arts {
	background-color: #d9d9d9;
	-webkit-border-radius: 6px;
	border-radius: 6px;
	margin: 10px 0px 0px 0px;
	padding: 0px;
	border: 1px solid #d9d9d9;
}
div.artItem {
	font-family: Verdana, Helvetica, sans-serif;
	color: #434343;
	padding: 10px;
}
div.artItem:nth-child(2n)
{
    background-color: #fafafa;
}
div.artItem:first-child {
	-webkit-border-top-left-radius: 6px;
	-webkit-border-top-right-radius: 6px;
	border-top-left-radius: 6px;
	border-top-right-radius: 6px;
}
div.artItem:last-child {
	-webkit-border-bottom-left-radius: 6px;
	-webkit-border-bottom-right-radius: 6px;
	border-bottom-left-radius: 6px;
	border-bottom-right-radius: 6px;
}

The AJAX Client and Cross-Domain GET Requests

In developing the client to consume the World of Art Web Service, I decided to stick with the ASP.Net Web Form (.aspx). This allowed me to take advantage of the master page concept already implemented in the World of Art Web App. Following is the markup source code of the .ASPX page. As you can see it has some very basic ingredients;

  • Page declaration with a reference to the web site master page
  • HTML Heading Tag
  • A script tag pointing to a JavaScript source code file called GetArtists.js

Here is the XHTML mark up code of the .aspx web form;

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/SiteMaster.Master" AutoEventWireup="true" CodeBehind="ArtistEntityAjax.aspx.cs" Inherits="WorldOfArtWebApp.Views.ArtistEntityAjax" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<link href="Styles/Art.css" rel="Stylesheet" type="text/css" />
<h2>
    List of Artists From World of Art Web Service
</h2>
<p>
 
</p>
<div id="arts">
</div>
<script type="text/javascript" src="../Scripts/GetArtists.js"></script>
 
</asp:Content>

The heart of the client application is the JavaScript in the GetArtists.js file. There are two primary functions;

  • getArtistsAjax() – Requests artist data from the World Of Art Web Service
  • updateArtists() – Dynamically generates the user interface

Here is the JavaScript source code of the client.

/*
* get the artist content of a JSON file using Ajax 
*
*/
 
 
$(document).ready(function () {
    getArtistsAjax();
 
});
 
 
function getArtistsAjax() {
    jQuery.ajax({
        type: 'GET',
        url: 'http://lexicon-software-apps.com/ArtService.svc/GetArtists',
        dataType: "jsonp",
        success: function (result) {
            updateArtists(result);
        },
        error: function (result) {
            requestFailed(result);
        }
    });
}
 
 
function updateArtists(artists) {
    if (artists.length == 0 || artists == null) {
        requestFailed(artists);
    }
    else {
        var artistDiv = document.getElementById("arts");
        for (var i = 0; i < artists.length; i++) {
            var artist = artists[i];
            var div = document.createElement("div");
            div.setAttribute("class", "artItem");
            div.innerHTML = artist.Name + " was born in " + artist.PlaceOfBirth + " on " + artist.DateOfBirthLongString;
            artistDiv.appendChild(div);
        }
    }
}
 
function requestFailed(results) {
    alert("The artist information you requested is not available");
}

Lets first examine the getArtistsAjax() function. There are many different ways to perform an HTTP GET request. After trying a number of different combinations, I found this implementation to be a straightforward and flexible solution. The getArtistsAjax() function uses the JQuery.ajax() method, to perform the asynchronous HTTP(Ajax) request for artist data from the ArtService. The jQuery.ajax() method can be configured with a multitude of settings and parameters. However, for the simple HTTP GET request required by this application, I found it necessary to only pass five arguments to the jQuery.ajax() method, which are coded as key/value pairs;

  • type: “GET” – The type of request to make (“POST” or “GET”)
  • url: ‘http://lexicon-software-apps.com/ArtService.svc/GetArtists’ – A string containing the URL to which the request is sent.
  • dataType: “jsonp” – Loads in a JSON block using JSONP. Adds an extra “?callback=?” to the end of your URL to specify the callback. Disables caching by appending a query string parameter, “_=[TIMESTAMP]“, to the URL unless the cache option is set to true.
  • success: function() – A function to be called if the request succeeds.
  • error: function() – A function to be called if the request fails.

The most interesting setting is the dataType set to “jsonP”. This gives the client flexibility to perform a “GET” request from a domain other than the one that served the original page request. The following illustrates an example of this. I setup an alternate domain at Winhost called Lexicon-Software-Learning.com. I published the World of Art Web Service at Lexicon-Software-Learning.com. I then changed the url setting to point to the learning domain. Here is the result;

Cross Domain Get Request

The artists entity web page is served from Lexicon-Software-Apps.com domain and the get artists data request is served from Lexicon-Software-Learning.com.

The other primary JavaScript function in GetArtists.js is the updateArtists() function. It receives the JSON formatted data result set from the HTTP GET request. The JSON data is basically an array of artist objects. This function simply iterates through the array of artist objects, and adds them as elements to the web pages’ Document Object Model (DOM) object. I also applied some new CSS 3 style sheet elements, to finish off the look and feel, of the list of artists page.

I will cover the user interface in more detail in my next post. We will also look at the evolution of the user interface in the World of Art Web App, from the first iteration which was server side generated, to this latest iteration which is client side generated.

Here is the CSS 3 Cascading Style Sheet

/* artists.css */
 
body {
	margin-left: 40px;
	margin-right: 40px;
}
div#arts {
	background-color: #d9d9d9;
	-webkit-border-radius: 6px;
	border-radius: 6px;
	margin: 10px 0px 0px 0px;
	padding: 0px;
	border: 1px solid #d9d9d9;
}
div.artItem {
	font-family: Verdana, Helvetica, sans-serif;
	color: #434343;
	padding: 10px;
}
div.artItem:nth-child(2n)
{
    background-color: #fafafa;
}
div.artItem:first-child {
	-webkit-border-top-left-radius: 6px;
	-webkit-border-top-right-radius: 6px;
	border-top-left-radius: 6px;
	border-top-right-radius: 6px;
}
div.artItem:last-child {
	-webkit-border-bottom-left-radius: 6px;
	-webkit-border-bottom-right-radius: 6px;
	border-bottom-left-radius: 6px;
	border-bottom-right-radius: 6px;
}

Implementation of the Web Service Interface

In my last post, we discussed the interface of the WCF application and how it forms a mutually binding contract, between the client and the service. The client must make their request in a format the service is expecting, and the service must fulfill the request in the format specified in the contract. This is all defined in the operation contract of the IArtService interface.

  • The request must be an XMLHttpRequest using the “GET” verb
  • The “GET” request must specifically request access to the ArtService.svc and the GetArtists method
  • The service must respond to the request with data serialized into the Json format

Here is a simple JavaScript function which would satisfy the contractual requirements for a request;

function getArtistsAjax() {
    $.ajax({
        type: 'GET',
        url: 'http://lexicon-software-apps.com/ArtService.svc/GetArtists?callback=updateArtists',
        dataType: "jsonp",
        success: function (result) {
            updateArtists(result);
        }
    });
}

Once again, here is the IArtService interface where the mutually binding contract between the service and clients is defined;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using ArtWorldObjects;
 
namespace WorldOfArtServiceApp
{
    [ServiceContract]
    public interface IArtService
    {
 
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        List<Artist> GetArtists();
    }
  }

As you can see, the interface also uses the System.Runtime.Serialization and System.ServiceModel.web name spaces to fulfill the request.

Now, lets examine the implementation of the IArtService interface. Here is the source code of the ArtService class which implements the IArtService interface;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Activation;
using System.Text;
using System.Net;
using ArtWorldObjects;
using WorldOfArtWebApp.DataAccess;
 
namespace WorldOfArtServiceApp
{
    public class ArtService : IArtService
    {
        protected ArtWorldCollectionArtist artistData;
 
        public List<Artist> GetArtists()
        {
            try
            {
                artistData = new ArtWorldCollectionArtist();
 
                if (artistData.ArtWorldCollection.Count > 0 && artistData.ExceptionMessage == string.Empty)
                {
                    return artistData.ArtWorldCollection;
                }
                else
                {
                    throw new WebFaultException(HttpStatusCode.BadRequest);
                }
            }
            catch 
            {
                throw new WebFaultException(HttpStatusCode.BadRequest);
 
            }
 
        }
    }
}

As I stated in an earlier post, the purpose of the Art Service Class is not to expose the business logic of the World of Art web app. Instead, the purpose of the Art Service, is to simply expose specific data elements from the World of Art domain, which can be served upon request, to various software clients. In order to retrieve data from the world of art domain, the ArtService class references two name spaces from the WorldOfArtWebApp;

  • ArtWorldObjects
  • WorldOfArtWebApp.DataAccess

With these references, the GetArtist() method can reuse components of the WorldOfArtWebApp from the Data Access Layer and the Data Model defined in the Entity Framework.

The GetArtist() method is bound by the Operation Contract, defined in the IArtService interface, to return a list of artist objects. This requirement is satisfied by simply creating a new instance of the ArtWorldCollectionArtist Class, and accessing the collection of artist objects in the ArtWorldCollection property. The collection of artist objects is retrieved from the WorldOfArtContext, generated from the Entity Framework. The WCF web service will serialize each of this artist objects into JSON format as specified in the operation contract.

In my next post, I will discuss how to specify which properties of the Artist object are exposed to the web service. Also, here is the source code for the ArtWorldCollectionArtist class, invoked by the GetArtist() method.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Objects;
using ArtWorldObjects;
using WorldOfArtWebApp.DataModels;
 
namespace WorldOfArtWebApp.DataAccess
{
    public class ArtWorldCollectionArtist : IArtWorldCollection<Artist>
    {
        protected WorldOfArtContext m_WorldOfArtEntities;
        protected List<Artist> m_artistList;
        protected string m_exceptionMessage;
        protected Artist m_artist;
 
        public ArtWorldCollectionArtist()
        {
            m_exceptionMessage = string.Empty;
            m_WorldOfArtEntities = new WorldOfArtContext();
            m_artistList = new List<Artist>();
            GetArtCollectionData();
        }
 
        public ObjectContext WorksOfArtContext
        {
            get { return m_WorldOfArtEntities; }
        }
 
        public List<Artist> ArtWorldCollection
        {
            get { return m_artistList; }
        }
 
        public string ExceptionMessage
        {
            get { return m_exceptionMessage; }
        }
 
        public void GetArtCollectionData()
        {
            try
            {
                using (m_WorldOfArtEntities)
                {
                    var artistQuery = from artists in m_WorldOfArtEntities.aspnet_Artist
                                      select artists;
                    foreach (var artist in artistQuery)
                    {
                        m_artist = new Artist();
                        m_artist.Name = artist.FirstName + " " + artist.LastName;
                        m_artist.PlaceOfBirth = artist.City + " " + artist.Country;
                        m_artist.DateOfBirth = (DateTime)artist.BirthDay;
 
                        m_artistList.Add(m_artist);
                    }
                }
            }
            catch (Exception ex)
            {
                m_exceptionMessage = ex.Message;
            }
        }
 
        public Artist[] GetListOfArtist()
        {
            Artist[] artistList = ArtWorldCollection.ToArray();
            return artistList;
        }
    }
}

Web Service Operational Parameters

Today I will continue the discussion of the service contract, as defined by the interface generated from the WCF application template. Once again, here is the source code of the interface;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using ArtWorldObjects;
 
namespace WorldOfArtServiceApp
{
    [ServiceContract]
    public interface IArtService
    {
 
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        List<Artist> GetArtists();
 
    }
 
}

The operational parameters of the service contract are defined as a method. In this application, the method is called GetArtists() and it returns a list of artist objects from the world of art domain, as defined in the ArtWorldObjects name space. Therefore, a reference to the ArtWorldObjects class library is necessary, as indicated by the using statement.

The GetArtists() method is enhanced with the Operation Contract Attribute, which indicates that a method defines an operation that is part of a service contract in a application. The operation contract attribute is also defined in the System.ServiceModel name space.

The GetArtists() method is also enhanced with the WebGetAttribute Class, which indicates that a service operation is logically a retrieval operation and that it can be called by the REST programming model. The WebGetAttribute Calss is defined in the System.ServiceModel.Web name space. The constructor method of the WebGetAttribute class will accept a variety of arguments, as named parameters, which populate the properties of the class and configure the operational contract between the service and client software. This first iteration of the web service is very simple and retrieves a very small data set, so I’m only passing the Response Format argument for now.

The Response Format parameter will set the ResponseFormat property of the WebGetAttribute class. This property determines the format of responses sent from a service operation. The two possible values are Xml and Json.

As you can see, the World of Art Service will return a response in the Json format. JSON stands for JavaScript Object Notation. JSON is syntax for storing and exchanging text information. The web service is now contractually obligated, to respond to requests with text. More specifically, text that is formatted in a way that JavaScript, running on the client, can parse and evaluate as objects. In this application the objects are abstract representations of artists. The clients will receive an array of artist objects. Click on this link, Get Artists to send a request to the World of Art Service, and see the JSON text returned by the service. This link, Artist will take you to the actual website that consumes this JSON data.

In my next post, I will discuss the implementation of the IArtService interface.

Web Service based on WCF and REST

Then next phase in the evolution of the World of Art Web App is the development of a web service, based on the Windows Communication Foundation (WCF), and the Representational State Transfer (REST) architectural model. SO lets get started.

Visual Studio 2010 and the .Net Framework 4.0 make development of web services a very straight forward process. As you would expect, Visual Studio has a WCF Service Application template already installed.

Visual Studio provides a WCF application template already installed

Visual Studio provides a WCF application template already installed

I decided to make the World of Art web service a separate project from the World of Art web app. The primary reason for doing this, is that later in the project, I want to demonstrate cross-domain access to web services, and keeping the service in a separate project will make deployment to multiple domains easier. Here is the solution explorer displaying all of components generated from the WCF application template.

WCF Project in Visual Studio 2010

WCF Project in Visual Studio 2010

The WCF application template generates three very important files for defining and developing the functionality of the web service;

  • Interface defining the contract and operations of the service
  • Web Configuration file
  • Service file

Here is the source code in these three files;

The service file, which I named ArtService.svc

<%@ ServiceHost Language="C#" Debug="true" Service="WorldOfArtServiceApp.ArtService" CodeBehind="ArtService.svc.cs" %>

The web configuration file

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="ApplicationServices" connectionString="Data Source=tcp:s07.winhost.com;Initial Catalog=DB_38836_aspnetdb;User ID=DB_38836_aspnetdb_user;Password=********;Integrated Security=False;" providerName="System.Data.SqlClient" />
    <add name="ConnectionStringArtWorld" connectionString="Data Source=tcp:s07.winhost.com;Initial Catalog=DB_38836_aspnetdb;User ID=DB_38836_aspnetdb_user;Password=********;Integrated Security=False;" providerName="System.Data.SqlClient" />
    <add name="DB_38836_aspnetdbConnectionString" connectionString="Data Source=s07.winhost.com;Initial Catalog=DB_38836_aspnetdb;Persist Security Info=True;User ID=DB_38836_aspnetdb_user;Password=********" providerName="System.Data.SqlClient" />
    <add name="WorldOfArtContext" connectionString="metadata=res://*/DataModels.WorldOfArt.csdl|res://*/DataModels.WorldOfArt.ssdl|res://*/DataModels.WorldOfArt.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=s07.winhost.com;initial catalog=DB_38836_aspnetdb;persist security info=True;user id=DB_38836_aspnetdb_user;password=********;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpRuntime maxRequestLength="524288" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="webHttpBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <webHttpBinding>
        <binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true" />
      </webHttpBinding>
    </bindings>
    <services>
      <service name="WorldOfArtServiceApp.ArtService">
        <endpoint address="" binding="webHttpBinding"
                  bindingConfiguration="webHttpBindingWithJsonP"
                  contract="WorldOfArtServiceApp.IArtService"
                  behaviorConfiguration="webHttpBehavior"/>
      </service>
    </services>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

The Interface

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using ArtWorldObjects;
 
namespace WorldOfArtServiceApp
{
    [ServiceContract]
    public interface IArtService
    {
 
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        List<Artist> GetArtists();
 
    }
 
}

The interface, which I named IArtService, defines both the service contract and the operational parameters of the service contract. The implementation of the interface, will facilitate the fulfillment of contractual requirements, between the client and the web service. The interface is enhanced with the service contract attribute, which indicates that an interface or a class defines a service contract in a application. This attribute is defined in the System.ServiceModel name space of the .NET Framework 4. This name space contains the classes, enumerations, and interfaces necessary to build service and client applications that can be used to build widely distributed applications.

In my next post I will cover the operational parameters of the service contract.

Data Access Layer – Implementing the Abstract Interface

In this post, I will demonstrate how I implemented the abstract interface called IArtWorldCollections. Below are two code snippets illustrating the implementation;

Following is the C# source code of the IArtWorldCollections interface. The interface has the following components;

  • A read only property, called WorksOfArtContext of type object context. The entity data model is an Object Context Class
  • A read only property, called ArtWorldCollection of type generic list. The Generic List Class Represents a strongly typed list of objects that can be accessed by index. It Provides methods to search, sort, and manipulate lists.
  • A read only property, called ExceptionMessage of type string. This property will store the message text, generated by any exceptions, thrown by any operations, performed in the methods of the class implementing the interface.
  • The final component is a method, called GetArtCollectionData, which accepts no parameters and returns no value. The purpose of this method, is to populate objects in the World Of Art Domain, with data from the World of Art entity data model. Then add each object, to the generic list property, called ArtWorldCollection.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
 
namespace WorldOfArtWebApp.DataAccess
{
    public interface IArtWorldCollection<T>
    {
        ObjectContext WorksOfArtContext
        { get; }
 
        List<T> ArtWorldCollection
        { get; }
 
        string ExceptionMessage
        { get; }
 
        void GetArtCollectionData();
    }
}

Now lets implement this interface in an actual C# class. Following is the C# source code, for a class I added to the data access layer. The class is called ArtWorldCollectionArtist, and as you can see, it implements the IArtWorldCollection interface, replacing the generic type T, with an object of type Artist, from the World of Art Domain. We replaced the generic object type of T, with the object type of Artist, because the purpose of this implementation is to generate a list of Artist objects, populated with data through the entity data model.

The three properties of the IArtWorldCollection interface are implemented with the following protected members of the class;

  • m_context, of type WorldOfArtContext, from the object context class of the WorldOfArt entity data model
  • m_artistList, of type Generic List, object type of Artist replaces the generic T type
  • m_exceptionMessage, of type string

The constructor method of the ArtWorldCollectionArtist class, initializes the protected members based on their object types. The constructor method also calls the GetArtCollectionData() method. In this method I use the Language-Integrated Query(LINQ) syntax available in C#, to perform a query against the World Of Art data model. We will cover LINQ in more detail in a future post. I employ a ForEach loop, to load the results of the query into the Artist List Collection. Notice how the query is not against a SQL Server databse table, instead the query is against the Artist property of the object context, in the World of Art Data Model. Therefore, I can create a new instance of the Artist object from each Artist in the result set of the query. I can populate the properties of the Artist object, with data from the properties of the Artist class in the data model.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Objects;
using ArtWorldObjects;
using WorldOfArtWebApp.DataModels;
 
namespace WorldOfArtWebApp.DataAccess
{
    public class ArtWorldCollectionArtist : IArtWorldCollection<Artist>
    {
        protected WorldOfArtContext m_WorldOfArtEntities;
        protected List<Artist> m_artistList;
        protected string m_exceptionMessage;
        protected Artist m_artist;
 
        public ArtWorldCollectionArtist()
        {
            m_exceptionMessage = string.Empty;
            m_WorldOfArtEntities = new WorldOfArtContext();
            m_artistList = new List<Artist>();
            GetArtCollectionData();
        }
 
        public ObjectContext WorksOfArtContext
        {
            get { return m_WorldOfArtEntities; }
        }
 
        public List<Artist> ArtWorldCollection
        {
            get { return m_artistList; }
        }
 
        public string ExceptionMessage
        {
            get { return m_exceptionMessage; }
        }
 
        public void GetArtCollectionData()
        {
            try
            {
                using (m_WorldOfArtEntities)
                {
                    var artistQuery = from artists in m_WorldOfArtEntities.aspnet_Artist
                                      select artists;
                    foreach (var artist in artistQuery)
                    {
                        m_artist = new Artist();
                        m_artist.Name = artist.FirstName + " " + artist.LastName;
                        m_artist.PlaceOfBirth = artist.City + " " + artist.Country;
                        m_artist.DateOfBirth = (DateTime)artist.BirthDay;
 
                        m_artistList.Add(m_artist);
                    }
                }
            }
            catch (Exception ex)
            {
                m_exceptionMessage = ex.Message;
            }
        }
 
        public Artist[] GetListOfArtist()
        {
            Artist[] artistList = ArtWorldCollection.ToArray();
            return artistList;
        }
    }
}

Finally, with the implementation of the IArtWorldCollection interface, we have achieved the separation of concerns we’ve been striving for. Notice how the ArtWorldCollectionArtist class has no concern for the source of the artist data. There is no code for opening and closing a connection to the database server. No need for hard coded SQL commands like “SELECT FirstName, LastName, BirthDay, City, Country, TypeOfArtist FROM aspnet_Artist” which can be severely impacted by changes to the database tables. The coding task is simplified by the entity data model, because now I’m coding against classes and properties, instead of hard coding table and column names. The hard tasks, of connecting to the database and accessing the tables of the database, have been abstracted into the entity data model. Even if the source of data changes from a Microsoft SQL Server database, to an ORACLE database, or even a data service, the ArtWorldCollectionArtist class would not be impacted by any of these changes.

One last comment on implementing a generic interface for data access, through the entity data model. The payoff for using this approach will continue to increase, as we further implement the interface, to access data and populate other elements in the World of Art domain; such as the works of art created by the artist. More on this in my next post.

Separation of Concerns – Data Access Layer

Now that the World of Art database has been abstracted, as an entity data model, we can focus on adding the data access layer to our architecture. This layer will act as an interface to the entity data model. The data access layer will create distance and independence from the data source, for the user interface layer, the business logic layer and the services layer.

The first thing I want to do in the data access layer, is create an abstract interface. The following code snippet illustrates this. As you can see, this is a generic interface. I’m using the System.Collections.Generic class, to declare this as a public interface called IArtWorldCollection, which implements a generic object type signified by “T”. The single purpose of this interface, is to create a generic list or collection of objects, from the World of Art Domain. We will reveal the details on how this is done, when we actually implement this Interface.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
 
namespace WorldOfArtWebApp.DataAccess
{
    public interface IArtWorldCollection<T>
    {
        ObjectContext WorksOfArtContext
        { get; }
 
        List<T> ArtWorldCollection
        { get; }
 
        string ExceptionMessage
        { get; }
 
        void GetArtCollectionData();
    }
}

The Data Model Layer

As discussed in the last post, we are going to apply a layered architectural structure, to the World of Art web app. The first layer we are going to develop, will be called the Data Model Layer. The purpose of this layer is to achieve a separation of concerns. To create distance and independence, between code supporting the application’s user interface, and code supporting access to the data source.

We will begin by adding an object model to the application. This object model is based on the World Of Art Relational Database, developed in a prior iteration. See Generating Data Model Based on Relational Database, for step by step instructions on generating the data model. As mentioned in previous posts, our data model layer is based on the Microsoft ADO.NET Entity Framework.

Now that the data model is generated, I’m going to display another illustration of the World of Art database diagram, which the data model is bases on. This diagram is more detailed, and shows the properties of each column of the two tables, currently in the database. Also, remember the “one-to-many” relationship between an artist and their works of art. An artist can create one or more works of art. This relationship is illustrated by the key and infinity symbols in the diagram. Please keep this diagram in mind, when we examine the data model diagram, based on this database.

Database Diagram for Data Model

World of Art Database Diagram

The next diagram illustrates the data model, which is based on the World of Art database. I used the Entity Data Model Wizard in Visual Studio 2010, to generate the data model. The data model has two classes, based on the two tables in the World of Art database. The Artist table and the Works of Art table, have been abstracted into two separate classes. The columns of the tables are now represented by the properties of each class. Also, notice how the one-to-many relationship between an artist and their works of art is maintained.

Data Model based on World of Art Database

Data Model based on World of Art database

The Entity Data Model Wizard in Visual Studio 2010, not only generates the entity data model diagram illustrated above, it also generates an entire C# code file, which the diagram is based on. The following image is a class diagram I generated in Visual Studio 2010. It’s based on the WorldOfArt.Designer.cs file which was generated by the Entity Data Model Wizard. As you can see, the wizard actually generated three classes. The one in the middle is the WorldOfArtContext class, it inherits the System.Data.Objects.ObjectContext class. The other two classes are based on the two tables in the World of Art database, and inherit the System.Data.Objects.DataClasses.EntityObject class. Like any typical C# class, they have private members and public properties, along with a wide range of partial methods and event handlers, for updating the tables.

WorldOfArt.Designer.cs Data Model Class Diagram

Class Diagram Based on World of Art Data Model

Finally, lets take a look at the World Of Art solution in Visual Studio, with the newly added Data Model layer. The highlighted folder, in the illustration below, represents the Data Model Layer in the World of Art project solution. The folder contains two files;

  • The WorldOfArt.edmx file, is the data model diagram. It can be viewed and modified, in the Entity Data Model Designer, in Visual Studio.
  • The WorldOfArtDesigner.cs file, is the C# source code of the Entity Data Model.
Data Model Layer in Solution Explorer

Data Model Layer in the World of Art Project Solution

In my next post, I’ll discuss the benefits derived from building a Data Model Architectural Layer, and an Entity Data Model.

Layered Architecture & Separation of Concerns

Now that I have dealt with my philosophical and project management issues, we can get back to improving the design of the World of Art web app. If you recall my previous post on Improving the Design, I identified several objectives for improving the application design;

  • Eliminate the tight coupling of the user interface and data access, by extracting database connectivity and data access, into a separate architectural layer of the application.
  • Design and build an abstracted view of the data access domain.
  • Develop an interface to the data access domain.

A tremendous amount of progress towards meeting these objectives, can be gained by implementing the Microsoft ADO.NET Entity Framework. The Entity Framework provides a means for achieving our design objects. However, the Entity Framework provides even greater benefits;

  • Enables me to program against a conceptual application model instead of programming directly against a relational database schema.
  • Decreases the amount of code and maintenance required for data-oriented applications.
  • Provides freedom to focus more on the problem/business domain issues, and much less on database access and query issues.

Now with all that said, the ADO.NET Entity Framework is no the complete solution for improving the design of our application. The core purpose of our design objectives is to establish a separation of concerns, by creating distance between dissimilar aspects of our code.

Separation of Concerns

Kyle Baley, Donald Belcham and James Kovacs, wrote an excellent series in MSDN Magazine called Extreme ASP.NET Makeover. Part six of this series deals with the subject of separation of concerns.

Another design improvement objective, is to introduce a layered architecture to our design. The traditional layered architecture of a software application, utilizes three basic layers for separating coding concerns;

  • User Interface
  • Business Logic
  • Data Access

Layered Architecture

Applying a layered architectural design to an app is always good practice, because it simplifies each component of the app, and improves maintainability in a way that lends itself very nicely to evolutionary improvements, as opposed to total re-writes. However, applying a layered design to large, complex, enterprise level applications, can introduce other levels of tight coupling which should be avoided.

Hendry Luk wrote a very good piece on this subject. See Software Development Fundamentals, Part 2: Layered Architecture

Jeffrey Palermo also tackles this issue in his series on The Onion Architecture.

Please keep in mind, the concepts covered by Hendry Luk and Jeffrey Palermo, are intended for large enterprise level apps, with complex behaviors and long running life cycles. However, it is good to study and understand these concepts. As developers, it is our responsibility to determine the best practical application of these concepts, based on a desire to satisfy our customer’s needs and our project requirements.

In my next post, we will introduce a Data Model Layer to our application. In this layer, we will utilize the ADO.NET Entity Framework, to create an object model over the World of Art Relation Database.

Improving the Design

As previously posted, The artist content page has been added to The World of Art web app. The ASP.net Web Form Model was implemented as the foundation for developing this component of the application.

Using the ASP.net Web Form model, provided a stable architectural software development platform, along with off the shelf software components, which facilitated rapid development and deployment, of the artist content page. If you recall, I used the ASP.Net SQL Data Source Control, to query artist information from the database. However, after spending a little time studying the overall design of the artist page, I do have some concerns regarding the use of the SQL Data Source Control;

  • More consideration should be given to scale, as the size of the artist database is certain to grow much larger.
  • Using the SQL Data Source control is acceptable for small applications. However, as the application grows in size and complexity, we will find this approach is too tightly coupled with the user interface. The current approach will require each web page, that renders dynamic database content, to have its own unique interface to the data source. This introduces some vulnerability to the impact of change. With each web page developed, with this tight coupling to the data source, the impact of future changes to data access requirements increases . As the impact of change increases, so does the level of effort in code maintenance.

In my next post, I will discuss an architectural approach for extracting data access into a separate design layer of the application, thus eliminating this tight coupling with the user interface layer. We will also design and build an abstracted view of the data access domain, like we did with the World of Art Domain. We will then develop an interface to our data source domain. ASP.Net provides some off the shelf components, which make this more sophisticated design, surprisingly easy to implement.