Exposing .NET Remoting Objects as Web Services

only for RuBoard

Now that you're more comfortable with exposing and consuming .NET web services, it's time to discuss the more advanced topic of the .NET Remoting Framework and how you can expose web services by using this Framework.

.NET Remoting Framework

Microsoft .NET Remoting provides a framework for objects that reside in different application domains, in different processes, and in different machines to seamlessly communicate with each other. .NET Remoting offers a powerful yet simple programming model and run-time support for making these interactions transparent. .NET Channel Services provides the underlying transport mechanism for this communication. The .NET Framework provides the HTTP and TCP channels. The HTTP channel uses SOAP by default to communicate, whereas the TCP channel uses binary payload by default. Different payload-protocol combinations are possible, but this section only discusses the SOAP/XML-HTTP payload-protocol combination.

Two main kinds of remotable objects exist:

  • Marshal- by-value ( MBV ) objects ” MBV objects are copied and passed out of the application domain. These objects declare their serialization rules (either by implementing ISerializable to implement their own serialization, or by being decorated with SerializableAttribute , which tells the system to serialize the object automatically), but do not extend MarshalByRefObject . The AddressEntry object that we shall be looking at in this section's example is a MBV object.

  • Marshal-by-reference ( MBR ) objects ” In MBR objects, a proxy is created and used by the client to access the object remotely. The AddressEntries object in the sample is a MBR object. MBR objects extend at least System.MarshalByRefObject .

Two types of activation for MBR objects exist:

  • Server-activated objects ” These objects are created by the server only when they are needed and not when the client proxy is created by calling new or Activator.GetObject() , but when the client invokes the first method on that proxy . These can be declared as Singleton or SingleCall objects. Singleton objects are objects for which there will always be only one instance, regardless of how many clients exist for that object, and which have a default lifetime. When an object is declared a SingleCall object, the system creates a new object for each client method invocation.

  • Client-activated objects ” These objects' lifetimes are controlled by the calling application domain, just as they would be if the objects were local to the client. These are created on the server when the client calls a new or Activator.CreateInstance() .

Creating a .NET Remoting Server Objects

Creating a Remoting Server Object is as simple as creating any other object. The only difference is that an MBR object extends System.MarshalByRefObject and the MBV object is serializable.

Listing 11.14 shows the AddressEntries Remotable Object.

Listing 11.14 The Server Object ( AddressEntries.cs )
 using System;  namespace RemotingAddressBookService  {      //The AddressEntries class represents a Remote Object       public class AddressEntries  : MarshalByRefObject       {           private int count = 10 ;            public AddressEntry GetAddressEntry(int addrEntryID)            {               AddressEntry addrEntry  = new AddressEntry(addrEntryID);                 addrEntry.FirstName = "Maria";                 addrEntry.LastName  = "Anders";                      addrEntry.Email     = "maria@alfreds-futterkiste.com";                 addrEntry.Phone     = "030-0074321";                 return addrEntry;            }            public int GetCount()            {                return count;            }       }  } 

Listing 11.15 shows the AddressEntry Remotable Object, which is an MBV object.

Listing 11.15 The Serializable Local Object ( AddressEntry.cs )
 using System;  namespace RemotingAddressBookService  {      //The AddressEntry class represents a local object       //that can be serialized to the client       [SerializableAttribute()]       public class AddressEntry       {           private int id;            private string firstName ;            private string lastName ;            private string email ;            private string phone ;            public AddressEntry(int addrEntryId)            {                id = addrEntryId ;            }            public string FirstName            {                get                 {                     return firstName;                 }                 set                 {                     firstName = value;                 }            }            public string LastName            {                     get                 {                     return lastName;                 }                 set                 {                     lastName = value;                 }            }            public string Email            {                get                 {                     return email;                 }                 set                 {                     email = value;                 }            }            public string Phone            {                get                 {                     return phone;                 }                 set                 {                     phone = value;                 }            }       }  } 

The Configuration File

The configuration file Remoting.config in Listing 11.15 specifies the Remoting-specific information for the AddressEntries Remote object.

Listing 11.16 The Remoting. config File
 <configuration>    <system.runtime.remoting>      <application name="RemotingAddressBookService">        <service>       <wellknown mode="SingleCall"  type="RemotingAddressBookService.AddressEntries,RemoteObject"                     objectUri="AddressEntries.soap" />        </service>        <channels>          <channel port="8085" ref="http" />        </channels>      </application>    </system.runtime.remoting>  </configuration> 

Creating the Server

You can now create a managed executable to register the channels and start listening to the client requests at port 8085, as specified in the configuration file in Listing 11.16. Listing 11.17 shows the code for this listener.

Listing 11.17 The Listener ( Listener.cs )
 using System;  using System.Runtime.Remoting;  using System.Runtime.Remoting.Channels;  using System.Runtime.Remoting.Channels.Http;  namespace RemotingAddressBookService  {      public class Listener       {           public static int Main(string [] args)            {                try                 {                     RemotingConfiguration.Configure("Remoting.config");  //the Following commented code shows the programmatic approach which is  //an alternative to using a configuration file                      /*                      HttpChannel chan = new HttpChannel(8085);                      ChannelServices.RegisterChannel(chan); graphics/ccc.gif RemotingConfiguration.RegisterWellKnownServiceType(Type.GetType("RemotingAddressBookService.AddressEntries,RemoteObject"), graphics/ccc.gif "AddressEntries.soap", WellKnownObjectMode.SingleCall);                      */                      System.Console.WriteLine("Address Book Remoting Service is waiting "                           + "for requests.");                 }                 catch(Exception e)                 {                   System.Console.WriteLine(e.Message);                 }NET;Remoting objects;exposing>                 System.Console.WriteLine("Press <Enter> to stop this Service...");                 System.Console.ReadLine();                 return 0;            }       }  } 

After you compile and run the executable, the service is running and listening to client requests, as shown in Figure 11.19.

Figure 11.19. The Remoting service is listening for requests.
graphics/11fig19.gif

Note

Instead of running an executable on the server machine, it is also possible to create a Windows Service. Creating a Windows Service is relatively simple in the .NET Framework. But because it is outside the scope of this book, it isn't discussed in this chapter. Another available option is to host the service in the Internet Information Server (IIS).


Consuming the Remote Service Through an ASP.NET Client Application

Now that you have the Remoting service running on the server, you must now look at creating an ASP.NET client to consume this service.

To compile a client that accesses the Remoting Server Object, we require the assembly reference for the Remote Object. This can be obtained if the client developer is provided with the Remote Object's assembly. The Remote Server Object developer can create an assembly, which defines the interface for the Remote object, and distribute this information to clients. Alternatively, the client can generate a proxy object by using the Soapsuds command-line utility and a WSDL file. This section looks at using the Soapsuds command-line utilityh and WSDL file. Note that a non-.NET consumer of the Remoting service can use a similar technique because this method doesn't depend on a .NET assembly.

The Soapsuds tool requires a WSDL file to generate the proxy object. The configuration file for the service specifies the HTTP channel running on port 8085 and the objectUri parameter as AddressEntries.soap . You can get a service description file by using the following URL:

http://localhost:8085/AddressEntries.soap?WSDL

You can check the generated WSDL by entering this URL in the address location of the browser. Figure 11.20 shows the generated WSDL file in a browser.

Figure 11.20. The generated WSDL file viewed in the browser.
graphics/11fig20.gif
Generating a proxy Using the Soapsuds Tool

After you have a WSDL file, you can create a proxy for the service by using the WSDL tool or by adding a web reference in a Visual Studio .NET project. Here, we use the Soapsuds tool to create the proxy . The following command creates the source file and the assembly for the proxy , which we can add to our client application:

 Soapsuds url:http://localhost:8085/AddressEntries.soap?WSDL  - oa:RemoteObject.dll 

For more information on all the available options for the Soapsuds tool, refer to Chapter 4.

Listing 11.18 shows the source generated by the Soapsuds tool for the proxy object.

Listing 11.18 Soapsuds Generated proxy Source Code ( RemoteObject.cs )
 namespace RemotingAddressBookService { using System;  using System.Runtime.Remoting.Messaging;  using System.Runtime.Remoting.Metadata;  using System.Runtime.Remoting.Metadata.W3cXsd2001;      [Serializable, SoapType(XmlNamespace="http://schemas.microsoft.com/clr/nsassem/ graphics/ccc.gif RemotingAddressBookService/RemoteObject", XmlTypeNamespace="http://schemas.microsoft.com/ graphics/ccc.gif clr/nsassem/RemotingAddressBookService/RemoteObject")]      public class AddressEntry      {         // Class Fields          public Int32 id;          public String firstName; NET;Remoting objects;consuming>          public String lastName;          public String email;          public String phone;      }      [SoapType(XmlNamespace="http://schemas.microsoft.com/clr/nsassem/Remoting graphics/ccc.gif AddressBookService/RemoteObject",XmlTypeNamespace="http:// schemas.microsoft.com/clr/ graphics/ccc.gif nsassem/RemotingAddressBookService/ RemoteObject")]      public class AddressEntries : System.Runtime.Remoting.Services.RemotingClientProxy      {         // Constructor          public AddressEntries()          {             base.ConfigureProxy(this.GetType(),  "http://165.193.123.15:8085/AddressEntries.soap");  System.Runtime.Remoting.SoapServices.PreLoad(typeof(RemotingAddressBook graphics/ccc.gif Service.AddressEntry));          }          // Class Methods  [SoapMethod(SoapAction="http://schemas.microsoft.com/clr/nsassem/Remoting graphics/ccc.gif AddressBookService.AddressEntries/RemoteObject#GetAddressEntry")]          public AddressEntry GetAddressEntry(Int32 addrEntryID)          {             return ((AddressEntries) _tp).GetAddressEntry(addrEntryID);          }  [SoapMethod(SoapAction="http://schemas.microsoft.com/clr/nsassem/Remoting graphics/ccc.gif AddressBookService.AddressEntries/RemoteObject#GetCount")]          public Int32 GetCount()          {             return ((AddressEntries) _tp).GetCount();          }      }  } 

Listing 11.19 shows the part of the code from an ASP.NET page that uses the Remoting Server Object.

Listing 11.19 An ASP.NET Client for the Remoting Server Object ( Client.aspx )
 private void Page_Load(object sender, System.EventArgs e)  { try  {      HttpChannel channel = null;       //Confirm that the channel is not alredy registered       if (ChannelServices.GetChannel("AddrHttpChannel")==null)       {           IDictionary props = new Hashtable();            props["name"] = "AddrHttpChannel";            channel = new HttpChannel(props,                 null,                 new  BinaryServerFormatterSinkProvider());            //Register the channel            ChannelServices.RegisterChannel(channel);       }       //Get the ObjRef for the  AddressEntries Remote Object       AddressEntries addrEntires =            (AddressEntries)Activator.GetObject(typeof(RemotingAddressBookService.AddressEntries)            , "http://localhost:8085/AddressEntries.soap");       if (addrEntires == null)       {           divAddrCount.InnerHtml = "<B>Could not locate server</B>";       }       else       {           //Call the method GetCount() on the AddressEntries Object            divAddrCount.InnerHtml = "<B>Total number of Addresses in the"                 + " Address Book: </B>" + addrEntires.GetCount();            //Call the method GetAddressEntry() on the AddressEntries Object            AddressEntry addrEntry = addrEntires.GetAddressEntry(1);            //Use the properties of the serialized AddressEntry Object            divAddressEntry.InnerHtml = "<B>Details of Address Entry [id =1]:</B>"                 + "<BR><B>First Name :</B>" + addrEntry.firstName                 + "<BR><B>Last Name :</B>" + addrEntry.lastName ;       }  }  catch(RemotingException remEx)  {  //Handle Remoting Exception       divAddrCount.InnerHtml = "<B>The following Remoting Exception occurred:</B><BR>"            + remEx.Message ;  }  catch(System.Net.WebException webEx)  {  //Handle Web Exception       divAddrCount.InnerHtml = "<B>The following Web Exception occurred:</B><BR>"            + webEx.Message + " Confirm that the Remoting service is started and try graphics/ccc.gif again.";  }  catch(Exception ex)  {  //Handle Web Exception       divAddrCount.InnerHtml = "<B>The following Exception occurred :</B><BR>"            + ex.Message ;  }  } 

Figure 11.21 shows the result of invoking the Client.aspx page.

Figure 11.21. The result of invoking the Client.aspx page.
graphics/11fig21.gif
only for RuBoard


XML and ASP. NET
XML and ASP.NET
ISBN: B000H2MXOM
EAN: N/A
Year: 2005
Pages: 184

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