From the discussion in the previous sections, you know that it is easy to create a serviced component all you need to do is inherit from the ServicedComponent class and apply attributes to use various COM+ component services. However, to use the COM+ component services, the component must be registered in the COM+ catalog. The following list summarizes the typical steps involved in creating and registering a serviced component. Create a class that inherits from the ServicedComponent class. Compile the class by assigning a strong name to create a strongly named assembly. Run the .NET Services Installation tool (regsvcs.exe) to install the assembly in the COM+ catalog. After you have installed the serviced component in the COM+ catalog, you can create instances of the serviced components, or you can use the Component Services administrative tool to configure it. Creating a Serviced Component Follow these steps to create a simple serviced component and register it with COM+: Create a new blank solution named C08 at C:\EC70320. Add a new Visual C# .NET Class Library project (Example8_1) to the solution. Rename the default Class1.cs to NorthwindSC.cs. Add a reference to the System.EnterpriseServices component. Open NorthwindSC.cs and replace the code with the following code: using System; using System.Data; using System.Data.SqlClient; using System.EnterpriseServices; using System.Runtime.InteropServices; namespace Example8_1 { public interface INorthwind { DataSet ExecuteQuery(string strQuery); int UpdateData(DataSet ds); } [Guid("0F1FD944-ADDC-4d34-A4D0-90F9AA707930")] [ClassInterface(ClassInterfaceType.None)] public class NorthwindSC : ServicedComponent, INorthwind { private SqlConnection sqlcnn; private SqlDataAdapter sqlda; private DataSet ds; public NorthwindSC() { sqlcnn = new SqlConnection(@"data source=(local)\NetSDK;" + "initial catalog=Northwind;integrated security=SSPI"); } // Executes a SELECT query and returns a DataSet object public DataSet ExecuteQuery(string strQuery) { // 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"); return ds; } // Updates the database with the changes in a DataSet object public int UpdateData(DataSet ds) { // Update the database and return the result SqlCommandBuilder sqlcb = new SqlCommandBuilder(sqlda); return sqlda.Update(ds.Tables["Results"]); } } } | You should use interfaces to make the methods in a .NET component visible to the COM clients. The ClassInterface attribute specifies how the interfaces will be generated for a class. It can take one of three values: ClassInterfaceType.AutoDispatch, ClassInterfaceType.AutoDual, or ClassInterfaceType.None. The AutoDispatch setting can lead to versioning problems and should be avoided in most cases. The AutoDual setting does not support early binding. The None setting requires explicit declaration of interfaces and is the most desirable option in most cases. |
| Each component in an assembly can be uniquely identified by applying the Guid attribute. If you don't hard-code any GUID for a component, a GUID is automatically generated for the component by the assembly-registration process each time a different version of the component is registered in the COM+ catalog. |
Launch the Visual Studio .NET command prompt. Change the directory to the folder where the C08 solution resides and issue the following command to create a pair of public/private keys: sn -k 70320.snk Open the AssemblyInfo.cs file in the project and add the following using directive: using System.EnterpriseServices; Add assembly level attributes ApplicationActivationControl, ApplicationName, Description, and ApplicationActivation to AssemblyInfo.cs as follows: [assembly: AssemblyVersion("1.0.0")] [assembly: ApplicationAccessControl()] [assembly: ApplicationName("Northwind Data Application")] [assembly: Description("Retrieve and Update data " + "from the Northwind database")] [assembly: ApplicationActivation(ActivationOption.Library)] [assembly: AssemblyKeyFile(@"..\..\..\70320.snk")] Build the project. This step packages the serviced component into the file Example8_1.dll, which is located in the bin directory of your project. Switch to the Visual Studio .NET command prompt and change the directory to where the Example8_1.dll file resides. Issue the following command to install the service component assembly to the COM+ Catalog: regsvcs Example8_1.dll | When a client application attempts to create an instance of a serviced component for the first time, the CLR automatically registers the assembly and configures the COM+ catalog. However, you should prefer registering the component by using the regsvcs.exe tool because this tool provides feedback about the errors encountered during the registration process. You might want to correct these errors before any client actually accesses the serviced component. |
Issue the following command to install the assembly to the Global Assembly Cache: gacutil /i Example8_1.dll | Installing the serviced components to the Global Assembly Cache is not mandatory but is highly recommended. Installation in the GAC ensures that the component is accessible to all the client applications on a computer. In addition, the GAC provides several other benefits, such as side-by-side versioning and file security. An assembly must be signed with a strong name before it can be installed in the GAC. |
After the serviced component is registered in the COM+ catalog, you can use the Component Services tool (available via the Administrative Tools section of the Windows Control Panel) to manage and configure the component, as shown in Figure 8.1. Figure 8.1. The Component Services tool enables you to manage and configure COM+ components. Consuming a Serviced Component Instantiating and using a serviced component is no different from doing so with any other managed component. Follow these steps to create a Windows form application that instantiates the serviced component that you just created: Add a new Visual C# .NET Windows Application project (Example8_2) to the solution. Add a reference to the System.EnterpriseServices and Example8_1 components. Add the following using directives to the Form1.cs code: using System.Data.SqlClient; using Example8_1; Place a TextBox control (txtQuery), two Button controls (btnExecute and btnUpdate), and a DataGrid control (dgResults) on the form. Add the following code in the class definition: // Declare the serviced component private NorthwindSC nsc; Double-click the form and add the following code in the Load event handler: private void Form1_Load(object sender, System.EventArgs e) { // Instantiate the serviced component nsc = new NorthwindSC(); } Double-click the Button controls and add the following code to their Click event handlers: private void btnExecute_Click(object sender, System.EventArgs e) { try { dgResults.DataSource = nsc.ExecuteQuery(txtQuery.Text); dgResults.DataMember = "Results"; } catch(Exception ex) { MessageBox.Show(ex.Message, "Invalid Query", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void btnUpdate_Click(object sender, System.EventArgs e) { try { int intRows = nsc.UpdateData((DataSet) dgResults.DataSource); MessageBox.Show(String.Format("{0} row(s) updated successfully", 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(Exception ex) { MessageBox.Show(ex.Message, "Update Failed", MessageBoxButtons.OK, MessageBoxIcon.Error) ; } } Build and run the project. Enter a query in the text box and click the button. The code invokes a method on the serviced component and binds the results to the DataGrid control. Make some changes to the data in the DataGrid control and click the Update button to save the changes to the database. If there is no error in the updates, a message box with the number of rows updated is displayed. |