Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# Bible - Jeff Ferguson, Brian Patterson, Jason Beres

.pdf
Скачиваний:
64
Добавлен:
24.05.2014
Размер:
4.21 Mб
Скачать

Table 36-4: System.Runtime.Remoting.Channels.Http Namespace

Class

 

Description

 

 

 

 

 

class.

 

 

 

HttpServerChannel

 

Provides an implementation for a server channel that

 

 

uses the HTTP protocol to transmit messages.

Up to this point, you can add the correct namespaces and code to register an HTTP channel and a TCP channel for the host application. Listing 36-2 shows how the host application should look after the channels are registered.

Listing 36-2: Registering Channels

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Remoting.Channels.Http;

namespace Client

{

///<summary>

///Summary description for Class1.

///</summary>

class RemotingClient

{

[STAThread]

static void Main(string[] args)

{

TcpChannel chan1 = new TcpChannel(8085); ChannelServices.RegisterChannel(chan1);

HttpChannel chan2 = new HttpChannel(8086);

ChannelServices.RegisterChannel(chan2);

}

}

}

Note You do not need to use an HTTP channel and a TCP channel in the host application. If you are enabling clients to call on both channel types, you can register both channel types; normally, however, you use one formatter, TCP or HTTP, based on the type of clients that are accessing your remote object.

Activating the remote object

The last task to perform to host the remote object is to register the assembly with the remoting framework. In your host application, before you can activate the assembly that contains your methods, you first need to add a reference to the assembly. Right-click the References object in the Solution Explorer, which brings up the Add Reference dialog box. In the application you are writing here, you need to browse to the C:\cSharpRemoting\HostObject directory and

add the HostObject.dll assembly to your application. After you add this, you can add the HostObject namespace to your class file using the using statement, as the following snippet shows:

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; using System.Runtime.Remoting.Channels.Tcp; using HostObject;

Now that you have added a reference to your remoting assembly created earlier, you can add the code that registers the object with the remoting framework. You can do this in one of two ways:

Use the RegisterWellKnownServiceType() method of the RemotingConfiguration class to pass the type of the object that you are creating, the URI of the object, and the activation mode of the object.

Use the Configure() method of the RemotingConfiguration class to pass a configuration file with the object activation details.

Each activation method works the same way, but storing your activation details in a configuration file gives you more flexibility if any of the activation details change, such as the port number of the channel you are using. You will consider both types of activation, but first examine the available methods and properties of the RemotingConfiguration class described in Table 36-5 and Table 36-6, respectively. Besides the activation methods described previously, you can use many helpful methods and properties in this class to discover information at runtime about your running objects.

Table 36-5: RemotingConfiguration class Methods

Method

 

Description

 

 

 

Configure

 

Reads the configuration file and configures the

 

 

remoting infrastructure.

 

 

 

GetRegisteredActivatedClientTypes

 

Retrieves an array of object types registered on the

 

 

client as types that will be activated remotely.

 

 

 

GetRegisteredActivatedServiceTypes

 

Retrieves an array of object types registered on the

 

 

service end as types that can be activated on request

 

 

from a client.

 

 

 

GetRegisteredWellKnownClientTypes

 

Retrieves an array of object types registered on the

 

 

client end as well-known types.

GetRegisteredWellKnownServiceTypes

 

Retrieves an array of object types registered on the

 

 

service end as well-known types.

 

 

 

GetType (inherited from Object)

 

Gets the type of the current instance.

 

 

 

IsActivationAllowed

 

Returns a Boolean value indicating whether the

 

 

specified type is allowed to be client activated.

 

 

 

IsRemotelyActivatedClientType

 

Overloaded. Checks whether the specified object

 

 

type is registered as a remotely activated client type.

 

 

 

IsWellKnownClientType

 

Overloaded. Checks whether the specified object

Table 36-5: RemotingConfiguration class Methods

Method

 

Description

 

 

 

 

 

type is registered as a well-known client type.

 

 

 

RegisterActivatedClientType

 

Overloaded. Registers an object type on the client

 

 

end as a type that can be activated on the server.

RegisterActivatedServiceType

Overloaded. Registers an object type on the service end as one that can be activated on request from a client.

RegisterWellKnownClientType

 

Overloaded. Registers an object type on the client

 

 

end as a well-known type (single call or singleton).

 

 

 

RegisterWellKnownServiceType

 

Overloaded. Registers an object Type on the service

 

 

end as a well-known type (single call or singleton).

 

Table 36-6: RemotingConfiguration Class Properties

Property

 

 

Description

 

 

 

 

ApplicationId

 

 

Gets the ID of the currently executing application

 

 

 

 

ApplicationName

 

 

Gets or sets the name of a remoting application

 

 

 

 

ProcessId

 

 

Gets the ID of the currently executing process

Registering objects with RegisterWellKnownServiceType

To register an object with the RegisterWellKnownServiceType() method of the RemotingConfiguration class, you simply pass the name of the class, which is HostObject.Class1; the URI of the remote object, which is ReturnName; and the type of mode in which the object will be created, which in this case is SingleCall. You look at the WellKnownObjectMode enumeration later in this section. Listing 36-3 completes the host application using the RegisterWellKnownServiceType method.

Listing 36-3: Using RegisterWellKnownServiceType

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; using System.Runtime.Remoting.Channels.Tcp; using HostObject;

namespace Host

{

///<summary>

///Summary description for Class1.

///</summary>

class Class1

{

///<summary>

///The main entry point for the application.

///</summary>

[STAThread]

static void Main(string[] args)

{

TcpChannel chan1 = new TcpChannel(8085);

ChannelServices.RegisterChannel(chan1);

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(HostObject.Class1), "ReturnName",

WellKnownObjectMode.SingleCall);

Console.WriteLine("Press any key to exit");

Console.ReadLine();

}

}

}

Because the host application is a console application, you add the Console. ReadLine statement at the end so that the console window stays open while clients are using the remote object. The lifetime of the channel is the length of time that window happens to be open. After you close the console window, the channel is destroyed and the lease on that particular channel is expired in the remoting framework.

The WellKnownObjectMode enumeration contains two members that define how objects are created. If the WellKnownObjectMode is SingleCall, then each request from a client is serviced by a new object instance. This would be represented by the following pseudo-code:

Create Object X

Call Method of Object X

Return data back to caller

Destroy Object X

Garbage Collect

If the WellKnownObjectMode is Singleton, then each request from a client is serviced by the same object instance. This can be described in the following pseudo-code:

Create Object X

Call Method of Object X Return data back to caller Call Method of Object X Return data back to caller

... continue until channel destroyed

This loop continues until the channel with which this object is registered in the remoting framework is destroyed.

Depending on the type of application you are writing, you determine which activation mode to use by considering the following factors:

Overhead: If creating the remote object consumes resources and takes time, then using the SingleCall mode may not be the most efficient way to create your object, as the object is destroyed after each client is done using it.

State Information: If you are storing state data in your remote object, such as properties, you use Singleton objects, which are capable of maintaining state data.

Registering objects with the Configure method

If you need a more flexible way of maintaining the configuration data that the remoting framework needs to register your object, you can use the Configure() method of the RemotingConfiguration class. The configuration information that is stored in the file is the same information that you can use in the RegisterWellKnownServiceType() method. The benefit of using a configuration file is that if any of the settings for the object change, you can alter the configuration file, and not change any of your code. The schema for the configuration is shown in Listing 36-4, with the explanation of each element in Table 36-7.

Listing 36-4: Remoting Configuration File

<configuration>

<system.runtime.remoting>

<application>

<lifetime> <channels> (Instance)

<channel> (Instance) <serverProviders> (Instance)

<provider> (Instance) <formatter> (Instance)

<clientProviders> (Instance) <provider> (Instance) <formatter> (Instance)

<client>

<wellknown> (Client Instance) <activated> (Client Instance)

<service>

<wellknown> (Service Instance) <activated> (Service Instance)

<soapInterop>

<interopXmlType>

<interopXmlElement>

<preLoad> <channels> (Template)

<channel> (Template) <serverProviders> (Instance)

<provider> (Instance) <formatter> (Instance)

<clientProviders> (Instance) <provider> (Instance) <formatter> (Instance)

<channelSinkProviders> <serverProviders> (Template)

<provider> (Template) <formatter> (Template)

<clientProviders> (Template) <provider> (Template) <formatter> (Template)

<debug>

Although there are many options in the configuration file, you only need to use what your application requires. For example, the snippet of code in Listing 36-5 represents a configuration file for an HTTP-activated object that is a SingleCall mode object.

Listing 36-5: Configuration File Example

<configuration>

<system.runtime.remoting>

<application>

<client url="http://localhost/HostObject"> <wellknown type="HostObject.Class1,

ReturnName" url="http://localhost/HostObject/Class1.soap" />

</client>

<channels>

<channel ref="http" /> </channels>

</application>

</system.runtime.remoting>

</configuration>

After you create the configuration file, creating the host object is dramatically simpler than it is when registering an object with the RegisterWellKnownServiceType() method of the RemotingConfiguration class. The code in Listing 36-6 demonstrates how to register the object using the Configure() method.

Listing 36-6: Using a Remoting Configuration File in the Host Class

namespace Host

{

///<summary>

///Summary description for Class1.

///</summary>

class Class1

{

///<summary>

///The main entry point for the application.

///</summary>

[STAThread]

static void Main(string[] args)

{

RemotingConfiguration.Configure("Host.Exe.Config");

Console.WriteLine("Press any key to exit");

Console.ReadLine();

}

}

}

As you can see, your code is reduced from about 15 lines to 1 line.

Note The name of the configuration file should be the name of the executable, including the exe extension, with an additional config extension added. In the case of the host application, the configuration file would be named host.exe.config, and the file would be located in the Bin directory where the executable file for the host application resides.

Table 36-7 lists all of the available elements and their uses for the remoting configuration file schema.

Table 36-7: Schema for Remoting Settings Configuration File

Element

 

Description

 

 

 

<system.runtime.remoting>

 

Contains information about remote objects and channels

 

 

 

<application>

 

Contains information about remote objects that the

 

 

application consumes and exposes

<lifetime>

<channels> (Instance)

<channel> (Instance)

<serverProviders> (Instance)

<provider> (Instance)

Contains information about the lifetime of all clientactivated objects serviced by this application

Contains channels that the application uses to communicate with remote objects

Configures the channel that the application uses to communicate with remote objects

Contains providers for channel sinks that are to become part of the default server-side channel sink call chain for this channel template when the template is referenced elsewhere in the configuration file

Contains the channel sink provider for a channel sink that is to be inserted into the channel sink chain

<formatter> (Instance)

 

Contains the channel sink provider for a formatter sink that

 

 

is to be inserted into the channel sink chain

 

 

 

<clientProviders> (Instance)

 

Contains providers for channel sinks that are to become

 

 

part of the default client-side channel sink call chain for

 

 

this channel template when the template is referenced

 

 

elsewhere in the configuration file

 

 

 

<client>

 

Contains objects that the application consumes

 

 

 

<wellknown> (Client Instance)

 

Contains information about server-activated (well-known)

 

 

objects the application wants to consume

 

 

 

<activated> (Client Instance)

 

Contains information about client-activated objects the

 

 

application wants to consume

 

 

 

<service>

 

Contains objects that the application exposes to other

 

 

application domains or contexts

 

 

 

<wellknown> (Service Instance)

 

Contains information about server-activated (well-known)

 

 

objects the application wants to publish

Table 36-7: Schema for Remoting Settings Configuration File

Element

 

Description

 

 

 

<activated> (Service Instance)

 

Contains information about client-activated objects the

 

 

application wants to publish

 

 

 

<soapInterop>

 

Contains type mappings used with SOAP

 

 

 

<interopXmlType>

 

Creates a bidirectional map between a common language

 

 

runtime type and an XML type and XML namespace

 

 

 

<interopXmlElement>

 

Creates a bidirectional map between a common language

 

 

runtime type and an XML element and XML namespace

 

 

 

<preLoad>

 

Specifies the type to load the mappings from classes that

 

 

extend SoapAttribute

<channels> (Template)

<channel> (Template)

<channelSinkProviders>

<serverProviders> (Template)

<provider> (Template)

<formatter> (Template)

<clientProviders> (Template)

Contains channel templates that the application uses to communicate with remote objects

Contains the channel template that specifies how to communicate with or listen to requests for remote objects

Contains templates for client and server channel sink providers. Any channel sink providers specified underneath this element can be referenced anywhere a channel sink provider might be registered

Contains channel sink templates that can be inserted into a server channel call chain

Contains the channel sink provider template for a channel sink that is to be inserted into the server or client channel sink chain

Contains the channel sink provider for a formatter sink that is to be inserted into the client or server channel sink chain

Contains channel sink templates that can be inserted into a client channel call chain

<debug>

 

Specifies whether types should be loaded in the

 

 

configuration file when the application starts

Until this point, this chapter has explained the intricacies of creating the host application that registers the remote object with the remoting framework. Now you need to write the client application that makes the requests to the remote object, which is the subject of the next section.

Writing the Remoting Client

So far, you have created the host object and the host server application that manages the client requests for the host object through the remoting framework. The final step in writing this remoting application is to write the client application that makes requests to the remote object. In this case, the client calls the ReturnName method of the HostObject assembly and passes a customerID parameter that is used by the ReturnNam() method to look up the customer's company name in the Northwind database.

To begin, create a new console application called Client in the C:\cSharpRemoting\Client directory. You can call the remote object with any type of application, but for simplicity, you create a console application.

Calling the remote object from the client can be accomplished in one of three ways:

Call the GetObject() method of the Activator class, which is server-activated.

Call the CreateInstance() method of the Activator class, which is client-activated.

Use the new keyword, which can be serveror client-activated.

The difference between client activation and server activation is when the object is actually created. Each type of activation can be accomplished programmatically or through a configuration file (using the same format as described in Table 36-7), but for client activation, a round-trip is made to the server to create the object when the CreateInstance() method is called. Conversely, when an object is server-activated, the server object is not created until a call is made to the method from the client. Server-activated objects create a proxy that the client uses to discover the properties and methods available on the server object. The major disadvantage to server activation is that only default constructors are allowed, so if you need to pass multiple parameters to a method's constructor, you need to use client-side activation through the CreateInstance() method of the Activator class. All of the methods of the Activator class are listed in Table 36-8.

 

 

Table 36-8: Activator Class Methods

 

 

 

Method

 

Description

 

 

 

CreateComInstanceFrom

 

Creates an instance of the COM object whose name is specified,

 

 

using the named assembly file and the constructor that best

 

 

matches the specified parameters.

 

 

 

CreateInstance

 

Overloaded. Creates an instance of the specified type using the

 

 

constructor that best matches the specified parameters.

 

 

 

CreateInstanceFrom

 

Overloaded. Creates an instance of the type whose name is

 

 

specified, using the named assembly file and the constructor that

 

 

best matches the specified parameters.

 

 

 

GetObject

 

Overloaded. Creates a proxy for a currently running remote

 

 

object, a server-activated well-known object, or an XML Web

 

 

service

 

 

 

After you decide what type of activation your application requires, you can write the client code. Listing 36-7 shows the full client application code. Like the host code, you register a channel first. When registering a channel from the client, you do not specify the channel number. The call to the URI's endpoint point the client to the correct channel, because it is included in the GetObject() method call; you specify the object that you are attempting to create and the location of the object. After the object is created, you can call methods and set properties as you would with any other class.

Listing 36-7: The remoting client application

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp; using HostObject;

namespace Client

{

///<summary>

///Summary description for Class1.

///</summary>

class RemotingClient

{

[STAThread]

static void Main(string[] args)

{

ChannelServices.RegisterChannel(new TcpChannel());

HostObject.Class1 x = (Class1)Activator.GetObject( typeof(Class1), "tcp://localhost:8085/ReturnName",null);

Console.WriteLine(x.ReturnName("ALFKI"));

Console.ReadLine();

}

}

}

After you write the client, you can run the Host.exe application and then run the client application; and you should see results similar to those shown in Figure 36-2. The host application stays open forever, or until you close it, while each client application call to the host application returns the company name for the customerID ALFKI, which is the customer ID passed in the client application.

Figure 36-2: Results of running Host.exe and Client.exe

If you leave the original host application's code in SingleCall mode, then each time you run the client application, the server object is destroyed and re-created. By changing the WellKnownObjectMode to Singleton, you notice the difference between SingleCall and Singleton mode. The following snippet shows the host application code that creates the object in Singleton mode:

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(HostObject.Class1), "ReturnName",

Соседние файлы в предмете Программирование