Creating Event Handlers

There are two ways to handle events in CMS: through the Global.ASAX file or through custom HTTP modules. The decision of where to put your event handlers is a question of reusability. Putting your event handlers in the Global.ASAX file makes them a little less portable from project to project than writing a custom HTTP module. However, it's much easier to put event handlers in Global.ASAX. Ultimately, the choice is yours.

Event Handlers in Global.ASAX

In order for the workflow events to fire, you first need to register the events. To register the CMS events, you need to add some code to the HTTPModules section of Web.Config. If you've used the CMS project templates and you've chosen MCMS Web Application, the code should already be added. However, if you started with a blank solution or the MCMS Empty Web Project, you'll have to add the following code manually:

[View full width]

<add name="CmsPosting" type="Microsoft.ContentManagement.Publishing.Events graphics/ccc.gif.PostingEventsModule, Microsoft.ContentManagement.Publishing"/>

Notice the name attribute of the "add" tag. This name will be used when you create the event handlers. The name is part of the "signature" for each of the event handlers. If you either don't add this module or your event handler signature and the registered module name don't match, your events will not fire.

Next, you'll need to add your event handler functions in Global.ASAX. Each event handler will correspond to a specific CMS event. As we mentioned earlier, you only need to create event handlers for those events that are germane to your project. Once you've added your signatures to Global.ASAX, you can begin to add code to them. In Listing 31-1 you'll find a list of all the event handlers available to you.

NOTE: The complete list of event handlers is also in the MCMS2002.CHM file provided with the product.


Listing 31-1 The event handler signatures

[View full width]

 public void CmsPosting_Approved( Object sender, ChangedEventArgs e ) {} public void CmsPosting_Approving( Object sender, ChangingEventArgs e ) {} public void CmsPosting_Changed( Object sender, ChangedEventArgs e ) {} public void CmsPosting_Changing( Object sender, ChangingEventArgs e ) {} public void CmsPosting_Created( Object sender, CreatedEventArgs e ) {} public void CmsPosting_Creating( Object sender, CreatingEventArgs e ) {} public void CmsPosting_CustomPropertyChanged( Object sender, Microsoft.ContentManagement graphics/ccc.gif.Publishing.Events.PropertyChangedEventArgs e ) {} public void CmsPosting_CustomPropertyChanging( Object sender, PropertyChangingEventArgs e ) {} public void CmsPosting_Declined( Object sender, ChangedEventArgs e ) {} public void CmsPosting_Declining( Object sender, ChangingEventArgs e ) {} public void CmsPosting_Deleted( Object sender,  ChangedEventArgs e ) {} public void CmsPosting_Deleting( Object sender, ChangingEventArgs e ) {} public void CmsPosting_Moved( Object sender, MovedEventArgs e ) {} public void CmsPosting_Moving( Object sender, MovingEventArgs e ) {} public void CmsPosting_PlaceholderPropertyChanged( Object sender, Microsoft graphics/ccc.gif.ContentManagement.Publishing.Events.PropertyChangedEventArgs e ) {} public void CmsPosting_PlaceholderPropertyChanging( Object sender, graphics/ccc.gif PropertyChangingEventArgs e ) {} public void CmsPosting_PropertyChanged( Object sender, Microsoft.ContentManagement graphics/ccc.gif.Publishing.Events.PropertyChangedEventArgs e ) {} public void CmsPosting_PropertyChanging( Object sender, PropertyChangingEventArgs e ) {} public void CmsPosting_Submitted( Object sender, ChangedEventArgs e ) {} public void CmsPosting_Submitting( Object sender, ChangingEventArgs e ) {} 

NOTE: In Listing 31-1, you'll notice that we occasionally specify the fully qualified namespace, and in some cases we don't. This is to avoid class ambiguity.


Writing a Generic Handler

There are a few ways to approach writing handlers. One approach is to code to a generic event like Changing or Changed. Both of these events will fire, regardless of what you're doing with a posting. Coding to a generic event has the advantage of providing you with "access" to all events and all objects. For example, you'll be able to see when a posting is created as well as when a placeholder value changes. Of course, this could also be a downside, since you'll have to add some conditional logic to filter out what you don't want.

In the BOTS Consulting site, we've created a generic handler to log events to a text file. This is not a terribly realistic example, but we wanted to demonstrate how CMS workflow events fire; the best way to do that is to write a simple log program, which writes out all the events along with the particular object information. In our example, we're using a function we wrote to write a string to a file called BOTSLog.TXT.

In Listing 31-2, we've provided the generic event handler that logs the events to the event log. We've not provided the code to write to the text file, since that's a little out of scope for this example.

Listing 31-2 Generic event handler
 public void CmsPosting_Changing( Object sender, ChangingEventArgs e )  { WriteLogEntry("A CHANGING event fired because a (an) "         + e.Target.ToString() + " fired a " + e.Action.ToString().ToUpper()         + " event."); } 

Although the example in Listing 31-2 isn't terribly complex, it does yield some interesting results. The log entries it produces give us insight into how CMS fires events. To test this code, we're going to create a new press release in the Press channel of BOTS. The Press Release Detail template has four HTML placeholders and one image placeholder. Based on this information, we should expect a number of events to fire. Remember, we're actually only catching this information in the Changing event, which means that everything we have in the log is only half of the transaction; this code will fire before any state changes occur, but doesn't log anything for the after event. The log output is provided in Listing 31-3 (we've numbered this list to make it more readable).

Listing 31-3 The log output from the Changing event handler

[View full width]

 1. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Channel graphics/ccc.gif fired a CREATE event. 2. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Posting graphics/ccc.gif fired a PROPERTYCHANGE event. 3. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Posting graphics/ccc.gif fired a PROPERTYCHANGE event. 4. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 5. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 6. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 7. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.ImagePlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 8. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.ImagePlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 9. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.ImagePlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 10. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing graphics/ccc.gif.Extensions.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 

What you should notice immediately is that there were more PlaceholderPropertyChange events than placeholders in our template (remember, we only have four in the press release template). What's going on here? Well, keep in mind that the Changing event fires anytime something changes in CMS. In this case, it appears that the image placeholder has more properties that change during the Save. To find out which properties are changing, we've added a specific handler to our Global.ASAX file.

Writing a Specific Handler

Writing a generic handler is pretty easy, and, as you saw in our earlier example, you can get at a lot of information. However, you end up seeing literally everything that happens. Sometimes this is desirable, but in most cases you'll want to simply concentrate on specific events. In this case, you need to add a signature for the specific event.

Continuing our work with the press release template and the generic handler we already wrote, we've added a specific handler to get a closer look at the PlaceholderPropertyChanging events we saw. In our Global.ASAX, we've added the CmsPosting_PlaceholderPropertyChanging function and a reference to our WriteLogEntry function. This will allow us to gather more specific information about the events we were seeing in the Changing handler. In Listing 31-4 you can see exactly what we did.

Listing 31-4 The new code in our PlaceholderPropertyChanging event

[View full width]

 public void CmsPosting_PlaceholderPropertyChanging( Object sender, graphics/ccc.gif PropertyChangingEventArgs e ) {       WriteLogEntry("The PLACEHOLDERPROPERTYCHANGING event fired because "             + ((Placeholder)e.Target).Name              + "'s " + e.PropertyName + " property changed."); } 

After we added the code and looked in the log, we ended up with the output shown in Listing 31-5.

Listing 31-5 Additional log data

[View full width]

 1. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Channel graphics/ccc.gif fired a CREATE event. 2. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Posting graphics/ccc.gif fired a PROPERTYCHANGE event. 3. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Posting graphics/ccc.gif fired a PROPERTYCHANGE event. 4. The PLACEHOLDERPROPERTYCHANGING event fired because Calendar's Html property changed. 5. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 6. The PLACEHOLDERPROPERTYCHANGING event fired because BodyCopy's Html property changed. 7. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 8. The PLACEHOLDERPROPERTYCHANGING event fired because Disclaimer's Html property changed. 9. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 10. The PLACEHOLDERPROPERTYCHANGING event fired because CallOutImage's Src property changed. 11. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing graphics/ccc.gif.Extensions.Placeholders.ImagePlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 12. The PLACEHOLDERPROPERTYCHANGING event fired because CallOutImage's Alt property changed. 13. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing graphics/ccc.gif.Extensions.Placeholders.ImagePlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 14. The PLACEHOLDERPROPERTYCHANGING event fired because CallOutImage's Href property changed. 15. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing graphics/ccc.gif.Extensions.Placeholders.ImagePlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 16. The PLACEHOLDERPROPERTYCHANGING event fired because CallOutImageCaption's Html graphics/ccc.gif property changed. 17. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing graphics/ccc.gif.Extensions.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 

So, as you can see, we were right about the properties. It appears that the image placeholder has three properties that change when a posting saves: ALT, HREF, and SRC. As a result, the changing event would fire three separate times, once for each property change. When you put all this together, the log shows the PlaceholderPropertyChanging event, followed by the more generic Changing event just as we predicted.

Now, it's possible to accomplish everything we've done here in the more generic handler. However, as we mentioned earlier, accomplishing everything we did here in the Changing event, for example, would require us to better qualify the event arguments determining the object's type and then casting it. By using the PlaceholderPropertyChanging event, we already know we're getting a placeholder back, and the base placeholder type provides us with a way to get to most of the properties we need to make other decisions, such as the name or even the posting. Of course, if you need a specific property, you'll have to cast it to a more specific placeholder type, like HtmlPlaceholder, ImagePlaceholder, or AttachmentPlaceholder.

Creating Custom HTTP Modules

Although using the HTTP module that CMS provides is generally the easiest to implement, you can also write a custom HTTP module. A custom HTTP module is implemented as a new class and can be used across CMS solutions. Building on the example we provided in the previous section, we're going to write a custom module for the PlaceholderPropertyChanging event. We'll use the same code, but it will be contained in our new HTTP module class.

The first step is to add a new project to our BOTS Consulting solution. Once we have our new project, we need to add a new class. In our example, we've called our new class CMSPlaceholderPropertyChanging. The new class will inherit from IHttpModule. Because we're creating a custom module, we'll have to write an Init and a Dispose function to wire up the right event to our class. Again, we're going to wire up our class to the PlaceholderPropertyChanging event. In Listing 31-6 we've provided the code for our new class, and in Listing 31-7 you can see the modified log output, showing the influence of the new HTTP module.

Listing 31-6 The new HTTP module class

[View full width]

 using System; using System.IO; using System.Web; using Microsoft.ContentManagement.Publishing; using Microsoft.ContentManagement.Publishing.Events; using Microsoft.ContentManagement.Publishing.Extensions; namespace botsconsulting.Classes {       /// <summary>       /// CMSPlaceholderPropertyChanging is a custom HTTP module for handling       /// a placeholder property change.  It writes a line in a text file       /// for every PlaceholderPropertyChangingEvent that occurs.       /// </summary>       public class CMSPlaceholderPropertyChanging : IHttpModule       {             // Implement the mandatory Init and Dispose functions             public void Init(HttpApplication myEventContext)             {                   PostingEvents myEvent = PostingEvents.Current;                   myEvent.PlaceholderPropertyChanging += new PropertyChangingEventHandler graphics/ccc.gif(this.OnPlaceholderPropertyChanging);             }             public void Dispose()             {                   PostingEvents myEvent = PostingEvents.Current;                   myEvent.PlaceholderPropertyChanging -= new PropertyChangingEventHandler graphics/ccc.gif(this.OnPlaceholderPropertyChanging);             }             // Create a delegate for the event and a private             // member variable to hold a reference to the event             public delegate void CUSTOMPlaceholderPropertyChanging(Object sender, graphics/ccc.gif PropertyChangingEventArgs e);             private CUSTOMPlaceholderPropertyChanging myCMSHandler = null;             // Wire up the event             public event CUSTOMPlaceholderPropertyChanging graphics/ccc.gif MyNewPlaceholderPropertyChangingEvent             {                   add{myCMSHandler += value;}                   remove{myCMSHandler -=value;}             }             // Create the actual custom event logic.  In this case, we're writing             // to our BOTSLog as we did in the Global.ASAX example.             public void OnPlaceholderPropertyChanging(Object sender, graphics/ccc.gif PropertyChangingEventArgs e)             {                   WriteLogEntry("CUSTOM HTTP MODULE - The PLACEHOLDERPROPERTYCHANGING graphics/ccc.gif event fired because "                         + ((Placeholder)e.Target).Name                         + "'s " + e.PropertyName + " property changed.");             }             // The WriteLogEntry function for actually writing to the             // text file             private void WriteLogEntry(string eventLogEntry)             {                   StreamWriter myLogfile = new StreamWriter("c:\\BOTSLog.txt",true);                   myLogFile.WriteLine(System.DateTime.Now.ToString() + " :: " + graphics/ccc.gif eventLogEntry);                   myLogFile.Close();             }       } } 

Before your new HTTP module will operate properly within your solution, you must register it in the Web.Config file. This is something we covered in the Global.ASAX section. For the new module we just created, this is what we needed to add to our Web.Config file in the <httpModules> section:

[View full width]

<add type="botsconsulting.Classes.CMSPlaceholderPropertyChanging, botsconsulting" graphics/ccc.gif name="myCustomEvent"/>

Once you've added the registration to Web.Config, you can run your solution. In our example, we ended up with the log entries shown in Listing 31-7 (we've only included a sampling of the output for brevity).

Listing 31-7 The modified log output

[View full width]

 1. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.ImagePlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 2. CUSTOM HTTP MODULE--The PLACEHOLDERPROPERTYCHANGING event fired because CallOutImage's graphics/ccc.gif Href property changed. 3. The PLACEHOLDERPROPERTYCHANGING event fired because CallOutImage's Href property changed. 4. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.ImagePlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 5. CUSTOM HTTP MODULE--The PLACEHOLDERPROPERTYCHANGING event fired because graphics/ccc.gif CallOutImageCaption's Html property changed. 6. The PLACEHOLDERPROPERTYCHANGING event fired because CallOutImageCaption's Html property graphics/ccc.gif changed. 7. A CHANGING event fired because a (an) Microsoft.ContentManagement.Publishing.Extensions graphics/ccc.gif.Placeholders.HtmlPlaceholder fired a PLACEHOLDERPROPERTYCHANGE event. 

As you can see from Listing 31-7, our code in Listing 31-6 produced the same result as the code we added to Global.ASAX. We modified the log-writing statement slightly to highlight which lines were produced by our custom module verses the code that still remains in Global.ASAX.



Microsoft Content Management Server 2002. A Complete Guide
Microsoft Content Management Server 2002: A Complete Guide
ISBN: 0321194446
EAN: 2147483647
Year: 2003
Pages: 298

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