From an upcoming INETA article, this demonstrates how to create a custom publisher using MSMQ.... Keep in mind that EMAB has been superceded by the Enterprise Integration Framework (EIF), but EMAB is extreemly lightweight, easy to use, and can feed EIF....

The following example illustrates using MSMQ to publish exceptions using a custom Publisher component.

 

To implement a custom publisher, one must create a class that implements the IExceptionPublisher interface. This interface requires you to implement the Publish method, which accepts three parameters:

 

exception

 

The Exception object to be published.

 

additionalInfo

The additional contextual information associated with the exception.

 

configSettings

 

A NameValueCollection object that contains the exception management settings from the application’s configuration file

 

In our example, we define the Publisher method as follows:

 

public class MSMQPublisher: IExceptionPublisher

       {

              void IExceptionPublisher.Publish(Exception exception, NameValueCollection additionalInfo, NameValueCollection configSettings)

              {

 

 

From there, it’s as simple as implementing our MSMQ logic. One caveat: what happens if there is an exception in our custom publisher code, preventing the publishing to MSMQ? For that, we turn to the ExceptionManager.PublishInternalException method, which will publish the exception to the default publisher, which is the Windows application event log.

 

Our sample code follows:

using System;

using Microsoft.ApplicationBlocks.ExceptionManagement;

using System.Xml;

using System.Text;

using System.Collections.Specialized;

using System.Messaging;

 

 

 

namespace EMABMSMQ

{

       public class MSMQPublisher: IExceptionPublisher

       {

              void IExceptionPublisher.Publish(Exception exception, NameValueCollection additionalInfo, NameValueCollection configSettings)

              {

                     string msmqpath="";

                     string subjectprefix="";

                     string subject="";

                     string body="";

                     //Get the configuration information

                     if (configSettings != null)

                     {

                           //get the msmq path

                           if (configSettings["msmqpath"]!=null&&configSettings["msmqpath"].Length>0)

                                  msmqpath=configSettings["msmqpath"];

                          

                           //get the subject line prefix

                           if (configSettings["subjectprefix"]!=null && configSettings["subjectprefix"].Length>0)

                           {

                                  subjectprefix=configSettings["subjectprefix"];

                           }

                           else

                           {

                                  subjectprefix="EX_MGMT_AP_BLOCK Exception:";

                           }

 

                     }

      

                     //Throw another exception if no valid config found

                     if (msmqpath=="")

                     {

                           //we do not have a queue name, so revert to application event log

                          

                           ExceptionManager.PublishInternalException(exception, additionalInfo);

                     }

 

 

                     //build the subject and contents of the msmq message

                     subject = System.DateTime.Now.ToString() + " ";

                     subject += subjectprefix;

                     subject += " ";

                     subject += exception.Source;

                     body += "Exception: " + " at " + System.DateTime.Now.ToString() +  System.Environment.NewLine ;

                     body += System.Environment.NewLine;

                     body += "Exception Information" + System.Environment.NewLine;

                     body += System.Environment.NewLine;

                     body += exception.Message.ToString() + System.Environment.NewLine;

                     body += "Additional Information" + System.Environment.NewLine;

                     foreach (string i in additionalInfo)

                     {

                           body+= additionalInfo.Get(i) + System.Environment.NewLine;

                     }

                     body += "Stack Trace" + System.Environment.NewLine;

                     body += exception.StackTrace.ToString();

                     body += System.Environment.NewLine;

 

                     try

                     {

                           string mqPath = @".\" + msmqpath;

                           if(!MessageQueue.Exists(mqPath))

                           {

                                  MessageQueue.Create(mqPath);

                           }

 

                           MessageQueue mq = new MessageQueue(mqPath);

                           mq.Label = subject;

                           mq.Send(body,subject);

                    

                     }

                     catch (System.Exception myex)

                     {

                           //if we get an exception with MSMQ, revert to our default publisher

                           ExceptionManager.PublishInternalException (exception,additionalInfo);

                     }

              }

      

      

       }

 

}

 

Now, of course, we need to get this sucker working!

 

To do this, we make use of our application configuration file. This XML file is either called WEB.CONFIG (if using ASP.NET), or APP.CONFIG, if developing a standard windows forms application.

 

This file specifies a configSettings block, which in turn references our custom publisher. The custom publisher information includes the assembly name and type, as well as any specific parameters our publisher might need to complete its work.

 

Here’s our app.config (note this is bare bones, yours might vary):

 

<configuration> 

  <configSections>

    <section name="exceptionManagement"

             type="Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionManagerSectionHandler, Microsoft.ApplicationBlocks.ExceptionManagement" />

  </configSections>

 

  <exceptionManagement>

  <!-- Configure our publisher here -->

    <publisher mode="on" assembly="Microsoft.ApplicationBlocks.ExceptionManagement" type="EMABMSMQ.MSMQPublisher"

               <!-- specify the prefix for messages -->

               subjectprefix = "MSMQ"

               <!-- specify the msmq path here -->

               msmqpath="private$\myexceptions"/>

  </exceptionManagement>

</configuration>

 

In this example, we have two custom settings that our publisher needs, the subjectprefix, and the msmqpath.

 

In order to test our publisher, I’ve built a really simple Windows Forms application. The form has two buttons, one to test the MSMQ functionality (can we write to our MSMQ queue), and the other to cause an exception.

 

To run this example, make sure you’ve create an MSMQ queue on your system. Typically, this would be a private queue. In our case, we are using a private queue with the name myexceptions .

 

Here is the code to test MSMQ from the button event:

 

              private void TestMSMQ_Click(object sender, System.EventArgs e)

              {

                     string mqPath = @".\private$\myexceptions";

                     if(!MessageQueue.Exists(mqPath))

                     {

                           MessageQueue.Create(mqPath);

                     }

 

                     MessageQueue mq = new MessageQueue(mqPath);

                     mq.Label = "adam1";

                     mq.Send("we created this!","my subject");

              }

 

And here’s the code to generate the exception:

 

              private void GenerateException_Click(object sender, System.EventArgs e)

              {

                     //assumes you don’t have a file called

                     //msmqdsfoo.xml in the root of drive C

 

System.Data.DataSet myds = new System.Data.DataSet();

                     try

                     {

                           myds.ReadXml(@"c:\msmqdsfoo.xml");

                     }

                     catch (System.Exception ex)

                     {

                           ExceptionManager.Publish(ex);

                     }

 

              }

 

As you can see, creating a custom publisher allows you to log exceptions where you want them, and is very lightweight. You can even use a custom publisher in conjunction with the default publisher (the application event log), or hook it into the EIF to bubble exceptions up to the enterprise level. In fact, you can chain as many publishers as you want together!

 

Deploying the exception management assemblies can be done for each application individually, or to the Global Assembly Cache for shared use. See the documentation that comes with EMAB to determine any specific steps for each scenario.

 

comments?