Course Order Application


To demonstrate the use of Message Queuing, in this section you create a sample solution to order courses. The sample solution is made up of three assemblies:

  • A component library (CourseOrder) that includes entity classes for the messages that are transferred

  • A Windows Forms application (CourseOrderSender) that sends messages to the message queue

  • A Windows Forms application (CourseOrderReceiver) that receives messages from the message queue

Course Order Class Library

Both the sending and the receiving application need the order information. For this reason, the entity classes are put into a separate assembly. The CourseOrder assembly includes three entity classes: CourseOrder, Course, and Customer. With the sample application, not all properties are implemented as they would be in a real application, but just enough properties to show the concept.

In the file Course.cs, the class Course is defined. This class just has one property for the title of the course:

  using System; namespace Wrox.ProCSharp.Messaging {    public class Course    {       public Course()       {       }       public Course(string title)       {          this.title = title;       }       private string title;       public string Title       {          get          {             return title;          }          set          {             title = value;          }       }    } } 

The file Customer.cs includes the class Customer, which includes properties for the company and contact names:

  using System; namespace Wrox.ProCSharp.Messaging {    public class Customer    {       public Customer()       {       }       public Customer(string company, string contact)       {          this.company = company;          this.contact = contact;       }       private string company;       public string Company       {          get          {             return company;          }          set          {             company = value;          }       }       private string contact;       public string Contact       {          get          {             return contact;          }          set          {             contact = value;          }       }    } } 

The class CourseOrder in the file CourseOrder.cs maps a customer and a course inside an order:

  using System; namespace Wrox.ProCSharp.Messaging {    public class CourseOrder    {       public CourseOrder()       {       }       private Customer customer;       public Customer Customer       {          get          {             return customer;          }          set          {             customer = value;          }       }       private Course course;       public Course Course       {          get          {             return course;          }          set          {             course = value;          }       }    } } 

Course Order Message Sender

The second part of the solution is a Windows application called CourseOrderSender. With this application, course orders are sent to the message queue. The assemblies System.Messaging and CourseOrder must be referenced.

The user interface of this application is shown in Figure 39-10. The items of the combo box comboBoxCourses include several courses such as Advanced .NET Programming, Windows Communication Foundation, and ADO.NET.

image from book
Figure 39-10

When the Submit the Order button is clicked, the handler method OnSubmitCourseOrder() is invoked. With this method, a CourseOrder object is created and filled with the content from the TextBox and ComboBox controls. Then a MessageQueue instance is created to open a public queue with a format name. The format name is used to send the message even in the case the queue cannot be reached currently. You can get the format name by using the Computer Management snap-in to read the ID of the message queue. With the Send() method, the CourseOrder object is passed to serialize it with the default XmlMessageFormatter and to write it to the queue:

  private void OnSubmitCourseOrder(object sender, EventArgs e) {    CourseOrder order = new CourseOrder();    order.Course = new Course(comboBoxCourses.SelectedItem.ToString());    order.Customer = new Customer(textCompany.Text, textContact.Text);    using (MessageQueue queue = new MessageQueue(          "FormatName:Public=")    {       queue.Send(order, "Course Order {" + order.Customer.Company + "}");    }    MessageBox.Show("Course Order submitted"); } 

Sending Priority and Recoverable Messages

Messages can be prioritized by setting the Priority property of the Message class. If messages are specially configured, a Message object must be created where the body of the message is passed in the constructor.

In the example, the priority is set to MessagePriority.High if the checkBoxPriority check box is checked. MessagePriority is an enumeration that allows you to set values from Lowest (0) to Highest (7). The default value, Normal, has a priority value of 3.

To make the message recoverable, the property Recoverable is set to true:

 private void OnSubmitCourseOrder(object sender, EventArgs e) {    CourseOrder order = new CourseOrder();    order.Course = new Course(comboBoxCourses.SelectedItem.ToString());    order.Customer = new Customer(textCompany.Text, textContact.Text);    using (MessageQueue queue = new MessageQueue(          "FormatName:Public="))    using (Message message = new Message(order))    {       if (checkBoxPriority.Checked)          message.Priority = MessagePriority.High;       message.Recoverable = true;       queue.Send(message, "Course Order {" + order.Customer.Company + "}");    }    MessageBox.Show("Course Order submitted"); }

Tip 

The namespaces System.Messaging defines a Message class, and the namespace System.Windows .Forms defines a Message struct. To avoid ambiguity an alias is set to the System.Messaging .Message class.

By running the application, you can add course orders to the message queue (see Figure 39-11).

image from book
Figure 39-11

Course Order Message Receiver

The design view of the Course Order receiving application that reads messages from the queue is shown in Figure 39-12. This application displays labels of every order in the listOrders list box. When an order is selected, the content of the order is displayed with the controls on the right side of the application.

image from book
Figure 39-12

In the constructor of the form class CourseOrderReceiverForm, the MessageQueue object is created that references the same queue that was used with the sending application. For reading messages, the XmlMessageFormatter with the types that are read is associated with the queue using the Formatter property.

To display the available messages in the list, a new thread is created that peeks at messages in the background. The thread’s main method is PeekMessages.

Tip 

You can read more about threads in Chapter 18, “Threading and Synchronization.”

 using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Threading; using System.Messaging; using Message = System.Messaging.Message; namespace Wrox.ProCSharp.Messaging {    public partial class CourseOrderReceiverForm : Form    {       private MessageQueue orderQueue;        public CourseOrderReceiverForm()       {          InitializeComponent();           orderQueue = new MessageQueue(                "FormatName:Public=");          System.Type[] types = new Type[3];          types[0] = typeof(CourseOrder);          types[1] = typeof(Customer);          types[2] = typeof(Course);          orderQueue.Formatter = new XmlMessageFormatter(types);           // start the thread that fills the ListBox with orders          Thread t1 = new Thread(PeekMessages);          t1.IsBackground = true;          t1.Start();       } 

The thread’s main method PeekMessages() uses the enumerator of the message queue to display all messages. Within the while loop, it is continuously checked if there is a new message in the queue. If there is no message in the queue, the thread waits three hours for the next message to arrive before it exits.

To display every message from the queue in the list box, the thread has to forward writing to the list box to the list box’s creator thread. Because Windows Forms controls are bound to a single thread, only the creator thread is allowed to access methods and properties. The Invoke() method forwards the request to the creator thread:

  private delegate void MethodInvoker(LabelIdMapping labelIdMapping); private void PeekMessages() {    using (MessageEnumerator messageEnum = orderQueue.GetMessageEnumerator())    {       while (messageEnum.MoveNext(TimeSpan.FromHours(3)))       {          Invoke(new MethodInvoker(AddListItem),                new LabelIdMapping(messageEnum.Current.Label,                messageEnum.Current.Id));       }    }    MessageBox.Show("No orders in the last 3 hours. Exiting thread"); } private void AddListItem(LabelIdMapping labelIdMapping) {    listOrders.Items.Add(labelIdMapping); } 

The ListBox control contains elements of the LabelIdMapping class. This class is used to display the labels of the messages in the list box, but to keep the ID of the message hidden. The ID of the message can be used to read the message at a later time:

  private class LabelIdMapping {    private string label;    private string id;    public LabelIdMapping(string label, string id)    {       this.label = label;       this.id = id;    }    public override string ToString()    {       return label;    }    public string Id    {       get       {           return id;       }    } } 

The ListBox control has the SelectedIndexChanged event associated with the method OnOrderSelectionChanged(). This method gets the LabelIdMapping object from the current selection, and uses the ID to peek at the message once more with the PeekById() method. Then the content of the message is displayed in the TextBox control:

  private void OnOrderSelectionChanged(object sender, EventArgs e) {    LabelIdMapping labelId = (LabelIdMapping)listOrders.SelectedItem;    if (labelId == null)       return;    Message message = orderQueue.PeekById(labelId.Id);    CourseOrder order = message.Body as CourseOrder;    if (order != null)    {       textCourse.Text = order.Course.Title;       textCompany.Text = order.Customer.Company;       textContact.Text = order.Customer.Contact;       buttonProcessOrder.Enabled = true;       if (message.Priority > MessagePriority.Normal)       {          labelPriority.Visible = true;       }       else       {          labelPriority.Visible = false;       }    }    else    {       MessageBox.Show("The selected item is not a course order");    } } 

When the Process Order button is clicked, the handler method OnProcessOrder() is invoked. Here again, the currently selected message from the list box is referenced, and the message is removed from the queue by calling the method ReceiveById():

        private void OnProcessOrder(object sender, EventArgs e)       {          LabelIdMapping labelId = (LabelIdMapping)listOrders.SelectedItem;          System.Messaging.Message message =                orderQueue.ReceiveById(labelId.Id);          listOrders.Items.Remove(labelId);          listOrders.SelectedIndex = -1;          buttonProcessOrder.Enabled = false;          textCompany.Text = "";          textContact.Text = "";          textCourse.Text = "";          MessageBox.Show("Course order processed");       }    } } 

Figure 39-13 shows the running receiving application that lists three orders in the queue, and one order is currently selected.

image from book
Figure 39-13




Professional C# 2005 with .NET 3.0
Professional C# 2005 with .NET 3.0
ISBN: 470124725
EAN: N/A
Year: 2007
Pages: 427

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