Skip to content

10. The [SimuPaie] application – version 6 – an ASP.NET client of a web service

10.1. The application architecture

We are evolving the client/server architecture of the NUnit test as follows:

In [1], the NUnit test is replaced by the version 8 web application. It is important to note here that this architecture includes two web servers not shown:

  • a web server that runs the [S] web service. It will run in a first instance of Visual Web Developer.
  • a web server that runs the web client [1]. It will run in a second instance of Visual Web Developer.

10.2. The Visual Web Developer project for the [web] client

We create a new ASP.NET Web project:

  • in [1], we select a C# web project
  • In [2], we select "ASP.NET Web Application"
  • in [3], we name the web project
  • in [4], we specify a location for this project
  • in [5], the project is created

We modify a few project properties:

  • in [1], the name of the assembly that will be generated
  • In [2], the default namespace for the classes and interfaces that will be created

To build the [pam-v6-client-webservice] project, we can retrieve the [Global.asax] and [Default.aspx] files from the [pam-v4-3tier-nhibernate-multivues-monopage] web project and copy them into the [pam-v6-client-webservice] project. We do this using Windows Explorer first:

  • in [1], the [pam-v4-3tier-nhibernate-multivues-monopage] project folder
  • in [2], the [pam-v6-client-webservice] project folder after copying
    • the [images, pam, resources] folders
    • the files [Global.asax, Global.asax.cs]
    • the files [Default.aspx, Default.aspx.cs, Default.aspx.designer.cs]
  • in [3], in Visual Studio Express, display all project files to show the newly added files
  • In [4], include the added folders and files in the project
  • in [5], the new project [pam-v6-client-webservice]

At this point, you can build the project for the first time [6]. You will get the following errors:

1
2
3
4
5
6
7
Error    1    The type or namespace 'Dao' does not exist in the 'Pam' namespace (is an assembly reference missing?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    3    11    pam-v6-client-webservice
Error    2    The type or namespace 'Metier' does not exist in the 'Pam' namespace (is an assembly reference missing?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    4    11    pam-v6-client-webservice
Error    3    The type or namespace name 'Dao' does not exist in the 'Pam' namespace (is an assembly reference missing?)    c:\temp\pam-aspnet\pam-v6-client-webservice\default.aspx.cs    5    11    pam-v6-client-webservice
Error    4    The type or namespace 'Spring' cannot be found (is a using directive or assembly reference missing?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    6    7    pam-v6-client-webservice
Error    5    The type or namespace 'Metier' does not exist in the 'Pam' namespace (is an assembly reference missing?)    c:\temp\pam-aspnet\pam-v6-client-webservice\default.aspx.cs    6    11    pam-v6-client-webservice
Error    6    The type or namespace 'Employee' cannot be found (is a using directive or assembly reference missing?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    13    19    pam-v6-client-webservice
Error    7    The type or namespace 'IPamMetier' cannot be found (is a using directive or assembly reference missing?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    14    19    pam-v6-client-webservice

To understand and fix these errors, we need to look at the architecture of the web project under development:

The [pam-v6-client-webservice] project is the [web] layer [1] in the diagram above. We can see that this layer communicates with the web service client [C], a client that we will generate shortly.

  • Errors 2, 5, and 7 stem from the fact that the code in [pam-v4] referenced the DLL of the [business] layer, a DLL that is now on the server side rather than the client side.
  • Errors 1 and 3 have the same cause, but this time regarding the [DAO] layer DLL.
  • Error 4 is caused by the fact that the code in [Global.asax] uses Spring, and our project does not reference the Spring DLL. We will add this reference.
  • Error 6 is caused by the fact that the [Employee] class is defined in the [DAO] layer, which does not exist on the client side.

The namespace errors 1, 2, 4, 5, 6, and 7 will be resolved by generating the C client for the web service. Error 3 is resolved by adding a reference to the Spring DLL in the project. We can proceed as follows:

  • In [1], add a reference to the [pam-v6-client-webservice] project
  • In [4], we added a reference to the [Spring.Core] DLL in the [lib] folder.

After adding this reference to Spring, the project generation shows one fewer error. All other errors are due to lines of code that reference objects from the [business] and [DAO] layers, which are now on the server. We will see that these missing objects will be generated in the web service client [C].

Before generating the web service client [C], we will change the namespace of the various classes present. They are currently in the [pam-v4] namespace. We change this namespace to [pam-v6]. The files involved are as follows: Default.aspx.cs, Default.aspx.designer.cs, Global.asax.cs. For example:


....
namespace pam_v6
{
  public class Global : System.Web.HttpApplication
  {
    // --- application static data ---
    public static Employee[] Employees;
    public static IPamMetier PamMetier = null;
....

Line 2: The pam_v4 namespace has been replaced by the pam_v6 namespace.

In addition, you must modify the markup in the following files: Default.aspx and Global.asax:

  

The markup for [Default.aspx] becomes:


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="pam_v6.PagePam" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
.....

Line 1: The Inherits attribute specifies the class name of the [Default.aspx.cs] file. We change the namespace.

The markup for [Global.asax] becomes:


<%@ Application Codebehind="Global.asax.cs" Inherits="pam_v6.Global" Language="C#" %>

Above, we change the namespace of the Inherits attribute.

We now generate the web service client [C].

To perform the following steps, the web service [S] [pam-v5-webservice] must be running in another instance of Visual Web Developer.

  • In [1], we add a reference to the web service [pam-v5-webservice] to the project [pam-v6-client-webservice]
  • In [2], enter the URI of the web service [pam-v5-webservice]. This is the URL of the WSDL file for this web service. When building the web service [pam-v5-webservice], we indicated how to find this URL.
  • In [3], ask the wizard to use the WSDL file specified in [2]
  • in [4], the discovered web service [Service1Soap] and in [5] the remote methods it exposes.
  • In [6], we set the namespace in which the classes and interfaces of the client [C] will be generated
  • We start generating the client [C]
  • In [1], the generated client. Double-click on it to access its contents.
  • In [2], in the Object Explorer, the classes and interfaces of the pam_v6.WsPam namespace are displayed. This is the namespace of the generated client.
  • [3] shows the class that implements the web service client.
  • In [4], the methods implemented by the client [Service1SoapClient]. Here we find the two methods of the remote web service [5] and [6].
  • In [2], the entity diagrams for the layers are shown:
    • [business] : Payroll, PayrollItems
    • [DAO]: Employee, Contributions, Allowances

Moving forward, keep in mind that these representations of the remote entities are located on the client side and in the pam_v6.WsPam namespace.

Let’s examine the methods and properties exposed by one of them:

  • In [1], we select the local [Employee] class
  • In [2], we see the properties of the remote [Employee] entity as well as private fields used for the local entity’s specific needs.

Let’s examine the code in [Global.asax.cs] that contains errors:

 
  • Lines 3 and 4 use namespaces that exist on the server but not on the client.
  • Line 13 uses a [Employee] class for which the correct namespace has not been declared
  • Line 14 uses an IPamMetier interface that is unknown to the client.

We have already encountered similar issues in the C# client discussed earlier.

In the architecture:

  • the local [business] layer is implemented by the client [C] of type pam_v6.WsPam.Service1SoapClient, which does not implement the IPamMetier interface even though it has methods with the same names.
  • The entities handled (Employee, Benefits, Contributions) by the generated [C] client are in the pam_v6.WsPam namespace

The code in [Global.asax.cs] changes as follows:


using System;
using System.Collections.Generic;
using Pam.Web;
using Spring.Context.Support;
using pam_v6.WsPam;

namespace pam_v6
{
  public class Global : System.Web.HttpApplication
  {
    // --- application static data ---
    public static Employee[] Employees;
    public static Service1SoapClient PamMetier = null;
    public static string Msg;
    public static bool Error = false;

    // Application startup
    public void Application_Start(object sender, EventArgs e)
    {
      // Load the configuration file
      try
      {
        // instantiate the [business] layer
        PamMetier = ContextRegistry.GetContext().GetObject("pammetier") as Service1SoapClient;
        // simplified list of employees
        Employees = PamMetier.GetAllEmployeeIdentities();
        // Success
        Msg = "Database loaded...";
      }
      catch (Exception ex)
      {
        // log the error
        Msg = string.Format("The following error occurred while accessing the database: {0}", ex);
        Error = true;
      }
    }

    public void Session_Start(object sender, EventArgs e)
    {
      // Add an empty list of simulations to the session 
      List<Simulation> simulations = new List<Simulation>();
      Session["simulations"] = simulations;
    }
  }
}

Line 24 instantiates layer [C] using Spring. The configuration required for this instantiation is defined in [web.config]:


<configSections>
      <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
 ...
      </sectionGroup>
      <sectionGroup name="spring">
        <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
        <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
      </sectionGroup>
    </configSections>

  <spring>
    <context>
      <resource uri="config://spring/objects" />
    </context>
      <objects xmlns="http://www.springframework.net">
        <object id="pammetier" type="pam_v6.WsPam.Service1SoapClient,pam-v6-client-webservice"/>
      </objects>
</spring>

Line 16: The [business] layer is an instance of the [pam_v6.WsPam.Service1SoapClient] class, which can be found in the [pam-v6-client-webservice] DLL. Recall that we configured the [pam-v6-client-webservice] project to generate this DLL.

There are still a few errors in [Default.aspx.cs]:

  • lines 5, 6: these namespaces no longer exist. The entities are now in the pam_v6 or pam_v6.WsPam namespace.
  • line 98: the generated client [C] did not inherit the [PamException] class from the [dao] layer. It could not do so since the web service does not expose this exception. We choose to replace PamException with its parent class Exception.

The code becomes:


...
using System.Web.UI.WebControls;
using pam_v6.WsPam;

namespace pam_v6
{

  public partial class PagePam : Page
  {
...

...
      try
      {
        payroll = Global.PamMetier.GetSalary(DropDownListEmployees.SelectedValue, HoursWorked, DaysWorked);
      }
      catch (Exception ex)
      {
...

Once these errors have been corrected, we can run the web application:

  • in [1], the URL of the web client for the remote web service
  • in [2], the employee dropdown has been populated. The data it contains comes from the web service.

We invite the reader to test this version 6, a copy of version 4.