Skip to content

10. L'applicazione [SimuPaie] – versione 6 – un client ASP.NET di un servizio web

10.1. L'architettura dell'applicazione

Stiamo evolvendo l'architettura client/server del test NUnit come segue:

In [1], il test NUnit viene sostituito dall'applicazione web versione 8. È importante notare che questa architettura include due server web non mostrati:

  • un server web che esegue il servizio web [S]. Verrà eseguito in una prima istanza di Visual Web Developer.
  • un server web che esegue il client web [1]. Verrà eseguito in una seconda istanza di Visual Web Developer.

10.2. Il progetto Visual Web Developer per il client [web]

Creiamo un nuovo progetto Web ASP.NET:

  • in [1], selezioniamo un progetto Web C#
  • In [2], selezioniamo "Applicazione Web ASP.NET"
  • in [3], assegniamo un nome al progetto web
  • in [4], specifichiamo una posizione per questo progetto
  • in [5], il progetto viene creato

Modifichiamo alcune proprietà del progetto:

  • in [1], il nome dell'assembly che verrà generato
  • In [2], lo spazio dei nomi predefinito per le classi e le interfacce che verranno create

Per compilare il progetto [pam-v6-client-webservice], possiamo recuperare i file [Global.asax] e [Default.aspx] dal progetto web [pam-v4-3tier-nhibernate-multivues-monopage] e copiarli nel progetto [pam-v6-client-webservice]. Per farlo, utilizziamo innanzitutto Esplora risorse:

  • in [1], la cartella del progetto [pam-v4-3tier-nhibernate-multivues-monopage]
  • in [2], la cartella del progetto [pam-v6-client-webservice] dopo la copia
    • le cartelle [images, pam, resources]
    • i file [Global.asax, Global.asax.cs]
    • i file [Default.aspx, Default.aspx.cs, Default.aspx.designer.cs]
  • in [3], in Visual Studio Express, visualizza tutti i file di progetto per mostrare i file appena aggiunti
  • In [4], includere le cartelle e i file aggiunti nel progetto
  • in [5], il nuovo progetto [pam-v6-client-webservice]

A questo punto, è possibile compilare il progetto per la prima volta [6]. Verranno visualizzati i seguenti errori:

1
2
3
4
5
6
7
Erreur    1    Le type ou le nom d'espace de noms 'Dao' n'existe pas dans l'espace de noms 'Pam' (une référence d'assembly est-elle manquante ?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    3    11    pam-v6-client-webservice
Erreur    2    Le type ou le nom d'espace de noms 'Metier' n'existe pas dans l'espace de noms 'Pam' (une référence d'assembly est-elle manquante ?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    4    11    pam-v6-client-webservice
Erreur    3    Le type ou le nom d'espace de noms 'Dao' n'existe pas dans l'espace de noms 'Pam' (une référence d'assembly est-elle manquante ?)    c:\temp\pam-aspnet\pam-v6-client-webservice\default.aspx.cs    5    11    pam-v6-client-webservice
Erreur    4    Le type ou le nom d'espace de noms 'Spring' est introuvable (une directive using ou une référence d'assembly est-elle manquante ?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    6    7    pam-v6-client-webservice
Erreur    5    Le type ou le nom d'espace de noms 'Metier' n'existe pas dans l'espace de noms 'Pam' (une référence d'assembly est-elle manquante ?)    c:\temp\pam-aspnet\pam-v6-client-webservice\default.aspx.cs    6    11    pam-v6-client-webservice
Erreur    6    Le type ou le nom d'espace de noms 'Employe' est introuvable (une directive using ou une référence d'assembly est-elle manquante ?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    13    19    pam-v6-client-webservice
Erreur    7    Le type ou le nom d'espace de noms 'IPamMetier' est introuvable (une directive using ou une référence d'assembly est-elle manquante ?)    C:\temp\pam-aspnet\pam-v6-client-webservice\Global.asax.cs    14    19    pam-v6-client-webservice

Per comprendere e correggere questi errori, dobbiamo esaminare l'architettura del progetto web in fase di sviluppo:

Il progetto [pam-v6-client-webservice] è il livello [web] [1] nel diagramma sopra riportato. Possiamo notare che questo livello comunica con il client del servizio web [C], un client che genereremo tra poco.

  • Gli errori 2, 5 e 7 derivano dal fatto che il codice in [pam-v4] faceva riferimento alla DLL del livello [business], una DLL che ora si trova sul lato server anziché sul lato client.
  • Gli errori 1 e 3 hanno la stessa causa, ma questa volta riguardano la DLL del livello [DAO].
  • L'errore 4 è causato dal fatto che il codice in [Global.asax] utilizza Spring, e il nostro progetto non fa riferimento alla DLL di Spring. Aggiungeremo questo riferimento.
  • L'errore 6 è causato dal fatto che la classe [Employee] è definita nel livello [DAO], che non esiste sul lato client.

Gli errori di namespace 1, 2, 4, 5, 6 e 7 saranno risolti generando il client C per il servizio web. L'errore 3 viene risolto aggiungendo un riferimento alla DLL di Spring nel progetto. Possiamo procedere come segue:

  • In [1], aggiungere un riferimento al progetto [pam-v6-client-webservice]
  • In [4], abbiamo aggiunto un riferimento alla DLL [Spring.Core] nella cartella [lib].

Dopo aver aggiunto questo riferimento a Spring, la generazione del progetto mostra un errore in meno. Tutti gli altri errori sono dovuti a righe di codice che fanno riferimento a oggetti dei livelli [business] e [DAO], che ora si trovano sul server. Vedremo che questi oggetti mancanti verranno generati nel client del servizio web [C].

Prima di generare il client del servizio web [C], modificheremo lo spazio dei nomi delle varie classi presenti. Attualmente si trovano nello spazio dei nomi [pam-v4]. Modifichiamo questo spazio dei nomi in [pam-v6]. I file interessati sono i seguenti: Default.aspx.cs, Default.aspx.designer.cs, Global.asax.cs. Ad esempio:


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

Riga 2: lo spazio dei nomi pam_v4 è stato sostituito dallo spazio dei nomi pam_v6.

Inoltre, è necessario modificare il markup nei seguenti file: Default.aspx e Global.asax:

  

Il codice di marcatura per [Default.aspx] diventa:


<%@ 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">
.....

Riga 1: L'attributo Inherits specifica il nome della classe del file [Default.aspx.cs]. Modifichiamo lo spazio dei nomi.

Il markup per [Global.asax] diventa:


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

Sopra, modifichiamo lo spazio dei nomi dell'attributo Inherits.

Ora generiamo il client del servizio web [C].

Per eseguire i passaggi seguenti, il servizio Web [S] [pam-v5-webservice] deve essere in esecuzione in un'altra istanza di Visual Web Developer.

  • In [1], aggiungiamo un riferimento al servizio web [pam-v5-webservice] al progetto [pam-v6-client-webservice]
  • In [2], inserisci l'URI del servizio web [pam-v5-webservice]. Si tratta dell'URL del file WSDL per questo servizio web. Durante la creazione del servizio web [pam-v5-webservice], abbiamo indicato come trovare questo URL.
  • In [3], chiedi alla procedura guidata di utilizzare il file WSDL specificato in [2]
  • in [4], il servizio web individuato [Service1Soap] e in [5] i metodi remoti che espone.
  • In [6], impostiamo lo spazio dei nomi in cui verranno generate le classi e le interfacce del client [C]
  • Iniziamo a generare il client [C]
  • In [1], il client generato. Fare doppio clic su di esso per accedere al suo contenuto.
  • In [2], in Esplora oggetti, vengono visualizzate le classi e le interfacce dello spazio dei nomi pam_v6.WsPam. Questo è lo spazio dei nomi del client generato.
  • [3] mostra la classe che implementa il client del servizio web.
  • In [4], i metodi implementati dal client [Service1SoapClient]. Qui troviamo i due metodi del servizio web remoto [5] e [6].
  • In [2] sono riportati i diagrammi delle entità relativi ai livelli:
    • [business] : Payroll, PayrollItems
    • [DAO]: Dipendente, Contributi, Indennità

Proseguendo, tieni presente che queste rappresentazioni delle entità remote si trovano sul lato client e nello spazio dei nomi pam_v6.WsPam.

Esaminiamo i metodi e le proprietà esposti da una di esse:

  • In [1], selezioniamo la classe locale [Employee]
  • In [2], vediamo le proprietà dell'entità remota [Employee] e i campi privati utilizzati per le esigenze specifiche dell'entità locale.

Esaminiamo il codice in [Global.asax.cs] che contiene errori:

 
  • Le righe 3 e 4 utilizzano spazi dei nomi presenti sul server ma non sul client.
  • La riga 13 utilizza una classe [Employee] per la quale non è stato dichiarato il namespace corretto
  • La riga 14 utilizza un'interfaccia IPamMetier sconosciuta al client.

Abbiamo già riscontrato problemi simili nel client C# discusso in precedenza.

Nell'architettura:

  • il livello [aziendale] locale è implementato dal client [C] di tipo pam_v6.WsPam.Service1SoapClient, che non implementa l'interfaccia IPamMetier anche se dispone di metodi con gli stessi nomi.
  • Le entità gestite (Employee, Benefits, Contributions) dal client [C] generato si trovano nello spazio dei nomi pam_v6.WsPam

Il codice in [Global.asax.cs] cambia come segue:


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
  {
    // --- static application data ---
    public static Employe[] Employes;
    public static Service1SoapClient PamMetier = null;
    public static string Msg;
    public static bool Erreur = false;
 
    // application startup
    public void Application_Start(object sender, EventArgs e)
    {
      // using the configuration file
      try
      {
        // instantiation layer [metier]
        PamMetier = ContextRegistry.GetContext().GetObject("pammetier") as Service1SoapClient;
        // simplified list of employees
        Employes = PamMetier.GetAllIdentitesEmployes();
        // we succeeded
        Msg = "Base chargée...";
      }
      catch (Exception ex)
      {
        // we note the error
        Msg = string.Format("L'erreur suivante s'est produite lors de l'accès à la base de données : {0}", ex);
        Erreur = true;
      }
    }
 
    public void Session_Start(object sender, EventArgs e)
    {
      // put an empty simulation list in the session 
      List<Simulation> simulations = new List<Simulation>();
      Session["simulations"] = simulations;
    }
  }
}

La riga 24 istanzia il livello [C] utilizzando Spring. La configurazione necessaria per questa istanziazione è definita 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>

Riga 16: Il livello [business] è un'istanza della classe [pam_v6.WsPam.Service1SoapClient], che si trova nella DLL [pam-v6-client-webservice]. Ricordiamo che abbiamo configurato il progetto [pam-v6-client-webservice] per generare questa DLL.

Ci sono ancora alcuni errori in [Default.aspx.cs]:

  • righe 5, 6: questi spazi dei nomi non esistono più. Le entità si trovano ora nello spazio dei nomi pam_v6 o pam_v6.WsPam.
  • riga 98: il client generato [C] non ha ereditato la classe [PamException] dal livello [dao]. Non ha potuto farlo poiché il servizio web non espone questa eccezione. Abbiamo scelto di sostituire PamException con la sua classe padre Exception.

Il codice diventa:


...
using System.Web.UI.WebControls;
using pam_v6.WsPam;
 
namespace pam_v6
{
 
  public partial class PagePam : Page
  {
...

...
      try
      {
        feuillesalaire = Global.PamMetier.GetSalaire(DropDownListEmployes.SelectedValue, HeuresTravaillées, JoursTravaillés);
      }
      catch (Exception ex)
      {
...

Una volta corretti questi errori, possiamo eseguire l'applicazione web:

  • in [1], l'URL del client web per il servizio web remoto
  • in [2], il menu a tendina dei dipendenti è stato popolato. I dati in esso contenuti provengono dal servizio web.

Invitiamo il lettore a provare questa versione 6, una copia della versione 4.