Skip to content

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

10.1. L'architettura dell'applicazione

Stiamo evolvendo l’architettura client/server del test NUnit nel modo seguente:

In [1], il test NUnit viene sostituito dall’applicazione web della versione 8. È importante ricordare che questa architettura comprende due server web non rappresentati:

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

10.2. Il progetto Visual Web Developer del client [web]

Creiamo un nuovo progetto Web ASP.NET:

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

Modifichiamo alcune proprietà del progetto:

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

Per compilare il progetto [pam-v6-client-webservice] è possibile 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, si utilizza innanzitutto Esplora risorse di Windows:

  • in [1], la cartella del progetto [pam-v4-3tier-nhibernate-multivues-monopage]
  • in [2], la cartella del progetto [pam-v6-client-webservice] dopo la ricopia
    • delle cartelle [images, pam, ressources]
    • dei file [Global.asax, Global.asax.cs]
    • dei file [Default.aspx, Default.aspx.cs, Default.aspx.designer.cs]
  • in [3], in Visual Studio Express, si visualizzano tutti i file del progetto, per far apparire i file appena aggiunti
  • in [4], si includono nel progetto le cartelle e i file aggiunti
  • in [5] il nuovo progetto [pam-v6-client-webservice]

A questo punto, è possibile generare il progetto una prima volta [6]. Si ottengono 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 questi errori e correggerli, è necessario tornare all’architettura del progetto web in fase di realizzazione:

Il progetto [pam-v6-client-webservice] corrisponde al livello [web] [1] nello schema sopra riportato. Si nota che questo livello comunica con il client [C] del servizio web, un client che genereremo a breve.

  • Gli errori 2, 5 e 7 derivano dal fatto che il codice di [pam-v4] faceva riferimento a DLL del livello [metier], DLL, che ora si trova sul lato server e non sul lato client.
  • Gli errori 1 e 3 hanno la stessa causa, ma questa volta riguardano il DLL del livello [dao]
  • l’errore 4 deriva dal fatto che il codice di [Global.asax] utilizza Spring e il nostro progetto non fa riferimento a DLL di Spring. Aggiungeremo questo riferimento.
  • L'errore 6 deriva dal fatto che la classe [Employe] è definita nel livello [dao], che non esiste sul lato client.

Gli errori relativi allo spazio dei nomi 1, 2, 4, 5, 6 e 7 saranno risolti dalla generazione del client C del servizio web. L’errore 3 viene risolto aggiungendo al progetto un riferimento a DLL di Spring. Possiamo procedere come segue:

  • in [1], si aggiunge un riferimento al progetto [pam-v6-client-webservice]
  • in [4], è stato aggiunto un riferimento a DLL e [Spring.Core] dalla cartella [lib].

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

Prima di generare il client [C] del servizio web, modificheremo lo spazio dei nomi delle diverse 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
  {
    // --- dati statici dell'applicazione ---
    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 dei file: Default.aspx e Global.asax:

  

Il markup di [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 indica il nome della classe del file [Default.aspx.cs]. Si modifica lo spazio dei nomi.

Il markup di [Global.asax] diventa:


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

Nell'esempio sopra riportato, si modifica lo spazio dei nomi dell'attributo Inherits.

Ora generiamo il client [C] del servizio web.

Per eseguire le operazioni successive, è necessario che il servizio web [S] [pam-v5-webservice] sia avviato in un'altra istanza di Visual Web Developer.

  • In [1], si aggiunge al progetto [pam-v6-client-webservice] un riferimento al servizio web [pam-v5-webservice]
  • in [2], l'URI del servizio web [pam-v5-webservice]. Si tratta dell'URL del file WSDL di questo servizio web. Nella creazione del servizio web [pam-v5-webservice], è stato spiegato come individuare questo URL.
  • In [3], si richiede all’assistente di elaborare il file WSDL indicato in [2]
  • in [4], il servizio web [Service1Soap] individuato e in [5] i metodi remoti che esso espone.
  • In [6], si imposta lo spazio dei nomi in cui verranno generate le classi e le interfacce del client [C]
  • Si avvia la generazione del client [C]
  • in [1], il client generato. Fare doppio clic su di esso per accedere al suo contenuto.
  • In [2], nell’esploratore degli oggetti, vengono visualizzate le classi e le interfacce dello spazio dei nomi pam_v6.WsPam. Si tratta dello spazio dei nomi del client generato.
  • In [3], la classe che implementa il client del servizio web.
  • In [4] sono riportati i metodi implementati dal client [Service1SoapClient]. Vi si trovano i due metodi del servizio web remoto [5] e [6].
  • In [2] sono presenti le immagini delle entità dei livelli:
    • [metier]: FeuilleSalaire, ElementsSalaire
    • [dao]: Employe, Cotisations, Indemnites

Di seguito, è importante ricordare che queste immagini 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], si seleziona la classe locale [Employe]
  • in [2], si trovano le proprietà dell’entità remota [Employe], nonché i campi privati utilizzati per le esigenze specifiche dell’entità locale.

Esaminiamo il codice di [Global.asax.cs] che presenta degli errori:

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

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

Nell'architettura:

  • il livello locale [metier] è implementato dal client [C] di tipo pam_v6.WsPam.Service1SoapClient, che non implementa l’interfaccia IPamMetier, sebbene presenti metodi con gli stessi nomi.
  • Le entità gestite (Employe, Indemnites, Cotisations) dal client [C] generato si trovano nello spazio dei nomi pam_v6.WsPam

Il codice di [Global.asax.cs] si evolve 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
  {
    // --- dati statici dell'applicazione ---
    public static Employe[] Employes;
    public static Service1SoapClient PamMetier = null;
    public static string Msg;
    public static bool Erreur = false;

    // avvio dell'applicazione
    public void Application_Start(object sender, EventArgs e)
    {
      // elaborazione del file di configurazione
      try
      {
        // istanziazione del livello [metier]
        PamMetier = ContextRegistry.GetContext().GetObject("pammetier") as Service1SoapClient;
        // elenco semplificato dei dipendenti
        Employes = PamMetier.GetAllIdentitesEmployes();
        // operazione riuscita
        Msg = "Base chargée...";
      }
      catch (Exception ex)
      {
        // si registra l'errore
        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)
    {
      // si inserisce un elenco di simulazioni vuoto nella sessione 
      List<Simulation> simulations = new List<Simulation>();
      Session["simulations"] = simulations;
    }
  }
}

La riga 24 istanzia il livello [C] tramite 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>

Alla riga 16, il livello [metier] è un'istanza della classe [pam_v6.WsPam.Service1SoapClient] che si trova in DLL [pam-v6-client-webservice]. Ricordiamo che abbiamo configurato il progetto [pam-v6-client-webservice] in modo che generi questo DLL.

Nel file [Default.aspx.cs] sono ancora presenti alcuni errori:

  • 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 poteva farlo poiché il servizio web non espone tale eccezione. Si decide 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 del servizio web remoto
  • in [2], il menu a tendina dei dipendenti è stato compilato. I dati in esso contenuti provengono dal servizio web.

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