320 likes | 450 Views
.Net Remoting. Configuration files The .config file Server side Client side Encapsulate Activator.GetObject A method Remote callback Callback in general How to do it. The .config file. Configuration files are widely used in .Net
E N D
.Net Remoting • Configuration files • The .config file • Server side • Client side • Encapsulate Activator.GetObject • A method • Remote callback • Callback in general • How to do it
The .config file • Configuration files are widely used in .Net • A configuration file provides an easy way of changing different kind of setting. • For example: • Database connection strings • Authorization settings • Remoting settings • Application specific properties • In Visual Studio: Add a new item using the “Application Configuration File” template • Leave the name as app.config. It will be renamed to <assemply filename>.config. • E.g.: MyProgram.exe.config
Server Configuration file • It is possible to do the most by configuration files. • Below is the configuration file for the server from the wko example: <configuration> <system.runtime.remoting> <application> <channels> <channelref="http"port="1234"/> </channels> <service> <wellknownmode="Singleton" type="Server.CustomerManager, Server" objectUri="CustomerManager.soap"/> </service> </application> </system.runtime.remoting> </configuration> <namespace>.<class> Assembly
Server.cs • Read the configuration file static void Main(string[] args) { Console.WriteLine("Start service"); String filename = @"..\..\server.exe.config"; RemotingConfiguration.Configure(filename,false); Console.WriteLine("Service startet"); Console.ReadLine(); }
Config file with security setting <configuration> <system.runtime.remoting> <application> <channels> <channelref="http"port="1234"> <serverProviders> <providerref="wsdl" /> <formatterref="soap" typeFilterLevel="Full" /> <formatterref="binary" typeFilterLevel="Full" /> </serverProviders> </channel> </channels> <service> <wellknownmode="Singleton" type="Server.CustomerManager, Server" objectUri="CustomerManager.soap"/> </service> </application> </system.runtime.remoting> </configuration>
client.exe.config • Same information as in the Activator.GetObject <configuration> <system.runtime.remoting> <application> <client> <wellknowntype="Server.ICustomerManager, Client" url="http://localhost:1234/CustomerManager.soap"/> </client> </application> </system.runtime.remoting> </configuration>
client.cs Here is a problem, which? String filename = @"..\..\client.exe.config"; RemotingConfiguration.Configure(filename); ICustomerManager mgr = (ICustomerManager)Activator.GetObject( typeof(ICustomerManager), "http://localhost:1234/CustomerManager.soap"); Console.WriteLine("Reference to CustomerManager created"+mgr); Customer cust = mgr.GetCustomer(4711); Information repeated in the Activator.GetObject
.Net Remoting • Configuration files • The .config file • Server side • Client side • Encapsulate Activator.GetObject • A method • Remote callback • Callback in general • How to do it
Better ways to use the configuration file on client side • Problems: • Activator.GetObject needs a url and a port • using new demands knowledge of the concrete class • Goal: • The client shall be able to instantiate remote objects from the interface without knowing the concrete class. • Use configuration files • Solution: • Encapsulate Activator Source: Ingo Rammer
Encapsulate Activator.GetObject Steps: • Construct a RemoteHelper class with a method GetObject. • Is initialized by looking up in the RemotingConfiguration and store available remote types in a table. • GetObject takes a Type as parameter (can be a interface or a class) • GetObject returns a remote object by calling Activator.GetObject The good news: The construction can be used for general purpose. It does not depend on a specific application Source: Ingo Rammer
RemotingHelper using System; using System.Collections; using System.Runtime.Remoting; classRemotingHelper { privatestaticbool _isInit; privatestaticIDictionary _wellKnownTypes; publicstaticObject GetObject(Type type) { if (!_isInit) InitTypeCache(); WellKnownClientTypeEntry entr = (WellKnownClientTypeEntry)_wellKnownTypes[type]; if (entr == null) { thrownewRemotingException("Type not found!"); } returnActivator.GetObject(entr.ObjectType, entr.ObjectUrl); } Continued…… Make table with remote types Lookup on the type Return the reference
RemotingHelperGenerate table publicstaticvoid InitTypeCache() { _isInit = true; _wellKnownTypes = newHashtable(); foreach (WellKnownClientTypeEntry entr in RemotingConfiguration.GetRegisteredWellKnownClientTypes()) { if (entr.ObjectType == null) { thrownewRemotingException("A configured type could not " + "be found. Please check spelling"); } _wellKnownTypes.Add(entr.ObjectType, entr); } } }
In the client: static void Main(string[] args) { string path = @"../../Client.exe.config"; RemotingConfiguration.Configure(path); IRemoteBank mgr = (IRemoteBank)RemotingHelper.GetObject(typeof(IRemoteBank)); ….. } Here is both goals achieved.
More on design... • Classes in the data and business components should not inherit from MarshalByRefObject • Use proxy pattern instead. • In other words: Construct a class (the proxy) with the same interface as the real class. Redelegate calls to the real class
.Net Remoting • Configuration files • The .config file • Server side • Client side • Encapsulate Activator.GetObject • A method • Remote callback • Callback in general • How to do it
Callback as in delegate or in observer pattern • Callback means that the called method or service calls a method on the requesting object instead of returning a value. • The advantage is that the program executing is not blocked, while waiting for a return. • Event models are in general built on callback principles • Here: The server is able to call a method on the client. • The following example shows an remote implementation of observer pattern, where the connected clients are informed every time a new client connects
Observer pattern Also called Observable in some litterature Might also be a interface
In the example • Observable is on the server. • Clients gets a reference to it by calling a get-method on a factory class (Factory pattern) • Observers are placed on the clients and attached to the Observable object. • The server calls back by calling the Notify method on the Observers
The remote interface and the observer interfaces public interface IObserver { voidNotify(stringmsg); } public interface IObservable { voidAttach(IObserverobj); voidUpdate(stringmsg); } public interface IObserverableFactory { IObservableGetFactory(); }
The factory class public class Factory : MarshalByRefObject, IObserverableFactory { IObservable _obsevable = null; public IObservableGetFactory() { if (_obsevable == null) _obsevable = new Observable(); return _obsevable; } }
The observable class public class Observable : MarshalByRefObject, IObservable { List<IObserver> _observers = new List<IObserver>(); public voidAttach(IObserverobj) { _observers.Add(obj); } public voidUpdate(stringmsg) { foreach (IObserver o in _observers) o.Notify(msg); } }
The config file <?xmlversion="1.0" encoding="utf-8" ?> <configuration> <system.runtime.remoting> <application> <channels> <channelref="http" port="1234"> <serverProviders> <providerref="wsdl" /> <formatterref="soap" typeFilterLevel="Full" /> </serverProviders> </channel> </channels> <service> <wellknownmode="Singleton” type="Server.Factory, Server" objectUri="observer.soap" /> </service> </application> </system.runtime.remoting> </configuration>
The observer class [Serializable] public class Observer : MarshalByRefObject, Shared.IObserver { public voidNotify(stringmsg) { Console.WriteLine(msg); } }
The client class [Serializable] public class Observer : MarshalByRefObject, Shared.IObserver { public voidNotify(stringmsg) { Console.WriteLine(msg); } }
The observer class class Program { static void Main(string[] args) { RemotingConfiguration.Configure("Client.exe.config",false); IObserverableFactory serverObj = (IObserverableFactory) RemotingHelper.GetObject (typeof(IObserverableFactory)); IObservable observable = serverObj.GetFactory(); observable.Attach(new Observer()); observable.Update(String.Format("{0}: {1}", DateTime.Now, ”Client startet")); Console.ReadLine(); } }
The config file <?xmlversion="1.0" encoding="utf-8" ?> <configuration> <system.runtime.remoting> <application> <channels> <channelref="http" port="0"> <serverProviders> <providerref="wsdl" /> <formatterref="soap" typeFilterLevel="Full" /> <formatterref="binary" typeFilterLevel="Full" /> </serverProviders> </channel> </channels> <client> <wellknowntype="Shared.IObserverableFactory, Shared" url="http://localhost:1234/observer.soap" /> </client> </application> </system.runtime.remoting> </configuration>
Run the example • Start the server • The client cannot be started from Visual Studio for security reasons • Therefore it has to be started from the bin directory. • Start the client twice. Look at the out on the first instance.
Exercises: • Exercise 1: • Change the server and the client in the remoting bank to use configuration files • Exercise 2: • Encapsulate the Activator.GetObject in the client • Exercise 3: • Make a simple chat application by changing the callback example