.NET Remoting; deel 3
In de vorige artikelen over .NET Remoting hebben we iedere keer een server programma gemaakt waarin het remote object gehost werd. We kunnen echter ook gebruik maken van Internet Information Server (IIS) om onze objecten te hosten. We maken dan gebruik van het HTTP protocol. De voorbeeldapplicatie die we in dit artikel gaan maken, genereert van een string een versleutelde waarde. De versleuteling gebeurt op basis van SHA-1 (Secure Hash Algorithm). Dit algoritme zit in de System.Security.Cryptography namespace van het .NET Framework en is vrij eenvoudig te gebruiken. De nadruk in dit artikel ligt op de toepassing van IIS voor remote objects, dus we staan niet te lang stil bij de werking van SHA.
We gaan ook in op het gebruik van een aparte interface assembly, die we gebruiken om onze cliëntapplicatie te compileren. Deze assembly bevat dus niet de implementatie van de versleutelingsmethode, maar slechts een interface.
Een publieke interface voor de remote service
In de vorige artikelen was het nodig dat de client beschikte over de assembly met metadata over de service. Zonder deze assembly kon de client immers niet gecompileerd worden. Dat is natuurlijk niet altijd eenvoudig en wenselijk, bijvoorbeeld wanneer de client en de service door verschillende partijen ontwikkeld worden. Om dit probleem op te lossen kunnen we gebruik maken van een publieke interface naar het object. Deze interface(-assembly) kan dan aan de ontwikkelaars van de client ter beschikking worden gesteld. In de volgende code zien we de interface voor het genereren van de SHA-waarde van een string.
VB.NET
Namespace RemoteEncrypter
Public Interface IStringEncrypter
Function Encrypt(ByVal inputStr As String) As String>
End Interface
End Namespace
C# namespace RemoteEncrypter
{
public interface IStringEncrypter
{
string Encrypt( string inputStr );
}
}
De remote encryptie class zal deze interface implementeren, en tijdens het compileren van de client zal deze refereren aan de assembly met de interface.
De EncryptionService Class
Nu kunnen we ons richten op de remote encryptie class zelf. Deze implementeert de RemoteEncrypter.IStringEncrypter interface waarin de Encrypt methode zit.
VB.NET
Imports System
Imports System.Security.Cryptography
Imports System.Text
Imports InterfaceToEncrypter.RemoteEncrypter
Namespace RemoteEncrypter
Public Class EncryptionService
Inherits MarshalByRefObject
Implements IStringEncrypter
Public Function Encrypt(ByVal inputStr As String) As String Implements
IStringEncrypter.Encrypt
Dim SHA1HASHValue() As Byte
'creeer een instantie van UnicodeEncoding om
'een string in een array van Unicode bytes te converteren
Dim UE As New UnicodeEncoding
'Hier converteren we de string een een byte-array
Dim MessageBytes As Byte() = UE.GetBytes(inputStr)
'Creeer een nieuwe instantie van SHA1Managed om de hash-waarde
'te berekenen
Dim SHhash As New SHA1Managed
'Bereken de hash waarde uit de byte-array
SHA1HASHValue = SHhash.ComputeHash(MessageBytes)
'maak een string waarde om terug te geven
Dim ReturnValue As String
Dim ByteFromHash As Byte
For Each ByteFromHash In SHA1HASHValue
ReturnValue += ByteFromHash.ToString()
Next ByteFromHash
Return ReturnValue
End Function
End Class
End Namespace
C#
using System;
using System.Security.Cryptography;
using System.Text;
using InterfaceToEncrypter.RemoteEncrypter;
namespace RemoteEncrypter
{
public class EncryptionService :MarshalByRefObject, IStringEncrypter
{
public override string Encrypt( string inputStr )
{
Byte[] SHA1HASHValue;
//creeer een instantie van UnicodeEncoding om
//een string in een array van Unicode bytes te converteren
UnicodeEncoding UE = new UnicodeEncoding();
//Hier converteren we de string een een byte-array
Byte[] MessageBytes = UE.GetBytes(inputStr);
//Creeer een nieuwe instantie van SHA1Managed om de hash-waarde
//te berekenen
SHA1Managed SHhash = new SHA1Managed();
//Bereken de hash waarde uit de byte-array
SHA1HASHValue = SHhash.ComputeHash(MessageBytes);
//maak een string waarde om terug te geven
string ReturnValue;
foreach( Byte ByteFromHash in SHA1HASHValue )
{
ReturnValue += ByteFromHash.ToString();
}
return ReturnValue;
}
}
}
Het doel van deze EncryptieService is het versleutelen van een stuk tekst. SHA-1 is een algoritme dat éénweg-encryptie toepast. Dat wil zeggen dat het niet mogelijk is om de versleutelde tekst te ontsleutelen naar het origineel. Dit kan bijvoorbeeld handig zijn bij het opslaan van wachtwoorden. Wachtwoorden kunnen versleuteld worden opgeslagen, en de invoer van een gebruiker kan dan, opnieuw versleuteld, vergeleken worden met de waarde in de database.
De Encrypt-methode accepteert een string als parameter en geeft ook een string terug. Omdat het object remote gehost wordt, in dit geval in IIS, geven we op dat de class erft van MarshalByRefObject. Bovendien specificeren we dat de IStringEncrypter interface geïmplementeerd wordt door deze class. Wanneer we dit in Visual Basic .NET doen, wordt direct de kale structuur van de te implementeren methode voor ons klaar gezet.
We gaan, zoals in de inleiding gezegd, niet al te diep in op het gebruik van SHA-1 encryptie. De commentaar regels in de code moeten voldoende zijn om de werking van deze methode te begrijpen.
De Client
Het volgende codeblok bevat de client voor de encryptieservice. Let er op dat je in je project ook een referentie opneemt naar System.Runtime.Remoting.dll. Doe je dit niet, dan wordt de System.Runtime.Remoting.Channels.Http namespace niet herkend.
VB.NET
Imports System
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http
Imports InterfaceToEncrypter.RemoteEncrypter
Namespace RemoteEncrypter
Public Class EncryptionClient
Public Shared Sub Main(ByVal args() As String)
ChannelServices.RegisterChannel(New HttpChannel)
Dim objRef As IStringEncrypter =_
CType(Activator.GetObject(_
GetType(IStringEncrypter),_
"http://localhost/RemoteEncrypter/EncryptionService.rem"),_
IStringEncrypter)
Dim InputString As String = "Wie weet waar Willem Wever woont?"
If args.Length > 0 Then InputString = args(0)
Console.WriteLine("Oorspronkelijke waarde: " & InputString)
Dim EncryptedString As String = objRef.Encrypt(InputString)
Console.WriteLine("Versleutelde waarde: " & EncryptedString)
End Sub
End Class
End Namespace
C#
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using InterfaceToEncrypter.RemoteEncrypter;
namespace RemoteEncrypter
{
public class EncryptionClient
{
[STAThread]
static void Main( string args )
{
ChannelServices.RegisterChannel( new HttpChannel() );
IStringEncrypter objRef = CType( Activator.GetObject(
GetType(IStringEncrypter),
"http://localhost/RemoteEncrypter/EncryptionService.rem" ),
IStringEncrypter);
string InputString = "Wie weet waar Willem Wever woont?";
if ( args.Length > 0 ) InputString = args(0);
Console.WriteLine( "Oorspronkelijke waarde: " + InputString );
string EncryptedString = objRef.Encrypt( InputString );
Console.WriteLine("Versleutelde waarde: " + EncryptedString);
}
}
}
We roepen in de client Activator.GetObject aan om een referentie te krijgen naar het remote object. We refereren hier nergens naar het type van het remote object, maar wel naar het interface type IStringEncrypter.
We kunnen nu alle onderdelen van de solution compileren.
Installatie van EncryptionService op IIS
Om de service op IIS te kunnen installeren maken we een virtual directory aan op de server. We noemen deze directory "RemoteEncrypter" en koppelen deze virtuele directory aan de fysieke folder. In deze fysieke folder maken een bin subfolder. We kopiëren de interface assembly InterfaceToEncrypter.dll en de assembly met het remote object EncryptionService.dll naar deze bin-folder.
Nu moeten we de remote service configureren. Bij een webapplicatie wordt de configuratie geplaatst in het bestand web.config. Dit bestand staat in de root-folder van de webapplicatie. In het volgende codeblok staat de inhoud van web.config. Het remote object wordt in Singleton mode geactiveerd.
Je ziet dat we EncryptionService.rem opgeven voor het attribuut objectUri. Je moet voor de objectUri een waarde opgeeft die eindigt op .rem of .soap wanneer je server-activated objecten host in IIS.
De Encryptie service testen
We hoeven nu niets speciaals meer te doen om het remote object in IIS te laden. IIS start automatisch een instantie van de class, zodra de eerste client hier om vraagt. We kunnen nu dus direct de client starten.

Conclusies
We hebben in dit artikel gezien hoe we remote objecten kunnen hosten in IIS. Dat is handig, omdat je daarmee niet een aparte service hoeft te schrijven om de remote objecten in te draaien.
Dit was het laatste artikel in de reeks over .NET Remoting. Het onderwerp is natuurlijk interessant genoeg om nog eens te behandelen. We kunnen dan bijvoorbeeld ingaan op het schrijven van een Windows Service voor het hosten van remote objecten. Ook is het goed om te weten dat het netwerkverkeer bij .NET Remoting standaard niet versleuteld is en dat een client niet zonder meer geauthenticeerd hoeft te worden om gebruik te maken van het remote object. Dat zijn dus zaken die men zelf dient te regelen, bijvoorbeeld via https en Windows authenticatie. Kortom, er is nog genoeg stof over voor nieuwe artikelen over .NET Remoting.
Meer informatie
Wil je meer weten over .NET Remoting in het algemeen of over het gebruik van IIS als server voor remote objecten, kijk dan eens op de volgende links: