.NET 3.0 has been made available to all the developers recently. With it comes a set of new set of API, which are simply there to unleash the .NET developer’s potential to create the next wave of powerful applications. These API, formerly called WinFX, take the form of four pillars – WCF, WF, WPF and WCS. In this post of mine, I would like to give a perspective on the Windows Communication Foundation (WCF).
Most typically, one starts off an introduction to WCF by explaining the four tenets of SOA, and how WCF embraces them from the ground-up. While this is very reasonable, I would like to think about WCF from a slightly different perspective which, of course, would eventually flow into confluence of the SOA tenets. To get a great insight into these tenets, I would urge you to look into this paper by the venerable Don Box.
WCF, in a nutshell, is all about facilitating message exchanges between endpoints. Note that ‘message’ and ‘endpoint’ are underlined. Well, these are but, what WCF is all about. These are concepts through which SOA is realized. Let me give you my understanding on these concepts:
If any entity needs to communicate with the world, it does so with Endpoints. Endpoint comprises of three elements (commonly called as ABC):
Address (Where) - Where can I find the service, the URI?
Binding (How) - How can I communicate with the service? What are security requirements, encoding requirements etc.?
Contract (What) – What is the structure of the messages that I need to communicate with the endpoint? What are the message exchange patterns (like Request/Reply, OneWay etc)
A WCF service would therefore, have at least one endpoint; it could have multiple based on different combinations of bindings, contracts or endpoint addresses.
If you really look at it, the concepts embodied by WCF aren’t new. They were pretty much present in ASMX. What lacked was that these concepts/abstractions were not explicitly codified in the ASMX (ASP.NET) framework. ASMX just seemed to be a quick way to get .NET classes to talk SOAP. So, caught in a world of classes and attributes, developers lost sight of underlying concepts that manifested as wsdl:portType, wsdl:port, wsdl:message and wsdl:binding.
WCF, on the other hand makes these concepts explicit, as seen in the ServiceEndPoint, Binding, ContractDescription, and EndPointAddress classes in the System.ServiceModel namespace. It is this object model that makes WCF very powerful. The number of out-of-the-box bindings available, and the existence of several extensibility points speak of the raw power of the WCF programming model. Also, this architecture is what makes unification of several programming models like MSMQ, COM+, WSE etc. possible.
“Message”, which can simply be thought of as the data/document/information exchanged between endpoints, is a first class citizen in the WCF programming model. Unlike its predecessor, where messages meant no more than an XML document (or stream) representing the SOAP envelope, WCF provides much better representation and finer control over messages. Messages are represented by the Message abstract class in the System.ServiceModel.Channels namespace.
Having seen how endpoints and messages are dealt with in WCF, it can be safely asserted that we are now consciously moving from the procedure call paradigm to a message exchange paradigm.
To find out more about WCF architecture, and the core classes that make up WCF, refer to this excellent paper by Yasser Shohoud.
Update:
As a part of the community launch of Windows Vista and Office 2007 in the B.NET User Group, we, a group of MVPs and other active community members authored a small e-book, comprising of articles on Vista, .NET 3.0 and Office 2007. Based on this post of mine, I wrote an article on what I thought the underpinnings concepts of WCF were. You could download the PDF of the e-book here.
I have come across several situations where I need some sort of Timeout functionality for a particular operation. At the same time, I also needed a provision for retrying the operation a few times before calling quits. I thought about a solution using ManualResetEvent and a Timer which I have outlined below:
const int MAX_RETRIES = 5;
const int RETRY_INTERVAL = 10; //10 seconds
const int OPERATION_TIMEOUT = 1; //1 minute
static void DoOperation()
{
int retries = 0;
int timeout = 0;
ManualResetEvent waitHandle = new ManualResetEvent(false);
//Use a timer to retry the opeation periodically
Timer retryTimer = null;
retryTimer = new Timer(
new TimerCallback(
//The operation to carry out is represented by this anonymous method.
delegate(object state)
{
try
{
if (retries > 0)
{
//The operation has failed before. So you may want to handle
// that situation here.
Console.WriteLine("Retry attempt: {0}", retries);
}
//Do the operation which may fail or timeout.
Console.WriteLine("Doing some major operation now.");
//throw new Exception("Some exception");
//Thread.Sleep(1000);
//Checking whether the operation timed out. In this case, the
// thread isnt forcefully aborted, so you can exit gracefully
//Else, you may need to handle the ThreadAbortException
if (timeout == ManualResetEvent.WaitTimeout)
{
Console.WriteLine("It seems that the operation timed out. Need to exit gracefully");
}
else
{
Console.WriteLine("Operation completed");
}
//Set the waithandle if the opeation is successful
waitHandle.Set();
//Everything went well. Close the timer.
retryTimer.Dispose();
}
catch (Exception e)
{
// Handle the exception
retries++;
//Check if the number of retries has exceeded the maximum allowed
if (retries > MAX_RETRIES)
{
//Do some logic to handle this situation
Console.WriteLine("Operation has exceeded maximum attempts");
// Set the waitHandle so that the method returns
waitHandle.Set();
}
else
{
//Retry the operation or any do alternative logic here
Console.WriteLine("The operation failed and will be retried in a short while.");
}
}
}),
null,
new TimeSpan(0, 0, 0),
new TimeSpan(0, 0, RETRY_INTERVAL)); // The timer retries the operation for the specified interval
//Wait for the operation to complete or timeout.
timeout = ManualResetEvent.WaitAny(
new WaitHandle[] { waitHandle },
(int)new TimeSpan(0, OPERATION_TIMEOUT, 0).TotalMilliseconds,
false);
if (timeout == ManualResetEvent.WaitTimeout)
{
// The operation timed out. Abort the operation thread or exit gracefully.
Console.WriteLine("The operation timed out.");
}
waitHandle.Close();
retryTimer.Dispose();
}
Let me explain this code section which may look a little convoluted at first. One of the easiest ways of implementing the timeout functionality is using WaitHandles. In the sample above, I have used a ManualResetEvent, but I guess you may use other WaitHandles like AutoResetEvent** etc, as you see fit. The idea is to spawn off a thread to execute an operation (which could possibly be a long one), and then wait for the thread to signal completion through the ManualResetEvent’s Set method. The ManualResetEvent provides a static method called WaitAny which can be used to wait for a specified period of time on one or many waithandles (In our case, it is just one).
Retry logic can be implemented using a Timer (System.Threading). The Timer event is where the meat of the work is done. The exception handler basically does the work of checking if further retries are required by checking a counter. Once, the process successfully completes, the WaitHandle is Set and the main thread is signaled.
**At first, it may be difficult to differentiate or choose between ManualResetEvent and AutoResetEvent. AutoResetEvent is analogous to the doorbell switch, which goes back to the off state once you press and release it. AutoResetEvent resets itself automatically once you set it. ManualResetEvent, on the other hand, does not reset automatically - it is like a normal switch. Therefore, ManualResetEvent can be used when signaling happens once and for all, and subsequently, threads need not wait again for another signal. AutoResetEvent , on the other hand, can be used for finer coordination between threads, when signaling can happen intermittently.
*Disclaimer:
I don’t suppose this is the best way to achieve timeout and retry – this is just one way. Do let me know if there are better techniques!
Generics offer tremendous flexibility – in more ways than you would ever know. Predicates are a good example for this. .NET 2.0 BCL comes with certain generic delegates – Action<T>, Predicate<T>, and Converter<Tin, Tout> respectively. Their definitions are given below:
public delegate TOutput Converter<TInput, TOutput>(TInput input);
public delegate void Action<T>(T obj);
public delegate bool Predicate<T>(T obj);
If you look at the definitions, you can guess that the instances of these delegates hold references to methods that do type specific operations. For example, the Predicate delegate represents a method which takes an instance as parameter, and determines if the instance meets a particular criteria. Quite obviously, these delegates would be most applicable to generic collections and arrays. The List<T> class for instance, employs them in Find, FindAll, Exists, FindIndex, FindLastIndex, ForEach methods. You could find similar usages in the Array class.
The real cool thing is using predicates in concert with anonymous methods. At first, it may look convoluted, but actually, that makes coding real easy (and fun). The oversimplified code snippet given below does a couple of things – given a list of accounts, it finds all accounts with a zero balance, and for each of these accounts sends a mail notifying the same. The FindAll method uses a Predicate<T> delegate and the ForEach delegate employs the Action<T> delegate.
List<Account> accounts = GetAllAccounts();
accounts.FindAll(
// Uses the Predicate<T> delegate
delegate(Account account)
{
return (account.Balance == 0);
}
).ForEach
(
//Uses the Action<T> delegate
delegate(Account account)
{
SendMail(account, "Be aware, you now have a zero balance");
}
);
What you may have noticed is that we have completed avoided nested for/foreach loops here. I have used anonymous methods inline here, but you can easily replace them with delegate instances so as to accommodate different criteria or action items at runtime. In more advanced cases, you could generate predicates at runtime based on user provided business rules or something like that.
Thus is the amount of flexibility could can reap out of generics! I would strongly recommend one to go over this interesting MSDN Magazine article on Predicates by Ken Getz to get a better idea.
In my previous post on Web 2.0, I mentioned that one of the new trends in the web today is that of “mashups”. The idea is about getting data from multiple, disparate sources and collating them in interesting ways. For example, let’s say we need to create a mashup involving a map showing all theatres playing the highest rated (most popular) movie in a particular city. Now, to develop this, one would need several pieces of data from several sources. First of all, you need to use map services (like Google Earth or Virtual Earth) to show a map. Secondly, you need a service that lists all popular theatres in a particular city, and what they are currently showing. You would also need ratings and reviews for all the movies that are being screened. Today, all these pieces of information are currently available, but mostly in several different websites. Each of these web sites could have their own revenue model revolving around special services they provide (maybe reviews, for example). So, our mashup which we conceived earlier would receive a setback if there is no data/service available which provides that information in an easily consumable form. In other words, you need structured data to make magic happen.
HTML traditionally, has not been considered as structured data. Perhaps, that is why we have XML to represent complex data forms. But how do you represent information in XML for the web? One answer would be SOAP and Web Services. As revolutionary as web services are for business applications, I feel they are not that conducive to AJAX-based Web 2.0 applications of today. The reason is that SOAP isn’t simple anymore; or at least, for naïve JavaScript-based clients. The evolution of WS-* has morphed SOAP into a monstrous stack of composable standards, which is beyond the reach of simple scripting today.
So, the order of the day is XML, but in simpler formats, and which are accessible through simpler protocols. Perhaps, this is the reason why RSS and ATOM were born, and are very popular today. Perhaps, this is the reason why REST is gaining momentum. Today, we see a large ecosystem of applications built around RSS and REST, and this can be attributed to their simplicity.
While XML is really powerful, the inherent concern of web applications to incorporate XML to express semantics could seem to be additional investment in time and space. If we go a step backwards towards HTML, and look for ways of expressing semantics, we wouldn’t have an answer, right? Wrong. Apparently, HTML has certain attributes like rel, class, and rev that are rich enough to express, and at the same time could be decoupled from visual markup. This is the idea underpinning a new way of semantic expression on the web – Microformats. Microformats, like RSS, are creating a whole new ecosystem of standards and applications (like crawlers and bots) that make structured data even more pervasive and accessible.
Microformats are a Web 2.0 phenomenon, and are testimonial to what I had to say earlier – Web 2.0 has brought about new "innovative techniques" of harnessing existing technology stacks. Be it through XML or Microformats, hopefully, the World Wide Web will evolve into one large blob of structured data available for everyone to create mashups like never before!
Web 2.0 – undoubtedly, is one of the most debated software buzzwords in the recent times. [The other term, in my opinion, which has attracted a lot of debate (and abuse) in the recent history is SOA]. To many, it is just about embracing new techniques, which are DHTML and JavaScript centric. But excavating the early manuscripts of Web 2.0 (like Tim O’Reilly's canonical Web 2.0 article) reveals a bigger picture.
So, what exactly is Web 2.0? Here’s another very brief perspective to add to thousand others already existing in different flavors. I would start by putting it this way (the world’s smallest definition of Web 2.0): A set of new ideologies combined with a set of novel techniques for building today’s web applications. Another definition could simply be – a new ecosystem of applications (or say “services”) built on the WWW platform.
The new ideologies:
1) The Web Platform
Websites today are not just places where static information is presented, or which offer a single service (like e-mail, storage, forums etc). Websites today are platforms in their own right. They offer the capability to “compose” disparate applications to build a very powerful whole. The word “Mash-Up” is a popular term used to represent this ideology of mixing (or re-mixing) data and functionality. Now, part of this realization is capable by seeing our large world of applications as services, which can be consumed in non-proprietary ways. Not just SOAP, but plain old JavaScript itself is turning out to be that duct-tape technology making this possible. Live, Google and PageFlakes are great examples of the same.
2) De-centralization of the Authority & Data
Websites of the past era basically owned the content and its presentation entirely. With Web 2.0, the authority on the source of the data and its presentation shifts to the user. The website or web application basically provides a canvas which the user leverages to consume (and compose) services from disparate sources to meet their needs. As an example, you could cite msn.com (of the yester years) giving way to Live.com of today.
3) Collaboration
This is new trend to surface in recent past. Websites today are opening the doors to the world to participate, contribute and collaborate. In this model, users directly contribute to the data/knowledge base of the website. The exemplar of this ideology is “Wiki”s, and Wikipedia, which is one of the most popular websites today. Tim O’Reilly’s article rightly calls this “Harnessing Collective Intelligence”.
The Novel Techniques:
HTTP, DHTML, JavaScript haven’t changed much in the recent times. But these days, you get to here a lot of new jargons popping all over the place, all of these based of these fundamental technologies. At the lead of this jargon parade is AJAX (Asynchronous JavaScript and XML). Some others in this list are Comet, JSON, etc. An extensive examination of these would reveal that these are nothing but simple tweaks and hacks to existing methodologies like XMLHTTP and JavaScript’s own eval function. Therefore, I term these seemingly “new technologies” as novel techniques.
New or otherwise, these techniques and ideologies definitely have resulted in new possibilities and opportunities for web application developers. We are seeing new revenue models which transcend the notion of simple buying and selling which we saw in the recent past. A new journey has just begun, it is time for us to get on the bus and be a part a long adventure!
The other day, I was watching the PDC presentations on WCF and one of them was on hosting WCF services by Steve Maine. Part of the presentation was about hosting Indigo on Windows services (or NT Services). One of the demos had a small and very interesting tip on debugging service startup, which I shall try to elaborate here.
I always wondered how the service startup code could be debugged. There are two problems which you would face invariably. First of all, there is no process to which you can attach a debugger to start with. I have done stupid things in the past to step into startup code - by adding a Thread.Sleep in the OnStart method, assuming that this would give me enough time to attach the debugger to the newly started process. This isn’t very smart as you would hit the second problem – the Service Controller Manager (SCM) would time the service out way too soon. Not to worry much - there is any elegant solution to both these problems.
You need not add a Thread.Sleep anymore – just add a Debugger.Break in your code. This isn’t new, but I simply hadn’t found a use for this before. This method is actually pretty useful if you want to conditionally attach the debugger in situations like this.
The solution to the problem of the SCM timing out is a method in the ServiceBase class (System.ServiceProcess) that has been added in .NET 2.0. This method is the RequestAdditionalTime, which takes a single parameter – the amount of time in milliseconds that the SCM has to wait additionally before pulling the plug on the service. Note that this method can only be called inside of OnStart, OnPause, OnContinue and OnStop (basically all the commands you can forward to the SCM).
Neat!
If your .NET class needs to generate events, at a minimum, you typically do the following:
1) Create a new class which derived from EventArgs – the instance of this class would be used to communicate certain information to the event handler about the event itself. For example, CacheExpiryEventArgs.
2) A new delegate type whose instance points to a method, the signature of which looks something like:
public delegate void CacheExpiryEventHandler(object sender, CacheExpiryEventArgs e);
3) You declare an event which is associated with the delegate you created in (2). For example,
public event CacheExpiryEventHandler CacheExpired
Now, for every event in your application, you invariably create as many delegate types. If you notice, each of those delegates differs only by the second argument of the event handler – the class representing the event arguments. Now, wouldn’t it be great if you had a generic delegate parameterized by the respective EventArgs argument. With generics in .NET 2.0, this is exactly what you get, in the form of EventHandler<TEventArgs>. With this in place, our example now would look like:
public event EventHandler<CacheExpiryEventArgs> CacheExpired;
This is definitely convenient, as it would reduce the number of delegates that are created in any application. Generics is a great addition in .NET 2.0, which not only gives you performance and strong-typing, but also certain productivity benefits like in this case, and for that matter Nullable<T>, List<T> and may such instances.
Nullable types, put in simple terms can be thought of as a way of having nullable value types. Quite obviously, one of the largest applicability of this concept is that of database programming, where you can associate a null value with any datatype. Not too long ago, while coding the data access layer, I did quite a lot of magic value checks on values to see whether I had to associate a null value (DBNull.Value) to the corresponding database parameter. This included Guid.Empty, Int32.MinValue, DateTime.MinValue and so on. So, I had to create one helper method for all the types that needed such checks. The example for int is shown below:
static object GetDbIntValue(int val)
{
if (val == int.MinValue)
{
return DBNull.Value;
}
else
{
return val;
}
}
Now, this effort is not good in a lot of ways though it serves its purpose. This methodology would require a handshake between the Business Logic Layer (BLL) and the Data Access Layer (DAL) as to what values are acceptable and what are not. The problem is that there is no universally accepted set for the same, and hence there would be semantic coupling between the Biz and the DAL layers. The handsome alternative to this situation would be to use Nullable types. Wherever you used magic values, replace them with the corresponding instances of Nullable<T>. Most typically, these would be in the data transfer objects (DTO). In the DAL, we could now have a single helper function (in lieu of many in the earlier case), which looks something like:
static object GetDbValue<T>(Nullable<T> val) where T : struct
{
if (val.HasValue)
{
return val.Value;
}
else
{
return DBNull.Value;
}
}
An adroit developer might question whether this helper nethod is really required. Why not have the IDbDataParameter instances 'infer' the right Dbtype from correponding nullable types. For example, you might have wanted this snippet to work without a hitch:
Guid? id = Guid.NewGuid(); //Just an example
SqlCommand cmd = new SqlCommand("Select * from Sample where id = @Id");
cmd.Parameters.AddWithValue("@Id", id);
But unfortunately, at this point of time, there is no conversions built in for nullable types and you would end up getting this exception message:
No mapping exists from object type System.Nullable`1[[System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] to a known managed provider native type.
So, till there is support for Nullable types from System.Data (not sure why it should not be), you are better off using the simple helper listed earlier.
Before closing off, I would recommend that you read this article to understand all aspects of Nullable types.
Nullable types, unfortunately, is fully supported only in C# 2.0, and not in VB. In other words, VB does not have the additional language additions and compiler changes needed to support nullable types in a way C# does. However, nothing stops you from using Nullable<T> in VB; it is just that you would not have the shortcut notations like in C# (int? etc). You are encouraged to read this blog post by Paul Vick, who explains this in detail.
I have mentioned umpteen number of times earlier - .NET 2.0 comes with a wealth of new classes that have been added to the BCL. Today’s turn is of BackgroundWorker. If you look at the available documentation (circa Beta 2), this is what you will find:
“Executes an operation on a separate thread”. You first reaction would be “Heck, what’s so “new” about that?” Okay, so let’s spelunk into its properties and methods and try to find out.
|
Methods |
|
RunWorkerAsync |
Starts the designated method on a separate threadpool thread. |
|
CancelAsync |
Requests the cancellation of the pending background operation |
|
Events |
|
ProgressedChanged |
This is called when the ReportProgress method is called |
|
RunWorkerCompleted |
Occurs when the background operation is completed |
|
DoWork |
Occurs when the RunAsync method is called. |
Again, after looking at these, you thoughts wouldn’t change – “Still, what’s so great about the same? I had created similar helpers in .NET 1.1.”. Fine, let me tell what’s new. The very interesting aspect about the BackgroundWorker is the fact that RunWorkerCompleted and ProgressChanged event handlers would execute on the thread that created the BackgroundWorker object – most typically on a Windows form main thread (the thread on which the UI controls are created). Therefore, you now do not fall into a trap that you used to fall into earlier – updating a winform control on the wrong thread and facing unpredictable results. (Note that the DoWork method runs on a separate threadpool thread – do not update UI controls on that method)
So, you would now say: “Cool, the BackgroundWorker probably has a reference to the ISynchronizeInvoke object, and it would call Invoke on it to dispatch the method on the right thread. (System.Windows.Forms.Contrtol class implements the ISynchronizeInvoke interface) ”.
If you look closely, the BackgroundWorker is actually agnostic of the environment it runs in. It could not even be a winform application, or even if it was, it does not really rely on ISynchronizeInvoke directly. So, how does this magic happen?
With the help of the valuable services of Reflector, I came to know about a new class (a set of them actually) introduced in .NET 2.0, which
are responsible for this magic – SynchronizationContext. Here’s what the documentation says:
“Provides the basic functionality for propagating a synchronization context in various synchronization models. The purpose of the synchronization model implemented by this class is to allow the internal asynchronous/synchronization operations of the common language runtime (CLR) to behave properly with different synchronization models. This model also simplifies some of the requirements that managed applications have had to follow in order to work correctly under different synchronization environments”
Can’t gather much from this explanation isn’t it? What is does mean perhaps is no more Control.Invoke. But it appears as if it is analogous to the thread’s Context object we had earlier, and a bit more specialized. By now, it would have rung another bell with you. As of .NET 2.0, in the case of Thread.Start method, the security context of the creating thread would be passed to the newly created thread. Guess what is behind this?
I tried a hand at this new class, simple stuff actually. I created a thread from the button click handler on a winform app and updated a control from the thread method (through anymymous method in this case). This is the snippet I tried:
private void button1_Click(object sender, EventArgs e)
{
ctx = SynchronizationContext.Current;
// thanks to anonymous methods, everything here is inline
// thanks to me, this is confusing
ThreadPool.QueueUserWorkItem(
delegate(object state)
{
// would be true
Debug.WriteLine(Thread.CurrentThread.IsThreadPoolThread.ToString());
ctx.Send(delegate(object someState)
{
// would be false
label1.Text = Thread.CurrentThread.IsThreadPoolThread.ToString();
},null);
}
);
}
Send is the method of the SynchronizationContext class to dispatch the method on the right thread synchronously. To do the same asynchronously, we call Post.
Another interesting thing to note is - in .NET 2.0, if you update a control on the wrong thread, you get an InvalidOperationException. As of 1.1, there was no exception, but the result was unpredicatable.
As you might have already guessed, there is not much documentation yet. But, unlike ContextBoundObject, ContextAttribute and other related classes, you might be seeing a lot of articles and proper documentation in the near future. At least, I shall spelunk a little more and come with an article of sorts.
The BCL in .NET 2.0 has a plethora of small additions, which are not that visible, but are very useful. I’ll try to cover many of these in my subsequent posts.
String.IsNullOrEmpty is one such method. As the name would indicate, this method returns true if the string argument passed to this method is either null (nothing in VB) or empty.
VB 2005 has some good additions too. Among others, I like the IsNot operator. How much more did you want this operator after writing code like this:
If Not obj Is Nothing
..
Then
Now,
If obj IsNot Nothing …looks much better.
MSMQ simply provides wonderful capabilities when it comes to building asynchronous messaging based applications. You typically run into situations where two applications exchange messages through a queue – one application sends messages to a known MSMQ destination and the other application “listens” to this queue and picks messages up as and when they arrive. The application which listens usually is a windows service which either has a dedicated thread making a blocking call on the Receive method or uses a timer of sorts to periodically check the queue for new messages. Either ways, to maximize throughput, you need to write the queue-listener code in such a way that you can have multiple threads simultaneously processing different messages that arrive at the queue.
MSMQ triggers provide one such solution where we can associate incoming messages to a COM component, based on certain rules, which can be application specific. MSMQ triggers are pretty powerful and also easy to administer. But there is one constraint, which has to do with the fact that only COM components are supported in this scheme, or in other words, message processors should be COM components. In a way, it isn’t that bad a choice after all. You still can create a CCW for a managed class and register the trigger. But, somehow, I didn’t like doing this.
To circumvent this problem, I decided to write a C# helper class, which doesn’t really do anything much, but helps realize a simple multithreaded job (message processing) dispatcher. The helper itself doesn’t do any message processing as such; whenever a message arrives at a queue, it just fires an event (on a new thread pool thread) with the message contents being in the event arguments.
public delegate void MessageReceivedEventHandler(object sender, MessageEventArgs args);
public class MSMQListener
{
private bool _listen;
private Type[] _types;
private MessageQueue _queue;
public event MessageReceivedEventHandler MessageReceived;
public Type[] FormatterTypes
{
get { return _types; }
set { _types = value; }
}
public MSMQListener(string queuePath)
{
_queue = new MessageQueue(queuePath);
}
public void Start()
{
_listen = true;
if (_types != null && _types.Length > 0)
{
// Using only the XmlMessageFormatter. You can use other formatters as well
_queue.Formatter = new XmlMessageFormatter(_types);
}
_queue.PeekCompleted += new PeekCompletedEventHandler(OnPeekCompleted);
_queue.ReceiveCompleted += new ReceiveCompletedEventHandler(OnReceiveCompleted);
StartListening();
}
public void Stop()
{
_listen = false;
_queue.PeekCompleted -= new PeekCompletedEventHandler(OnPeekCompleted);
_queue.ReceiveCompleted -= new ReceiveCompletedEventHandler(OnReceiveCompleted);
}
private void StartListening()
{
if (!_listen)
{
return;
}
// The MSMQ class does not have a BeginRecieve method that can take in a
// MSMQ transaction object. This is a workaround - we do a BeginPeek and then
// recieve the message synchronously in a transaction.
// Check documentation for more details
if (_queue.Transactional)
{
_queue.BeginPeek();
}
else
{
_queue.BeginReceive();
}
}
private void OnPeekCompleted(object sender, PeekCompletedEventArgs e)
{
_queue.EndPeek(e.AsyncResult);
MessageQueueTransaction trans = new MessageQueueTransaction();
Message msg = null;
try
{
trans.Begin();
msg = _queue.Receive(trans);
trans.Commit();
StartListening();
FireRecieveEvent(msg.Body);
}
catch
{
trans.Abort();
}
}
private void FireRecieveEvent(object body)
{
if (MessageReceived != null)
{
MessageReceived(this, new MessageEventArgs(body));
}
}
private void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
Message msg = _queue.EndReceive(e.AsyncResult);
StartListening();
FireRecieveEvent(msg.Body);
}
}
public class MessageEventArgs : EventArgs
{
private object _messageBody;
public object MessageBody
{
get { return _messageBody; }
}
public MessageEventArgs(object body)
{
_messageBody = body;
}
}
As you can see, the helper class is indeed simple. One thing to notice though is that, I switch to BeginPeek if the queue is transactional. The reason behind this is there is no overload of the BeginRecieve method that takes a MessageQueueTransaction object and the MSDN documentation also explains the same. The workaround is to use BeginPeek and then do call Receive (synchronous/blocking operation) in the EndPeek method.
At this point of time, this class does not provide much control to the consumer. For instance, it does not allow you to set the maximum number of concurrent threads that can be processing messages - This class queues as many jobs as that supported by the .NET Thread pool. Also, I haven’t tested this code in all scenarios – I have not seen if this works well in the context of a distributed (DTC based) transaction. I shall update this version every now and then to make it more powerful and to work seamlessly in all scenarios.
The ThreadPool class is very handy to developers. You could queue a method to run on a separate thread and forget about it, without worrying about managing the thread object or about a possible thread explosion scenario. That’s because the .NET ThreadPool keeps a tab on the number of executing threads, which I believe is a maximum of 25 per processor. This might sound just fine, but recently, I came across a situation where even 25 threads per processor looked expensive – I needed to limit the count to something like 10. Unfortunately, the ThreadPool class didn’t give me a method/property where I could set a thread count in the pool to something smaller. I wasn’t adept enough to host the CLR, where I could tweak this count. Instead, I decided to write a simplistic wrapper over the ThreadPool class, which basically did these things:
- Keep a count on the number of active threads (which I wanted to limit in the first place)
- Maintain a queue to store requests is threads aren’t available
- A timer implementation, where a thread periodically checks whether queued jobs can now be pushed to the thread pool
Quite obviously, this is a logical replica of the ThreadPool implementation itself, which is pretty wasteful. But that was until .NET Framework 1.1. In .NET 2.0, the ThreadPool class comes with this new method called SetMaxThreads – just what I craved for. You can use this to set the maximum number threads in the thread pool. There are two values to set here – one for the worker threads (which is more relevant in my case), and one for IO Port completion (this is useful for asynchronous IO operations).
Again, it is one's responsibility not to set an arbitrary high value of worker threads; Do I need to explain why?
More Posts
Next page »