In an enterprise application, you might be required to expose business objects remotely. In that case, a general practice is to add an extra tier that handles remote communication between the client and server. You can use your knowledge of .NET remoting and XML Web services to create such a tier .
In this exercise, you learn how to expose a serviced component via a remoting server. You'll create three projects: a serviced component that provides access to the Northwind database, a singleton remoting server that exposes the serviced component, and a client program that connects to the remoting server to invoke methods on the serviced component.
Estimated Time : 45 minutes.
Launch Visual Studio .NET. Select File, New, Blank Solution, and name the new solution 310C07Exercises . Click OK.
Add a new Visual Basic .NET Class library project named Exercise7-1SC to the solution.
In the Solution Explorer, right-click project Exercise7-1SC and select Add Reference from the context menu to add references to the System.EnterpriseServices component.
In the Solution Explorer, rename the default Class1.vb to NorthwindSC.vb .
Open the NorthwindSC.vb and replace the code with the following code (change the Guid attribute to one generated on your own computer):
Imports System Imports System.Data Imports System.Data.SqlClient Imports System.EnterpriseServices Imports System.Runtime.InteropServices Imports System.Diagnostics Public Interface INorthwind Function ExecuteQuery(_ ByVal strQuery As String) As DataSet Function UpdateData(_ ByVal strQuery As String, ByVal ds As DataSet) _ As Integer End Interface <EventTrackingEnabled(True), _ JustInTimeActivation(True), _ ObjectPooling(True, 2, 4), _ Guid("ABD66595-EFF2-430e-9821-A7F77DE70723"), _ ClassInterface(ClassInterfaceType.None)> _ Public Class NorthwindSC Inherits ServicedComponent Implements INorthwind Private sqlcnn As SqlConnection Private sqlda As SqlDataAdapter Private ds As DataSet Private el As EventLog Public Sub New() ' Create a connection to the ' Northwind SQL Server database sqlcnn = New SqlConnection(_ "data source=(local);" & _ "initial catalog=Northwind;" & _ "integrated security=SSPI") ' Create an EventLog object ' and assign its source el = New EventLog() el.Source = "Exercise7-1" ' Write an entry to the event log el.WriteEntry("A new " & _ "NorthwindSC object is created " & _ " and added to the object pool") End Sub Protected Overrides Sub Activate() el.WriteEntry(_ "A NorthwindSC object is " & _ "activated from the object pool") End Sub Protected Overrides Sub Deactivate() el.WriteEntry(_ "A NorthwindSC object is " & _ " deactivated and is " & _ "returned to the object pool") End Sub Protected Overrides Function CanBePooled() _ As Boolean CanBePooled = True End Function Public Function ExecuteQuery(_ ByVal strquery As String) As DataSet _ Implements INorthwind.ExecuteQuery ' Create a SqlDataAdapter object ' to talk to the database sqlda = New SqlDataAdapter(_ strquery, sqlcnn) ' Create a DataSet object ' to hold the results ds = New DataSet() ' Fill the DataSet object sqlda.Fill(ds, "Results") ' Deactivate the object ' when the method returns ContextUtil.DeactivateOnReturn = True ExecuteQuery = ds End Function <AutoComplete()> _ Public Function UpdateData(_ ByVal strQuery As String, _ ByVal ds As DataSet) As Integer _ Implements INorthwind.UpdateData ' Update the database sqlda = New SqlDataAdapter(_ strQuery, sqlcnn) Dim sqlcb As SqlCommandBuilder = _ New SqlCommandBuilder(sqlda) UpdateData = sqlda.Update(_ ds.Tables("Results")) End Function End Class
Open the AssemblyInfo.vb file in the project and add the following Imports directive:
Imports System.EnterpriseServices
Add the following assembly level attributes in the AssemblyInfo.vb file:
<Assembly: ApplicationName(_ "Northwind Data Application " & _ "exposed via Remoting")> <Assembly: Description(_ "Retrieve and Update data " & _ "from the Northwind database")> <Assembly: ApplicationActivation(_ ActivationOption.Server)>
Copy the 70310.snk key pair file to the exercise's solution folder. Change the AssemblyVersion and AssemblyKeyFile attributes in the AssemblyInfo.vb file as shown here:
<Assembly: AssemblyVersion("1.0")> <Assembly: AssemblyKeyFile("..\..\..310.snk")>
Build the project. An Exercise7-1SC.dll is generated, and a strong name is assigned to the file based on the specified key file.
Launch the Visual Studio .NET command prompt and change the directory to the folder where the DLL file generated in step 9 resides. Issue the following command to install the assembly to the GAC:
gacutil /i Exercise7-1SC.dll
In the command prompt, issue the following command to install the service component assembly to the COM+ Catalog:
regsvcs Exercise7-1SC.dll
Add a new Visual Basic .NET Console application named Exercise7-1Server to the solution.
In the Solution Explorer, right-click project Exercise7-1Server and select Add Reference from the context menu to add references to the System.Runtime.Remoting , System.EnterpriseServices , and Exercise7-1SC components.
In the Solution Explorer, rename the default Module1.vb to NorthwindSCServer.vb . Open the file and change the name of the module to NorthwindSCServer in the module declaration.
Add the following Imports directives:
Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.Tcp
Add the following code in the Main() method:
Sub Main() ' Create and Register a TCP ' server channel that ' listens on port 1234 Dim channel As TcpServerChannel = _ New TcpServerChannel(1234) ChannelServices.RegisterChannel(_ channel) ' Register the service that ' publishes NorthwindSC for ' remote access in Singleton mode RemotingConfiguration. _ RegisterWellKnownServiceType(_ GetType(Exercise7_1SC.NorthwindSC), _ "NorthwindSC", _ WellKnownObjectMode.Singleton) Console.WriteLine(_ "Started server " & _ "in the Singleton mode") Console.WriteLine(_ "Press <ENTER> to " & _ "terminate server...") Console.ReadLine() End Sub
Build the project. This step creates a remoting server capable of registering the Exercise7_1SC.NorthwindSC serviced component for remote invocation using the SingleCall activation mode.
Add a new Visual Basic .NET Windows application named Exercise7-1Client to the solution.
Add references to the .NET assembly System.Runtime.Remoting and System.EnterpriseServices , as well as the project Exercise7-1SC (the serviced component class assembly).
Add the following Imports directives:
Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.Tcp Imports Exercise7_1SC
Place a TextBox control ( txtQuery ), two Button controls ( btnExecute and btnUpdate ), and a DataGrid control ( dgResults ) on the form. Arrange the controls as shown in Figure 7.17.
Double-click the form and add the following code in the Load event handler:
Private Sub Form1_Load(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load ' Register a TCP client channel Dim channel As TcpClientChannel = _ New TcpClientChannel() ChannelServices.RegisterChannel(_ channel) ' Register the remote class as a valid ' type in the client's ' application domain RemotingConfiguration. _ RegisterWellKnownClientType(_ GetType(NorthwindSC), _ "tcp://localhost:1234/NorthwindSC") End Sub
Double-click the Button controls and add the following code in their Click event handlers:
Private Sub btnExecute_Click(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnExecute.Click ' Declare and Instantiate ' the remote serviced component Dim nsc As NorthwindSC = _ New NorthwindSC() Try ' Call the ExecuteQuery() method dgResults.DataSource = _ nsc.ExecuteQuery(txtQuery.Text) dgResults.DataMember = "Results" Catch ex As Exception MessageBox.Show(ex.Message, _ "Invalid Query", _ MessageBoxButtons.OK, _ MessageBoxIcon.Error) End Try End Sub Private Sub btnUpdate_Click(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnUpdate.Click ' Declare and Instantiate ' the remote serviced component Dim nsc As NorthwindSC = _ New NorthwindSC() Try ' Call the UpdateData() method Dim intRows As Integer = _ nsc.UpdateData(_ txtQuery.Text, _ CType(dgResults.DataSource, _ DataSet)) MessageBox.Show(String.Format(_ "{0} row(s) updated", intRows), _ "Row(s) Updated", _ MessageBoxButtons.OK, _ MessageBoxIcon.Information) ' Load the updates and bind the ' grid with the updates dgResults.DataSource = _ nsc.ExecuteQuery(txtQuery.Text) dgResults.DataMember = "Results" Catch ex As Exception MessageBox.Show(ex.Message, _ "Update Failed", _ MessageBoxButtons.OK, _ MessageBoxIcon.Error) End Try End Sub
Build the project. Start the remoting server and then start the client. Enter some queries to retrieve data from the Northwind database to test your programs.
Application pooling allows more than one instance of the COM+ server application to run at a time. By default, the size of application pool is set to 1. If you set this size to a higher value, for example 4, the first four activation requests to the application create four instances of dllhost.exe each running this application. Later requests for applications are then routed through this pool of dllhost.exe processes. Application activation increases the scalability of the application and provides support for application failover.
Using the automatic application recycling service, you can configure an application to shut down and restart automatically when a problem occurs. Some of the criteria on which you can configure recycling include lifetime limit, memory limit, call limit, and so on.
Both application pooling and recycling are features of COM+ 1.5. Currently, the .NET Framework SDK does not provide any attribute to configure these services in your program. If you need to configure these services in a program, you must instead rely on the COM+ Administrative SDK support.
However, you can also use the Component Services administrative tool to administratively configure these services. In this exercise, you learn how to configure application pooling and recycling on a machine running COM+ 1.5 (that is, on Windows XP and Windows .NET computers).
Estimated Time : 5 minutes.
Open the Component services administrative tool.
Right-click the Ordering Application and select Properties from the shortcut menu. In the Ordering Application Properties dialog box, select the Pooling & Recycling tab as shown in Figure 7.36.
Set the Pool Size to 4, the Lifetime limit to 5 minutes, and the Call Limit to 10.
Apply the changes. Start the order form and place a few orders. See the list of the running processes; you see that multiple instances of dllhost.exe are created for the Ordering Application and if you wait for five minutes or place 10 orders, a new dllhost.exe process is started.
1: | What is the COM+ catalog and what it is used for? |
A1: | The COM+ catalog is a repository that is used by COM+ to store the information about the serviced components and their runtime requirements. |
2: | What is the significance of using the AutoComplete attribute in a method declaration? |
A2: | Using the AutoComplete attribute in a method declaration is equivalent to writing code to call ContextUtil.SetComplete() or ContextUtil.SetAbort() , respectively when a method successfully completes or when it completes with an error. |
3: | What is the use of the CanBePooled() method for a pooled object? |
A3: | When a pooled object is about to be deactivated, the CanBePooled() method is called to check whether the object should be returned to the object pool or be destroyed . An object is returned to the object pool only when the CanBePooled() method returns true. |
4: | How does a client instantiate a queued component? |
A4: | To instantiate a queued object, the client uses Marshal.BindToObject() method. This method accepts a moniker name that identifies the target queued component. This method then instantiates a recorder for the queued component. The client can record all the calls on this recorder. When the queued component becomes available, the recorded calls are played back to the queued component. |
5: | How can you use COM+ services to increase the throughput of an application? |
A5: | You can use the COM+ just-in-time activation and object pooling services for the following reasons:
|
6: | How would you specify the type of transaction available to a serviced component? |
A6: | The Transaction attribute can be used to specify the type of transaction available to a component. This is done by setting its value to one of the TransactionOption values Disabled , NotSupported , Required , RequiresNew , or Supported . |
7: | What is the use of the ContextUtil class? |
A7: | The ContextUtil class provides several methods and properties to obtain information about the COM+ object contexts. |
8: | What are some of the scenarios in which you might like to use the COM+ object pooling service? |
A8: | Some of these scenarios include
|
9: | State a few guidelines for designing a queued component. |
A9: | While designing a queued component, you must consider the following guidelines:
|
10: | What is a COM Callable Wrapper (CCW)? |
A10: | A CCW is a proxy object generated by the CLR so that existing COM applications can use the .NET Framework components transparently . |
1: | You create a COM+ application named Inventory Application. This application contains a single serviced component named InventoryStatus that is present in an assembly named inventorystatus.dll . The InventoryStatus component is used by many client applications to monitor the status of the inventory. The client applications access the serviced component on a frequent basis. Which of the following options should you choose to ensure that the methods on InventoryStatus are processed as quickly as possible?
|
A1: | B. Method calls will execute fastest when the application is configured as a library application because the library application executes in the client's process. |
2: | You are creating a serviced component that will be called from both managed and unmanaged client applications. You write the business logic using a class library project and then compile the project into a strongly named assembly. As a next step, you want to register the assembly in the COM+ catalog. You want to detect and correct any registration errors before any client applications use the component. Which of the following tools should you use to register the assembly?
|
A2: | D. Among the given options, the only tool that actually registers a strongly named assembly with the COM+ catalog is the .NET Services Installation Tool (regsvcs.exe). |
3: | You create a serviced component that allows users to connect to a homegrown ERP system that your company uses for various critical business operations. You register the component in the COM+ catalog of the main application server. You enable object pooling services for the component and set Minimum Pool Size to 10 and Maximum Pool Size to 75. You monitor the statistics for the serviced component and find that 75 objects are already in use. What is the most likely result if one more request for an object is received?
|
A3: | A. If no object is available and no new object can be created because of the size restriction of the pool, the client requests are queued to receive the first available object from the pool. If an object cannot be made available within the time specified in the CreationTimeOut property, an exception is thrown. |
4: | You create a serviced component named OrderProcess . This component updates several SQL Server databases to complete a customer's order. The OrderProcess class includes the following code: <Transaction(TransactionOption.Required)> _ Public Class OrderProcess Implements ServicedComponent Public Sub PlaceOrder(ByVal o As OrderInfo) ' Code to update various databases End Sub End Class You must ensure the reliability of the PlaceOrder() method. The PlaceOrder() method should either update all or none of the databases. What should you do?
|
A4: | B. When you use the AutoComplete attribute with a method, COM+ intercepts to set the done bit and consistent bits after the method call returns. If there were no errors in the method call, the consistent bit is set to True ; otherwise , the consistent bit is set to False . This setting ensures that the changes to the database are committed or rolled backed reliably. |
5: | You create a serviced component named OrderProcess . This component receives orders from the client applications in an asynchronous fashion. The OrderProcess class includes the following code: Public Interface IOrderProcess Sub PlaceOrder(o _ As OrderInfo) End Interface <Transaction(TransactionOption.Required), _ InterfaceQueuing(Enabled:=True, _ Interface:="IOrdering")> _ Public Class OrderProcess Inherits ServicedComponent, Implements IOrderProcess Public Sub PlaceOrder(o As OrderInfo) ' Code to update various databases End Sub End Class You need to write code for a client program that uses the OrderProcess component to place an order. Which code segment should you use?
|
A5: | C. You use the Marshal.BindToMoniker() method to get an object containing a reference to the interface pointer identified by given queue moniker. |
6: | You create a queued component named OrderProcess . This component receives orders from the client applications in an asynchronous fashion. The OrderProcess class includes the following code: Public Interface IOrderProcess Function PlaceOrder(o As OrderInfo) _ As Boolean End Interface <Transaction(TransactionOption.Required), _ InterfaceQueuing(Enabled:=true, _ Interface:="IOrderProcess")> _ Public Class OrderProcess Inherits ServicedComponent Implements IOrderProcess Public Function PlaceOrder(_ o As OrderInfo) As Boolean ' code to update various databases End Function End Class You get no compilation errors, but when you register this component using the .NET Framework Services Installation Tool (regsvcs.exe), you get an error message"Queuing not supported on interface 'IOrderProcess'." What should you do in order to resolve this error?
|
A6: | C. The interface that a queued component uses for queuing must have Sub methods having only pass- by-value parameters. Therefore, you need to change the PlaceOrder() method from a function, returning a Boolean value to a Sub procedure. |
7: | You are developing a serviced component that will be used by several client applications. Some client applications are COM based, whereas other client applications run on the .NET Framework. In the future, you plan to release new versions of your serviced component but do not want to recompile the client applications. How should you design the interfaces for such a serviced component?
|
A7: | A. ClassInterfaceType.None is the recommended setting for the ClassInterface attribute. ClassInterfaceType.AutoDual causes versioning problems, and ClassInterfaceType.AutoDispatch supports only late binding and does not allow the configuration of methods through the Component Services administrative tool. |
8: | You are writing a serviced component that will be used by users over the network. The number of users simultaneously supported by the component depends on the license agreement. Which of the following attributes would you use to restrict the number of simultaneous connections to the serviced component?
|
A8: | D. You use can use the COM+ object pooling service to restrict the number of objects for a serviced component. Therefore, you use the ObjectPooling attribute. |
9: | Your colleague is testing a queued component that she just developed. She is able to configure the serviced component using the Component Services administrative tool, but the client application cannot find the component. Of the following options, what should you suggest to your colleague to resolve this problem?
|
A9: | B. A queued component is activated as a server application. To ensure that the client is able to locate the component, you must install the component in the Global Assembly Cache. |
10: | You are creating a serviced component named DataConnector . After the component is deployed, the system administrators should be able to configure the component to connect to various data sources by specifying the connection string of the data source. The serviced component will be used by both COM and .NET applications. You want to retrieve the specified connection string in your component and change the behavior of the serviced component. Which of the following techniques should you use to achieve this?
|
A10: | B. You should override the Construct() method to receive the connection string specified by the administrator. |
11: | You have created a business object using Visual Basic .NET. You want the business object to be used by COM clients as well as .NET clients. You want to deploy the business object on the client computers in such a way that the client can take advantage of late binding as well as early binding with the interfaces exposed by the business object. Which of the following methods would you use to accomplish this?
|
A11: | B. Regasm.exe, when used with the /tlb option, registers the assembly in the registry (for late binding) as well as creates a CCW in a tlb file, which can be used by the client programs at the time of compilation (early binding). |
12: | You have written the following code for a serviced component. Public Interface IOrderProcess Function PlaceOrder(_ o As OrderInf) As Boolean End Interface <JustInTimeActivation(True), _ Transaction(TransactionOption.Required)> _ Public Class OrderProcess Inherits ServicedComponent, ImplementsIOrderProcess Public Function PlaceOrder(_ o As OrderInfo) As Boolean ' Code to update various databases End Function End Class In the PlaceOrder() method, you decide whether all the databases have been updated correctly. If yes, you commit the transaction and deactivate the current OrderProcess object. Which of the following methods should you use in the PlaceOrder() method to accomplish this requirement?
|
A12: | D. You should use the SetComplete() method because it sets the consistent bit as well as the done bit to True . Using the EnableCommit() method sets the consistent bit to True but also sets the done bit to False , which does not deactivate the object after the method call returns. |
13: | You create a serviced component that will only be used by .NET client programs. You want to use the COM+ object creation service from the serviced component. Which of the following options must you take in order for the programs to use the serviced component? (Select all that apply.)
|
A13: | C and D. You must at least sign the component with a strong name and then register the component in the global assembly cache. Just registering the component with Windows Registry is not sufficient because the component must be available to COM+. In addition, installing the component in the Global Assembly Cache is not required as long as you make sure that the process can locate the assembly. |
14: | You are developing a distributed order processing application for your company. The sales associates receive the orders over the telephone. The orders are entered in the ordering system through a Windows form application. The Windows form application calls a set of serviced components to accomplish its task. You must continue to receive orders even if one or more order processing component fails. Which of the following COM+ services should you use in the serviced components to ensure high availability of the system?
|
A14: | A. To ensure high availability of the components, you should use the COM+ queued component service. |
15: | You have been given an assignment to develop the order processing application for your organization. The application needs to support a large amount of users and should perform well even between 8 a.m. and noon, which is the peak time for receiving and processing orders. Which of the following COM+ services would you use in your application? (Select all that apply.)
|
A15: | C and D. For achieving maximum performance, you can use COM+ object pooling and just-in-time activation services. |
1. Visual Studio .NET Combined Help Collection
Writing Serviced Components
Serviced Components Programming Guidelines
COM+ Programming Overview
2. Building Distributed Applications with .NET, msdn.microsoft.com/nhp/default.asp?contentid=28001271.
3. The .NET Six-week series guide, msdn.microsoft.com/net/guide.
4. MSDN Index of How-To Articles, msdn.microsoft.com/howto/howto_index.asp.
5. .NET Architectural Sample Applications, msdn.microsoft.com/library/en-us/dnbda/html/bdadotnetsamp0.asp.
6. Enterprise Development Technology Map, msdn.microsoft.com/library/en-us/Dndotnet/html/Techmap_enterprise1.asp.
7. Lowy, Juval, COM and .NET Component Services (O'Reilly, 2002).
Top |