Dynamic Publication

Programmatic registration is really just a tool that can enable you to implement your own custom registration schemes. This can prove useful if you have several servers that host different remote components and run different component hosts. Keeping track of the active component hosts, available channels, and usable URL endpoints is no small task.

One interesting approach is to borrow an idea from peer-to-peer programming and create a centralized discovery and lookup server. The idea is that one XML Web service (and one database) can store information that tracks all your active objects. This gives you an easy way to query summary information and troubleshoot connection problems.

Recording Connection Information with an XML Web Service

The next example shows a simple coordination XML Web service designed to help clients find the remote objects they need. A single server is used to run the coordination XML Web service and host the database, which contains a Remote­Objects table listing all the currently available endpoints. This table pairs remote object type names with a URL where they can be found. Figure 11-5 shows that there are two component servers that provide three endpoints, plus two distinct objects (CustomerDB and OrderDB).

Figure 11-5. The RemoteObjects table

graphics/f11dp05.jpg

The coordination XML Web service provides three Web methods: RegisterUrls, UnregisterUrls, and GetUrls. The RegisterUrls and UregisterUrls methods require an object name and an array of URLs in string format. These allow a component host to submit all the registration information for a remote object in one message rather than suffer the increased latency of multiple messages. However, the component host still needs to send a separate message for every object type. To overcome this limitation and further optimize performance, you can create a custom structure that encapsulates the type name and URL information.

Listing 11-19 shows the Web methods for registering and unregistering objects.

Listing 11-19 The RegisterUrls and UnregisterUrls Web methods
 Public Class CoordinationService     Private ConnectionString As String = _      "Data Source=localhost;Initial Catalog=Services;" & _      "Integrated Security=SSPI"     <WebMethod()> _     Public Sub RegisterUrls(typeName As String, urls As String())         Dim Sql As String         Dim con As New SqlConnection(ConnectionString)         Dim cmd As New SqlCommand(con)         Try             con.Open()             ' Insert a record for each URL.             Dim Url As String             For Each Url In urls                 Sql = "INSERT INTO RemoteObjects "                 Sql &= "(TypeName, ObjectURL) VALUES ('"                 Sql &= typeName & "', '"                 Sql &= Url & "')"                 cmd.CommandText = Sql                 cmd.ExecuteNonQuery()             Next         Catch Err As Exception             ' Use "caller inform" exception handling pattern.             Throw New ApplicationException( _              "Exception encountered when executing command.", Err) 
         Finally             con.Close()         End Try     End Sub     <WebMethod()> _     Public Sub UnregisterUrls(typeName As String, urls As String())         Dim Sql As String         Dim con As New SqlConnection(ConnectionString)         Dim cmd As New SqlCommand(con)         Try             con.Open()             ' Insert a record for each URL.             Dim Url As String             For Each Url In urls                 Sql = "DELETE FROM RemoteObjects "                 Sql &= "WHERE TypeName='"                 Sql &= typeName & "' AND ObjectURL='"                 Sql &= Url & "'"                 cmd.CommandText = Sql                 cmd.ExecuteNonQuery()             Next         Catch Err As Exception             ' Use "caller inform" exception handling pattern.             Throw New ApplicationException( _              "Exception encountered when executing command.", Err)         Finally             con.Close()         End Try     End Sub     ' (RetrieveUrls method omitted.) End Class 

Each component host uses these methods to publish information about its available types. For example, on startup a component host might register its CustomerDB URLs by using the code in Listing 11-20. This approach requires the component host to know which types it exposes. Optionally, you can move this information into a custom configuration file or use the ChannelS­ervices.GetUrlsForObject method.

Listing 11-20 Registering remote URLs with the coordination service
  ' Retrieve a reference to the first channel. Dim Channel As TcpServerChannel = ChannelServices.RegisteredChannels(0) ' This value could be retrieved from a configuration file. Dim TypeName As String = "CustomerDB.CustomerDB" ' Determine the CustomerDB URLs this channel exposes. Dim Urls As String() = Channel.GetUrlsForUri(TypeName) ' Register the channels. Dim Proxy As New localhost.CoordinationService() Proxy.RegisterUrls(Typename, Urls) 

The component host would have to take similar steps to unregister all channels before it shuts down.

The next ingredient is the GetUrls method in the coordination service, which returns a string array with all the current URL endpoints for that object on the system (as shown in Listing 11-21).

Listing 11-21 The GetUrls Web method
 Public Function GetUrls(typeName As String) As ArrayList     Dim Sql As String     Sql = "SELECT * FROM RemoteObjects WHERE TypeName ='"     Sql &= typeName & "'"          Dim con As New SqlConnection(ConnectionString)     Dim cmd As New SqlCommand(Sql, con)     Dim Reader As SqlDataReader     Dim Matches As New ArrayList()     Try         con.Open()         Reader = cmd.ExecuteReader() 
         ' Add the retrieved URLs to the ArrayList.         Do While Reader.Read()             Matches.Add(Reader("ObjectURL"))         Loop     Catch Err As Exception         ' Use caller inform pattern.         Throw New ApplicationException( _          "Exception encountered when executing command.", Err)     Finally         con.Close()     End Try     Return Matches End Function 

Now a client can retrieve the URLs for a given object programmatically (as shown in Listing 11-22).

Listing 11-22 Finding an URL using the coordination service
  ' Configure client channel. RemotingConfiguration.Configure("Client.exe.config") ' This value could be retrieved from a configuration file. Dim TypeName As String = "CustomerDB.CustomerDB" ' Retrieve the URL. Dim Proxy As New localhost.CoordinationService() Dim Urls As ArrayList = Proxy.GetUrls(TypeName) ' Try to connect with the first URL. Dim RemoteObj As Object RemoteObj = Activator.GetObject( _                     GetType(CustomerDBInterfaces.ICustomerDB), _                     ArrayList(0)) ' Access the remote object to the interface. CustomerDB = CType(RemoteObj, CustomerDBInterfaces.ICustomerDB) 

This design is more complicated, but it can prove extremely useful in a network where components hosts are not permanently online. The client can wrap its Activator.GetObject method calls in exception-handling code and try multiple URLs until one succeeds. This might be necessary in an environment in which the client is separated from some component hosts by a firewall.

You can implement the coordination service design in countless other ways. In this example, the component host still has the power to determine what ports and channels to use based on the configuration file settings. However, you can modify the component host code so that it retrieves the port number or channel it should use (or even the type name of the objects it should register). The component host can then create these endpoints using dynamic registration, which we discussed in the preceding section.

Another option is to store more information about each object. You might store version number information, for example, allowing a client to find the version it requires or choose the closest similar version. You also can include a priority field that indicates the relative network speed or server throughput of a given endpoint. This allows your client to implement a "quality-of-service" approach, in which it attempts the best link first and then moves progressively through the list if the connection can't succeed. All of these ideas represent different ways that you might want to enhance this example to meet your own needs when coordinating a large network of client and distributed Remoting providers.

Note

You can implement a basic form of static load balancing (called round-robin load balancing) using the coordination service design. Here's how it works. Your coordination XML Web service stores links to remote objects on several servers. Each time a client makes a request, it randomly chooses one. Over time, the client load is distributed over the available servers. This can't replace the sophisticated load balancing of a product such as Microsoft Application Center 2000, but it's useful when you create a coordination service. In the preceding example, there's a good chance that all clients will just try to connect to the first server on the list. If the database doesn't change frequently, this will be the same server, and it will receive a disproportionate amount of the client load.


A Closer Look at ObjRef

There is another approach to linking remote components hosted at different places on the network. It involves using the power of object references.

You'll no doubt remember that when a client creates a remote object, the client doesn't really hold a reference to the object. Instead, the client holds the reference to a proxy object. The CLR generates this proxy using the information sent by the server, which includes the following:

  • The fully qualified type name of the remote object, including its assembly

  • The type names of all the remote object's base classes and all the interfaces implemented by the remote object

  • The object URL

All this information is wrapped in a special .NET object: System.Run­time.Remoting.ObjRef. This is a serializable class type, which means it can be sent to any .NET client. You can think of the ObjRef object as a sort of network pointer. It can be shipped around the network anywhere you want, but it always points to a specific instance on the originating computer.

Now consider this scenario. A client creates a remote object and passes the remote object reference to a different remote object. This second remote object attempts to call a method on the first remote object. What happens?

This scenario is actually no different from the normal one in which a client deals with a remotable object it created directly. The ObjRef transmits all the information required. Therefore, the second remote object contacts the first remote object directly (provided no firewall or other network issue intervenes). The client will no longer play any part. It can even shut down.

This gives you an idea of another way that remote objects can be related. For example, you might connect to several different remote applications through one component host. Alternatively, you might create a master remote component that creates other remotable components and returns references to them. Remember, however, that as interesting as these designs are, you should introduce only as many features as you need to simplify your setup. Centralizing remote components to a single server (or a load-balanced set of servers) will always be the easiest approach to manage.



Microsoft. NET Distributed Applications(c) Integrating XML Web Services and. NET Remoting
MicrosoftВ® .NET Distributed Applications: Integrating XML Web Services and .NET Remoting (Pro-Developer)
ISBN: 0735619336
EAN: 2147483647
Year: 2005
Pages: 174

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net