Microsoft KB Archive/318185

= HOW TO: Use Loosely Coupled Events from Visual Studio .NET =

Article ID: 318185

Article Last Modified on 9/24/2003

-

APPLIES TO


 * Microsoft Visual Studio .NET 2002 Professional Edition
 * Microsoft .NET Framework Class Libraries 1.0

-



This article was previously published under Q318185





IN THIS TASK
SUMMARY
 * Requirements
 * Create a .NET Assembly that Uses Loosely Coupled Events
 * Code for the Class1.cs File
 * Code for the AssemblyInfo.cs File
 * Code for the Form1.cs File
 * Verify it Works
 * Troubleshooting

REFERENCES



SUMMARY
Use this step-by-step guide to create a .NET assembly containing a publisher, a subscriber, and an interface for handling loosely coupled events in Microsoft COM+ Services.

back to the top

Requirements
The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:
 * Microsoft Windows 2000 Professional, Microsoft Windows 2000 Server, Microsoft Windows XP Professional, or Microsoft Windows XP Server.
 * Microsoft .NET Framework.
 * Microsoft Visual Studio .NET.
 * Microsoft Visual C# .NET.
 * Microsoft COM+.

This article assumes that you are familiar with the following topics:
 * COM and Enterprise Services.
 * Extending meta data by using attributes.

back to the top

Create a .NET Assembly that Uses Loosely Coupled Events
The following procedure creates a .NET assembly containing a publisher, a subscriber, and an interface that handles loosely coupled events in COM+ Services:  Click Start, point to Programs, point to Microsoft Visual Studio .NET, and then click Microsoft Visual Studio .NET. Click New Project. In Project Types, click Visual C# Projects. In Templates, select Windows Application. In the Name box, type HowToLCE, and then click OK.

You now have a Solution containing the shell of a Windows Forms application. Create a Class Library that contains code for the publisher, the subscriber, and the interface that is shared by both. On the File menu, point to Add Project and then click New Project.</li> In Project Types, click Visual C# Projects.</li> In Templates, click Class Library.</li> In the Name box, type ClassLibLCE, and then click OK.</li> In Solution Explorer, under ClassLibLCE, right-click References, and then click Add Reference.</li> On the .NET tab, under References, click System.EnterpriseServices and then click Select. Click OK.</li>  Add the following Using directives at the top of the Class1.cs file to access classes in these namespaces: using System.EnterpriseServices; using System.Diagnostics; When you compile the Class Library component, it becomes a .NET assembly. After you register it, you can run it under COM+ Services because the publisher and subscriber derive from EnterpriseServices.ServicedComponents. </li>  Declare the interface these two classes will share. In the Class1.cs file, add the following code after public class Class1: public interface IEvSink {   void OnEvent1; void OnEvent2; }                   </li>  Replace public class Class1 with the following code for the Publisher class: [EventClass] public class MyPublisher : ServicedComponent, IEvSink {   public MyPublisher {   //     // TODO: Add constructor logic here. //    }    public void OnEvent1 {}     public void OnEvent2 {}   } Notice the preceding class is decorated with the [EventClass] attribute. This attribute is critical. It tells COM+ Services that this class forms the connection between the publisher and its subscriber(s). When you have worked through all the code in this article, notice that there are no direct calls to the MyPublisher class. In other words, the interaction between publisher and subscriber is handled by COM+ Services by the class with the [EventClass] attribute. Therefore, the publisher does not have any direct knowledge of the subscriber(s). Any subscriber registered with COM+ Services for this application that uses the IEvSink interface can receive events from the publisher. </li>  The final bit of code required in the Class Library is for the subscriber. This class handles the events fired by the publisher. In this case, you make a simple entry in the Event Log to show that the subscriber is notified when a call is made to the published interface. Add the following code after the MyPublisher class: public class MySubscriber : ServicedComponent, IEvSink {   EventLog ev = new EventLog(&quot;Application&quot;);

public void OnEvent1 {       ev.Source = &quot;ClassLibLCE&quot;; ev.WriteEntry(&quot;OnEvent1 Fired&quot;); }

public void OnEvent2 {       ev.Source = &quot;ClassLibLCE&quot;; ev.WriteEntry(&quot;OnEvent2 Fired&quot;); } }                   </li> To use the assembly compiled from the Class Library, give it a strong name. To generate this cryptographic key pair, use the SN tool (Sn.exe). It is located in the \bin folder where the .NET Framework Software Developer's Kit (SDK) documentation is installed. The SN Tool is very easy to use. The command line statement uses the following syntax:

sn -k &quot;C:\%DirectoryToPlaceKey%\%KeyName%.snk&quot;

</li> Run this command from the Visual Studio .NET command prompt. Click Start, point to Programs, point to Microsoft Visual Studio .NET, point to Visual Studio .NET Tools, and then click Visual Studio .NET Command Prompt. At the command prompt, type the following:

sn -k &quot;C:\ClassLibLCE\key.snk&quot;

If your Class Library project is not in this path, change the path to the root of the project folder for your Class Library project.

A key is generated. To verify this, in Solution Explorer, select ClassLibLCE and then click the Show All Files button on the Solution Explorer toolbar.

Notice the key.snk item under ClassLibLCE.</li> Because this key is not yet associated with the Class Library assembly, create this association. In Solution Explorer, under ClassLibLCE, double-click AssemblyInfo.cs. In AssemblyKeyFile, type the following between the existing quotation marks:

&quot;..\\..\\key.snk&quot;

</li> Complete the code for the whole solution by wiring up a Windows Form to the Class Library. Remember that this Form is merely for demonstration purposes. It basically serves as a &quot;test harness&quot;. Add the appropriate references. <ol style="list-style-type: lower-alpha;"> In Solution Explorer, under HowToLCE, right-click References, and then click Add Reference on the shortcut menu.</li> On the .NET tab, click System.EnterpriseServices.</li> On the Projects tab, click ClassLibLCE.</li> <li>Click Select.</li> <li>Click OK.

Notice the System.EnterpriseServices and ClassLibLCE items listed under References.</li></ol> </li> <li> In the Code Editor, click the Form1.cs [Design] tab. Double-click anywhere on the Form to create a Form1_Load event handler. To this event handler add the following code.

Notice that there are two sections. The first is solely for the purpose of registering the Class Library. It is used only one time. The second triggers the publisher events. // Section #1 // Register Class Library as a COM+ application. ClassLibLCE.MySubscriber l = new ClassLibLCE.MySubscriber ;

// Section #2 // Call Events on Publisher // ClassLibLCE.MyPublisher l = new ClassLibLCE.MyPublisher; // l.OnEvent1; // l.OnEvent2; </li> <li>Press F5 to run the application and register the Class Library.

This makes the subscriber accessible to, but not yet registered with, COM+ Services. After the Form loads, close it. This is the simplest method of registering a .NET Assembly so that it can take advantage of COM+ Services. However, to register in this manner you must be logged on to the local computer with Administrative rights. If users who use your application do not have Administrative rights to their local computer, you can register an assembly by using the Regasm.exe utility for them when you deploy the application.</li> <li>Run the Component Services snap-in.

You cannot set up subscribers by using attributes in .NET version 1.0. But, you can do this manually by running the Component Services snap-in: Open Control Panel, double-click Administrative Tools, and then double-click Component Services.

NOTE: If you want, you can write code to automate the following steps by using the COM+ 1.0 Admin Library. For additional information, view the Library contents in the Object Browser.</li> <li>Expand Component Services. Expand Computers. Expand My Computer. Expand COM+ Applications. Expand ClassLibLCE. Expand Components. Expand ClassLibLCE.MySubscriber.</li> <li>Right-click the Subscriptions folder, point to New, and then click Subscription.</li> <li>In the COM+ New Subscription Wizard, click Next. Select the Subscribe to the IEvSink interface option. Click Next.</li> <li>In the Select Event Class page, click ClassLibLCE.MyPublisher. (This is the class that was decorated with the [EventClass] attribute.) Click Next.</li> <li>Enter the name you want to use and then click to select the Enable this subscription immediately check box. Click Next. Click Finish.</li></ol>

back to the top

Code for the Class1.cs File
using System; using System.EnterpriseServices; using System.Diagnostics;

namespace ClassLibLCE {      ///        /// Summary description for Class1. ///       [EventClass] public class MyPublisher : ServicedComponent, IEvSink {        public MyPublisher {        //          // TODO: Add constructor logic here. //         }

public void OnEvent1 {}

public void OnEvent2 {}        }

public class MySubscriber : ServicedComponent, IEvSink {       EventLog ev = new EventLog(&quot;Application&quot;);

public void OnEvent1 {           ev.Source = &quot;ClassLibLCE&quot;; ev.WriteEntry(&quot;OnEvent1 Fired&quot;); }

public void OnEvent2 {           ev.Source = &quot;ClassLibLCE&quot;; ev.WriteEntry(&quot;OnEvent2 Fired&quot;); }   }

public interface IEvSink {       void OnEvent1; void OnEvent2; } } back to the top

Code for the AssemblyInfo.cs File
using System.Reflection; using System.Runtime.CompilerServices;

// // General information about an assembly is controlled through the // following set of attributes. Change these attribute values to modify // the information associated with an assembly. // [assembly: AssemblyTitle(&quot;&quot;)] [assembly: AssemblyDescription(&quot;&quot;)] [assembly: AssemblyConfiguration(&quot;&quot;)] [assembly: AssemblyCompany(&quot;&quot;)] [assembly: AssemblyProduct(&quot;&quot;)] [assembly: AssemblyCopyright(&quot;&quot;)] [assembly: AssemblyTrademark(&quot;&quot;)] [assembly: AssemblyCulture(&quot;&quot;)]

// // Version information for an assembly includes the following four // values: //     Major Version //     Minor Version //     Build Number //     Revision // // You can specify all the values or you can use the default Revision and // Build Numbers by using the '*', similar to this:

[assembly: AssemblyVersion(&quot;1.0.*&quot;)]

// // To sign your assembly, specify a key to use. For more // information about assembly signing, see the Microsoft .NET Framework // documentation. // // Use the following attributes to control which key is used for signing. // // NOTES: //  (*) If no key is specified, the assembly is not signed. //  (*) KeyName refers to a key that is installed in the Crypto Service //      Provider (CSP) on your computer. KeyFile refers to a file that //      contains a key. //  (*) If the KeyFile and the KeyName values are both specified, the //      following processing occurs: //      (1) If the KeyName is found in the CSP, that key is used. //      (2) If the KeyName does not exist and the KeyFile does exist, the //          key in the KeyFile is installed into the CSP and used. //  (*) To create a KeyFile, you can use the Sn.exe (Strong Name) //      tool. When specifying the KeyFile, the location of the KeyFile //      must be relative to the project output folder which is //       %Project Directory%\obj\. For example, if your //      KeyFile is located in the project folder, specify the //      AssemblyKeyFile attribute as //          [assembly: AssemblyKeyFile(&quot;..\\..\\mykey.snk&quot;)] //  (*) Delay Signing is an advanced option. For more information, see the //      Microsoft .NET Framework documentation. // [assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile(&quot;..\\..\\key.snk&quot;)] [assembly: AssemblyKeyName(&quot;&quot;)] back to the top

Code for the Form1.cs File
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;

namespace HowToLCE {   ///     /// Summary description for Form1. ///    public class Form1 : System.Windows.Forms.Form {       ///         /// Required designer variable. ///        private System.ComponentModel.Container components = null;

public Form1 {           //             // Required for Windows Form Designer support. //            InitializeComponent;

//            // TODO: Add any constructor code after the // InitializeComponent call. //        }

///        /// Clean up any resources being used. ///        protected override void Dispose( bool disposing ) {           if( disposing ) {               if (components != null) {                   components.Dispose; }           }            base.Dispose( disposing ); }

#region Windows Form Designer generated code ///        /// Required method for Designer support; do not modify /// the contents of this method with the Code Editor. ///        private void InitializeComponent {           //             // Form1 //            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 266); this.Name = &quot;Form1&quot;; this.Text = &quot;Form1&quot;; this.Load += new System.EventHandler(this.Form1_Load);

}       #endregion

///        /// The main entry point for the application. ///        [STAThread] static void Main {           Application.Run(new Form1); }

private void Form1_Load(object sender, System.EventArgs e)       { //Section #1 // Register Class Library as a COM+ application. //         ClassLibLCE.MySubscriber l = new ClassLibLCE.MySubscriber;

//Section #2 // Call Events on Publisher. ClassLibLCE.MySubscriber l = new ClassLibLCE.MySubscriber; l.OnEvent1; l.OnEvent2; }   } } back to the top

Verify it Works

 * 1) In the Code Editor window, comment the code in Section #1 of the Form1.cs file and uncomment the code in Section #2.
 * 2) Run only the executable for the HowToLCE project. To do this, click Configuration Manager on the Build menu. Clear the Build check box for ClassLibLCE. Click Close.
 * 3) Press F5 to run the application in debug mode.
 * 4) When the Form loads, close it.
 * 5) Press CTRL+ALT+S to start Server Explorer. Expand Servers. Expand  . Expand Event Logs. Expand Application. Expand ClassLibLCE.

Notice the two Event Log entries.

back to the top

Troubleshooting

 * 1) Refresh the Event Log to see the entries in Server Explorer.
 * 2) If you make changes to the Class Library after running through the aforementioned procedures and then rebuild the Class Library it is very likely that the assembly will be locked by component services. To work around this, use either of the following methods:
 * 3) * Right-click the component in Component Services and then click Shut Down.

-or-
 * 1) * Delete the component if you want to make significant changes to your code.

back to the top

<div class="references_section">