Difference between revisions of "CSharp:WebAPI Esempi"
From Aino Wiki
(→Controller) |
(No difference)
|
Latest revision as of 18:08, 10 September 2024
Tutorial Microsoft
Video corsi Microsoft
Contents
Partenza
Prima di iniziare diciamo che Visual Studio consente di creare una prima versione in base ad un template standard.
Creare una solution
Creare una nuova solution
Quindi scegliere il nome della solution, la versione del framework etc, quindi:
Una solution potrebbe esser strutturata come segue:
Nel template è inclusa una pagina di partenza come è possibile vedere sotto:
.\Views\Home
, pagina "index.cshtml" che supporta un menu con una pagina elenco delle API esportate ed una pagina di help stessa.
I primi steps saranno aggiungere una classe modello (ovvero una entità quel che sul database potrà corrispondere ad una tabella), ed un controller ovvero una classe con i metodi\azioni che agiranno sul modello.
Controller
Risponde all'esegenza di far compiere azioni alla app Web API, nel segeunte esempio, di costruzione di un controller, esso è implementato in una classe contenete i metodi che eseguiranno le azioni, queste azioni\metodi sono invocate direttamente mediante una URL appositamente costruita e rispondente ad un modello template.
L'implementazione dell'associazione delle azioni, invocate mediante URL, con i metodi nella classe custom controller, avviene mediante automatismi trasparenti e vedremo come etichettare i metodi affinché sia Visual Studio stesso a preoccuparsi di costruirne il collegamento semantico.
Esempio di aggiunta di un controller.
Nel esempio ho aggiunto una cartella, DAL
, con le classi di accesso al DB (MS SQL Server) *DAOed una classe Helper per automatizzare il binding da query verso SQL server.
Nella cartella Controllers
ho aggiunto una classe base cui per comodità si potranno far ereditere da tutti i nuovi controller.
Notare il Web.config
che a sua volta è composto in una versione Debug ed una Release a seconda della compilazione\pubblicazione in debug o release con configurazioni specifiche. Questa soluzione consente di definire una stringa di connessione al DB per il debug ed una per la Release.
Aggiungere librerie
Conviene da subito integrare la solution con funzionalità tipiche provenienti da librerie esterne.
Ad esempio per il debug si può integrare NLog per il logging, Swagger per debuggare\testare i metodi della Web API. Allo scopo basta lanciare il manager dei package di NuGet:
Per accedere alla pagina di test di Swagger dei metodi della Web API basta aggiungere \Swagger all'URL di default, es.:
https://localhost:44368/swagger/ui/index
Web.Config
Per gestire in automatico la versione della stringa di connessione al DB segue un esempio:
web.config
E' necessario comunque definire la sezione di configurazione delle stringa di connessione
<configuration> <appSettings> ... </appSettings> <connectionStrings> <add name="Digitalk_DB" connectionString="Data Source=localhost;Initial Catalog=Digitalk;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /> </connectionStrings> <configuration>
web.Debug.config
Notare il riferimento a "XML-Document-Transform" che indica che si adotterà un motore di sostituzione dell'XML della configurazione affinché si applichi l'automatismo di sostituzione della stringa di connessione come voluto.
l'attributo xdt:Transform="SetAttributes" xdt:Locator="Match(name)"
serve a fare la sostituzione automatica dell'attributo name del TAG connectionStrings
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add name="Digitalk_DB" connectionString="Data Source=NomeServerDebug;Initial Catalog=NomeDB;;User ID=utenteApplicativoDB;Password=passwordUtente;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" /> </connectionStrings> <system.web> ... </system.web> </configuration>
web.Release.config
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings> <add name="Digitalk_DB" connectionString="Data Source=NomeServerProduzione;Initial Catalog=NomeDB;;User ID=utenteApplicativoDB;Password=passwordUtente;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" /> </connectionStrings> <system.web> ... </system.web> </configuration>
HTTP o HTTPS
Link interni:
Esempio semplice
Modificato e adattato da tutorial Microsoft
Model
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WebAPI_ToTestMultiUpdater.Models { public class ShipPackage { public string ShipFullCode { get; set; } public string ShipCode { get; set; } public string CompanyCode { get; set; } public string CompanyName { get; set; } public string PackageFileName { get; set; } } }
Controller
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using WebAPI_ToTestMultiUpdater.Models; namespace WebAPI_ToTestMultiUpdater.Controllers { public class ShipPackagesController : ApiController { ShipPackage[] shipPackages = new ShipPackage[] { new ShipPackage { ShipFullCode = "C_DI", ShipCode = "DI", CompanyCode = "C", CompanyName = "Costa", PackageFileName = "K:\\zighinè\\C_DI_20160518_1619" }, new ShipPackage { ShipFullCode = "C_PA", ShipCode = "PA", CompanyCode = "C", CompanyName = "Costa", PackageFileName = "C:\\KT\\C_PA_20160518_1620" }, new ShipPackage { ShipFullCode = "C_FA", ShipCode = "FA", CompanyCode = "C", CompanyName = "Costa", PackageFileName = "d:\\KT\\C_FA_20160518_1621" }, new ShipPackage { ShipFullCode = "A_ST", ShipCode = "ST", CompanyCode = "A", CompanyName = "Aida", PackageFileName = "A_ST_20160518_1622" } }; public IEnumerable<ShipPackage> GetAllShipPackages() { return shipPackages; } public IHttpActionResult GetShipPackage(string id) // ATTENZIONE il nome della variabile si DEVE chiamare id { var shipPackage = shipPackages.FirstOrDefault((p) => p.ShipFullCode == id); if (shipPackage == null) { return NotFound(); } return Ok(shipPackage); } } }
Client
Supponendo una applicazione client che usi la WebAPI occorre installare e referenziare nella solution del client il pacchetto "Microsoft.AspNet.WebApi.SelfHost", a tal scopo si può usare NuGet. EsempioSegue un pezzo di codice di una mia Windows Form application (molti using non servono):
using NLog; using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System.Diagnostics; using System.Xml; using System.Threading; using Microsoft.Win32; using System.Text.RegularExpressions; using System.Net.Http; using System.Net; using System.Net.Http.Headers; namespace MultiPrepareKTUpdater { // Classe contenitore.... private void BtnMultiCopy_Export_Click(object sender, EventArgs e) { string exportDestinationRootPath = string.Empty; string strOutput = string.Empty; try { Cursor.Current = Cursors.WaitCursor; exportDestinationRootPath = TxtExportDestinationRootPath.Text.Trim(); if (!string.IsNullOrWhiteSpace(exportDestinationRootPath)) { // http://localhost:60098/api/ShipPackage var handler = new HttpClientHandler(); handler.UseDefaultCredentials = true; handler.PreAuthenticate = true; handler.ClientCertificateOptions = ClientCertificateOption.Automatic; //handler.Credentials = new NetworkCredential("test01", "test01"); m_HTTPClient = new HttpClient(handler); m_HTTPClient.BaseAddress = new Uri("http://localhost:60098"); //var resp = m_HTTPClient.GetAsync(string.Format("api/books/{0}", id)).Result; var resp = m_HTTPClient.GetAsync(string.Format("api/ShipPackages")).Result; resp.EnsureSuccessStatusCode(); var shipPackages = resp.Content.ReadAsAsync<IEnumerable<ShipPackage>>().Result; foreach (var p in shipPackages) { //Console.WriteLine("{0} {1} {2} ({3})", p.Id, p.Name, p.Author, p.Rating); strOutput += string.Format("ShipCode = '{0}'\tCompanyCode = '{1}'\tCompanyName = '{2}'\tPackageFileName = '{3}'\r\n", p.ShipCode, p.CompanyCode, p.CompanyName, p.PackageFileName); } MessageBox.Show(string.Format("From Web API:\r\n\r\n{0}", strOutput), string.Format("BtnMultiCopy_Export_Click"), MessageBoxButtons.OK, MessageBoxIcon.Information); } else { Cursor.Current = Cursors.Default; MessageBox.Show(string.Format("Type the root path where copy the configuration files."), string.Format("BtnMultiCopy_Export_Click"), MessageBoxButtons.OK, MessageBoxIcon.Error); } } catch (Exception ex) { Cursor.Current = Cursors.Default; m_loggerForm.Error("Ex.: '{0}'\r\n\r\n{1}", ex.Message, ex.StackTrace); MessageBox.Show(string.Format("{0}", ex.Message), string.Format("BtnMultiCopy_Export_Click"), MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { Cursor.Current = Cursors.Default; Application.DoEvents(); } } } //..... Oggetto da aggiungere da qualche parte. Nota che è ugale all'oggetto inserito nella solution della Web API public class ShipPackage { public string ShipFullCode { get; set; } public string ShipCode { get; set; } public string CompanyCode { get; set; } public string CompanyName { get; set; } public string PackageFileName { get; set; } }
Un altro modo con cui si può chiamare la web API è quello di specificare puntualmente quel che si vuole come id dell'oggetto. Segue URL:
http://localhost:65342/api/ShipPackages/C_FA
Restituirà solo il seguente item XML (è quel che si vedrebbe in un browser):
<ShipPackage xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebAPI_ToTestMultiUpdater.Models"> <CompanyCode>C</CompanyCode> <CompanyName>Costa</CompanyName> <PackageFileName>d:\KT\C_FA_20160518_1621</PackageFileName> <ShipCode>FA</ShipCode> <ShipFullCode>C_FA</ShipFullCode> </ShipPackage>
Esempio POST realistico
E' un metodo POST che genera au file system un file PDF usando la libreria PDFSharp e MiraDoc
using efabbisognoweb.common; using efabbisognoweb.DAL; using efabbisognoweb.Interfaces; using log4net; using MigraDoc.DocumentObjectModel; using MigraDoc.DocumentObjectModel.Shapes; using MigraDoc.DocumentObjectModel.Tables; using MigraDoc.Rendering; using PdfSharp; using PdfSharp.Pdf; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Web.Http; using System.Web.UI; using TheArtOfDev.HtmlRenderer.PdfSharp; namespace efabbisognoweb.api { public class StampeController : ApiController { #region Costanti private static readonly ILog log = LogManager.GetLogger(typeof(StampeController)); private static readonly string c_logo_RelativePath = "\\content\\xxx_logo.jpg"; private static readonly string c_PDF_RelativeOutputPath = "\\DocRepository\\"; // RGB colors Color c_TableBorder = new Color(81, 125, 192); Color c_TableBlue = new Color(235, 240, 249); // Colore dell'intestazione Color c_TableGray = new Color(242, 242, 242); // Colore delle righe pari #endregion string m_logoFullPath = string.Empty; #region Stampa Anteprima Ordini Fornitori /// <summary> /// Dato un JSON in input costruisce un report PDF ponendolo in una cartella convenzionata (dove il clinet si aspetta che ci sia). /// Se tutto va bene in output fornisce il percorso relativo, comprensivo del nome file generato, /// altrimenti fornisce l'errore generato /// </summary> /// <param name="aof">JSON in input</param> /// <returns>percorso relativo, comprensivo del nome file, dove è collocato il file generato</returns> [ActionName("stampa-menu-anteprimaordini")] [Route("stampa-menu-anteprimaordini")] [HttpPost] public HttpResponseMessage Post_Stampa_menu_anteprimaordini_HttpResponse(AnteprimaOrdiniFornitoriIN aof) { log4net.Config.XmlConfigurator.Configure(); HttpResponseMessage cResponse; string fileNameRelativePath = string.Empty; string pdfFileNameFullPath = string.Empty; try { if (aof == null) { throw new Exception("Il JSON di Input risulta vuoto."); } log.InfoFormat("Impianto {0}, dal {1}, al {2}, Nr fornitori {3}, Totale Ordini {4}, User account '{5}'.", aof.codice_impianto, aof.data_dal, aof.data_al, aof.numero_fornitori, aof.totale_ordini, aof.account); // Pulizia fiels vecchi di precedenti elaborazioni int maxMinutesOld = 10; string pathPDF = System.Web.HttpRuntime.AppDomainAppPath + c_PDF_RelativeOutputPath; FileSystemHelper fsh = new FileSystemHelper(log); fsh.PuliziaVecchiFile(pathPDF, "PDF", maxMinutesOld); #region Verifica informazioni propedeutiche if (string.IsNullOrWhiteSpace(aof.codice_impianto)) { throw new Exception("Non è stato indicato in input il codcie impianto."); } if (aof.ordini == null || aof.ordini.Length == 0) { throw new Exception("Non risultano ordini di cui produrre anteprima."); } #endregion CostruisciPDF_AnteprimaOrdini(aof, ref pdfFileNameFullPath); // <-- ! fileNameRelativePath = string.Format("{0}{1}", c_PDF_RelativeOutputPath, Path.GetFileName(pdfFileNameFullPath)); cResponse = new HttpResponseMessage(HttpStatusCode.OK); cResponse.Content = new StringContent(fileNameRelativePath, System.Text.Encoding.Unicode, "text/html"); } catch (Exception e) { string errorMessage = string.Format("Path relativo PDF: '{0}'. Errore generico {1}, {2}", pdfFileNameFullPath, e.HResult, e.Message); log.ErrorFormat(errorMessage); cResponse = new HttpResponseMessage(HttpStatusCode.InternalServerError); cResponse.Content = new StringContent(errorMessage, System.Text.Encoding.Unicode, "text/html"); } return cResponse; } private MemoryStream CostruisciPDF_AnteprimaOrdini(AnteprimaOrdiniFornitoriIN aof, ref string pdfFileNameFullPath, bool pdfStreamOut = false) { MemoryStream stream = new MemoryStream(); try { InfoColonna[] infoTabColonne; #region Definizione array delle colonne delle tabelle di dati infoTabColonne = new InfoColonna[] { new InfoColonna { Label = "Cod.Art.", Ampiezza = "2.2cm", AllineamentoOrizzontale = ParagraphAlignment.Center, AllineamentoVerticale = VerticalAlignment.Center }, new InfoColonna { Label = "Articolo", Ampiezza = "7.3cm", AllineamentoOrizzontale = ParagraphAlignment.Left, AllineamentoVerticale = VerticalAlignment.Center }, new InfoColonna { Label = "U.M.", Ampiezza = "1.2cm", AllineamentoOrizzontale = ParagraphAlignment.Center, AllineamentoVerticale = VerticalAlignment.Center }, new InfoColonna { Label = "M.Imb.", Ampiezza = "2cm", AllineamentoOrizzontale = ParagraphAlignment.Right, AllineamentoVerticale = VerticalAlignment.Center }, new InfoColonna { Label = "Prezzo", Ampiezza = "2.3cm", AllineamentoOrizzontale = ParagraphAlignment.Right, AllineamentoVerticale = VerticalAlignment.Center }, new InfoColonna { Label = "Q.tà", Ampiezza = "1.7cm", AllineamentoOrizzontale = ParagraphAlignment.Right, AllineamentoVerticale = VerticalAlignment.Center }, new InfoColonna { Label = "Costo", Ampiezza = "2.7cm", AllineamentoOrizzontale = ParagraphAlignment.Right, AllineamentoVerticale = VerticalAlignment.Center } }; #endregion var currentApp = System.Web.HttpRuntime.AppDomainAppPath; m_logoFullPath = currentApp + c_logo_RelativePath; Document pdfDocument = new Document(); pdfDocument.Info.Title = "Anteprima Ordini"; pdfDocument.Info.Subject = string.Format("Anteprima ordini del {0}. Utente '{1}'", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss.fff"), aof.account); pdfDocument.Info.Author = "yyy"; string codiceImpianto = aof.codice_impianto; Section section = new Section(); //----------------------------------------------------------------------- DefineStyles(ref pdfDocument); CreatePage(ref pdfDocument, ref section, infoTabColonne, codiceImpianto); FillContent(aof, ref section, infoTabColonne); //----------------------------------------------------------------------- // Create a renderer for PDF that uses Unicode font encoding PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(true); // Set the MigraDoc document pdfRenderer.Document = pdfDocument; // Create the PDF document pdfRenderer.RenderDocument(); string nomeFilePDF = string.Format("AnteprimaOrdini_{0}.pdf", Guid.NewGuid()); pdfFileNameFullPath = string.Format("{0}{1}{2}", currentApp, c_PDF_RelativeOutputPath, nomeFilePDF); #region Salva il PDF if (pdfStreamOut) { // Salva nel memory stream pdfRenderer.Save(stream, false); // Salva su FileSystem using (var fileStream = new FileStream(pdfFileNameFullPath, FileMode.CreateNew)) { // write to just created file stream.WriteTo(fileStream); } } else { pdfRenderer.Save(pdfFileNameFullPath); } #endregion } catch (Exception e) { log.ErrorFormat("Errore generico {0}, {1}", e.HResult, e.Message); throw; } return stream; } #region PDF Anteprima Ordini private void DefineStyles(ref Document pdfDocument) { // Si allargano i margini utili pdfDocument.DefaultPageSetup.LeftMargin = 20; pdfDocument.DefaultPageSetup.RightMargin = 20; //pdfDocument.DefaultPageSetup.HeaderDistance = "6.3cm"; // 1.3 Distance between header and pageTop of the pages //pdfDocument.DefaultPageSetup.PageHeight = "10cm"; // E' l'altezza complessiva della pagina // Get the predefined style Normal. Style style = pdfDocument.Styles["Normal"]; // Because all styles are derived from Normal, the next line changes the // font of the whole document. Or, more exactly, it changes the font of // all styles and paragraphs that do not redefine the font. style.Font.Name = "Verdana"; style = pdfDocument.Styles[StyleNames.Header]; style.ParagraphFormat.AddTabStop("16cm", TabAlignment.Right); // Cos'è un TabStop ?????????????????? style = pdfDocument.Styles[StyleNames.Footer]; style.ParagraphFormat.AddTabStop("8cm", TabAlignment.Center); // Create a new style called Table based on style Normal style = pdfDocument.Styles.AddStyle("Table", "Normal"); style.Font.Name = "Verdana"; style.Font.Size = 9; // Create a new style called Reference based on style Normal style = pdfDocument.Styles.AddStyle("Reference", "Normal"); style.ParagraphFormat.SpaceBefore = "5mm"; style.ParagraphFormat.SpaceAfter = "5mm"; style.ParagraphFormat.TabStops.AddTabStop("16cm", TabAlignment.Right); } private void CreatePage(ref Document pdfDocument, ref Section section, InfoColonna[] infoTabColonne, string codiceImpianto) { #region doc /* Document * L-> Section * | * Headers.Primary * +--> Image (LOGO) * +--> TextFrame * +--> Paragraph (TITOLO) * +--> Text * +--> Table (Tabella di inizioPagina) * | * +--> Table (Prima tabella nel corpo della prima pagina) * | * Footers.Primary * +--> Paragraph * +--> Text (PIEDE PAGINA) */ #endregion try { // Each MigraDoc document needs at least one SECTION !!! section = pdfDocument.AddSection(); // You have to set the TopMargin of the PageSetup to reserve space for the header. section.PageSetup.TopMargin = Unit.FromCentimeter(3.97); // http://forum.pdfsharp.net/viewtopic.php?p=3077 // [Section].PageSetup.BottomMargin = Unit.FromCentimeter(x) #region Intestazione #region LOGO // Put a logo in the header Image imageLogo = section.Headers.Primary.AddImage(m_logoFullPath); // Ex.: "../../PowerBooks.png"); imageLogo.Height = "1.7cm"; // Ex 2.5cm imageLogo.LockAspectRatio = true; // Proprorzioni dell'immagine imageLogo.RelativeVertical = RelativeVertical.Line; imageLogo.RelativeHorizontal = RelativeHorizontal.Margin; imageLogo.Top = ShapePosition.Top; imageLogo.Left = ShapePosition.Left; // Ex. ShapePosition.Right; imageLogo.WrapFormat.Style = WrapStyle.TopBottom; // ex. WrapStyle.Through; #endregion #region Aggiunta TITOLO: Nome doc + Intestazione tabella TextFrame titoloFrame = section.Headers.Primary.AddTextFrame(); titoloFrame.WrapFormat.Style = WrapStyle.Through;// <--- tentativo per evitare la sovrascrittura in seconda pagina titoloFrame.Height = "5.0cm"; // Ex.: 3.0cm titoloFrame.Width = "19.6cm"; //Ex. 7.0cm titoloFrame.Left = ShapePosition.Center; // Ex.: ShapePosition.Left; titoloFrame.RelativeHorizontal = RelativeHorizontal.Margin; titoloFrame.Top = "2.3cm"; // Distanza dal TOP // Ex.: "5.0cm" OK 2.6cm titoloFrame.RelativeVertical = RelativeVertical.Page; // Riempimento del Titolo text frame Paragraph paragraphTitolo = titoloFrame.AddParagraph(); paragraphTitolo.Format.Font.Bold = true; paragraphTitolo.Format.Font.Size = 12; paragraphTitolo.Format.Alignment = ParagraphAlignment.Center; paragraphTitolo.AddText("Anteprima Ordini"); paragraphTitolo.AddLineBreak(); Font fontCodImpiantolABEL = new Font(); // ToDo Togliere da qui e mettere nel metodo DefineStyles fontCodImpiantolABEL.Bold = true; fontCodImpiantolABEL.Size = 9; paragraphTitolo.AddFormattedText("Impianto: ", fontCodImpiantolABEL); Font fontCodImpianto = new Font(); // ToDo Togliere da qui e mettere nel metodo DefineStyles fontCodImpianto.Bold = false; fontCodImpianto.Size = 10; paragraphTitolo.AddFormattedText(codiceImpianto, fontCodImpianto); // objAnteprimaOrdini.codice_impianto, fontCodImpianto); #endregion //----------------------- //ex Table tabellaHeader = section.Headers.Primary.AddTable(); Table tabellaHeader = titoloFrame.AddTable(); DefinizioneIntestazioneTabella(ref tabellaHeader, infoTabColonne); double topPadding = 3.8; RiempieIntestazioneTabellaHeader(ref tabellaHeader, infoTabColonne, topPadding); #endregion #region Pie' di pagina: Data e nr Pagina // Create footer Paragraph paragraph = section.Footers.Primary.AddParagraph(); paragraph.Format.Alignment = ParagraphAlignment.Left; paragraph.AddText(string.Format("{0}", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"))); // Ex.: "PowerBooks Inc · Sample Street 42 · 56789 Cologne · Germany"); paragraph.AddTab(); paragraph.AddTab(); paragraph.AddTab(); paragraph.AddTab(); paragraph.AddTab(); paragraph.AddTab(); paragraph.AddTab(); paragraph.AddTab(); paragraph.AddText("Pagina "); paragraph.AddPageField(); paragraph.AddText(" di "); paragraph.AddNumPagesField(); paragraph.Format.Font.Size = 9; #endregion } catch (Exception e) { log.ErrorFormat("Errore {0}, {1}", e.HResult, e.Message); throw; } } private void FillContent(AnteprimaOrdiniFornitoriIN aof, ref Section section, InfoColonna[] infoTabColonne) { string codiceFornitore = string.Empty; string dataConsegna = string.Empty; try { IFormatProvider culture = new System.Globalization.CultureInfo("it-IT", true); int numero_fornitori = aof.numero_fornitori; decimal totale_ordini= aof.totale_ordini; Table table = new Table(); Paragraph paragrafoRighaVuota = new Paragraph(); // Per ogni ordine a fornitore (ci posson essere +ordini per stesso fornitore, l'ordinamento è per data) foreach (OrdineFornitore of in aof.ordini.OrderBy(x => DateTime.Parse(x.data_consegna, culture, System.Globalization.DateTimeStyles.AssumeLocal))) { table = section.AddTable(); DefinizioneIntestazioneTabella(ref table, infoTabColonne); RiempieIntestazioneTabellaDati(ref table, of); codiceFornitore = of.codice_fornitore; dataConsegna = of.data_consegna; RiempieTabellaDati(ref table, codiceFornitore, dataConsegna, of); paragrafoRighaVuota = table.Section.AddParagraph(" "); } #region Tabella RIEPILOGO table = section.AddTable(); DefinizioneIntestazioneTabella(ref table, infoTabColonne); Row row = table.AddRow(); row.Format.Font.Bold = true; row.Shading.Color = c_TableBlue; // Colore di sfondo della intestazione row.Cells[0].AddParagraph(string.Format("Nr Fornitori: {0}", aof.numero_fornitori)); row.Cells[0].MergeRight = 3; // Unisce sino alla colonna 3 ovvero del M.Imb row.Cells[0].Format.Alignment = ParagraphAlignment.Left; row.Cells[0].Format.Borders.Right.Visible = false; // Non funziona row.Cells[4].AddParagraph(string.Format("Totale Ordini")); row.Cells[4].MergeRight = 1; // Unisce sino alla colonna 5 ovvero del Q.tà row.Cells[4].Format.Alignment = ParagraphAlignment.Right; row.Cells[4].Format.Borders.Left.Visible = false; // Non funziona row.Cells[6].AddParagraph(aof.totale_ordini.ToString("0.0000")); row.Cells[6].Format.Alignment = ParagraphAlignment.Right; row.Cells[6].Format.Borders.Left.Visible = false; // Non funziona #endregion } catch (Exception e) { log.ErrorFormat("Codice Fornitore {0}, DataConsegna {1}. Errore {0}, {1}", codiceFornitore, dataConsegna, e.HResult, e.Message); throw; } } #region Metodi di servizio /// <summary> /// Assegna lo stile generale della tabella e poi definisce le colonne in base a "infoTabColonne", /// per ciascuna colonna si definisce l'ampiezza e l'allineamento. /// La tabella occuperà l'intero rigo utile della pagina che si presume sia 19.5 centimetri /// </summary> /// <param name="table"></param> /// <param name="infoTabColonne"></param> private void DefinizioneIntestazioneTabella(ref Table table, InfoColonna[] infoTabColonne) { try { // ATTENZIONE la posizione della seguuente tabella dipende dal fatto // che nelle istruzioni che precedono si sia aggiuto un PARAGRAFO // Create the item table table.Style = "Table"; table.Borders.Color = c_TableBorder; table.Borders.Width = 0.25; table.Borders.Left.Width = 0.5; table.Borders.Right.Width = 0.5; table.Rows.LeftIndent = 0; // Before you can add a row, you must define the columns // ATTENZIONE attualmente l'ampiezza della pagina è di 19.5cm #region Aggiunta delle colonne alla tabella Column column; for (int i = 0; i < infoTabColonne.Length; i++) { column = table.AddColumn(infoTabColonne[i].Ampiezza); column.Format.Alignment = infoTabColonne[i].AllineamentoOrizzontale; } #endregion } catch (Exception e) { log.ErrorFormat("Errore {0}, {1}", e.HResult, e.Message); throw; } } private void RiempieIntestazioneTabellaHeader(ref Table table, InfoColonna[] infoTabColonne, double padding = 1.5) { try { // Create the header of the table #region Riga INTESTAZIONE Tabella // PRIMO RIGO rigo di intestazione Row row = table.AddRow(); row.HeadingFormat = true; // <-- if you set this, for the first n rows of your table, you mark this rows as header rows !!! row.Format.Alignment = ParagraphAlignment.Center; row.Format.Font.Bold = true; row.Shading.Color = c_TableBlue; // Colore di sfondo della intestazione if (padding != 1.5) { row.TopPadding = padding; row.BottomPadding = padding; } for (int i = 0; i < infoTabColonne.Length; i++) { row.Cells[i].AddParagraph(infoTabColonne[i].Label); // Testo intestazione row.Cells[i].Format.Alignment = infoTabColonne[i].AllineamentoOrizzontale; row.Cells[i].VerticalAlignment = infoTabColonne[i].AllineamentoVerticale; } #endregion // Impostazione del bordo table.SetEdge(0, 0, infoTabColonne.Length, 1, Edge.Box, BorderStyle.Single, 0.75, Color.Empty); } catch (Exception e) { log.ErrorFormat("Errore {0}, {1}", e.HResult, e.Message); } } private void RiempieIntestazioneTabellaDati(ref Table table, OrdineFornitore of) { try { // Create the header of the table #region Riga INTESTAZIONE Tabella // PRIMO RIGO rigo di intestazione Row row = table.AddRow(); row.HeadingFormat = true; // <-- if you set this, for the first n rows of your table, you mark this rows as header rows !!! row.Format.Alignment = ParagraphAlignment.Center; row.Format.Font.Bold = true; row.Shading.Color = c_TableBlue; // Colore di sfondo della intestazione row.Cells[0].AddParagraph(string.Format("{0} - {1}", of.codice_fornitore, of.descrizione_fornitore)); row.Cells[0].MergeRight = 5; // Unisce sino alla colonna 5 ovvero del Costo row.Cells[0].Format.Alignment = ParagraphAlignment.Left; row.Cells[0].Format.Borders.Right.Visible = false; // Non funziona row.Cells[6].AddParagraph(string.Format("{0}", of.data_consegna)); row.Cells[6].Format.Alignment = ParagraphAlignment.Right; row.Cells[6].Format.Borders.Left.Visible = false; // Non funziona #endregion // Impostazione del bordo table.SetEdge(0, 0, 7, 1, Edge.Box, BorderStyle.Single, 0.75, Color.Empty); } catch (Exception e) { log.ErrorFormat("Errore {0}, {1}", e.HResult, e.Message); //throw; } } private void RiempieTabellaDati(ref Table table, string codiceFornitore, string dataConsegna, OrdineFornitore of) { string ultimoCodiceArticolo = string.Empty; int rigo = 0; try { foreach (ArticoloFornitore a in of.articoli) { rigo++; Row row = table.AddRow(); ultimoCodiceArticolo = a.codice_articolo; // Le pagine pari avranno lo sfondo in grigio per facilitare la lettura if (rigo % 2 == 0) { row.Shading.Color = c_TableGray; // Colore di sfondo } row.Cells[0].AddParagraph(a.codice_articolo); // Codice Articolo row.Cells[0].Format.Alignment = ParagraphAlignment.Center; row.Cells[1].AddParagraph(a.descrizione_articolo); // Descrizione articolo row.Cells[1].Format.Alignment = ParagraphAlignment.Left; row.Cells[2].AddParagraph(a.unita_misura); // UM row.Cells[2].Format.Alignment = ParagraphAlignment.Center; row.Cells[3].AddParagraph(a.imballo_minimo.ToString("0.00")); // M.Imb. row.Cells[3].Format.Alignment = ParagraphAlignment.Right; row.Cells[4].AddParagraph(a.prezzo.ToString("0.00")); // Prezzo row.Cells[4].Format.Alignment = ParagraphAlignment.Right; row.Cells[5].AddParagraph(a.quantita_ordine.ToString("0.00")); // Quantità row.Cells[5].Format.Alignment = ParagraphAlignment.Right; row.Cells[6].AddParagraph(a.costo_totale.ToString("0.0000")); // Costo row.Cells[6].Format.Alignment = ParagraphAlignment.Right; // Impostazione del bordo //table.SetEdge(0, table.Rows.Count - 1, 7, 2, Edge.Box, BorderStyle.Single, 0.75); } // Ultima riga con il totale Row rowRecap = table.AddRow(); rowRecap.Cells[0].AddParagraph(string.Format("Totale ordine Fornitore:")); rowRecap.Cells[0].MergeRight = 5; // Unisce sino alla colonna 5 ovvero del Costo rowRecap.Cells[0].Format.Alignment = ParagraphAlignment.Right; rowRecap.Cells[0].Format.Borders.Right.Visible = false; // Non funziona rowRecap.Cells[6].AddParagraph(string.Format("{0}", of.totale_ordine_fornitore.ToString("0.0000"))); rowRecap.Cells[6].Format.Alignment = ParagraphAlignment.Right; rowRecap.Cells[6].Format.Borders.Left.Visible = false; // Non funziona // Impostazione del bordo table.SetEdge(0, table.Rows.Count - 1, 7, 1, Edge.Box, BorderStyle.Single, 0.75, Color.Empty); } catch (Exception e) { log.ErrorFormat("Fornitore {0}, DataConsegna {1}, Ultimo Articolo {2}. Errore {3}, {4}", codiceFornitore, dataConsegna, ultimoCodiceArticolo, e.HResult, e.Message); } } #endregion #endregion #endregion #region Oggetti per le tabelle PDF MigraDoc private class InfoColonna { public string Label { get; set; } /// <summary> /// With della colonna, es.: "1.7cm" /// </summary> public string Ampiezza { get; set; } public ParagraphAlignment AllineamentoOrizzontale { get; set; } public VerticalAlignment AllineamentoVerticale { get; set; } } #endregion } }
Post o Get
Un metodo di default è interpretato come POST, se lo si vuole invece come GET occorrerà usare l'attributo di direttiva [GET]. Segue esempio di POST:
using System; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.ServiceModel.Channels; using System.Web; using System.Web.Http; using VF_Digitalk_Model; namespace WebAPISrv_455_Simulator.Controllers { public class DonationController : ApiController { [System.Web.Http.Route("ivr_donate")] public HttpResponseMessage Donate(string msisdn, string user_check_id, string amount_id, string short_numner) { //Es: https://localhost:44356/ivr_donate?msisdn=12345&user_check_id=666&amount_id=5&short_numner=45566 HttpResponseMessage response = new HttpResponseMessage(); DateTime startExec = DateTime.Now; DonationResponseOutput objOut = new DonationResponseOutput(); try { m_logger.Info("Controller - ivr_donate - Ver. {0}\t\tClient IP {1}" , System.Reflection.Assembly.GetExecutingAssembly().GetName().Version , GetClientIp()); objOut.ResultCode = "0"; objOut.TransactionID = GenerateTransactionId(); response = Request.CreateResponse(HttpStatusCode.OK, objOut); } catch (Exception ex) { m_logger.Error(ex); objOut.ResultCode = "1"; response = Request.CreateResponse(HttpStatusCode.InternalServerError, objOut); //? ok ? } response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); m_logger.Debug("Execution duration: {0}\"\r\n\r\n\r\n" , DateTime.Now.Subtract(startExec).TotalSeconds); return response; } #region Private methods private string GenerateTransactionId() { string transactionId = "000000"; int range = 999999; Random r = new Random(); double rDouble = r.NextDouble() * range; //for doubles transactionId = (rDouble.ToString() + transactionId).Substring(0, 6); return transactionId; } private string GetClientIp(HttpRequestMessage request = null) { try { request = request ?? Request; if (request.Properties.ContainsKey("MS_HttpContext")) { return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress; } else if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name)) { RemoteEndpointMessageProperty prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name]; return prop.Address; } else if (HttpContext.Current != null) { return HttpContext.Current.Request.UserHostAddress; } } catch (Exception ex) { m_logger.Error(ex); } return string.Empty; } #endregion } }
ATTENZIONE stesso ed identico codice ma con metodo che sarà interpretato come GET
//... public class DonationController : ApiController { [HttpGet] [System.Web.Http.Route("ivr_donate")] public HttpResponseMessage Donate(string msisdn, string user_check_id, string amount_id, string short_numner) { //Es: https://localhost:44356/ivr_donate?msisdn=12345&user_check_id=666&amount_id=5&short_numner=45566 HttpResponseMessage response = new HttpResponseMessage(); DateTime startExec = DateTime.Now; DonationResponseOutput objOut = new DonationResponseOutput(); try { m_logger.Info("Controller - ivr_donate - Ver. {0}\t\tClient IP {1}" , System.Reflection.Assembly.GetExecutingAssembly().GetName().Version , GetClientIp()); objOut.ResultCode = "0"; objOut.TransactionID = GenerateTransactionId(); response = Request.CreateResponse(HttpStatusCode.OK, objOut); } catch (Exception ex) { m_logger.Error(ex); objOut.ResultCode = "1"; response = Request.CreateResponse(HttpStatusCode.InternalServerError, objOut); //? ok ? } response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); m_logger.Debug("Execution duration: {0}\"\r\n\r\n\r\n" , DateTime.Now.Subtract(startExec).TotalSeconds); return response; } //...etc }
Sarà richiamabile come segue:
https://localhost:56544/ivr_donate?msisdn=12345&user_check_id=666&amount_id=5&short_numner=45566
Notare la query string! In effetti usare la GET è più comoda perché non si dovrà comporre un JSON per inviare i 5 parametri invece passati via query string.
Mappa e Link
WEB API | WebAPI Esempi | C# | Teoria