Sommario
Nell'articolo sono descritti i passi da seguire per poter creare un esempio di un'applicazione scritta in linguaggio C# che consente di effettuare l'autenticazione al prodotto Perfetto4 e l'inserimento del documento, utilizzando la tecnologia Magic Link.
Per facilitare la lettura dell'articolo di seguito un indice delle sezioni dell'articolo:
- Creazione del progetto
- Creazione della maschera di login e inserimento
- Connessione ai Web Service di Perfetto
- Autenticazione
- Invio dati dipendente a Perfetto
- Disconnessione
Creazione del progetto
- aprire "Visual Studio", in questo esempio è stato utilizzato Visual Studio 2022;
- selezionare "Nuovo progetto...";
- scegliere "Applicazione Windows Form";
- inserire il nome del progetto, in questo caso: "ExampleProject_Utility_CS".
Creazione della maschera di Login e inserimento del dipendente
Nel seguente sezione è mostrato come creare l'interfaccia grafica dell'applicazione. Essa è divisa in due parti, una rivolta alla gestione dell'autenticazione e una con una tab dedicata all'inserimento del documento.
I passi da seguire per realizzare l'interfaccia sono:
-
Inserire i campi relativi alla fase di login:
Schermata di "Login" -
Inserire i campi relativi alla fase di inserimento del dipendente:
Schermata dell'inserimento del "Tecnico"
Connessione ai Web Service di Perfetto4
Per poter accedere ai metodi web che consentono all'utente di registrarsi e inserire i dati in Perfetto4, è necessario aggiungere i riferimenti ai servizi di Perfetto4.
Le operazioni da seguire per aggiungere un riferimento ad un servizio sono le seguenti:
- posizionarsi sul nodo del progetto dell'albero dell'"Esplora soluzioni";
- fare click con il tasto destro del mouse;
- selezionare la voce "Aggiungi riferimento al servizio";
- selezionare la voce "WCF Web Service" e procedere;
- procedere lasciando le opzioni di default come nello screenshot seguente;
- inserire il percorso del Web Service ed effettuare l'individuazione del servizio per avere una conferma;
- scegliere un Namespace per il servizio che stiamo aggiungendo;
- finalizzare l'aggiunta del servizio premendo Avanti;
Per l'esempio è necessario inserire il riferimento per LoginManager e TbServices.
Una volta inseriti i riferimenti ai Web Service è necessario creare una loro istanza nel seguente modo:
Esempio C#: esempio di instanziazione dei client dei servizi
AppSession.BaseUrl = $"{protocol.Trim()}://{server.Trim()}:{port.Trim()}/{instance.Trim()}"; // Nella Solution i valori vengono presi dalla schermata di Login iniziale
using var loginManagerClient = new MicroareaLoginManagerSoapClient(
MicroareaLoginManagerSoapClient.EndpointConfiguration.MicroareaLoginManagerSoap,
$"{AppSession.BaseUrl.TrimEnd('/')}/LoginManager/LoginManager.asmx");
using var tbServicesClient = new TbServicesSoapClient(
TbServicesSoapClient.EndpointConfiguration.TbServicesSoap,
$"{AppSession.BaseUrl.TrimEnd('/')}/TbServices/TbServices.asmx");
Autenticazione
Per effettuare l'autenticazione al sistema è utilizzato il metodo web LoginCompact del LoginManager.
Nel seguente snippet di codice è mostrato come recuperare i valori dei campi relativi alla login e passare tali valori al metodo LoginCompact per ottenere il codice di autenticazione:
Esempio C#: logica di connessione al server e login ad un'azienda
//--------------------------------------------------------------------------
private async void buttonConnect_Click(object? sender, EventArgs e)
{
string protocol = comboBoxProtocol.SelectedItem?.ToString() ?? "http";
string server = textBoxServer.Text;
string port = string.IsNullOrWhiteSpace(textBoxPort.Text) ? "80" : textBoxPort.Text;
string instance = textBoxInstanceFolder.Text;
toolStripStatusLoginConnectedColor.BackColor = Color.Orange;
toolStripStatusLoginConnectedLabel.Text = "Connecting...";
Cursor.Current = Cursors.WaitCursor;
var result = await _connectionService.TestConnectionAsync(protocol, server, port, instance);
if (result.Success)
{
AppSession.BaseUrl = $"{protocol.Trim()}://{server.Trim()}:{port.Trim()}/{instance.Trim()}";
groupBoxLogin.Enabled = true;
LoadCompanies(false);
Cursor.Current = Cursors.Default;
toolStripStatusLoginConnectedColor.BackColor = Color.Green;
toolStripStatusLoginConnectedLabel.Text = "Connected ";
MessageBox.Show(result.Message, "Connected ", MessageBoxButtons.OK, MessageBoxIcon.Information);
groupBoxConnection.Enabled = false;
buttonDisconnect.Enabled = true;
}
else
{
groupBoxLogin.Enabled = false;
Cursor.Current = Cursors.Default;
MessageBox.Show(result.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
//--------------------------------------------------------------------------
private void buttonLogin_Click(object? sender, EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
if (!groupBoxLogin.Enabled)
{
MessageBox.Show("Connect first.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (string.IsNullOrWhiteSpace(textBoxUser.Text) || string.IsNullOrWhiteSpace(textBoxPwd.Text))
{
MessageBox.Show("Username and password are required.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
AppSession.Username = textBoxUser.Text.Trim();
Password = textBoxPwd.Text.Trim();
AppSession.ProducerKey = textBoxProducerKey.Text.Trim();
if (!PerformLogin())
return;
Cursor.Current = Cursors.Default;
DialogResult = DialogResult.OK;
Close();
}
//--------------------------------------------------------------------------
private bool PerformLogin()
{
string authToken = string.Empty;
if (string.IsNullOrEmpty(textBoxUser.Text) || string.IsNullOrEmpty(comboBoxCompany.Text))
{
MessageBox.Show("Select a company.");
return false;
}
string user = textBoxUser.Text;
string company = comboBoxCompany.Text;
using var client = new MicroareaLoginManagerSoapClient(
MicroareaLoginManagerSoapClient.EndpointConfiguration.MicroareaLoginManagerSoap,
$"{AppSession.BaseUrl.TrimEnd('/')}/LoginManager/LoginManager.asmx");
int result = client.LoginCompact(ref user, ref company, Password, AppSession.ProducerKey, false, out authToken);
if (result == 14)
{
var force = MessageBox.Show(
"Session already exists. Do you want to force the login?",
"Simultaneous login",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning);
if (force == DialogResult.Yes)
{
result = client.LoginCompact(ref user, ref company, Password, AppSession.ProducerKey, true, out authToken);
}
}
if (result == 0)
{
AppSession.AuthenticationToken = authToken;
AppSession.Company = company;
AppSession.Username = textBoxUser.Text;
AppSession.ProducerKey = textBoxProducerKey.Text.Trim();
return true;
}
MessageBox.Show($"Failed login. Code: {result}", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
Se la fase di autenticazione va a buon fine viene salvato il codice di autenticazione.
Invio dati dipendente a Perfetto4
Per inviare a Perfetto4 i dati di un documento si deve utilizzare il metodo SetData del Web Service TbService e passare ad esso una stringa xml, formattata secondo il profilo di esportazione, contenente i dati del documento.
Nel codice seguente è mostrato come creare la stringa xml dei dati da inviare, come invocare il metodo SetData impostando i parametri in modo corretto e come mostrare il parametro di output del metodo.
In questo specifico esempio è stato anche implementato un semplice Trace per tenere traccia degli step eseguiti dal metodo:
Esempio C#: esempio di inserimento dati nell'anagrafica di un Tecnico
//--------------------------------------------------------------------------
private void buttonInsert_Click(object? sender, EventArgs e)
{
if ((string.IsNullOrWhiteSpace(textBoxCode.Text)) ||
(textBoxCode.Text.Length > 21))
{
MessageBox.Show("Please enter a valid code for the employee.");
return;
}
string aXMLData = "<?xml version=\"1.0\"?>" +
"<maxs:Employees xmlns:maxs=\"http://www.microarea.it/Schema/2004/Smart/Perfetto/PCore/Employees/Standard/Default.xsd\" tbNamespace=\"Document.Perfetto.PCore.Documents.Employees\" xTechProfile=\"Default\">" +
"<maxs:Data>" +
"<maxs:Employees master=\"true\">" +
"<maxs:Employee>" + System.Security.SecurityElement.Escape(textBoxCode.Text) + "</maxs:Employee>" +
"<maxs:Name>" + System.Security.SecurityElement.Escape(textBoxName.Text) + "</maxs:Name>" +
"<maxs:Address>" + System.Security.SecurityElement.Escape(textBoxAddress.Text) + "</maxs:Address>" +
"<maxs:City>" + System.Security.SecurityElement.Escape(textBoxCity.Text) + "</maxs:City>" +
"<maxs:ZipCode>" + System.Security.SecurityElement.Escape(textBoxZipCode.Text) + "</maxs:ZipCode>" +
"<maxs:Telephone1>" + System.Security.SecurityElement.Escape(textBoxTelephone.Text) + "</maxs:Telephone1>" +
"</maxs:Employees>" +
"</maxs:Data>" +
"</maxs:Employees>";
string aResult = string.Empty;
try
{
DateTime applicationDate = DateTime.Now;
string tbServicesUrl = $"{AppSession.BaseUrl.TrimEnd('/')}/TbServices/TbServices.asmx";
AppendLog("--------------------------------------------------");
AppendLog($"Starting SetData transaction on {tbServicesUrl}");
AppendLog($"Request XML:\n{aXMLData}");
using var client = new TbServicesSoapClient(
TbServicesSoapClient.EndpointConfiguration.TbServicesSoap,
tbServicesUrl);
Stopwatch sw = Stopwatch.StartNew();
bool success = client.SetData(AppSession.AuthenticationToken, aXMLData, applicationDate, 0, false, out aResult);
sw.Stop();
AppendLog($"Transaction completed in {sw.ElapsedMilliseconds} ms.");
AppendLog($"Response XML:\n{aResult}");
if (success)
{
if (string.IsNullOrWhiteSpace(aResult))
{
AppendLog("WARNING: Employee inserted, but no XML details were returned by the service.");
MessageBox.Show("Employee inserted, but no XML details were returned by the service.");
}
else
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(aResult);
XmlNamespaceManager xmlNsManager = new XmlNamespaceManager(doc.NameTable);
xmlNsManager.AddNamespace(doc.DocumentElement.Prefix, doc.DocumentElement.NamespaceURI);
XmlNode emplNode = doc.SelectSingleNode("//maxs:Employees//maxs:Data//maxs:Employees//maxs:Employee", xmlNsManager);
string postedEmployeeCode = emplNode?.InnerText ?? "Unknown Code";
AppendLog($"SUCCESS: Employee '{postedEmployeeCode}' posted correctly.");
MessageBox.Show("Employee posted correctly!");
}
textBoxCode.Clear();
textBoxName.Clear();
textBoxAddress.Clear();
textBoxCity.Clear();
textBoxZipCode.Clear();
textBoxTelephone.Clear();
}
else
{
if (string.IsNullOrWhiteSpace(aResult))
{
AppendLog("ERROR: The webservice failed and returned an empty response.");
MessageBox.Show("Not posted! The webservice failed and returned an empty response.");
}
else
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(aResult);
XmlNamespaceManager xmlNsManager = new XmlNamespaceManager(doc.NameTable);
xmlNsManager.AddNamespace(doc.DocumentElement.Prefix, doc.DocumentElement.NamespaceURI);
XmlNodeList errors = doc.SelectNodes("//maxs:Employees//maxs:Diagnostic//maxs:Errors//maxs:Error", xmlNsManager);
string strMessage = string.Empty;
if (errors != null)
{
foreach (XmlNode node in errors)
{
strMessage += node.SelectSingleNode("maxs:Message", xmlNsManager)?.InnerText + "\n";
}
}
AppendLog($"FAILURE SPECIFIED: {strMessage.Replace("\n", " | ")}");
MessageBox.Show(string.Format("Not posted, some error occurred!\n {0}", strMessage));
}
}
}
catch (Exception tbExc)
{
AppendLog($"EXCEPTION: {tbExc.GetType().Name} - {tbExc.Message}");
MessageBox.Show(string.Format("Exception occurred: {0}", tbExc.Message));
}
}
Disconnessione
Alla chiusura dell'applicazione è necessario disconnettere l'utente dal sistema invocando il metodo LogOff.
Di seguito il codice per eseguire la disconnessione:
private void LogoutCurrentUser()
{
try
{
if (!string.IsNullOrEmpty(AppSession.AuthenticationToken))
{
using var client = new MicroareaLoginManagerSoapClient(
MicroareaLoginManagerSoapClient.EndpointConfiguration.MicroareaLoginManagerSoap,
$"{AppSession.BaseUrl.TrimEnd('/')}/LoginManager/LoginManager.asmx");
client.LogOff(AppSession.AuthenticationToken);
}
}
catch { }
}
Commenti