Serialisatie en deserialisatie in C#
- Inleiding
- Distributed applications
- Serialiseren en Deserialiseren
- Technologieën voor Distributed applications
- Web services met XML
- Web API met JSON
- Slot
Inleiding
Gesloten gecentraliseerde systemen (mainframes) domineren al lang niet meer het ICT landschap. Systemen kunnen her en der over de planeet verspreid zijn waarbij ze via het internet contact met elkaar maken. Het contact gaat vaak gepaard met het uitwisselen van gegevens waarvoor dingen geserialiseerd en gedeserialiseerd moeten worden.
Systemen kunnen voor hun interactie gebruik maken van talloze technologieën. In deze post demonstreren we de Web Service waarbij XML als berichtformaat wordt gebruikt. Verder geven we een demo aan de hand van een Web API waarbij JSON als berichtformaat wordt gebruikt.
Distributed applications
We zagen in de post over TCP/IP dat systemen via een open TCP / IP netwerk met elkaar in verbinding kunnen staan waarbij over en weer gegevens worden uitgewisseld.
Een “distributed” applicatie is een applicatie dat in meerdere delen is opgesplitst. De applicatie onderdelen kunnen op dezelfde computer gehuisvest zijn, maar ze kunnen zich ook op systemen bevinden die her en der over de planeet zijn verspreid. Deze “globalisering” hoeft vanuit technisch oogpunt geen probleem te zijn omdat de systemen via het internet met elkaar verbonden kunnen worden. Distributed applications worden ook wel Connected systems genoemd.
Web applicaties voor web winkels kunnen beschouwd worden als distributed applications. Dit omdat in de meeste gevallen het betalingsgedeelte is uitbesteed aan een andere partij (iDeal, PayPal). Een partij dat volledig is gespecialiseerd in het doen van betalingen waarbij de systemen op een server in het buitenland kunnen staan.
Serialiseren en Deserialiseren
Op een server staat dus allerlei software dat bezig is voor andere software (clients). Je kan als client via het internet contact leggen met een programma op een server, maar het programma op de server moet je dan wel kunnen begrijpen. De client en server moeten dezelfde “taal” spreken.
Clients en servers hebben hun objecten en men wil een object naar een ontvanger sturen omdat die ontvanger iets met dat object moet doen. De objecten kun je meestal niet direct naar de ontvanger sturen omdat de ontvanger misschien wel een andere technologie gebruikt waardoor hij het object niet kan lezen. Je zal een object dus moeten omzetten naar iets met een universeel tussenformaat.
Men noemt het “verzendklaar” maken van objecten serialiseren. Daarbij wordt een object geserialiseerd naar een universeel berichtformaat en alles wordt in dat berichtformaat naar een ontvanger gestuurd. Het “uitpakken” van objecten noemt men deserialiseren. Daarbij komt een “pakketje” binnen in een universeel berichtformaat en dat “pakketje” ga je dan omzetten naar een object waarbij dat object een formaat heeft dat gangbaar is binnen het systeem van de ontvanger.
XML (eXtensible Markup Language) en JSON (JAvaScript Object Notation) zijn momenteel de meest gebruikte universele berichtformaten. De meeste clients en servers kunnen overweg met XML en JSON.
Technologieën voor distributed applications
Je kan inmiddels iedereen wereldwijd per email bereiken dankzij het internet en wat je van die persoon wil, dat verwoord je in een tekst waarbij je Latijnse letters gebruikt. Zo gezegd zo gedaan, een persoon krijgt een email waardoor hij / zij weet dat iemand iets van hem/haar wil en de tekst is ook enigszins leesbaar want het zijn Latijnse tekens en die tekens worden door de meeste character encoding tabellen en fonts ondersteund.
Maar dan ben je er nog niet want wat als het bericht is opgesteld in het Nederlands, maar de ontvanger is een Finse dame? De mail bestaat weliswaar uit Latijnse karakters en die komen ook in het Fins voor, maar het bericht zegt de goede dame uit Finland nog steeds niks.
Er moet een taal gebruikt worden dat allebei de partijen begrijpen en dat kan bijvoorbeeld het Engels zijn. Als we de vergelijking doortrekken naar de diverse technologieën voor distributed applications dan staat het Engels voor bijvoorbeeld de Web API technologie waarbij berichten worden uitgewisseld in universele berichtformaten zoals JSON of XML. De partijen begrijpen elkaar als allebei de partijen uitgaan van een in het Engels geschreven brief / Web API met een universeel JSON of XML berichtformaat.
Heel wat technieken voor distributed applications hebben in de spotlights gestaan of staan nog steeds in de spotlights en de “hall of fame” bestaat uit illustere namen als Enterprise Services, Dot Net Remoting, MSMQ, Web Services, WCF en Web API.
Technologieën komen en gaan, maar er zijn genoeg bedrijfskritieke systemen te vinden die naar tevredenheid gebruik maken van een legacy technologie. In veel gevallen een technologie dat door iedereen is afgeschreven en waar iedereen het liefst van af wil, maar niet van af raakt omdat veel bedrijfskritieke systemen er nog gebruik van maken.
In deze post demonstreren we de Web Service (een technologie dat op het moment van het schrijven van deze post al behoorlijk legacy is?) waarbij XML als berichtformaat wordt gebruikt en we geven een demo aan de hand van een Web API waarbij JSON als berichtformaat wordt gebruikt.
Web services met XML
Als je je applicatie “distributed” wilt maken dan kan je bijvoorbeeld gebruik maken van asmx web services. De asmx web service staat dan ergens op een server en een client kan de web service aanroepen. We creëren voor de demo een solution in Visual Studio waarbij de solution uit deze projecten bestaat:
Klasse
In de Class Library definiëren we klasse Eigenaar. De clients die een beroep doen op de web service zullen uiteindelijk XML ontvangen waarbij ze de XML naar deze klasse moeten deserialiseren.
namespace deClassLibrary
{
public class Eigenaar
{
// Backing Variables
private string _omschrijving;
private string _regio;
private int _id;
private string _abonnement;
// Lege Constructor
public Eigenaar() {}
// Constructor
public Eigenaar(int id, string omschrijving,
string regio, string abonnement)
{
_id = id;
_omschrijving = omschrijving;
_regio = regio;
_abonnement = abonnement;
}
public int Id
{
get { return _id; }
set { _id = value; }
}
public string Omschrijving
{
get { return _omschrijving; }
set { _omschrijving = value; }
}
public string Regio
{
get { return _regio; }
set { _regio = value; }
}
public string Abonnement
{
get { return _abonnement; }
set { _abonnement = value; }
}
}
}
Web Service
De asmx web service bestaat uit Web Methode EigenaarOpvragen en een client zal deze web methode aanroepen. De web methode serialiseert met XMLSerializer een object naar XML en de methode retourneert vervolgens de XML. De client zal de ontvangen XML weer deserialiseren .
using System;
using System.IO;
using System.Web.Services;
using System.Xml;
using System.Xml.Serialization;
using deClassLibrary;
namespace Serialisatie
{
/// <summary>
/// Summary description for EigenaarWebService
/// </summary>
[WebService(Namespace
= "http://MRAsoft.nl/webservice/")]
[WebServiceBinding(ConformsTo
= WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called
// from script, using ASP.NET AJAX,
// uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class EigenaarWebService
: System.Web.Services.WebService
{
[WebMethod]
public XmlDocument EigenaarOpvragen(int id)
{
// Het object
Eigenaar eigenaar
= new Eigenaar(
id: id,
omschrijving: "Sandra's Auto",
regio: "Noord",
abonnement: "Goud");
// Object serialiseren naar XML
// en in het geheugen zetten
MemoryStream memoryStream
= new MemoryStream();
XmlSerializer xmlSerializer
= new XmlSerializer(typeof(Eigenaar));
xmlSerializer.Serialize(memoryStream, eigenaar);
// XML vanuit geheugen toekennen aan XmlDocument
memoryStream.Position = 0;
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(memoryStream);
// XMLDocument naar client sturen
return xmlDocument;
}
}
}
We kunnen de asmx web service openen in een browser en we krijgen dan onderstaand dialoogscherm te zien. We kunnen de asmx web service vanuit dat dialoogscherm testen.
We klikken op de Invoke-button en we zien dat de output van de asmx web service XML is:
Console applicatie
Een console applicatie gaat in dit voorbeeld gebruik maken van de web service en de console applicatie is in dit geval dan ook de client. Met Add Service Reference leggen we voor de client een link naar de web service zodat de client gebruik kan maken van de web service. We zien ook web methode EigenaarOpvragen en dat is de web methode die in dit voorbeeld door de client wordt aangeroepen.
En ten slotte de console applicatie die gebruik gaat maken van de web service en methode EigenaarOpvragen zal aanroepen. Het antwoord van de server wordt met XMLSerializer weer gedeserialiseerd naar een object.
using System;
using System.IO;
using System.Xml.Serialization;
using deClassLibrary;
namespace deConsoleApplicatie
{
class Program
{
static void Main(string[] args)
{
// input
int id;
id = 123;
// Maak verbinding met de Web Service
deWebService
.EigenaarWebServiceSoapClient client
= new deWebService
.EigenaarWebServiceSoapClient();
// Roep de Webservice aan
Console.WriteLine(
"We roepen de Web service
aan met id = {0}.\r\n", id);
Console.WriteLine(
"En we krijgen dit terug:\r\n", id);
string ontvangenXML
= @Convert.ToString
(client.EigenaarOpvragen(id));
Console.WriteLine(ontvangenXML);
// Deserialiseer naar Object
Console.WriteLine(
"\r\nWat we deserialiseren
naar een object:\r\n");
XmlSerializer xmlSerializerEigenaar
= new XmlSerializer(typeof(Eigenaar));
StringReader stringreaderEigenaar
= new StringReader(ontvangenXML);
Eigenaar eigenaar_deserialized
= (Eigenaar)xmlSerializerEigenaar
.Deserialize(stringreaderEigenaar);
// Resultaat
Console.WriteLine("id {0}", id);
Console.WriteLine(
"- heeft betrekking op {0}",
eigenaar_deserialized
.Omschrijving);
Console.WriteLine(
"- de persoon komt uit regio {0}",
eigenaar_deserialized.Regio);
Console.WriteLine(
"- en heeft abonnement {0}",
eigenaar_deserialized.Abonnement);
Console.WriteLine(
"\r\nHit any key to continue...");
Console.ReadKey();
}
}
}
Resultaat
Resultaat, we laten zien wat we van de web service ontvangen en hoe het is deserialiseerd naar een object.
We roepen de Web service aan met id = 123.
En we krijgen dit terug:
<Eigenaar xmlns:xsi="http://www.w3.org/
2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="">
<Id>123</Id>
<Omschrijving>Sandra's Auto</Omschrijving>
<Regio>Noord</Regio>
<Abonnement>Goud</Abonnement>
</Eigenaar>
Wat we deserialiseren naar een object:
id 123
- heeft betrekking op Sandra's Auto
- de persoon komt uit regio Noord
- en heeft abonnement Goud
Hit any key to continue...
We hebben in bovenstaand voorbeeld voor het serialiseren en het deserialiseren de XMLSerializer gebruikt. Een bekende andere serializer is de DataContractSerializer. De DataContractSerializer heeft wat meer mogelijkheden t.o.v. de XMLSerializer en de DataContractSerializer wordt met name bij WCF applicaties gebruikt.
Web API met JSON
Als je je applicatie “distributed” wilt maken dan kan je ook gebruik maken van “Web API“. Een client kan dan een programma aanroepen dat ergens op een server staat en het heeft via een Web API (application programming interface) toegang tot dat programma. We creëren voor de demo een Web API solution in Visual Studio:
Web API
Via een Web API wordt uiteindelijk programma EigenaarOpvragen aangeroepen. Programma EigenaarOpvragen is geen web pagina. Het programma stuurt alleen resultaten in JSON formaat naar de browser. Het programma zelf wordt in tegenstelling tot een web pagina niet naar de browser op een lokale PC gestuurd.
In programma EigenaarOpvragen serialiseren we object Eigenaar naar JSON en we maken daarvoor gebruik van James Newton-King’s NewtonSoft library. Zie voor de klassendefinitie van klasse/object Eigenaar de listing in het Web Service voorbeeld. We hebben voor het Web API voorbeeld dezelfde klassendefinitie gebruikt. Het geserialiseerde wordt uiteindelijk naar de client gestuurd.
using System.Web.Http;
using System.Diagnostics;
using Newtonsoft.Json;
using deClassLibrary;
namespace Serialisatie.Controllers
{
public class EigenaarController : ApiController
{
[HttpGet]
[Route("api/EigenaarOpvragen")]
public string EigenaarOpvragen([FromUri]int id)
{
// Inkomend
Debug.WriteLine("Inkomende id:{0}",id);
// Het object
Eigenaar eigenaar =
new Eigenaar(
id: id,
omschrijving: "Sandra's Auto",
regio: "Noord",
abonnement: "Goud");
// We gebruiken James Newton-King's
// Newtonsoft library
// om te serialiseren
// Retourneer
return JsonConvert
.SerializeObject(eigenaar);
}
}
}
We kunnen programma EigenaarOpvragen ook handmatig vanuit de web browser opstarten door de url in de adresbalk van de server te “plakken”. We zien dat de output van programma EigenaarOpvragen JSON is:
Web pagina
De client is bij een web applicatie meestal een web pagina dat vanuit een web browser wordt opgestart. Veel systeembeheerders zijn dol op web applicaties omdat voor de web applicatie op de desbetreffende PC alleen maar een browser geïnstalleerd hoeft te worden.
De web pagina van een web applicatie wordt vanuit de browser opgestart middels een url. De web browser zal bij een eerste opstart van een web applicatie de web pagina met alle client software downloaden van de server en in zijn cache op de lokale PC zetten. De browser ziet bij een volgende keer of de inhoud van zijn cache verschilt van datgene wat op de server staat. Dat is dan ook de reden dat een web pagina bij een eerste opstart vrij traag is. De web pagina zal na die eerste keer beduidend sneller zijn. Er is meestal niks gewijzigd t.o.v. die eerste keer waardoor ook niks gedownload hoeft te worden.
In onderstaand voorbeeld is de client een web pagina met een jQuery script (index.html). De jQuery script roept een programma aan op de server en het heeft toegang tot dat programma omdat voor dat programma een Web API aanwezig is.
We krijgen van dat programma op de server iets terug en dat deserialiseren we in de browser naar een JavaScript object met JSON.stringify(…).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Voorbeeld Web API</title>
<script src="Scripts/jquery-3.5.1.js">
</script>
<script type="text/javascript">
$(document).ready(
function () {
$('#btn01').click(
function () {
var id;
id = 123;
var Eigenaar = {};
$('#txtArea01').val("We roepen de Web API
aan met id " +
id + "\r\n");
$.ajax(
{
url: "http://localhost:50834/api/
EigenaarOpvragen/?id=" + id,
type: 'GET',
contentType: 'application/json;charset=utf-8',
dataType: 'json',
data: JSON.stringify(Eigenaar)
})
.done(function (result) {
$('#txtArea01').val($('#txtArea01').val() +
"\r\nEn we krijgen dit terug:\r\n");
$('#txtArea01').val($('#txtArea01').val() +
result + "\r\n\r\n");
// Deserialiseren
$('#txtArea01').val($('#txtArea01').val() +
"Wat we deserialiseren naar
een object:\r\n\r\n");
Eigenaar = JSON.parse(result);
$('#txtArea01').val($('#txtArea01').val() +
"id " + Eigenaar["Id"] + "\r\n");
$('#txtArea01').val($('#txtArea01').val() +
"- heeft betrekking op " +
Eigenaar["Omschrijving"] + "\r\n");
$('#txtArea01').val($('#txtArea01').val() +
"- de persoon komt uit regio " +
Eigenaar["Regio"] + "\r\n");
$('#txtArea01').val($('#txtArea01').val() +
"- en heeft abonnement " +
Eigenaar["Abonnement"]);
})
.fail(function (fail) {
$('#txtArea01').val($('#txtArea01').val() +
"Er gaat wat fout, de Web API
kan uw verzoek
niet uitvoeren.");
});
}
);
$('#btn02').click(
function () {
$('#txtArea01').val(null);
}
);
}
);
</script>
</head>
<body>
<h1>Voorbeeld Web API</h1>
<textarea id="txtArea01"
rows="16" cols="80">
</textarea><br />
<button id="btn01">Go</button>
<button id="btn02">Clear</button>
</body>
</html>
Resultaat
We maken een web pagina met een user interface. De user interface zal getoond worden in de browser en het zal buttons bevatten waarmee (in dit voorbeeld) een jQuery script wordt gestart. De jQuery script zal op zijn beurt weer programma EigenaarOpvragen aanroepen. De resultaten van de server worden in een HTML <textarea> gezet en we zien dit in de browser:
Slot
In deze post heb ik laten zien hoe een programma (de client) een ander programma (de server) op een ander systeem kan aanroepen. Systemen kunnen voor hun interactie gebruik maken van talloze technologieën.
Systemen kunnen interactie met elkaar hebben middels de Web Service. We hebben laten zien hoe we met een C# client console applicatie contact maken met een asmx web service waarbij we een web methode aanroepen. De Web API is een wat recentere technologie en we hebben laten zien hoe we met een web pagina met jQuery vanuit de browser contact maken met een Web API programma.
Clients en servers maken voor hun communicatie meestal gebruik van berichten in een universeel tussenformaat. XML (eXtensible Markup Language) en JSON (JAvaScript Object Notation) zijn momenteel de meest gebruikte universele berichtformaten.
Men noemt het “verzendklaar” maken van objecten serialiseren. Daarbij wordt een object geserialiseerd naar een universeel berichtformaat en alles wordt in dat berichtformaat naar een ontvanger gestuurd. Het “uitpakken” van objecten noemt men deserialiseren. Daarbij komt een “pakketje” binnen in een universeel berichtformaat en dat “pakketje” ga je dan omzetten naar een object waarbij dat object een formaat heeft dat gangbaar is binnen het systeem van de ontvanger.
Hopelijk ben je met deze posting weer wat wijzer geworden en ik hoop je weer terug te zien in één van mijn volgende blog posts. Wil je weten wat ik nog meer over C# heb geschreven? Hit the C# button…