tag:blogger.com,1999:blog-86434508267449326542024-02-19T17:25:36.314-08:00The Senile CoderChrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.comBlogger40125tag:blogger.com,1999:blog-8643450826744932654.post-75317323411489680062019-02-19T07:16:00.001-08:002019-02-19T07:16:04.594-08:00Two RabbitMQ Messaging Patterns<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px;">
Don't want to read this article? The short version is, "If you didn't create a queue, don't pull messages from it." Removing messages from a queue is a destructive action.</div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px;">
<br /></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px;">
This post is really a summary of the RabbitMQ docs. It's a quick highlight of the two big messaging patterns commonly seen on the broker.</div>
<h1 style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 24px; font-weight: normal; line-height: 1.25; margin: 30px 0px 0px;">
How does Rabbit work?</h1>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
RabbitMQ is, at its heart, a message broker. It has one focus. That focus is to deliver messages sent it to consumers. That's all it does, and it does it very well. It does not offer more complex patterns like sagas.</div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
Key to understanding how Rabbit works is knowing that there are two parts to the broker: exchanges, and queues. Exchanges receive messages from publishers. Queues hold messages for subscribers. Inside the broker, messages move from exchanges to queues based on different rules. Once a message is taken from the queue, Rabbit forgets about it. Exchanges can send copies of a message to different queues, but they do not send multiple copies to the same queue.</div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<br /></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9vIjK4ZQQeqAscQUNVr_PkQ2Q-Es0jPv2GscSRqto6TkXE49ADGXb2O3E_Cf1dIxjaSuZzWX6MRKTsWDQVcWnVKiB9PJIz5atFpsjvqnuXrkSCn9qwuknmgmnoVd7xAzMPbHQmrqCeo0/s1600/Publisher+Consumer.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="55" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9vIjK4ZQQeqAscQUNVr_PkQ2Q-Es0jPv2GscSRqto6TkXE49ADGXb2O3E_Cf1dIxjaSuZzWX6MRKTsWDQVcWnVKiB9PJIz5atFpsjvqnuXrkSCn9qwuknmgmnoVd7xAzMPbHQmrqCeo0/s400/Publisher+Consumer.png" width="400" /></a></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<br /></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<br /></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
Above is pictured the basic message flow. This can be expanded in two ways. Multiple consumers can get messages from the same queue. Multiple queues can be wired to the same exchange. Multiple consumers pulling messages from the same queue create the competing consumer pattern. Multiple queues wired to the same exchange create the Publish/Subscribe pattern. These patterns are not exclusive; it is possible to have competing consumers on one of the pub/sub queues.</div>
<h1 style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 24px; font-weight: normal; line-height: 1.25; margin: 30px 0px 0px;">
What are Competing Consumers?</h1>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
The <a href="https://www.rabbitmq.com/tutorials/tutorial-two-dotnet.html" style="color: #0052cc; text-decoration-line: none;">Rabbit docs</a> describe a work queue as a queue with multiple consumers connected. The intent is to distribute tasks to multiple consumers. This lets the tasks be distributed across all the consumers connected to a queue. Want to scale horizontally? Just add more consumers. Rabbit will deal the message out, one per consumer, until all messages have been dealt. It is important to know that <em>each message will be sent only once</em>. Once a message has been passed to a consumer, it will be removed from the queue. That means it will be <em>unavailable to any other consumers of that queue. </em>Below is an illustration of how the messages flow.</div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<br /></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRT1y71ottq8S_Vo3mYd3PLrp5rOtMXmfMvuy-pZUJ27I2bIzi5uj3EKXUuCUFFec0DGVO5mw19gREj1KDEMENvG1PfPtnjqPldvr3zvhESelR7-Lv8HdhH72-tohNNTXtqY66qezpGEk/s1600/Work+Queue.png" imageanchor="1"><img border="0" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRT1y71ottq8S_Vo3mYd3PLrp5rOtMXmfMvuy-pZUJ27I2bIzi5uj3EKXUuCUFFec0DGVO5mw19gREj1KDEMENvG1PfPtnjqPldvr3zvhESelR7-Lv8HdhH72-tohNNTXtqY66qezpGEk/s400/Work+Queue.png" width="400" /></a></div>
<h1 style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 24px; font-weight: normal; line-height: 1.25; margin: 30px 0px 0px;">
What is Publish/Subscribe?</h1>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
Publish/subscribe is another common use of brokers. This is the pattern to use if you want multiple copies of the same message to be sent to different consumers. In this pattern, exchanges are used to send copies of messages to multiple queues. This pattern is especially useful for logging, audits, or passing messages to consumers with very different purposes. It is important to remember that multiple consumers on a queue will form competing consumers on that queue. The illustration below shows publish/subscribe, along with a competing consumer on one of the queues.</div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<br /></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOoiKn63TF_RswWTEfq-y20mVoTYbxoUhaMMzuybRo2ZMphquNpRzc0iVgRN5muJ9v0V_RIF8yiGA_kjSqft7c2cqe3-Mrh6w4qaG_Py1PZRYTui-FH1gMxC5Ve6GZjXXLxYEnYO-kd0U/s1600/Pubsub.png" imageanchor="1"><img border="0" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOoiKn63TF_RswWTEfq-y20mVoTYbxoUhaMMzuybRo2ZMphquNpRzc0iVgRN5muJ9v0V_RIF8yiGA_kjSqft7c2cqe3-Mrh6w4qaG_Py1PZRYTui-FH1gMxC5Ve6GZjXXLxYEnYO-kd0U/s400/Pubsub.png" width="400" /></a></div>
<h1 style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 24px; font-weight: normal; line-height: 1.25; margin: 30px 0px 0px;">
In closing...</h1>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
Remember that when you want only one copy of a message to be distributed across consumers, the competing consumer pattern is the way to go. Using publish/subscribe will send copies of messages to different consumers. If you want the same message to go to different consumers, publish/subscribe is your friend.</div>
<h1 style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 24px; font-weight: normal; line-height: 1.25; margin: 30px 0px 0px;">
Further Reading</h1>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<a href="https://www.rabbitmq.com/best-practices.html" style="color: #0052cc; text-decoration-line: none;">RabbitMQ Best Practices</a></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<a href="https://www.rabbitmq.com/tutorials/tutorial-two-dotnet.html" style="color: #0052cc; text-decoration-line: none;">RabbitMQ Work Queues Tutorial</a></div>
<div style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-size: 14px; margin-top: 10px;">
<a href="https://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html" style="color: #0052cc; text-decoration-line: none;">RabbitMQ Publish/Subscribe Tutorial</a></div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-14622614973053509342018-01-11T08:54:00.001-08:002018-01-11T08:54:05.992-08:00Visual Studio 2017 & IIS: Unable to start debugging on the Web Server.<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Can't Debug?</span><br />
<br />
Ok, first I have to say that I've always thought it to be a failure when I'm using the debugger. That said, there are times when being able to hit F5 in Visual Studio, have it launch the web app, and connect debugging to IIS is convenient.<br />
<br />
Imagine my surprise, and frustration when I hit F5 and got the following dialog:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8QbxhxWW9EXvBfF105PgdLsGwxYLpvF1VoM6iHxTS8UZDSf5WlclfnVHYKMRRJyCa08PVj1-ks2LB8kLc0ZrO0nSvFrGb8VocbDqBGkQl64xGz40ehyMxD6edRxfGBur6wo1TEbpK2t8/s1600/error+screen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="172" data-original-width="394" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8QbxhxWW9EXvBfF105PgdLsGwxYLpvF1VoM6iHxTS8UZDSf5WlclfnVHYKMRRJyCa08PVj1-ks2LB8kLc0ZrO0nSvFrGb8VocbDqBGkQl64xGz40ehyMxD6edRxfGBur6wo1TEbpK2t8/s320/error+screen.png" width="320" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Doing the research...</span><br />
<br />
Googling the message led me to the <a href="https://docs.microsoft.com/en-us/visualstudio/debugger/error-unable-to-start-debugging-on-the-web-server" rel="nofollow" target="_blank">MSDN article</a> for the error. The section of that page which covers the remote server returning errors offered the following, "Make sure that the Application Pool is configured for the correct version of ASP.NET." I verified the Application Pool was configured correctly. A reinstall of the Framework, and reboot didn't help either.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">So, what was it?</span><br />
<br />
It turns out I had some features disabled. Searching the Windows Features window, I found a category (Application Development Features) buried within the Internet Information Services feature. They were all disabled.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPkjl4IyXB8yp_GJm1PC7ZWWIicC-AVnncO0io3xVb4gZKqS2Mcwm-hRv9DD1YIJZx5LtnUzZa5EONwken9BBSJn1AuMeolqtz_qsclvci_r_SQAY9OEYIiWYU73ZqJw6p9agpAu9aoiQ/s1600/features+off.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="610" data-original-width="415" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPkjl4IyXB8yp_GJm1PC7ZWWIicC-AVnncO0io3xVb4gZKqS2Mcwm-hRv9DD1YIJZx5LtnUzZa5EONwken9BBSJn1AuMeolqtz_qsclvci_r_SQAY9OEYIiWYU73ZqJw6p9agpAu9aoiQ/s320/features+off.png" width="217" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Fixing the issue was a simple matter of enabling the features, and rebooting. I chose the following features.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJHY6210065bl_nR-CZZYPp46WQ_6fQ4mEZ4wIKc-tnd7enVlbyEOGbmUJh0Wz4FwCWn4tls4zhYlLnLrcf8YyT3H2dpb9Fc45FCet3EFICNI6snN0TKQekPTemKz3kkm70B6BEErRuDY/s1600/features+on.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="610" data-original-width="415" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJHY6210065bl_nR-CZZYPp46WQ_6fQ4mEZ4wIKc-tnd7enVlbyEOGbmUJh0Wz4FwCWn4tls4zhYlLnLrcf8YyT3H2dpb9Fc45FCet3EFICNI6snN0TKQekPTemKz3kkm70B6BEErRuDY/s320/features+on.png" width="217" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now, I can use the debugger again. But, I still prefer to rely on TDD. ;)</div>
<br />Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-27823243315876001062017-08-10T04:45:00.003-07:002017-08-10T04:45:36.751-07:00Building a Pipeline (the Template Pattern)<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: large;">Building a Simple Pipeline</span><br />
<br />
A lot of my development experience has been building back-end systems. There's been plenty of times where something I've built needed to process a request which was composed of a number of tasks. These tasks had to be performed in the correct sequence forming an algorithm. I've heard these things called many different names including Pipelines.<br />
<div>
<br /></div>
<div>
Unfortunately, many times this need leads to a class which contains both the steps of the algorithm, and the logic to complete the steps. These classes quickly turn into huge monsters. They also tend to become a real pain to test. It turns out, there's a GoF pattern for them: <a href="http://www.blackwasp.co.uk/TemplateMethod.aspx" target="_blank">Template Method Design Pattern</a>.</div>
<div>
<br />
In other words, I wanted to express these simple algorithms like this:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">FileCreator</span> : IRequestHandler<CreatePackage>
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IPipeline<CreatePackage> pipeline;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">FileCreator</span>(IPipeline<CreatePackage> pipeline)
{
<span style="color: #008800; font-weight: bold;">this</span>.pipeline = pipeline;
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Handle</span>(CreatePackage request)
{
pipeline.Subject(request);
pipelline.Do<BoxTheItems>();
pipelline.Do<CreateTheShippingLabel>();
pipeline.Do<ShipTheBox>();
pipeline.Do<SendShippingNotification>();
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
PS - <a href="https://github.com/jbogard/MediatR" target="_blank">MediatR</a> is awesome. That's where <span style="font-family: "courier new" , "courier" , monospace;">IRequestHandler<T></span> comes from.<br />
<br /></div>
<div>
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: large;">Enter LittlePipeline</span></div>
<div>
<br /></div>
<div>
<a href="https://preview.nuget.org/packages/LittlePipeline/" target="_blank">LittlePipeline</a> is a small library, or set of example code on how one can build a template that is easy to read, easy to test, and can work with an IoC container. It's designed to be a starting point, not an end-all solution to the problem. The gist of using the library (or classes if you want to copy/paste the code) is simple...<br />
<br />
Start with a subject class. This class is the guy who holds the data necessary to process the request. It can be as dumb (or smart) as you need. The only requirement is the subject be a reference object (a class).<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3
4
5
6</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">CreatePackage</span>
{
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">int</span> OrderId { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }
<span style="color: #008800; font-weight: bold;">public</span> Address ShipTo { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">string</span> TrackingNumber { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
Create any number of tasks. These tasks should implement the <span style="font-family: "courier new" , "courier" , monospace;">ITask<T></span> interface where <span style="font-family: "courier new" , "courier" , monospace;">T</span> is the subject type you created earlier.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">SendShippingNotification</span> : ITask<CreatePackage>
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IBus bus;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">SendShippingNotification</span>(IBus bus)
{
<span style="color: #008800; font-weight: bold;">this</span>.bus = bus;
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Run</span>(CreatePackage subject)
{
<span style="color: #333399; font-weight: bold;">var</span> notification = <span style="color: #008800; font-weight: bold;">new</span> ShippingNotification { TrackingNumber = subject.TrackingNumber };
bus.Publish(notification);
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
Use the baked-in pipeline creator, or your favorite IoC container to register the tasks, and create the pipeline. Then, use it like in the class above. Here's the built-in, no frills, no guaranties example.<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #333399; font-weight: bold;">var</span> pipeline = MakePipeline.ForSubject<FirstTestSubject>()
.With<Increment>(() => <span style="color: #008800; font-weight: bold;">new</span> Increment())
.Build();
</pre>
</td></tr>
</tbody></table>
</div>
<br />
Oh, and this is what testing a pipeline looks like (with FakeItEasy):<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">PipelineTestExample</span>
{
<span style="color: #0000cc;"> [Test]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ThePipelineCanBeTested</span>()
{
<span style="color: #333399; font-weight: bold;">var</span> pipeline = A.Fake<IPipeline<FirstTestSubject>>();
<span style="color: #333399; font-weight: bold;">var</span> example = <span style="color: #008800; font-weight: bold;">new</span> ThingThatUsesThePipeline(pipeline);
<span style="color: #333399; font-weight: bold;">var</span> subject = <span style="color: #008800; font-weight: bold;">new</span> FirstTestSubject();
example.Run(subject);
A.CallTo(() => pipeline.Subject(subject)).MustHaveHappened()
.Then(A.CallTo(() => pipeline.Do<Increment>()).MustHaveHappened())
.Then(A.CallTo(() => pipeline.Do<Square>()).MustHaveHappened());
}
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">ThingThatUsesThePipeline</span>
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IPipeline<FirstTestSubject> pipeline;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">ThingThatUsesThePipeline</span>(IPipeline<FirstTestSubject> pipeline)
{
<span style="color: #008800; font-weight: bold;">this</span>.pipeline = pipeline;
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Run</span>(FirstTestSubject subject)
{
pipeline.Subject(subject);
pipeline.Do<Increment>();
pipeline.Do<Square>();
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: large;">That's It</span><br />
<br />
There you have it, a simple template class that (hopefully) helps clean up some code by separating the algorithm steps from their implementations. The code is on <a href="https://github.com/caloggins/LittlePipeline" target="_blank">github</a>. The <a href="https://github.com/caloggins/LittlePipeline/blob/master/ReadMe.md">ReadMe.md</a> file gives some information about how it might be tested.</div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-32372430254306829682017-02-14T12:08:00.000-08:002017-02-14T12:08:02.444-08:00NUnit Exception: Error Loading SettingsThis applies to NUnit 3.4.1.<br />
<br />
I was doing some TDD one day, when Visual Studio crashed. After a few choice words, I booted things back up. Running the tests after starting back up threw up an error window I'd never seen before. It only showed when I used the R# test runner.<br />
<br />
<div style="text-align: center;">
</div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Vjn7u_bVp3UAAXmq70LygeCZYFXxjAqwKEMPTbqu1BAy2IDYfUffpB13CD3LI5SDg2oRDVBN1dA7G_9SRZeb_axv68Z1JyfbdMCwxSZuD8d7KX8a431jfTcEnCSg8tR4yCzu_dDFM3E/s1600/ReSharper+dialog.png" imageanchor="1"><img border="0" height="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Vjn7u_bVp3UAAXmq70LygeCZYFXxjAqwKEMPTbqu1BAy2IDYfUffpB13CD3LI5SDg2oRDVBN1dA7G_9SRZeb_axv68Z1JyfbdMCwxSZuD8d7KX8a431jfTcEnCSg8tR4yCzu_dDFM3E/s400/ReSharper+dialog.png" width="400" /></a></div>
<br />
It wasn't very helpful, since half the message didn't seem to be showing. I was able to get the error message using the first trick from <a href="https://www.raymond.cc/blog/how-to-copy-text-or-error-messages-from-any-dialog-boxes-in-windows/" target="_blank">this article</a>. That error message wasn't much help either.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre>
</td><td><pre style="line-height: 125%; margin: 0;">---------------------------
ReSharper Ultimate – System.ApplicationException: Error loading settings file
---------------------------
at NUnit.Engine.Internal.SettingsStore.LoadSettings()
at NUnit.Engine.Services.SettingsService.StartService()
at NUnit.Engine.Services.ServiceManager.StartServices()
at NUnit.Engine.TestEngine.Initialize()
at NUnit.Engine.TestEngine.GetRunner(TestPackage package)
at JetBrains.ReSharper.UnitTestRunner.nUnit30.BuiltInNUnitRunner.<>c__DisplayClass1.<RunTests>b__0()
at JetBrains.ReSharper.UnitTestRunner.nUnit30.BuiltInNUnitRunner.WithExtensiveErrorHandling(IRemoteTaskServer server, Action action)
---------------------------
OK
---------------------------
</pre>
</td></tr>
</tbody></table>
</div>
<br />
Fortunately, this project happened to have a build script which also ran the unit tests. Running the build script returned the full error text. That error message showed me the real problem. It turns out the NUnit settings file was empty. That was causing the root element missing error.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNK5BTBVyW7aUoQ-00sKyUr_sfjG9x0577Ata5hKUdSB9XiZcjaQIixBwhp6WiXDFRAW1e7T0P5GFKlRTAm8nkX5Pvlmd6B0vF6UXxpvAwSR5J27jNZdymVN0xmJciWTywNFH9BVjnR5s/s1600/Console+Message.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNK5BTBVyW7aUoQ-00sKyUr_sfjG9x0577Ata5hKUdSB9XiZcjaQIixBwhp6WiXDFRAW1e7T0P5GFKlRTAm8nkX5Pvlmd6B0vF6UXxpvAwSR5J27jNZdymVN0xmJciWTywNFH9BVjnR5s/s400/Console+Message.png" width="400" /></a></div>
<br />
Deleting the <span style="font-family: Courier New, Courier, monospace;">NUnit30Settings.xml</span> file from the <span style="font-family: Courier New, Courier, monospace;">$AppData$\Local\NUnit</span> directory cleared the problem.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com1tag:blogger.com,1999:blog-8643450826744932654.post-66221262530006780682016-12-23T04:37:00.001-08:002016-12-23T04:37:16.374-08:00MediatR, FluentValidation, and Ninject using Decorators (Pt. 2)<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Validate all the Things?</span><br />
<br />
The last post showed how to combine MediatR, FluentValidation, and Ninject to handle the validation of requests handled by MediatR. The drawback in the previous post is that all requests must have a corresponding validator implemented. Here, we'll look at using the null object pattern to bypass validation when a validator isn't present.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Null Object What?</span><br />
<br />
The <a href="https://en.wikipedia.org/wiki/Null_Object_pattern" target="_blank">null object pattern</a> is a way to pass an object which represents nothing, but does not throw a runtime exception when used. This pattern can be used to add default behavior to a process when there is nothing for the process to use.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23</pre>
</td><td><pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">ValidatingHandler</span><TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
<span style="color: #008800; font-weight: bold;">where</span> TRequest : IRequest<TResponse>
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IRequestHandler<TRequest, TResponse> handler;
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IValidator<TRequest> validator;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">ValidatingHandler</span>(IRequestHandler<TRequest, TResponse> handler, IValidator<TRequest> validator)
{
<span style="color: #008800; font-weight: bold;">this</span>.handler = handler;
<span style="color: #008800; font-weight: bold;">this</span>.validator = validator;
}
<span style="color: #0000cc;"> [DebuggerStepThrough]</span>
<span style="color: #008800; font-weight: bold;">public</span> TResponse <span style="color: #0066bb; font-weight: bold;">Handle</span>(TRequest message)
{
<span style="color: #333399; font-weight: bold;">var</span> validationResult = validator.Validate(message);
<span style="color: #008800; font-weight: bold;">if</span> (validationResult.IsValid)
<span style="color: #008800; font-weight: bold;">return</span> handler.Handle(message);
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">ValidationException</span>(validationResult.Errors);
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
The handler above is taken from the last post. It accepts a handler and validator for a given request. It validates the request, then either passes the request to the next handler, or throws an exception. Ninject will throw an exception when it cannot find an appropriate validator for the request.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3
4</pre>
</td><td><pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">NullValidator</span><TType> : AbstractValidator<TType>
{
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
Enter a null validator. This validator has no rules. When used, it will return no errors, because there are no rules defined in it. Because it's defined as a generic, it can be used to validate any request. When the handler processes a request, the validation passes by default, and the request is passed down the chain.<br />
<br />
The cool thing is there's no extra steps needed. Just add the null validator to the solution. It will be picked up by Ninject in the normal registration process. When Ninject can't find the appropriate validator for a request, it will fall back to the generic implementation.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">PS...</span><br />
<br />
That's all there is to adding a class which will provide a default behavior of passing requests that have no validation rules defined. Adding code like this is also a great example of the open-closed principle: It was possible to extend the behavior of the validator without changing the code of the validator. So, there ya go. Default, passing validation using the null object pattern.<br />
<br />
As always, the <a href="https://github.com/caloggins/ExampleCode/tree/master/MediatrDecorators" target="_blank">code is on GitHub</a>.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-14591431180892167152016-12-08T12:49:00.001-08:002016-12-13T16:25:30.060-08:00MediatR, FluentValidation, and Ninject using Decorators<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: large;">Notebook</span><br />
<br />
I recently had to fiddle with getting <a href="http://www.ninject.org/" target="_blank">Ninject</a> to use decorators for validation with Jimmy Bogard's library, <a href="https://github.com/jbogard/MediatR" target="_blank">MedatR</a>. Sure, there's tons of blogs out there. There's even some articles on the MediatR and Ninject sites. I had problems getting them to work. So, here's my solution.<br />
<br />
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: large;">CQRS</span><br />
<br />
I've been a fan of the <a href="http://martinfowler.com/bliki/CQRS.html" target="_blank">CQRS pattern</a> for some time. For me it's just seems to be a more elegant way to do things. It has some cons: there are usually more classes, and the workflow is not always as clear.<br />
<br />
CQRS is Command Query Responsibility Separation (or Segregation). Martin Fowler has a good posting which describes it. It's what it sounds like: separating code logic into commands, queries, and (sometimes) events. One common way of implementing the pattern is to have small objects which are little more than DTOs. These objects are passed to handlers which perform logic based on the contents of the small object.<br />
<br />
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: large;">MediatR</span><br />
<br />
Some time ago, I created a set of classes I used for doing this in projects. These classes were based of Jimmy Bogard's work. Fast-forward a couple years, and I've discovered his library, MediatR. It's as good or better than the set of classes I was using. That was enough for me to make the switch, since I'm a fan reuse when possible.<br />
<br />
MediatR is well documented, so I won't repeat all of it. But, for a basic understanding, here's a test showing how a command can be handled by MediatR:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #0000cc;">[Test]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ItShouldHandleBasicCommands</span>()
{
<span style="color: #333399; font-weight: bold;">var</span> mediator = GetMediator();
<span style="color: #333399; font-weight: bold;">var</span> command = <span style="color: #008800; font-weight: bold;">new</span> Command();
<span style="color: #333399; font-weight: bold;">var</span> response = mediator.Send(command);
response.Should().NotBeNull();
}</pre>
</td></tr>
</tbody></table>
</div>
<br />
The basic working pieces are the command and the handler. MediatR receives a command, and dispatches it to the appropriate handler. This is what they look like:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Command</span> : IRequest<Response>
{
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">CommandHandler</span> : IRequestHandler<Command, Response>
{
<span style="color: #008800; font-weight: bold;">public</span> Response <span style="color: #0066bb; font-weight: bold;">Handle</span>(Command message)
{
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">Response</span>();
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
Registering commands and command handlers is pretty easy. Since I've been using Ninject a lot lately, here's an example of registration using Ninject's convention-based registers. It says, find all the handler interfaces, and bind them.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3
4</pre>
</td><td><pre style="line-height: 125%; margin: 0;">kernel.Bind(scan => scan.FromThisAssembly()
.SelectAllClasses()
.Where(o => o.IsAssignableFrom(<span style="color: #008800; font-weight: bold;">typeof</span>(IRequestHandler<,>)))
.BindAllInterfaces());</pre>
</td></tr>
</tbody></table>
</div>
<br />
There are a couple other registrations which are important when hooking MediatR and Ninject up. Registering the IMediator interface depends on three calls. The instance factory calls tell MediatR how to resolve single or multiple instances. Then, of course, we register MediatR.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3
4
5</pre>
</td><td><pre style="line-height: 125%; margin: 0;">kernel.Bind<SingleInstanceFactory>()
.ToMethod(context => (type => context.Kernel.Get(type)));
kernel.Bind<MultiInstanceFactory>()
.ToMethod(context => (type => context.Kernel.GetAll(type)));
<span style="color: #333399; font-weight: bold;">var</span> mediator = kernel.Get<IMediator>();
</pre>
</td></tr>
</tbody></table>
</div>
<br />
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: large;">Validation and Decorators</span><br />
<br />
The <a href="https://en.wikipedia.org/wiki/Decorator_pattern" target="_blank">decorator pattern</a> is a way of adding behavior to an object without changing the object itself. Decorators can be used to add a number of cross-cutting concerns to another class. One common use is adding input validation. Wrapping a command handler with a decorator makes it possible to validate the command, before the handler processes it. The following command and command handler simply returns a response.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Foo</span> : IRequest<Response>
{
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">string</span> Message { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">FooHandler</span> : IRequestHandler<Foo, Response>
{
<span style="color: #008800; font-weight: bold;">public</span> Response <span style="color: #0066bb; font-weight: bold;">Handle</span>(Foo message)
{
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">Response</span>();
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
If we wanted to ensure the command, Foo, has a message, we'd want to validate it. <a href="https://github.com/JeremySkinner/FluentValidation" target="_blank">FluentValidation</a> is a really handy validation package. Validation requires a validation class, and those classes need to be registered with Ninject.<br />
<br />
This is an example of a simple validator. It checks to see if the Message property is empty. If it is, it will return an error.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3
4
5
6
7</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">FooValidator</span> : AbstractValidator<Foo>
{
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">FooValidator</span>()
{
RuleFor(ping => ping.Message).NotEmpty();
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
Registering the validator with Ninject is pretty easy. This line binds all validators in the assembly.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;">1
2
3
4</pre>
</td><td><pre style="line-height: 125%; margin: 0;">kernel.Bind(scan => scan.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom(<span style="color: #008800; font-weight: bold;">typeof</span>(AbstractValidator<>))
.BindAllInterfaces());
</pre>
</td></tr>
</tbody></table>
</div>
<br />
The next step is to work in a class which will use the validator. The class below comes from Jimmy Bogard's site. It's a pretty common example of how to implement a decorator class which will validate a command, before it is passed to the next handler class.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">ValidatingHandler</span><TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
<span style="color: #008800; font-weight: bold;">where</span> TRequest : IRequest<TResponse>
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IRequestHandler<TRequest, TResponse> handler;
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">readonly</span> IValidator<TRequest> validator;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">ValidatingHandler</span>(IRequestHandler<TRequest, TResponse> handler, IValidator<TRequest> validator)
{
<span style="color: #008800; font-weight: bold;">this</span>.handler = handler;
<span style="color: #008800; font-weight: bold;">this</span>.validator = validator;
}
<span style="color: #0000cc;"> [DebuggerStepThrough]</span>
<span style="color: #008800; font-weight: bold;">public</span> TResponse <span style="color: #0066bb; font-weight: bold;">Handle</span>(TRequest message)
{
<span style="color: #333399; font-weight: bold;">var</span> validationResult = validator.Validate(message);
<span style="color: #008800; font-weight: bold;">if</span> (validationResult.IsValid)
<span style="color: #008800; font-weight: bold;">return</span> handler.Handle(message);
<span style="color: #008800; font-weight: bold;">throw</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">ValidationException</span>(validationResult.Errors);
}
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
The next step is working out how to configure Ninject to create a handler and decorate it. <a href="http://jupaol.blogspot.com/2015/03/binding-decorators-with-ninject.html" target="_blank">This blog post</a> has a really good description of the process. I've distilled it down for validation below. It says, "Register the handlers. When a validating handler is created, inject a handler. When a handler is requested, return the validating handler." To be honest, I'm not quite sure why the ValidatingHandler has to be registered twice.<br />
<br />
When Ninject is asked to create a handler, it first creating a validating handler. It injects the correct command handler and validator into the validating handler.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12</pre>
</td><td><pre style="line-height: 125%; margin: 0;">kernel.Bind(scan => scan.FromThisAssembly()
.SelectAllClasses()
.Where(o => o.IsAssignableFrom(<span style="color: #008800; font-weight: bold;">typeof</span>(IRequestHandler<,>)))
.BindAllInterfaces());
kernel.Bind(scan => scan.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom(<span style="color: #008800; font-weight: bold;">typeof</span>(IRequestHandler<,>))
.BindAllInterfaces()
.Configure(o => o.WhenInjectedInto(<span style="color: #008800; font-weight: bold;">typeof</span>(ValidatingHandler<,>))));
kernel.Bind(<span style="color: #008800; font-weight: bold;">typeof</span>(IRequestHandler<,>)).To(<span style="color: #008800; font-weight: bold;">typeof</span>(ValidatingHandler<,>));
</pre>
</td></tr>
</tbody></table>
</div>
<br />
The tests below capture what should happen when the command's message is empty or not.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<table><tbody>
<tr><td><pre style="line-height: 125%; margin: 0;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21</pre>
</td><td><pre style="line-height: 125%; margin: 0;"><span style="color: #0000cc;">[Test]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ItShouldProcessCommands</span>()
{
<span style="color: #333399; font-weight: bold;">var</span> mediator = GetMediator();
<span style="color: #333399; font-weight: bold;">var</span> command = <span style="color: #008800; font-weight: bold;">new</span> Foo { Message = <span style="background-color: #fff0f0;">"valid ping"</span> };
<span style="color: #333399; font-weight: bold;">var</span> response = mediator.Send(command);
response.Should().NotBeNull();
}
<span style="color: #0000cc;">[Test]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ItShouldValidateTheCommand</span>()
{
<span style="color: #333399; font-weight: bold;">var</span> mediator = GetMediator();
<span style="color: #333399; font-weight: bold;">var</span> ping = <span style="color: #008800; font-weight: bold;">new</span> Foo();
Action act = () => mediator.Send(ping);
act.ShouldThrow<ValidationException>();
}
</pre>
</td></tr>
</tbody></table>
</div>
<br />
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: large;">Conclusion</span><br />
<br />
There it is. That's the basics of setting up command validation with Ninject, MediatR, and FluentValidation. It's also a good demonstration of how a decorator can be used to modify behavior without changing existing objects.<br />
<br />
As always, there is a <a href="https://github.com/caloggins/ExampleCode/tree/master/MediatrDecorators" target="_blank">sample project</a> on GitHub which has the code from this blog.<br />
<br />
<br />Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com2tag:blogger.com,1999:blog-8643450826744932654.post-73052977343937241492016-11-17T08:29:00.001-08:002016-11-17T08:29:22.137-08:00NancyFX: Stateless Auth Example<b><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An Update...</span></b><br />
<br />
Some time ago, I did an example of using JWTs with Nancy. This post is an update to that. It shows a lighter way of consuming JWTs with a Nancy service. The <a href="https://github.com/caloggins/ExampleCode/tree/master/NancyWithTokens" target="_blank">example solution</a> is hosted on Github.<br />
<br />
This example uses the following libraries:<br />
<ul>
<li>Nancy</li>
<li>Nancy.Hosting.Aspnet</li>
<li>Nancy.Authentication.Stateless</li>
<li>JWT.</li>
</ul>
The test project adds the following libraries:<br />
<ul>
<li>FakeItEasy</li>
<li>NBuilder</li>
<li>FluentAssertions</li>
<li>Nancy.Testing</li>
</ul>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><b>A Word on JWTs</b></span></div>
<div>
<br /></div>
<div>
JWTs are one of the token formats that are quite common today. The jwt.io site has a pretty good introductory page on them. The short story is they are a compact way to securely move information between parties (to paraphrase the jwt.io site).</div>
<div>
<br /></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><b>The Bootstrap Class</b></span></div>
<div>
<br /></div>
<div>
I'll start with the Nancy Bootstrap class. This class initializes the stateless authentication when the application is started. It gets an instance of the stateless authentication configuration, and enables it with a call to StatelessAuthentication.Enable(pipelines, configuration);.</div>
<div>
<br /></div>
<script src="https://gist.github.com/caloggins/600a9074b6d7eadd7671a7d210bf71f4.js"></script>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><b>Verifying The Token</b></span></div>
<div>
<br /></div>
<div>
The StatelessAuthConfigurationFactory returns a configuration used in the previous step. It contains the steps used to verify the JWT is valid. This is done by ensuring the issuer and audience are correct, checking if the token has expired, and if the user is valid.</div>
<div>
<br /></div>
<script src="https://gist.github.com/caloggins/843323e31da60cf40dfcc0a44e19cb13.js"></script>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><b>Securing the Endpoint</b></span></div>
<div>
<br />
The last bit part of the process is securing the endpoint(s). Nancy has a number of extension methods to help with this. The Health module will respond to any call with an OK status. It's not a great way to report the health of a service, but it demonstrates the idea.<br />
<br />
<script src="https://gist.github.com/caloggins/e62f1f56d0122692137f8101e9e9d05b.js"></script>
The Secure module demonstrates a few ways to use the extension methods. What's really cool is the requirements can be placed at the module level as well as the endpoint level. There are two endpoints in the example: /secure and /needsclaim. Both endpoints require the call use SSL and be made with a valid JWT. The /needsclaim endpoint further requires the authenticated user be an administrator.</div>
<br />
<script src="https://gist.github.com/caloggins/4f6184b0649039e1b5aa642144798c00.js"></script><br />
<b style="font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;">The End</b><br />
<br />
That's the basics for getting started with stateless authentication and Nancy.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-2970243953363964212015-11-19T14:08:00.000-08:002015-11-19T14:08:44.067-08:00IoC Battle Thoughts...<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">IoC Comparisons</span><br />
<br />
A co-worker sent me an article, <i><a href="http://cardinalcore.co.uk/2015/01/28/ioc-battle-in-2015-results-using-ninject-think-again/" target="_blank">IoC Battle in 2015...</a></i>, comparing the speed differences between several IoC containers. It's a topic that comes up every once in a while. This usually happens when developers are debating which container is best. I'm a big fan of dependency injection, so I was interested to see the results.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">I Ran It And Then...</span><br />
<br />
I saw the results, and forked the linked <a href="https://github.com/cardinal252/IOCBattle" target="_blank">repository</a>. My first run of the benchmark app produced results similar to the article:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZxWfBpcBt_Zh6dw58vzdPKKxHUiRZUOF0dRMzVaAG3B3qxQM9KYMr-ppApW5CKwiH589qtU8BaETDnKL8762TUIkmHIVz58uFJgn-XZTVUzcZG6wvH-pvk2ekx_Tgy2gn5cno0d8RIkk/s1600/initial+results.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="32" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZxWfBpcBt_Zh6dw58vzdPKKxHUiRZUOF0dRMzVaAG3B3qxQM9KYMr-ppApW5CKwiH589qtU8BaETDnKL8762TUIkmHIVz58uFJgn-XZTVUzcZG6wvH-pvk2ekx_Tgy2gn5cno0d8RIkk/s320/initial+results.png" width="320" /></a></div>
<br />
<br />
I dug into the code, wanting to see what was up with Windsor. The registration code was really funky. Each component was registered in a separate registration call. Regular users of Windsor know this isn't the right way to do this.<br />
<br />
The old registrations looked like this;<br />
<br />
<script src="https://gist.github.com/caloggins/98c0173b53da13dad07c.js"></script>
After I updated them, they looked like this (I'm just showing the singleton registrations):<br />
<br />
<script src="https://gist.github.com/caloggins/e5a9c127cec211b891d2.js"></script>
I reran the benchmark and got these results. The most stunning was the transient registration times. They were roughly 10% of the first run. I didn't spend much time on this. It would be interesting to see if things could be optimized further.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxX7N6b5SNkPIAQJxFLtc1BYFo_MVJuTDxvOD1_hN674NoH7X3Lds_k4d8dhRA5k04BU6H6KliCYoCHqTgY3mVERZ276RkUXQHDQpcP-ODNOj06qy3bLpG5Qn1j_WqLjD9BlL1hl4kjjc/s1600/registerfast.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="34" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxX7N6b5SNkPIAQJxFLtc1BYFo_MVJuTDxvOD1_hN674NoH7X3Lds_k4d8dhRA5k04BU6H6KliCYoCHqTgY3mVERZ276RkUXQHDQpcP-ODNOj06qy3bLpG5Qn1j_WqLjD9BlL1hl4kjjc/s320/registerfast.png" width="320" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">My Thoughts</span><br />
<br />
It's important to use something correctly when doing benchmarks.<br />
<br />
Different containers run at different speeds. The resolutions were for 1 million "web services" each which had fairly deep object graphs. So, yeah, it took Windsor some 30 seconds to do this. But then, it's unlikely a single app will be doing that. When you hit that performance demand, it's time to start scaling horizontally (more on that some other time).<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">In a Nutshell</span><br />
<br />
Donald Knuth is quoted as having written, "The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming." If you're at the point you're worried about how fast resolving 1M object graphs is, then it's a problem. Until then, use the container that works for you.<br />
<br />
I put my <a href="https://github.com/caloggins/IOCBattle" target="_blank">fork of this project</a> on GitHub.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-2111302853873240222015-10-26T08:02:00.000-07:002015-10-26T08:02:06.226-07:00GitHub: Error: Permission denied (publickey)With a new computer came the need to setup posh-git again. I try to use the SSH connections were possible. This time, I hit an issue. git pull in posh-git returned an error (below), but the GitHub app was working normally.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAL81_fgMC0UBJaX1Px1nUkZMfCZLqyTiJG6Kn0sEFgPaNtBX7f2aGu1EwPqF1J8M28uoDlNWh0RV891j6Gpoz36TUrB2DVM05cKFKXtZOu9JmLWKvqDcyoRxAzO5kQDPlkxj73H-5eik/s1600/permission+denied.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAL81_fgMC0UBJaX1Px1nUkZMfCZLqyTiJG6Kn0sEFgPaNtBX7f2aGu1EwPqF1J8M28uoDlNWh0RV891j6Gpoz36TUrB2DVM05cKFKXtZOu9JmLWKvqDcyoRxAzO5kQDPlkxj73H-5eik/s320/permission+denied.png" width="320" /></a></div>
<br />
Using git bash, I checked to see if I could connect to GitHub. The results showed me that posh-git was using the default RSA key file name, id_rsa.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbNda9i049-9cIvVE1edi40KGezqtM1_oRp5Y9nAHWcXezHwhMzdowE4tL4G-T-y27RQQENnzB59dnDKadAmqkRTLL1mNq8mpqNrZxtUVtbFXTr8YBfIhvYtcWgmPGwLrL5nC_KfbR0ks/s1600/git+bash.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbNda9i049-9cIvVE1edi40KGezqtM1_oRp5Y9nAHWcXezHwhMzdowE4tL4G-T-y27RQQENnzB59dnDKadAmqkRTLL1mNq8mpqNrZxtUVtbFXTr8YBfIhvYtcWgmPGwLrL5nC_KfbR0ks/s320/git+bash.png" width="254" /></a></div>
<br />
The fix was pretty easy: I just needed to add an entry in my ssh config file. This file is usually located in c:\Users\<your name>\.ssh. After adding the entry, I needed to restart the ssh agent. After that, everything worked fine.<br />
<br />
<script src="https://gist.github.com/caloggins/5f7c45d516a204b365f8.js"></script><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisEH56EcaUX_P0Vx8SOxsPtCcXCai1qk8IKX3_kdIwKLGkn9e7s-GIw7XvFaFUcoXGAEf_gvrGCoNl3Mc-zapRBJhPiwOHSEfd42nD0q4mHpAV14fal2xUHmtDqluWS3eA6WL9s0_iMJw/s1600/working.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisEH56EcaUX_P0Vx8SOxsPtCcXCai1qk8IKX3_kdIwKLGkn9e7s-GIw7XvFaFUcoXGAEf_gvrGCoNl3Mc-zapRBJhPiwOHSEfd42nD0q4mHpAV14fal2xUHmtDqluWS3eA6WL9s0_iMJw/s320/working.png" width="320" /></a></div>
<br />
<br />
<br />Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-58246148218833749052015-10-01T06:44:00.001-07:002015-10-01T06:44:52.841-07:00Documenting Your CodeThese are my thoughts about <a href="http://www.continuousimprover.com/" target="_blank">Dennis Doomen's post</a> on documenting code...<br />
<br />
I dislike comments in code. They represent a failure on the author's part to express an idea in the language they're using (C#, Java, etc.). That doesn't mean I never use them, or find them completely useless. They should be the exception not the norm.<br />
<br />
I use the class, method, and parameter names to infer what the code will do. If I have questions using an API, I try to write some form of test which captures what I want to do. If I want to know more about the implementation details, I'll go look. I think well named components and a suite of tests do a lot more to document code. They also don't go stale. I'll also favor writing tests around my code to demonstrate how it works or what it does.<br />
<br />
When I need to see how a library works, I'll look for code examples. The online docs, and available online resources are my resources. It's rare I'll simply use the comments on the public/protected members.<br />
<br />
Inline comments are a real red flag to me. Way too often I see them when a dev hasn't expressed themselves well enough in the language they're using. These should be really, really, really rare. The nice thing about these being so rare is they stand out. Most of the devs I've worked with have learned that an inline comment is a danger sign that we've left for one another. They also tend to disappear as a code base matures.<br />
<br />
Commit messages are stupid important. I don't know if I consider this documenting the code. It's more a history of what happened and why it happened. It's helpful if the commit messages focus on what the changes did: "Added login screen," or, "updated main landing screen to show user name."<br />
<br />
There's my $.02.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-76868136793635253912015-08-13T06:45:00.001-07:002015-08-13T06:45:08.037-07:00Nancy Authentication with Owin and JWTA huge part of this stuff is based upon blog posts by <a href="http://blog.jonathanchannon.com/2014/05/07/introducing-owin-statelessauth-with-nancy-angular-demo/" target="_blank">Jonathan Channon</a> and <a href="http://mikehadlow.blogspot.com/2014/04/json-web-tokens-owin-and-angularjs.html" target="_blank">Mike Hadlow</a>.<br />
<br />
It took me a bit of time to figure out all the working bits to building something atop Nancy using JWT for authentication. I decided to create an example app that could be used as a reference when I need to do this again. This isn't a tutorial. It's the descriptions of all the different moving parts.<br />
<br />
The app has a very basic SPA, some RESTful endpoints, and basic unit tests. This particular app is setup for ASP.NET hosting (handy for hosting it in Azure).<br />
<br />
<a href="https://github.com/caloggins/ExampleCode/tree/master/NancyAspNetOwin" target="_blank">The example app is on GitHub</a>.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Solution Layout</span><br />
<br />
The solution consists of two projects: NancyAspNetOwin.WebApp and NancyAspNetOwin.WebApp.UnitTests. The App directory contains all the files which comprise the SPA front-end. The Authentication directory houses the C# classes which support the token authentication. It also includes the Nancy Module which provides the endpoints that support authentication. Content, fonts, and Scripts all hold the plumbing bits such as Bootstrapper, KnockoutJS, etc. MyBootstrapper.cs and Startup.cs wire up the Nancy and Owin bits. index.html and IndexModule.cs are the kick off point.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxaBizU0_OuRo5JmQehyphenhyphenfZGog3-7t5al-psGf4GUxi-PHXg_m2nQyE1MO5YHHwETcUdxiQPHdeHvLVHEERJDqbn3bgS9o7G8GQp-_a2Ol5xWCB7xQUlpMslvwxmqviEF5XYU0UJZrNv0U/s1600/solution-layout.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxaBizU0_OuRo5JmQehyphenhyphenfZGog3-7t5al-psGf4GUxi-PHXg_m2nQyE1MO5YHHwETcUdxiQPHdeHvLVHEERJDqbn3bgS9o7G8GQp-_a2Ol5xWCB7xQUlpMslvwxmqviEF5XYU0UJZrNv0U/s320/solution-layout.png" width="271" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Setting Things Up</span><br />
<br />
There are a boat load of NuGet packages which need to be added when starting from an empty web application project. Some are the Nancy/Owin related stuff for the back-end. Others support the front-end SPA stuff. For this app, there were a few other things I dropped.<br />
<br />
Nancy/Owin NuGet Packages:<br />
<ul>
<li>JWT</li>
<li>Microsoft.Owin</li>
<li>Microsoft.Owin.Host.SystemWeb</li>
<li>Nancy</li>
<li>Nancy.Hosting.Aspnet</li>
<li>Nancy.Owin</li>
<li>OWIN</li>
<li>Owin.StatelessAuth</li>
</ul>
<div>
SPA NuGet Packages:<br />
<ul>
<li>Bootstrap CSS</li>
<li>KnockoutJS</li>
<li>RequireJS</li>
<li>Require.JS.Text</li>
</ul>
Other Bits:<br />
<ul>
<li>login.css - Pulled from bootsnip.com.</li>
<li>form.css</li>
</ul>
<br />
The <a href="https://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp/Web.config" rel="nofollow" target="_blank">web.config</a> file needs to be updated. The system.web and system.webServer sections need things for Nancy. An appSettings entry is created for the OWIN middleware.</div>
<div>
<br /></div>
<div>
You'll also want to <a href="http://www.codeproject.com/Tips/766918/Visual-Studio-Use-HTTPS-SSL-On-Web-Application-Pro">set the project to use HTTPS</a>.</div>
<ul>
</ul>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Workflow</span><br />
<br />
The flow for this app is pretty simple. A login form is displayed when first landing on the home page. When the credentials are entered, a token is retrieved from the login endpoint. This token is then used to pull the greeting from the secure endpoint.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjrhTPwdAMRtD9fX-jt3cAZ-i5N7yxilWaXC8rDuoQTRdwIqbeoTR0FcLR7OB7tmOj4NmuAkKW9UVXYp1zCJaswYxubrCu6AMR4IeAdP52ecOJrvFeveaU8mpQRxv2eUJuziBVdZ6LPrU/s1600/flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="99" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjrhTPwdAMRtD9fX-jt3cAZ-i5N7yxilWaXC8rDuoQTRdwIqbeoTR0FcLR7OB7tmOj4NmuAkKW9UVXYp1zCJaswYxubrCu6AMR4IeAdP52ecOJrvFeveaU8mpQRxv2eUJuziBVdZ6LPrU/s400/flow.png" width="400" /></a></div>
<br /></div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Startup Code</span><br />
<div>
<br />
There are two files running the show here: <i>Startup.cs</i> and <i>MyBootstrapper.cs</i>. <i>Startup.cs</i> has the Owin stuff. The <i>pathsToIgnore </i>variable contains all the routes we want exempted from the token-based security. These paths, along with an instance of the <i>SecureTokenValidator </i>class are passed into the <i>RequiresStatelessAuth() </i>method.<br />
<br />
<script src="http://gist-it.appspot.com/http://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp/Startup.cs"></script><br />
<br />
MyBootstrapper has two overrides. The <i>RequestStartup() </i>override contains the glue for the Owin stuff. The <i>ConfigureConventions() </i>override tells Nancy about the other directories that hold static content (JavaScript files, CSS files, etc.).<br />
<br />
<script src="http://gist-it.appspot.com/http://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp/MyBootstrapper.cs"></script><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Client UI</span></div>
<div>
<br /></div>
<div>
The UI implementation starts with the <i>index.html</i> file. Its layout was pulled from a template site. The rest of the client app is housed within the App folder. It contains the two knockout components, the config for RequireJS (<i>config.js</i>), and the basic application view model (<i>myapp.js</i>).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglitrbaX-5Y24u9VdCt3D_FLvuACMtjQc9Nub0aRaMVhbbZuZ6Ka-d6zq9qCIxPSWokc6a3kWbgx_syGU1lyfFp72GXspz8sJykJ4FDRUbiD8Ce7RNgTGcW58KhO_FTGj9bjSdA7w_tBA/s1600/app-folder.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglitrbaX-5Y24u9VdCt3D_FLvuACMtjQc9Nub0aRaMVhbbZuZ6Ka-d6zq9qCIxPSWokc6a3kWbgx_syGU1lyfFp72GXspz8sJykJ4FDRUbiD8Ce7RNgTGcW58KhO_FTGj9bjSdA7w_tBA/s1600/app-folder.png" /></a></div>
<br />
The <i>index.html</i> and <i>myapp.js</i> files act as the main view/view model for the app. <i>index.html</i> contains the markup, CSS file references, and script file references. <i>myapp.js</i> has the data bindings used by the app.<br />
<br />
Each component is split into three files. These three files contain the HTML which serves as the view, the JavaScript view model, and code to register the component in Knockout.<br />
<br />
The login component view (<i>login-control.html</i>) is a basic html file.<br />
<br />
<script src="http://gist-it.appspot.com/https://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp/App/Authentication/login-control.html"></script><br />
The login component view model (<i>login-control.js</i>) is a little more interesting. The params are come from a data binding on the <i>index.html</i> page. If a token is returned the page adds the token to future headers, raises an event, and hides the form. This is the spot you could <a href="https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/" target="_blank">store the token in a cookie or something</a>.<br />
<br />
<script src="http://gist-it.appspot.com/https://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp/App/Authentication/login-control.js"></script><br />
The login component registration (<i>login-control-register.js</i>) tells Knockout what files to use to display the component. Pay attention to the template property. The use of "text!" lets RequireJS know that the file isn't a code file.<br />
<br />
<script src="http://gist-it.appspot.com/https://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp/App/Authentication/login-control-register.js"></script><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Service Stuff</span><br />
<br />
Nancy supports a number of view engines, routing definitions, etc. The NancyModule is quite capable of returning views, exposing RESTful endpoints, etc. Each module can support different authentication requirements.<br />
<i><br /></i>
<i>IndexModule.cs </i>is a NancyModule with two endpoints: <i>/,</i> and .<i>/health.</i> Both require an https call. <i>/health </i>requires that the caller supply a valid token in the request header. The <i>RequiresAuthentication() </i>method uses the <i>ClaimsPrincipal </i>data created by the <i>SecureTokenValidator </i>class.<br />
<br />
<script src="http://gist-it.appspot.com/https://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp/IndexModule.cs"></script><br />
The SecureTokenValidator class (lifted from <a href="http://blog.jonathanchannon.com/2014/05/07/introducing-owin-statelessauth-with-nancy-angular-demo/" target="_blank">here</a>) verifies that the token provided in a request is valid. It also converts the token into the <i>ClaimsPrincipal </i>object used by Nancy. It's interesting to note that I've seen two variations on this class. Both have noted that the token does not directly decode to a set of claims.<br />
<br />
<script src="http://gist-it.appspot.com/https://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp/Authentication/SecureTokenValidator.cs"></script><br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Testing Notes</span><br />
<br />
Nancy was designed to be very testable. There's the <a href="https://www.nuget.org/packages/Nancy.Testing/" target="_blank">Nancy.Testing</a> package goes a long way to helping with that. The <a href="https://github.com/NancyFx/Nancy/wiki/Testing-your-application" target="_blank">Nancy documentation</a> does a good job of explaining how to test your Nancy app. Testing Nancy with OWIN is a little more involved. You'll need the <a href="https://www.nuget.org/packages/Microsoft.Owin.Testing/" target="_blank">Microsoft.Owin.Testing</a> package. <a href="https://github.com/caloggins/ExampleCode/blob/master/NancyAspNetOwin/NancyAspNetOwin.WebApp.UnitTests/OwinTests.cs" target="_blank">OwinTests.cs</a> in the test project gives an example of how those tests are done.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">In Closing</span><br />
<br />
That's all I have so far. Hopefully, this will help some other people who are trying to work through these issues.</div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com1tag:blogger.com,1999:blog-8643450826744932654.post-12532080026323935602015-07-09T06:12:00.001-07:002015-07-09T06:12:58.260-07:00SPA NotesThis is an outline of some stuff for weaving KnockoutJS, RequireJS, and Bootstrap into a site. I'm not saying these are best practices or anything. Just my notes on what I have been doing. Mostly geared towards SPAs.<br />
<div>
<br /></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Setup (Config) File</span></div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/caloggins/9e9b414960afac86da17.js"></script></div>
<div>
<br /></div>
<div>
Notice that the JavaScript files do not have the .js extension in the config file. The <i>shim </i>property is used to ensure certain load orders (Bootstrap requires jQuery). The <i>paths </i>can be combined when loading dependencies.</div>
<div>
<br /></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The HTML File</span></div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/caloggins/bf24ecc58fa74b567142.js"></script></div>
<div>
<br /></div>
<div>
It still needs the css files. The <i>data-main</i> attribute in the scripts tag tells RequireJS to get everything from that file.</div>
<div>
<br /></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Modules</span><br />
<br />
<script src="https://gist.github.com/caloggins/98ccdf5a85d7652d1c1d.js"></script><br />
<br />
It's not necessary to have a parameter for each dependency. The above module uses a bootstrap modal function, but doesn't need a variable (lines 34 and 55).<br />
<br />
Examples of getting and posting some json are at lines 24 and 48. I use the $.ajax at 48, because it lets me specify the contentType. I ran into problems using $.post.<br />
<br />
More to come on this...</div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-61488043657817064702015-06-04T07:18:00.000-07:002015-06-04T07:19:15.970-07:00TDD ResourcesThis is a quick and dirty post listing some (imho) good resources for <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a>.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Definitions</span><br />
<br />
<ul>
<li>Unit Test - A test which verifies a unit of work. There must not be any interaction with external resources (databases, file systems, etc.). May or may not test more than one component or class.</li>
<li>Integration Test - A test which verifies a unit of work. These tests interact with external resources (databases, file systems, etc.).</li>
</ul>
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Books</span><br />
<br />
<ul>
<li><a href="http://www.amazon.com/Art-Unit-Testing-examples/dp/1617290890">The Art of Unit Testing, 2nd Ed.</a></li>
<li><a href="http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052">Working With Legacy Code</a></li>
</ul>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Blog Posts</span></div>
<div>
<ul>
<li><a href="http://osherove.com/tdd-kata-1/">String Calculator Kata</a> - A daily exercise.</li>
<li><a href="http://thesenilecoder.blogspot.com/2015/03/a-quick-tdd-example.html">Unit Test Samples</a> - Some quick examples I made.</li>
<li><a href="http://www.telerik.com/blogs/top-5-tdd-mistakes">Top 5 TDD Mistakes</a></li>
<li><a href="http://blogs.msdn.com/b/elee/archive/2009/01/20/bdd-with-mstest.aspx">Context Specification</a></li>
</ul>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Videos</span></div>
<div>
<ul>
<li><a href="https://www.youtube.com/playlist?list=PL2C6L1jlMsNCpaA2wO8fj7kCW8BpXbURy">TDD Go Engine</a></li>
<li><a href="https://www.youtube.com/playlist?list=PLg12NUVvuAkIIzAtEYqEo2lw4dz-zsb1V">Chess TDD</a></li>
</ul>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Tools</span></div>
</div>
</div>
<div>
<ul>
<li><a href="http://www.nuget.org/packages?q=nunit">NUnit</a></li>
<li><a href="http://www.nuget.org/packages/FluentAssertions/">FluentAssertions</a></li>
<li><a href="http://www.nuget.org/packages/FakeItEasy">FakeItEasy</a></li>
<li><a href="http://www.nuget.org/packages/NBuilder">NBuilder</a></li>
</ul>
</div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-17767266162386549552015-05-20T05:25:00.000-07:002015-05-20T05:25:57.331-07:00NancyFX Notes: Static Content<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">NancyFX Notes</span><br />
<br />
<span style="font-family: inherit;">This is part of a set of articles that are my developer notes for working with <a href="http://nancyfx.org/">Nancy</a>. Taken from the Nancy introduction, "<span style="background-color: white; color: #333333; line-height: 25.6000003814697px;">Nancy is a lightweight, low-ceremony, framework for building HTTP based services on .Net and </span><a href="http://mono-project.com/" style="background-color: white; box-sizing: border-box; color: #4183c4; line-height: 25.6000003814697px; text-decoration: none;">Mono</a><span style="background-color: white; color: #333333; line-height: 25.6000003814697px;">." It's (she's?) great for building microservices and other things.</span></span><br />
<span style="font-family: inherit;"><span style="background-color: white; color: #333333; line-height: 25.6000003814697px;"><br /></span></span>
<span style="background-color: white; color: #333333; font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large; line-height: 25.6000003814697px;">Static Content</span><br />
<br />
Static content are files like images, JavaScript files, css files, etc. Nancy automatically supports static files which are placed in the Content directory. The <a href="https://github.com/caloggins/ExampleCode/tree/master/NancyFXStaticContentExample">example on GitHub</a> has custom directories for the 3rd-party scripts and the application-specific scripts. These are Scripts and App directories.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIeZDV1lQDvGjPZOLDGA4bcRP-yEZ6kOEiBaYhQg4pjDN2QSgw9Pqhm15eMtbnm-AMlJ0MYR0lTDfkIF2FcXtl6jR1T3t46UgMoBgoFWhTlV3ite_Y2I6jiQ6SHBpXXoYVxFL1MMu45qc/s1600/example.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIeZDV1lQDvGjPZOLDGA4bcRP-yEZ6kOEiBaYhQg4pjDN2QSgw9Pqhm15eMtbnm-AMlJ0MYR0lTDfkIF2FcXtl6jR1T3t46UgMoBgoFWhTlV3ite_Y2I6jiQ6SHBpXXoYVxFL1MMu45qc/s1600/example.png" /></a></div>
<br />
<br />
Other directories can be included by adding to NancyConventions.StaticContentConventions property. Do this by overriding the ConfigureConventions method in your bootstrapper.<br />
<br />
<script src="http://gist-it.appspot.com/github/caloggins/ExampleCode/blob/master/NancyFXStaticContentExample/StaticContentExample/MyBootstrapper.cs"></script><br />
<br />
The shot from Fiddler below shows a before and after. The calls from 5-8 were made before the additions to the bootstrapper. The later calls show that the changes enabled Nancy hosting the files in those directories.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFDNe5qpbjXcG-Rea9uAgyTKw65VyBNzZVcfbb_9sGMXNuUXzX_L-TFPj6onRc0ztFL34LB2iA9MhG2Ot34MgYG9NPwoxVYATJeke-ZSqYwuGN4Y1gfKeLDjGR9Cq3PxIfpD6hrd_2stU/s1600/beforeafter.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFDNe5qpbjXcG-Rea9uAgyTKw65VyBNzZVcfbb_9sGMXNuUXzX_L-TFPj6onRc0ztFL34LB2iA9MhG2Ot34MgYG9NPwoxVYATJeke-ZSqYwuGN4Y1gfKeLDjGR9Cq3PxIfpD6hrd_2stU/s320/beforeafter.png" width="320" /></a></div>
<br />Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-51098514580789622562014-11-19T13:01:00.003-08:002014-12-04T08:23:02.601-08:00Continuous Deployment Notes<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
Continuous integration and deployment are important concepts in efficiently delivering products. Here's some notes I've made about setting up a continuous deployment pipeline using TFS, TeamCity, and Octopus Deploy. It's a work in progress, but I hope it will help someone else out there.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Process</span><br />
<br />
The process is pretty simple. Code is checked into source control. A build server picks up the changes. It uses a build script to create a .nupkg file containing the build artifacts. This .nupkg file is uploaded to an Octopus-hosted NuGet repository. Octopus is then used to deploy the artifacts to a target environment.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Build Server</span><br />
<br />
Here's some details on the build server. It is a Server 2008 R2 machine with SP1. It's got .NET 4.5.1, Visual Studio and TeamCity installed. Some things were dropped into a 'Tools' directory on the main drive: <a href="https://www.nuget.org/packages/MSBuildTasks">MsBuildTasks</a>, a custom Regex task, <a href="http://www.nuget.org/">NuGet</a>, <a href="http://www.nunit.org/">NUnit</a>, and Octo.exe.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Sample Project</span><br />
<br />
I'll be using a small, sample project illustrate where things go, and how they are used. The project structure, as it is checked into source control is similar to the following:<br />
<br />
<pre>./SampleProject/
SampleProject.proj
src/
SampleProject.sln
Version.cs
SampleProject.Host/
SampleProject.Library/
SampleProject.Library.UnitTests/</pre>
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Project File</span><br />
<br />
The sample project uses the SampleProject.proj file to define the steps necessary for building the solution. Using a project file allows us to have a (mostly) product independent build sequence. All the major steps for creating a product artifact are codified in the project file. Be sure to check out the <a href="http://msdn.microsoft.com/en-us/library/2208a1f2.aspx">project file documentation</a> on MSDN's site.<br />
<br />
<script src="https://gist.github.com/caloggins/7d94efe0fac9fba6a483.js"></script><br />
<br />
Yes, it could use some cleanup, but this is what's running now. It was originally designed to work with either Jenkins or TeamCity. It's being updated to work only with TeamCity.<br />
<br />
Why use a file instead of setting the steps up in TeamCity? With the exception of the NUnitTeamCity addin, the script can be used in Jenkins. That means you can pick this file up and go with whatever CI server you want. I'm hoping to post something about that later. It's also easier for me to visualize the build process in one file, versus the million option pages that is TeamCity.<br />
<br />
<br />
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Versioning</span></div>
<div>
<br /></div>
<div>
Mike Hadlow has a pretty nifty trick for assembly versions in a solution. It uses one file to set the version information for all the artifacts in a solution. His <a href="http://mikehadlow.blogspot.com/2010/10/use-single-version-file-for-all.html">blog post</a> explains it. I'm a big fan of <a href="http://semver.org/">Semantic Versions</a>. Using the one-file trick really eases process of maintaining the changes to the version numbers.<br />
<br />
Using the one-file trick, it became possible to use a regex task to update the file. This made it possible to have the version number based on the TeamCity build number. A co-worker found the build task, so I'm not sure where it originally came from. This custom task is also added to the Build Server's tools directory.<br />
<br />
<br /></div>
<script src="https://gist.github.com/caloggins/7a235b59b700c5775052.js"></script><br />
<div>
<br /></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">TeamCity</span></div>
<div>
<br /></div>
<div>
The bummer about TeamCity is the clicky-ness of the interface. There are roughly a million different links, each leading to a new page. Each page has a dozen or so things you can set. Sure, it's amazingly powerful and flexible. But, it's easy to get lost. This isn't a knock on TeamCity. I'm just easily confused.</div>
<div>
<br /></div>
<div>
The first thing to set in TeamCity is the build number format. This is accessible on the first page of the build configuration settings.</div>
<div>
<br /></div>
<div>
Note: The format of the variable changes when used in a MSBuild file. In the project file, the any '.' in the variable name must be replaced with an '_'. That means 'build.number' becomes 'build_number'.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVEGw_HlIBrklJzSTW1fmwqSkjHx_uAWtL5EF1_E9QPidAWx4F139CQNZuMcMK8XUEAisqSgj9IMh53jFmve20B2QM0h7oVrTpf9WMYMffMaYLX8-qkBQdIwaHOO5xn7Hv46w-b7bVJj0/s1600/TeamCity+Build+Number.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVEGw_HlIBrklJzSTW1fmwqSkjHx_uAWtL5EF1_E9QPidAWx4F139CQNZuMcMK8XUEAisqSgj9IMh53jFmve20B2QM0h7oVrTpf9WMYMffMaYLX8-qkBQdIwaHOO5xn7Hv46w-b7bVJj0/s1600/TeamCity+Build+Number.png" height="46" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Octopus</span></div>
<div>
<br /></div>
<div>
Using Octopus to deploy is a straightforward process: create an environment, add some machines, create a release. Installing Octopus and tentacles on target machines is covered in the <a href="http://docs.octopusdeploy.com/display/OD/Home">Octopus online documentation</a>.</div>
<div>
<br /></div>
<div>
The first step is to create an <a href="http://docs.octopusdeploy.com/display/OD/Environments">environment</a>. Once the environment is setup with machines, a <a href="http://docs.octopusdeploy.com/display/OD/Projects">project</a> is needed. Finally, a release is created to actually <a href="http://docs.octopusdeploy.com/display/OD/Deploying+applications">deploy the artifacts</a>. Once the environment is setup, you can perform your deployment as normal.</div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8BLQTrLBs6y9_yoCVoe-RtlfL4IvAmMpCL2kI_tJXPXONVR3bG77IL6vuOvDCzWTXfdVUEeXt40BYuM3PmtxBdAutlbrNMqGkZsVR6lKeykro4c3cf5gLM_H44TE7jrARFiSk6YtkXw8/s1600/Octopus+Environment.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8BLQTrLBs6y9_yoCVoe-RtlfL4IvAmMpCL2kI_tJXPXONVR3bG77IL6vuOvDCzWTXfdVUEeXt40BYuM3PmtxBdAutlbrNMqGkZsVR6lKeykro4c3cf5gLM_H44TE7jrARFiSk6YtkXw8/s1600/Octopus+Environment.png" height="191" width="320" /></a></div>
<br /></div>
<div>
<br /></div>
<div>
Octopus is pretty flexible in terms of the scripting and other custom install actions. The sample project is a TopShelf service. Installing and uninstalling it just needs a couple custom actions around the deploy action.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLowX9Co4K4BUJduaoLRhBjZ7T2bVOj3uLprpQva2f4GQUBJcn2ZJBqcl-RSRxTBFe2QUPf5IvrkqWGKYmEl2p4DMvZLiZzFWhI6xZ93acdlQogGpMaG4Jr8yH5mgAgDQx7xSy3orw8U0/s1600/Deployment+Process.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLowX9Co4K4BUJduaoLRhBjZ7T2bVOj3uLprpQva2f4GQUBJcn2ZJBqcl-RSRxTBFe2QUPf5IvrkqWGKYmEl2p4DMvZLiZzFWhI6xZ93acdlQogGpMaG4Jr8yH5mgAgDQx7xSy3orw8U0/s1600/Deployment+Process.png" height="167" width="320" /></a></div>
-<br />
<br />
<pre>The scripts can be as simple as, C:\Services\SampleProject\SampleProject.Host.exe uninstall.</pre>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Wrapping It Up</span><br />
<br />
Hopefully this will help someone resolve some of the issues with setting up a CI build process.</div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-29810700924369394402014-10-09T09:36:00.001-07:002014-10-09T09:36:12.896-07:00Toggling With Windsor<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
There are a number of times when we've all had to implement new features or modify the implementation of an existing code base. An intern recently asked me how to <a href="http://martinfowler.com/bliki/FeatureToggle.html">feature toggle</a> something using Castle.Windsor. This post will show how to use some Castle.Windsor features to toggle implementations. The example code can be found on <a href="https://github.com/caloggins/ExampleCode/tree/master/WindsorFeatureToggle">GitHub</a>.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Primitive Dependencies</span><br />
<br />
The toggle will be an app setting in the application's config file. It will be loaded by Castle.Windsor by using a custom dependency resolver. This resolver is taken from Mark Seeman's <a href="http://blog.ploeh.dk/2012/11/07/AppSettingsconventionforCastleWindsor/">post on AppSettings</a>.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Service</span><br />
<br />
We'll be using a simple interface as our service definition. There will be two implementations. One represents an old implementation, the other a new.<br />
<br />
<script src="https://gist.github.com/caloggins/f355c2164b472d154fc6.js"></script>
<br />
It's useful to note that this is a common way to achieve some <a href="http://martinfowler.com/bliki/BranchByAbstraction.html">branching by abstraction</a>. This is done by replacing calls to a service with an interface. This interface is the abstraction. Once the calls to the old service are replaced, you are free to implement a new service. When ready, the new service can be substituted for the old without the consumers being aware since they depend on the interface not the concrete.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Typed Factory Selector</span><br />
<br />
Castle.Windsor comes with a handy little bit: the typed factory facility. The typed factory facility lets Castle.Windsor create a factory implementation from an interface defined by you. This relieves you of the task of implementing the factory on your own. It is especially useful if you want to defer the creation of the object.<br />
<br />
<script src="https://gist.github.com/caloggins/03c15958637ac62f8149.js"></script>
<br />
Our class will use this factory to get an instance of our service, and call the .Print() method. The default for this object will be the first one registered in the container. This behavior can be overridden by implementing a custom selector.<br />
<br />
<script src="https://gist.github.com/caloggins/b8e8b0d107ea3e126017.js"></script>
<br />
The typed factory and selector must both be registered with the container. The selector must also be specified in the configuration of the typed factory. This is done on lines 21 and 22 of the ContainerFactory class.<br />
<br />
<script src="https://gist.github.com/caloggins/37062f086583e0dbc241.js"></script>
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Using IHandlerSelector</span><br />
<br />
Mike Hadlow provides a <a href="http://mikehadlow.blogspot.com/2008/11/multi-tenancy-part-2-components-and.html">very good example</a> of using a custom IHandlerSelector.<br />
<br />
We can use a similar technique to pull in a config value and supply the appropriate implementation at run time. The custom IHandlerSelector uses the config value to select the appropriate handler. If no handlers are found it throws an exception. This handler is then returned.<br />
<br />
<script src="https://gist.github.com/caloggins/bf2e8319096f53322430.js"></script>
<br />
This service handler must be registered and added to the container's kernel. Line 19 of the ContainerFactory class show the registration. Line 26 shows the selector being added to the kernel. While there is only one selector in this example, the snippet shows how to add more than one.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Running the Console</span><br />
<br />
Changing the config value and running the console app shows that the selectors are functioning correctly.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4qfIh00BaS9ulBbLcJqadhFVGRXGNceUlTetVd4BqU8xTJ8RAlmCnTMgLR6l9ZKj-AYfnVvznE1oOykj89d1v0QohJRRO_MKfohhHD-sq5wTlXH_scZE7G87K2bAQ7cjk9SW4wzipO4A/s1600/consoleapp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4qfIh00BaS9ulBbLcJqadhFVGRXGNceUlTetVd4BqU8xTJ8RAlmCnTMgLR6l9ZKj-AYfnVvznE1oOykj89d1v0QohJRRO_MKfohhHD-sq5wTlXH_scZE7G87K2bAQ7cjk9SW4wzipO4A/s1600/consoleapp.png" height="131" width="400" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Wrapping It Up</span><br />
<br />
Feature toggles and branching by abstraction are powerful ways to control whether new code is being used in production. They provide a way to replace old behavior with new, while maintaining the integrity of the product's build. Hopefully these two examples will help you integrate feature toggling into your builds.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-62644454421546372822014-07-22T10:45:00.000-07:002014-07-22T10:45:12.844-07:00Basics: Removing the 'if' (Using Polymorphism)<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
Performing transformations of one object type to another type is a very common task in programming. It might be publishing an event based on a command, or an externally known DTO from an internal DTO. It's pretty common to see some use of the if or switch keywords to determine the code flow. I thought I'd take a minute to show how we can go from a typical implementation using if statements to one which uses Linq and AutoMapper to reduce the coupling in the implementation.<br />
<br />
The <a href="https://github.com/caloggins/ExampleCode/tree/master/PolyMapExample">example code</a> uses the following tools:<br />
<ul>
<li><a href="http://www.nunit.org/">NUnit</a>
</li>
<li>NUnit Test Adapter for VS2012 and VS2013
</li>
<li><a href="https://github.com/dennisdoomen/FluentAssertions">Fluent Assertions</a></li>
<li><a href="https://github.com/FakeItEasy/FakeItEasy">FakeItEasy</a></li>
<li><a href="http://automapper.org/">AutoMapper</a></li>
</ul>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Interface</span><br />
<br />
For this example, we'll have three different publishers. Each will implement a common interface: IPublisher. The implementations will be responsible for accepting a Command object and publishing the associated Event object. We'll be using two commands and events: Start -> Started, Stop -> Stopped.<br />
<br />
The Publish method on the IPublisher interface is intentionally not using a generic declaration.<br />
<br />
<script src="https://gist.github.com/caloggins/7f7b6f248e2cb9346ac6.js"></script>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Overloading</span><br />
<br />
The first Publisher accepts a command. It checks the type of the command received, and calls the appropriate overload. Each overloaded method creates the appropriate event, and publishes it.<br />
<br />
<script src="https://gist.github.com/caloggins/30e5f3c838d0fc3fd712.js"></script>
<br />
This works, but it has a few problems. It both uses an if to determine which type to publish, and manually maps the inbound command to the outbound event. That means this class is responsible for both determining what kind of event to publish and creating that event.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Adding AutoMapper</span><br />
<br />
AutoMapper removes the responsibility of creating the event from the publisher class. AutoMapper Profiles could be used to map more complex associations, but the DynamicMap method works just fine here. Our publisher class is relieved of this responsibility, limiting it to just sorting out the type of event to be published.<br />
<br />
<script src="https://gist.github.com/caloggins/fc8bf70bc62083f44b84.js"></script>
It still has the problem of using the if statement to determine the type of command received (and event to be be published).<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Removing the 'if'</span><br />
<br />
Introducing a map from the commands and a Linq query allows us to remove the if statements. The class is still responsible for selecting the appropriate action. The concept of associating commands to events is distilled into the dictionary. This leaves the class' methods to simply select the appropriate action and execute it.<br />
<br />
<script src="https://gist.github.com/caloggins/5a852c4e46685b0ea946.js"></script>
The Dictionary was left inside the publisher class to keep everything in once class. It wouldn't take much to move the mappings out of the class. This would further reduce the coupling on the Publisher. More complex mappings could be introduced by changing the Dictionary out for a custom type.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Wrapping It Up</span><br />
<br />
This was a quick demonstration of removing two concerns from a class. The manual mapping of one class to another by introducing AutoMapper. The if statement was removed by introducing a map between the two types. I hope this helped describe a different was of building classes with reduced responsibilities.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-66314967078373276042014-02-06T06:36:00.000-08:002014-02-06T17:07:53.137-08:00RabbitMQ Federated Queues<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
RabbitMQ added support for federated queues in <a href="http://www.rabbitmq.com/release-notes/README-3.2.0.txt">v3.2.0</a>. This feature gives a simple way to move messages from one Rabbit cluster to another. I'll show you one way to set this up. The <a href="https://github.com/caloggins/ExampleCode/tree/master/MoreRabbitFederations">sample code</a> can be found on GitHub. I'm using <a href="http://easynetq.com/">EasyNetQ</a> to handle the publishing and subscription. It's a very nice RabbitMQ client library. Check it out.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Clusters</span><br />
<br />
Note: The virtual host names are not the same on the two clusters. Broker A is using the virtual host FederationDemo. Broker B is using the virtual host FederatedStuff.<br />
<br />
The RabbitMQ documentation does cover the <a href="http://www.rabbitmq.com/federation.html">federation plug-in</a>. In our scenario, there are two clusters. Each is an upstream for the other. Message hops are at 1 to prevent the messages from circling back to the publisher. Below are pictures of the upstreams defined on each of the clusters.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCWfwEiPJU_jO-4lOgQVkYRN62r7tbKBtzNJHbifSHyES_ZZiK39HdBvC_NyftA-RorJ7i4MW7gwO0p8DgUvxTwNP92y6nnDAhcPTyMwOEXpJKWaBpAgkIsmT3MFbAOWj2-izaVnHUei4/s1600/brokera+upstream.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Shows the upstream definition on Broker A." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCWfwEiPJU_jO-4lOgQVkYRN62r7tbKBtzNJHbifSHyES_ZZiK39HdBvC_NyftA-RorJ7i4MW7gwO0p8DgUvxTwNP92y6nnDAhcPTyMwOEXpJKWaBpAgkIsmT3MFbAOWj2-izaVnHUei4/s1600/brokera+upstream.png" height="102" title="" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Broker A Upstream</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPCadSUCd0pgJZmxvBO2xYyMRdfUeQx28HxzSPrtbhyUt8kf5Jnk5sC6mrDTLmE9RB_BnthvKFJ9R01rzj4klo42A0wBgQqJaFnvVXAz1I4zVrKxIBg8Fdjj_PncSFp5vajJSIgHxacQw/s1600/brokerb+upstream.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="Shows the upstream definition on Broker B." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPCadSUCd0pgJZmxvBO2xYyMRdfUeQx28HxzSPrtbhyUt8kf5Jnk5sC6mrDTLmE9RB_BnthvKFJ9R01rzj4klo42A0wBgQqJaFnvVXAz1I4zVrKxIBg8Fdjj_PncSFp5vajJSIgHxacQw/s1600/brokerb+upstream.png" height="106" title="" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Broker B Upstream</td></tr>
</tbody></table>
<br />
<br />
Each broker will need to have a policy defined. This policy is used by the broker to figure out what things come from the upstream bluster. The policies are very similar for both clusters. Below are pictures of the policies:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7VsJZytdU_RRyr327jUCcUYcw7IFMvkLnu1RGrOCqbSXDYevJ09U0W32pLWcoKhFIOWB5FJIF0vHqOxF49dNZPB45R2cFQjFUayZOFbez8fwcxz_1ZpisTs4351GirlTXwYBFVIkIUVM/s1600/brokera+policy.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7VsJZytdU_RRyr327jUCcUYcw7IFMvkLnu1RGrOCqbSXDYevJ09U0W32pLWcoKhFIOWB5FJIF0vHqOxF49dNZPB45R2cFQjFUayZOFbez8fwcxz_1ZpisTs4351GirlTXwYBFVIkIUVM/s1600/brokera+policy.png" height="146" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Federation Policy on Broker A</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1NHfVBWT-rJTb5oez94pKNKMAP-L3Xa8fPJqJ0_XwGJLgGgCMW6eobUo99h8old3rpgMCxSlKLDMAe-Boq6naaXx0G5Dj6hEzHiOnNhEJtWSLw2LKj7tbtS2Am5A3tlt3s0_rI8tI90w/s1600/brokerb+policy.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1NHfVBWT-rJTb5oez94pKNKMAP-L3Xa8fPJqJ0_XwGJLgGgCMW6eobUo99h8old3rpgMCxSlKLDMAe-Boq6naaXx0G5Dj6hEzHiOnNhEJtWSLw2LKj7tbtS2Am5A3tlt3s0_rI8tI90w/s1600/brokerb+policy.png" height="146" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Federation Policy on Broker B</td></tr>
</tbody></table>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Clients</span><br />
<br />
This example will use two console applications. Each will subscribe to and publish two messages. The messages will ping-pong between the two clients. The first client, FooConsole, will publish two messages: start, and stop. The second client, BarConsole, will publish the following: started and stopped.<br />
<br />
This example uses two clients. A message from one client will be transported to another. Then a response message will be transported back to the original client.The message sequence is Start, Started, Stop, and Stopped.<br />
<br />
I've put the publishing and subscriptions into one class, so we could see everything going on. Both classes, Foo and Bar, are very similar. Here's a look at the Foo class:<br />
<br />
<script src="https://gist.github.com/caloggins/fd4e965bc2898079fc89.js"></script>
<br />
<div>
Foo subscribes to two messages: Started and Stopped. It then publishes a Start message to get the ball rolling. On the other end, Bar subscribes to Start and Stop messages. It responds to each message with one of its own messages. A Start from Foo causes Bar to send Started. A Stop from Foo causes Bar to send a Stopped message.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Wiring Two Joints</span><br />
<br />
When an app uses EasyNetQ to subscribe, EasyNetQ creates the queues and exchanges for us. This doesn't happen when working with federated queues. The queues will be federated, but there will be no bindings made on the upstream cluster. The pictures below show the downstream and upstream clusters after a client subscribes to a message.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS_YNNguQ3G317pHBDU-sSKqqIeZ07o4f73k9CdTjU_59YBX2aGA9VW5r0obHQCZJWkN2D2_AuRCXtUxm1ofh8URsjbF1GGy_pihafacin-LiliYfu7ksRr7TFuCNRXdgthPagTZlLzeQ/s1600/brokerb+queues+subscription.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS_YNNguQ3G317pHBDU-sSKqqIeZ07o4f73k9CdTjU_59YBX2aGA9VW5r0obHQCZJWkN2D2_AuRCXtUxm1ofh8URsjbF1GGy_pihafacin-LiliYfu7ksRr7TFuCNRXdgthPagTZlLzeQ/s1600/brokerb+queues+subscription.png" height="102" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Upstream (publisher) Federated Queues</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfq20Rv7B5WVib6A_vQdoCu86Tz8Lxa-pggMjbj6M7KV0cLsF-t0XDrJ1bfNwiZh4j9nvfVH6J9wUfI_KUWy7GjZdgnarHOc_zIrgnm9pzP2W7pgYIYG8CPGj5AoR1s-TcJCmAcTRCN7U/s1600/brokera+queues+subscription.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfq20Rv7B5WVib6A_vQdoCu86Tz8Lxa-pggMjbj6M7KV0cLsF-t0XDrJ1bfNwiZh4j9nvfVH6J9wUfI_KUWy7GjZdgnarHOc_zIrgnm9pzP2W7pgYIYG8CPGj5AoR1s-TcJCmAcTRCN7U/s1600/brokera+queues+subscription.png" height="88" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Downstream (subscriber) Federated Queues</td></tr>
</tbody></table>
<br />
<br />
The last little bit is to bind the exchange to the queue on the upstream cluster. This allows the messages to flow from the upstream publisher to the downstream subscriber.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-s2r0FLt9C4QAmWzKHc13OI7fQGyQ-5safywi8UGiP0r4ZebTN3v1wNFMtK4IbYunxkybEqZR242FDmaDeIf2_vk1jUkpE0egfT05Wh-qrhnKxDa0KWYIRqpTzdVcCkBoBT_ourCdAOY/s1600/federated+queue+no+binding.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-s2r0FLt9C4QAmWzKHc13OI7fQGyQ-5safywi8UGiP0r4ZebTN3v1wNFMtK4IbYunxkybEqZR242FDmaDeIf2_vk1jUkpE0egfT05Wh-qrhnKxDa0KWYIRqpTzdVcCkBoBT_ourCdAOY/s1600/federated+queue+no+binding.png" height="242" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Federated Queue Without Binding</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOsNkA_Jaz7XYg0k-XwNhw4-RgFUyVEI78kbumfx7MNXpvgqKQm_21tJ-ER9xEjINoMn2a3hhycj0H-4G9YN-PteVtB6-cdgVnzLYsarIWeaYSVXRWb4fkF1OgOS07TVNBZsVnzcyFdME/s1600/brokera+bind+exchange+to+queue.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOsNkA_Jaz7XYg0k-XwNhw4-RgFUyVEI78kbumfx7MNXpvgqKQm_21tJ-ER9xEjINoMn2a3hhycj0H-4G9YN-PteVtB6-cdgVnzLYsarIWeaYSVXRWb4fkF1OgOS07TVNBZsVnzcyFdME/s1600/brokera+bind+exchange+to+queue.png" height="163" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Publishing Exchange Bound To Queue</td></tr>
</tbody></table>
<br />
<br />
With everything put together, it's now possible to show the two console apps passing messages across the broker. Note: I've disabled EasyNetQ's default debug logging by using a null logger.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7kT8uLR-YuqmtYW6Eh-_FFabNpUCsHsYDqZHCMihmAXnEHcsouKh_uA2u26_kEaQLUXcFBC8b4D-a-IUuyL6QUV8bjUbJbUlzpgWleZPQg25mkHM2Zz44nOAd_w5JTq6lI8b32KpG8Qo/s1600/console+apps.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7kT8uLR-YuqmtYW6Eh-_FFabNpUCsHsYDqZHCMihmAXnEHcsouKh_uA2u26_kEaQLUXcFBC8b4D-a-IUuyL6QUV8bjUbJbUlzpgWleZPQg25mkHM2Zz44nOAd_w5JTq6lI8b32KpG8Qo/s1600/console+apps.png" height="21" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The Console Display</td></tr>
</tbody></table>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Wrapping It Up</span><br />
<br />
The addition of federated queues to RabbitMQ really simplifies transporting messages between clusters. Hopefully this helps show how you can get two clients to communicate across a federation.<br />
<br /></div>Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-984274163419707272013-09-17T05:36:00.002-07:002013-09-17T05:36:26.931-07:00RabbitMQ Federation with Credentials<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
The <a href="http://thesenilecoder.blogspot.com/2013/09/getting-started-with-rabbitmq_13.html" target="_blank">last post</a> illustrated setting up a basic RabbitMQ federation. That post used the basic guest account when connecting similarly named virtual hosts on the downstream to the upstream. It's also possible to use different users and connect different virtual hosts.<br />
<br />
<span style="font-size: large;">Connections</span><br />
<br />
The picture below is a shot of the connections on the upstream broker. It shows that there is a connection to the FederationDemo virtual host. You can see that it is the guest user which is connected.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTD-QwsGNf0sWkdO6ZpPQeqOORGH3hchFoAQdRKZ3QujiaXYk3xy5R5PRsy-hBeyop1abW9LZthwZmNQeuKldrL82orRHWYhJB_7X19G6J-m7mCnxNDN8xKOkGD07ny8Xiwg_s0QLDkL8/s1600/Upstream+Connections+Guest.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Connections with a guest user." border="0" height="35" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTD-QwsGNf0sWkdO6ZpPQeqOORGH3hchFoAQdRKZ3QujiaXYk3xy5R5PRsy-hBeyop1abW9LZthwZmNQeuKldrL82orRHWYhJB_7X19G6J-m7mCnxNDN8xKOkGD07ny8Xiwg_s0QLDkL8/s320/Upstream+Connections+Guest.png" title="" width="320" /></a></div>
<br />
<br />
The credentials are specified in the URI used when creating the upstream. Just below the 'Add new upstream' panel is a panel with different examples. These show how use various credentials.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAZ4Rwd891cJPwAWxmKTBIEBHXbnMZw5ag3spiRDFgejFcDFAfxduMtoT6h-S1u9KAQNJD40LrK3URJEFLKo3dZ7ZxN_WygI0pMXKEP9dX9n1WwHhfqthai34nwwo18P8CEb1VLvfP3YQ/s1600/URI+Examples.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="URI examples from management page." border="0" height="44" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAZ4Rwd891cJPwAWxmKTBIEBHXbnMZw5ag3spiRDFgejFcDFAfxduMtoT6h-S1u9KAQNJD40LrK3URJEFLKo3dZ7ZxN_WygI0pMXKEP9dX9n1WwHhfqthai34nwwo18P8CEb1VLvfP3YQ/s320/URI+Examples.png" title="" width="320" /></a></div>
<br />
<br />
When different credentials are supplied in the URI, the federation is created with a different user. It holds that the user must have access to the upstream virtual host. Thus, an upstream created with a URI like <span style="font-family: Courier New, Courier, monospace;">amqp://FederatedUser:user@RABBIT/FederationDemo</span> opens the following connection:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKxzTBiyIwp0jGanyOlC9CS-KwkGhgsWLa3XH9qz_rJ8O57vDbNXw-PALjtO0iyHH8Cp13Pr6kQGiVoRR-lc1pDtDt_f9k-Tp7TBhPE7G3BG0mZQeKwgPXez5wRGC8OtbM8xnS18e_ud8/s1600/Upstream+Connections+FederatedUser.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Connections with a different user." border="0" height="34" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKxzTBiyIwp0jGanyOlC9CS-KwkGhgsWLa3XH9qz_rJ8O57vDbNXw-PALjtO0iyHH8Cp13Pr6kQGiVoRR-lc1pDtDt_f9k-Tp7TBhPE7G3BG0mZQeKwgPXez5wRGC8OtbM8xnS18e_ud8/s320/Upstream+Connections+FederatedUser.png" title="" width="320" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">That's It</span><br />
<br />
Connecting with different credentials is easy. You can specify a different user, or a different virtual host.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-49806262770702706602013-09-13T13:31:00.000-07:002013-09-13T13:32:18.504-07:00Getting Started with RabbitMQ Federations and EasyNetQ<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
One of the uses we needed out of RabbitMQ was passing messages between two separate departments. These departments each had their own Rabbit cluster. They each had their own LAN. This led us down the path of using a federated exchange to transport messages between the clusters.<br />
<br />
The <a href="https://github.com/caloggins/ExampleCode/tree/master/RabbitMqFederationTests" target="_blank">source code</a> is available on GitHub.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Stuff Used</span><br />
<ol>
<li>Two RabbitMQ clusters.</li>
<li>Management plugin.</li>
<li>Federation plugin.</li>
<li>EasyNetQ client library.</li>
<li>Similarly named virtual hosts on each cluster (FederationDemo is used in this example).</li>
</ol>
<i>Disclaimer</i><br />
<br />
RabbitMQ is very flexible. There are always about a dozen ways to solve the same problem. This is an example of how to use topic-based routing across a federated exchange with EasyNetQ as a client library. This is not meant to be the one true way of doing it.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">About Federations</span><br />
<br />
A federation allows messages to flow from one RabbitMQ cluster to one or more downstream clusters. The simplest RabbitMQ federation exists between two clusters: an upstream and a downstream. The downstream cluster can be thought of as subscribing to messages from the upstream cluster.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Getting Started</span><br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Downstream (or Beta)</span><br />
<br />
The downstream cluster will be receiving messages from the upstream server. There are a few things which have to be set up on the downstream cluster:<br />
<br />
<ol>
<li>An upstream address.</li>
<li>A policy to identify the federated exchange.</li>
<li>An exchange to be federated in the virtual host.</li>
<li>Exchanges for the messages bound to the subscriber.</li>
</ol>
<br />
<i>Define the Policy</i><br />
<br />
A good place to start is by defining the policy. Policies are managed in the Admin->Policies screen. It’s important that the correct virtual host is selected. You’ll also want to make note of the pattern you use.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY-93juFFl3_dFFINi23ogr3-BQzm3VMIlryYvuAbk-YSIJHk4ShK8MZ6YYbCI32B0wIpZJGXyr_kVJyr1x4J16FNfl_Zzsfg6WuxA5yAoFvCJoNNiJtQ_Sbx8Jb80Z_UCPRlL-K8QA4Q/s1600/Downstream+Define+Policy.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY-93juFFl3_dFFINi23ogr3-BQzm3VMIlryYvuAbk-YSIJHk4ShK8MZ6YYbCI32B0wIpZJGXyr_kVJyr1x4J16FNfl_Zzsfg6WuxA5yAoFvCJoNNiJtQ_Sbx8Jb80Z_UCPRlL-K8QA4Q/s320/Downstream+Define+Policy.png" width="320" /></a></div>
<br />
<br />
<i>Define the Upstream</i><br />
<br />
Next up is defining the address of the upstream cluster. This can be done in the Admini->Federation Upstreams screen. Again, be sure to have the correct virtual host selected.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgomkzDqZ0h9QEBS0ik66dMpniROySu-MwhVByFc9u8OH8rnsFWjx__oXK8Pb54iVYXc_VXoZNt4RTRZb0oRodnLhbYINLlxtgwPSjBzLp8zaH1CoMnRXqREKZ6ELNzqQu-HdbtFoVoLrg/s1600/Downstream+Adding+Upstream.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgomkzDqZ0h9QEBS0ik66dMpniROySu-MwhVByFc9u8OH8rnsFWjx__oXK8Pb54iVYXc_VXoZNt4RTRZb0oRodnLhbYINLlxtgwPSjBzLp8zaH1CoMnRXqREKZ6ELNzqQu-HdbtFoVoLrg/s320/Downstream+Adding+Upstream.png" width="320" /></a></div>
<br />
<br />
<i>Message Queues and Exchanges</i><br />
<br />
The easiest way to create the queues and exchanges is to let EasyNetQ do it for us. Subscribing to a message with EasyNetQ causes it to create the appropriate Queues and Exchanges. It also binds the Exchanges to the Queues. After running the subscriber, create an excahnge named ‘fed.exchange’. The policy should be applied if the exchange name matches the pattern.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTC7o_w4IZBzvhT__t5KkTdolu_1hyphenhyphen3XH8g_nWllnBkOC5qnBi6zRo41okCC7Tq-OD8PngZE-bNRTt5XZ5bLPYic71GXSLy7q9uj8-FX0j3lNysqXRlcddnbhRn5nwEt1Qo5cGNsaGaBM/s1600/Downstream+Exchanges.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTC7o_w4IZBzvhT__t5KkTdolu_1hyphenhyphen3XH8g_nWllnBkOC5qnBi6zRo41okCC7Tq-OD8PngZE-bNRTt5XZ5bLPYic71GXSLy7q9uj8-FX0j3lNysqXRlcddnbhRn5nwEt1Qo5cGNsaGaBM/s320/Downstream+Exchanges.png" width="320" /></a></div>
<br />
<br />
The subscriber code would be similar to the following:<br />
<br />
<pre brush="class:csharp;"> public void Run()
{
bus.Subscribe<VisaTransaction>("Beta", PrintTransaction, configuration => configuration.WithTopic(typeof(VisaTransaction).Name));
bus.Subscribe<MasterCardTransaction>("Beta", PrintTransaction,
configuration => configuration.WithTopic(typeof(MasterCardTransaction).Name));
SpinWait.SpinUntil(() => Console.ReadKey().Key == ConsoleKey.Escape);
}
</pre>
<br />
Once the federated exchange has been created, it will need to be bound to the message exchanges. Since we’re using topics to route the various messages, we’ll want to ensure that the topics are passed through. For now, we’ll just use a ‘#’ to indicate that all topics should be passed through. The bindings should then look like the following image:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvuWlqwMGKp7H_RK1vCoFWrrs7xxQRRaSKjv9NcmI8CJUYcA7gpnLcH1w6423xRAhJuIkmpz3pfVoH-aEkE7-XiAo2zdaOoLQxojUHj5mE1hTvzmBHwrkOe-cOGAlVJvwoq25FdRjkTyQ/s1600/Downstream+Exchange+Bindings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="134" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvuWlqwMGKp7H_RK1vCoFWrrs7xxQRRaSKjv9NcmI8CJUYcA7gpnLcH1w6423xRAhJuIkmpz3pfVoH-aEkE7-XiAo2zdaOoLQxojUHj5mE1hTvzmBHwrkOe-cOGAlVJvwoq25FdRjkTyQ/s320/Downstream+Exchange+Bindings.png" width="320" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Upstream (or Alpha)</span><br />
<br />
Setting up the upstream is pretty simple. The virtual host needs to be created. It needs the appropriate users assigned to it. We’ll be using the default guest account for this demo. If the guest account isn’t granted access to the virtual host, then the the downstream cluster will not be able to establish a connection.<br />
<br />
As with the subscriber, EasyNetQ can create the exchanges for us. Messages will be discarded, until the exchanges are bound to something. Fortunately, the outbound exchange will have been created when the downstream cluster connects.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcdJiotlJmp8cRM3vesc4ItXo-Uxo_VzyZHbQYGz-2vk_W2SjDWPV_HIZ-sIvrOkydkt-rUalDtUFgwiF3OcC5My_NShDIOQzTB2Herpty3WpZ876mr4RNbgk_yDbQ0sxHXkgKZXqZjgs/s1600/Upstream+Federated+Exchange.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcdJiotlJmp8cRM3vesc4ItXo-Uxo_VzyZHbQYGz-2vk_W2SjDWPV_HIZ-sIvrOkydkt-rUalDtUFgwiF3OcC5My_NShDIOQzTB2Herpty3WpZ876mr4RNbgk_yDbQ0sxHXkgKZXqZjgs/s320/Upstream+Federated+Exchange.png" width="320" /></a></div>
<br />
<br />
The publishing code looks like this:<br />
<br />
<pre class="brush:csharp;"> private void PublishMessage<T>() where T : Transaction
{
var message = Builder<T>.CreateNew().Build();
using (var channel = bus.OpenPublishChannel())
channel.Publish(message, configuration => configuration.WithTopic(typeof(T).Name));
}
</pre>
<br />
<br />
Here, we’re going to bind the exchanges to the outbound federated exchange. We’ll want to bind the upstream clusters exchanges to the federated exchange. It’s important to remember the ‘#’ as a routing key. These bindings should be similar to the following picture.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9T5KUpvarP28m6NK07BHHmvg4vhaUwy4lDhxD6_PD3mRQKBIpQnvBvHTHTRWw7ksqs95iyc4MNosD_gPYzAFvBoqoaJlAe1h0NTRHk2Oufz5XTu73yCG9nooh8qlYI9X71oO85Sp4H1M/s1600/Upstream+Federated+Exchange+Bindings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9T5KUpvarP28m6NK07BHHmvg4vhaUwy4lDhxD6_PD3mRQKBIpQnvBvHTHTRWw7ksqs95iyc4MNosD_gPYzAFvBoqoaJlAe1h0NTRHk2Oufz5XTu73yCG9nooh8qlYI9X71oO85Sp4H1M/s320/Upstream+Federated+Exchange+Bindings.png" width="320" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Running the Apps</span><br />
<br />
When the apps are run, you can see that the messages are transported from the publisher to the client. The publisher sends them to the upstream cluster. The upstream cluster then dispatches them to the downstream cluster. The downstream cluster then passes them to the subscriber.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI_PZLUDKCi_oc9kDU7DdIOFLR21DjvzV140O6nS114mG9c8XljBwuw57mbbf0mK-npzJOaVwC2udhmoAfH-8ij52HCJObb03RnHq5vFr_Qm3R02vJ4wnOq0_Z8aFLUkgqvOrMT704wuY/s1600/Publisher+Console.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="61" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI_PZLUDKCi_oc9kDU7DdIOFLR21DjvzV140O6nS114mG9c8XljBwuw57mbbf0mK-npzJOaVwC2udhmoAfH-8ij52HCJObb03RnHq5vFr_Qm3R02vJ4wnOq0_Z8aFLUkgqvOrMT704wuY/s320/Publisher+Console.png" width="320" /></a></div>
<br />
Note that the highlighted bits show the messages were translated into the correct types:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF17LUFhwWkjoVBGdiAbmD306uPYQyrsP3Vr2eoXHZipIp0qBpnQ4jFx1XjarLF_hbuuSwxksXEdLJaUtx9ZUmYZ6vbY9HMiAMPI6_kBvqoD6GUUsfiZvNcnIkSOwrwlqcq25PxjRd35g/s1600/Subscriber+Console.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjF17LUFhwWkjoVBGdiAbmD306uPYQyrsP3Vr2eoXHZipIp0qBpnQ4jFx1XjarLF_hbuuSwxksXEdLJaUtx9ZUmYZ6vbY9HMiAMPI6_kBvqoD6GUUsfiZvNcnIkSOwrwlqcq25PxjRd35g/s320/Subscriber+Console.png" width="320" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Wrapping It Up</span><br />
<br />
That’s the basics of getting a federation up and running between two clusters. The federated exchange is capable of transporting two different types of messages. Those messages are routed to the correct subscriber, based on the topic of the message.<br />
<br />
One final note… There are a lot of other considerations when federating clusters and using topic-based routing. This blog represents the very basics. You’ll want to make sure you’ve familiarized yourself with the subject.<br />
<br />Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com1tag:blogger.com,1999:blog-8643450826744932654.post-72741213061235051612013-08-22T11:48:00.001-07:002013-08-22T11:48:20.659-07:00RabbitMQ connection_closed_abruptly error<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
One of the hiccups we encountered when starting with RabbitMQ occurred when we put a proxy in front of our cluster. The proxy began probing the broker's nodes to ensure they were alive. This resulted in a lot of spam in the logs:<br />
<br />
<pre class="brush:plain;">=INFO REPORT==== 21-Aug-2013::11:14:32 ===
accepting AMQP connection <0.12744.35> (<proxy ip>:55613 -> <rabbit ip>:5672)
=WARNING REPORT==== 21-Aug-2013::11:14:32 ===
closing AMQP connection <0.12744.35> (<proxy ip>:55613 -> <rabbit ip>:5672):
connection_closed_abruptly</pre>
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">A Typical(?) Cluster</span><br />
<br />
I'm not certain there is a typical setup for a RabbitMQ cluster. In our case, we went with what we've been calling a binary star. We took this phrase from the <a href="http://zguide.zeromq.org/page:all#High-Availability-Pair-Binary-Star-Pattern" target="_blank">0mq docs</a>. The idea is pretty simple: it's an active/active or active/passive pair with mirrored queues.<br />
<br />
A proxy is placed between the clients and the binary star. This separates the clients from the cluster implementation. The biggest benefit for is is the consistent IP for clients. This simplifies the client configurations. It also allows us to perform maintenance on the cluster w/o interrupting service.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">RabbitMQ.config</span><br />
<br />
The default Windows location for the config file, rabbitmq.config, is in the %appdata%/RabbitMQ directory. It's possible to change this location, but we'll assume the default location for now. A clean install will often not have this config file.<br />
<br />
The first step is to create the rabbitmq.config file. You can create this in any text editor. Just remember that it must be named rabbitmq.config. It may not have a .txt or any other extension. Add the following to the file, and save it:<br />
<br />
<pre class="brush:plain;">[
{rabbit, [
{log_levels,[{connection, error}]},
]}
].</pre>
<br />
This will configure the connection logging to only log errors. The other types of logging, like start up messages, will be unaffected by this.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Making It Take Affect</span><br />
<br />
The RabbitMQ documents indicate that the service should be restarted for the new config to take affect. We have found it necessary to re-install the broker. Fortunately, re-installation of the broker did not wipe the setup. The steps are as follows:<br />
<ol>
<li>Stop the service in the services management screen.</li>
<li>Uninstall RabbitMQ.</li>
<li>Install RabbiMQ.</li>
<li>Verify the service is running.</li>
</ol>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">More RabbitMQ.config</span></div>
<div>
<br />
It's also possible to enable TCP keepalive support, by adding the appropriate line (#11):<br />
<br />
<pre class="brush:plain;">[
{rabbit, [
{log_levels,[{connection, error}]},
{tcp_listen_options,
[binary,
{packet,raw},
{reuseaddr,true},
{backlog,128},
{nodelay,true},
{exit_on_close,false},
{keepalive,true}]}
]}
].
</pre>
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Wrap Up</span><br />
<br />
The big gotcha was having to re-install the RabbitMQ service to get the .config file changes to stick. Otherwise, this was a basic config change to ease up on the logging. Hopefully, this will help someone else...</div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-29221748931123809262013-08-14T11:06:00.000-07:002013-09-05T05:22:05.369-07:00Getting Started With RabbitMQ<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
I was tasked with giving a quick RabbitMQ intro to another development group. This post is the result of that task. Most of this stuff will be regurgitated from other sources on the web. It's just meant to help people get up and running.<br />
<br />
First we'll look at installing RabbitMQ. Next we'll do some basic configuration, and take a quick peek at the management plug-in. Finally, we'll build a couple simple console apps to use the broker.<br />
<br />
RabbitMQ is based on Erlang. There is a <a href="http://en.wikipedia.org/wiki/RabbitMQ" rel="nofollow" target="_blank">Wikipedia article</a> which summarizes what RabbitMQ is. There's also a <a href="http://www.youtube.com/watch?v=ZQogoEVXBSA" rel="nofollow" target="_blank">Google Tech Talk video</a> on YouTube.<br />
<br />
This article will assume that you know how to use Visual Studio: create solutions, add projects to solutions, etc. It will also assume that you are familiar with using NuGet.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Getting Ready</span><br />
<br />
Before doing the exercises in this tutorial, you'll need to grab the Erlang and RabbitMQ installers.<br />
<br />
<i>Installers</i><br />
<ol>
<li><a href="http://www.erlang.org/download.html" target="_blank">Erlang</a> - R16B01 was used.</li>
<li><a href="http://www.rabbitmq.com/install-windows.html" target="_blank">RabbitMQ</a> - 3.1.4 was used.</li>
</ol>
<i>Tools Used</i><br />
<ol>
<li>Visual Studio 2012</li>
<li><a href="http://www.nuget.org/" target="_blank">NuGet</a></li>
<li><a href="http://easynetq.com/" target="_blank">EasyNetQ</a> - v0.11.1.104 was used.</li>
<li>Windows 7 - No, we haven't switched, and we might not. ;P</li>
</ol>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Installing Erlang and RabbitMQ</span><br />
<br />
The RabbitMQ installation page describes how to install the components. It's pretty short and simple. It amounts to first installing Erlang, then installing RabbitMQ. The default settings should suffice.<br />
<br />
The installers should take care of any firewall settings. If they don't, you may see a dialog similar to the one below. Go ahead and add the rules for Erlang.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFzoqhQc2qqafKuNfNcGNG316vljfpgwu7ZjgQ1_Go1aLooMSzkCBdyWwC9Mg0zrEjP1DQtWePyBpLPZulY5GUJaQIwFjNmrIUwkenUN6Ov3gOKcx30vbxFuGbhwtRRGSjKjW85mD01II/s1600/Erlang+Firewall+Dialog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Windows Firewall dialog for Erlang." border="0" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFzoqhQc2qqafKuNfNcGNG316vljfpgwu7ZjgQ1_Go1aLooMSzkCBdyWwC9Mg0zrEjP1DQtWePyBpLPZulY5GUJaQIwFjNmrIUwkenUN6Ov3gOKcx30vbxFuGbhwtRRGSjKjW85mD01II/s320/Erlang+Firewall+Dialog.png" title="" width="320" /></a></div>
<br />
<br />
The RabbitMQ management plug-in uses a different port: 15672. If you want to access the management page remotely, you'll need to add the appropriate firewall rules for it.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Copy The Cookie</span><br />
<br />
Once installation is complete, you'll want to copy the .erlang.cookie file to your RabbitMQ profile directory. Doing this now will avoid some headaches later in life, especially if you decide to cluster nodes. It should be located in your %systemroot% directory. Copy it to your %appdata%/RabbitMQ directory. It is important that these files be identical.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Batch Files and Initial Status</span><br />
<br />
The installer should have added items to your Start menu. They'll be located in Start->All Programs->RabbitMQ Server. Open the RabbitMQ Command Prompt (sbin dir) shortcut.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtJBS4FS85a7FKYXok7zozgp5MuyfbN-t1U3FdMMCBzUZ404YsnOeBDp1NfjNecfm-4RpDYv7c1jZTvMw1GI3A0Q0LZByY1_CXCBj8zXrb2vpxaFkNDz-7JKs43oN8l9YWm5A8_WWbUSc/s1600/Start+Menu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Start menu with RabbitMQ stuff." border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtJBS4FS85a7FKYXok7zozgp5MuyfbN-t1U3FdMMCBzUZ404YsnOeBDp1NfjNecfm-4RpDYv7c1jZTvMw1GI3A0Q0LZByY1_CXCBj8zXrb2vpxaFkNDz-7JKs43oN8l9YWm5A8_WWbUSc/s320/Start+Menu.png" title="" width="178" /></a></div>
<br />
<br />
This will open a command prompt. A number of operations can be performed with this console window: starting/stopping the broker, enabling plug-ins, etc. Checking the broker's status can be done by entering 'rabbitmqctl status' at the prompt.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJTmBClJYinYtvBvhtrEOgEmKIYmFyDXJRlzUALkfEw8_BCaL2kDFpyg5xUcUhXOFC4UCl1DxefPXZIAFd0VN4h-PHIiki8GqrMWXO-rPw0Y5gclDZJ07SOwPQOIYm6RraxWtVnfjBL2E/s1600/Rabbit+Status.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Sample 'rabbitmqctl status' output." border="0" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJTmBClJYinYtvBvhtrEOgEmKIYmFyDXJRlzUALkfEw8_BCaL2kDFpyg5xUcUhXOFC4UCl1DxefPXZIAFd0VN4h-PHIiki8GqrMWXO-rPw0Y5gclDZJ07SOwPQOIYm6RraxWtVnfjBL2E/s320/Rabbit+Status.png" title="" width="320" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Enabling the Management Plug-in</span><br />
<br />
The next step to perform is to enable the management plug-in. This plug-in provides a web interface for controlling the broker. It can be used to manage users, exchanges, etc. The management plug-in can be issuing the commands illustrated in the following image. Also note that in most cases, I've found it necessary to restart the RabbitMQ service from the services control panel.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9UgVjyFEvRDu2COtTJAsZDTiLeJu0OERUnGlTCk42lOXuiW_05pxgQl27Z2WoeL57ZOXgX2DyVJH4kWFqq3ehM0_8WCZosvlnuhXd_Nf1M46lxZsVJ2SLMPkC9Ln7imZSitsoY7NjNpc/s1600/RabbitMQ+Management+Install.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Enabling the management plug-in." border="0" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9UgVjyFEvRDu2COtTJAsZDTiLeJu0OERUnGlTCk42lOXuiW_05pxgQl27Z2WoeL57ZOXgX2DyVJH4kWFqq3ehM0_8WCZosvlnuhXd_Nf1M46lxZsVJ2SLMPkC9Ln7imZSitsoY7NjNpc/s320/RabbitMQ+Management+Install.png" title="" width="320" /></a></div>
<br />
The commands are (in order):<br />
<br />
<ol>
<li><span style="font-family: Courier New, Courier, monospace;">rabbitmqctl stop_app</span></li>
<li><span style="font-family: Courier New, Courier, monospace;">rabbitmq-plugins enable rabbitmq_management</span></li>
<li><span style="font-family: Courier New, Courier, monospace;">rabbitmqctl start_app</span></li>
</ol>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Using the Management Web Page</span><br />
<br />
The <a href="http://www.rabbitmq.com/management.html" target="_blank">plug-in docs</a> describe many of the features available. We're going to use the UI to create a test user and a virtual host. Later we'll use it to see the broker at work, create a queue, and alter some bindings.<br />
<br />
You can access the management UI by opening a browser and navigating to <i>http://localhost:15672</i>. You'll be prompted with the login screen. The default username and password are guest/guest. There are a number of tabs available after logging in. The first is the Overview:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitqKo5T2AY-Nnjo_oWhHiGG3xXBgtsVwNh859HBe8DO5fF3k1adfyR_V1DgyzbTXcOgHhUnRj2x-IukoCKorgNAuHbJ2_6xcnTZ1ITU4xbaxMeZ2sTJ_cnEqvLYZEhRnKOlc8OyXD30Zk/s1600/Management+Overview.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="RabbitMQ management Overview." border="0" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitqKo5T2AY-Nnjo_oWhHiGG3xXBgtsVwNh859HBe8DO5fF3k1adfyR_V1DgyzbTXcOgHhUnRj2x-IukoCKorgNAuHbJ2_6xcnTZ1ITU4xbaxMeZ2sTJ_cnEqvLYZEhRnKOlc8OyXD30Zk/s320/Management+Overview.png" title="" width="320" /></a></div>
<br />
<br />
First we'll create a virtual host for testing. Virtual hosts are managed in the Virtual Host tab of the Admin screen. We'll create one called Sandbox:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC-6G8kUPiWSGNNVHN2MJeCpjRGItOhSVkEvktgAS3DfqCq_sZrlbdxb00lvIlVqQXpu4lLPDbwWR2QcXqT3GVeEcJb6Kx_Er0SvvWiLXp1826cG0FVQ-yO5Un04H31TCW3yyFCX7p8IY/s1600/Management+Create+Virtual+Host.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="RabbitMQ management UI Virtual Hosts screen." border="0" height="167" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC-6G8kUPiWSGNNVHN2MJeCpjRGItOhSVkEvktgAS3DfqCq_sZrlbdxb00lvIlVqQXpu4lLPDbwWR2QcXqT3GVeEcJb6Kx_Er0SvvWiLXp1826cG0FVQ-yO5Un04H31TCW3yyFCX7p8IY/s320/Management+Create+Virtual+Host.png" title="" width="320" /></a></div>
<br />
<br />
Users are managed in the Users tab of the Admin screen. Expand the 'Add a user' accordion and enter a name along with a password. For this example, I used SandboxUser as the username, and sandbox as the password:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-2uEFXsWUw5nBKqycQ-EJKYcyr3veZz0lrQFkuKq-kdX4UXEhBWpZ-dNfq2VIjlKcc7RXgfqd_LbhS4nzpGZCOsnYHcKRJtJmcAKJS7p1Cm1aub72M6QqcLftTNLyGr65nt1Juyzayoc/s1600/Adding+a+User.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="113" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-2uEFXsWUw5nBKqycQ-EJKYcyr3veZz0lrQFkuKq-kdX4UXEhBWpZ-dNfq2VIjlKcc7RXgfqd_LbhS4nzpGZCOsnYHcKRJtJmcAKJS7p1Cm1aub72M6QqcLftTNLyGr65nt1Juyzayoc/s320/Adding+a+User.png" width="320" /></a></div>
<br />
<br />
Users must have permission to access virtual hosts. There are a few ways to do this, but we'll use the Virtual Hosts tab of the Admin screen. Click on the Sandbox virtual host and expand the 'Permissions' accordion. Select the user name in the 'User' drop down and click the 'Set Permission' button. Do this for both the SandboxUser and guest users:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXp1DoClQtnjzOL-TBgE3GPAR0O9hiLRNqkHp_U_fFqJ9sULrAF5oX2zFe4kAFV8Nzmwc2aVIvoe4n9qTx982PEjr5JAs9Missckb7EwanIp84HDmdIH6sbEg-IUZTyE8Rv2knflx8lFQ/s1600/Management+Add+Users.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXp1DoClQtnjzOL-TBgE3GPAR0O9hiLRNqkHp_U_fFqJ9sULrAF5oX2zFe4kAFV8Nzmwc2aVIvoe4n9qTx982PEjr5JAs9Missckb7EwanIp84HDmdIH6sbEg-IUZTyE8Rv2knflx8lFQ/s320/Management+Add+Users.png" width="320" /></a></div>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Sample Apps</span><br />
<br />
The source code in this article can be found on <a href="https://github.com/caloggins/ExampleCode/tree/master/RabbitGettingStarted" target="_blank">GitHub</a>. The solution is divided into three projects: Publisher, Subscriber, and Messages. The name of each project implies what it does. I'm bypassing use of an IoC or test projects for simplicity. Hopefully, I'll get some time in a future post to illustrate how one can mix an IoC container and do some TDD...<br />
<br />
Here's what it looks like:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRzbOBHtcv3gbW1bdCeX-RylW2h2YBcQZE98hIWMpvsxVYnwXR_W4r_c4dnZdu0hhsvO3mmTDhrtFFlCDe7CRhHC2Ems7VlWQSCN4uZvkX2afuOj0F546qIZ6fhXl28nEMnm9WhX3-_W8/s1600/Solution+Contents.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Sample solution contents." border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRzbOBHtcv3gbW1bdCeX-RylW2h2YBcQZE98hIWMpvsxVYnwXR_W4r_c4dnZdu0hhsvO3mmTDhrtFFlCDe7CRhHC2Ems7VlWQSCN4uZvkX2afuOj0F546qIZ6fhXl28nEMnm9WhX3-_W8/s320/Solution+Contents.png" title="" width="182" /></a></div>
<br />
<br />
The publisher sends messages to the broker. The subscriber listens to the broker for a message. The message contract is defined in the Messages project. It is referenced in both the Publisher and Subscriber.<br />
<br />
The publisher and subscriber projects both reference a library called EasyNetQ. EasyNetQ provides a fairly simple API for interacting with a RabbitMQ broker. At the heart of this is the IBus interface. IBus is used in publishing and subscribing to messages. Our apps use a BusFactory class to create an instance of this interface:<br />
<br />
<pre class="brush:c-sharp;"> public static class BusFactory
{
public static IBus Create()
{
var settings = ConfigurationManager.ConnectionStrings["rabbit"];
if (settings == null || string.IsNullOrEmpty(settings.ConnectionString))
throw new InvalidOperationException("Missing connection string.");
return RabbitHutch.CreateBus(settings.ConnectionString);
}
}
</pre>
<br />
<br />
The BusFactory class uses a connection string defined in the app.config:<br />
<br />
<pre class="brush:xml;"> <connectionStrings>
<add name="rabbit" connectionString="host=localhost;virtualHost=Sandbox;username=SandboxUser;password=sandbox;prefetchcount=1;" />
</connectionStrings>
</pre>
<br />
<br />
The heart of our demo is in the DemoPublisher. This class illustrates the heart of the publishing operation. A message is created, a publishing channel is opened, and the message is published.<br />
<br />
<pre class="brush:c-sharp;"> public class DemoPublisher
{
private readonly IBus bus;
public DemoPublisher(IBus bus)
{
this.bus = bus;
}
public void Publish()
{
var message = new ExampleMessage { Greeting = "Hello, world!" };
using (var channel = bus.OpenPublishChannel())
channel.Publish(message);
}
}
</pre>
<br />
<br />
At the other end of the demo is the subscriber. The DemoSubscriber.ListenForAMessage() method uses an instance of IBus to notify the broker that it is listening for messages of type 'ExampleMessage'. When a message of that type is received, it writes the greeting to the console, and marks the done flag as true.<br />
<br />
<pre class="brush:c-sharp;"> public class DemoSubscriber
{
private readonly IBus bus;
public DemoSubscriber(IBus bus)
{
this.bus = bus;
}
public void ListenForAMessage()
{
var done = false;
bus.Subscribe<ExampleMessage>("subscriber", message =>
{
Console.WriteLine(message.Greeting);
done = true;
});
SpinWait.SpinUntil(() => done);
}
}
</pre>
<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Running the Publisher</span><br />
<br />
When the publisher is run by itself for the first time, EasyNetQ will create an exchange. However the message sent to the broker seems to disappear. This is because there is no queue defined to receive it. We can create a test queue to catch the message.<br />
<br />
First we create a queue:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi-RbZKpeFu_mRDyYhiMHDI66tms8_hKhWeyWuFy0qtUa_exWA2aFMoKOxLLhr_iUUXN1CGaEYiUgyRNZrma2UdIZ_Z8nTxabCsP44Lc9lOFPM5lWLo4MMBtRO6mpLhcgeukOXCjA16E8/s1600/TestQueue+Creation+Before.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Creating a queue in the management UI." border="0" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi-RbZKpeFu_mRDyYhiMHDI66tms8_hKhWeyWuFy0qtUa_exWA2aFMoKOxLLhr_iUUXN1CGaEYiUgyRNZrma2UdIZ_Z8nTxabCsP44Lc9lOFPM5lWLo4MMBtRO6mpLhcgeukOXCjA16E8/s320/TestQueue+Creation+Before.png" title="" width="320" /></a></div>
<br />
<br />
Then we bind the exchange to the queue. This can be done either in the queue detail view, or in the exchange detail view. This example shows it being done in the queue detail view. This view is reached by clicking on the queue name, after it's been created. It's important to note that the name must match exactly. It's okay to leave the 'Routing key' and 'Arguments' sections blank.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiydD17oMaUYvdVrDW6O4iL81UW3oQBidAX6LDGQGj57wo4HanMZ3Fv7j3HdPsjhw_ftMFe9ehn_9QOs0q9TpmggMyhqh8sUVGy73hoCwmj1vV7zDL3lCHS5Oa_nyXeOB7tiIBEFdPEnNQ/s1600/Management+Bind+Exch+To+Queue.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Binding an exchange to a queue in the management UI." border="0" height="281" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiydD17oMaUYvdVrDW6O4iL81UW3oQBidAX6LDGQGj57wo4HanMZ3Fv7j3HdPsjhw_ftMFe9ehn_9QOs0q9TpmggMyhqh8sUVGy73hoCwmj1vV7zDL3lCHS5Oa_nyXeOB7tiIBEFdPEnNQ/s320/Management+Bind+Exch+To+Queue.png" title="" width="320" /></a></div>
<br />
<br />
When the publisher sends a message to the broker, that message is directed to the queue, TestQueue.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQj_Cy3IBtU3au7pXnQva9ITjGX4JS2L7AvHrgZGMiAR9K7LSqJ7f7VLEeW122Q5jXRvqqux7DXC4r18IoVncmF91CZPRNWDOioa2w_lyW7emPb76BO0S49i9Qszxpply116fSUKBbEkM/s1600/TestQueue.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Showing the message count in a queue." border="0" height="33" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQj_Cy3IBtU3au7pXnQva9ITjGX4JS2L7AvHrgZGMiAR9K7LSqJ7f7VLEeW122Q5jXRvqqux7DXC4r18IoVncmF91CZPRNWDOioa2w_lyW7emPb76BO0S49i9Qszxpply116fSUKBbEkM/s320/TestQueue.png" title="" width="320" /></a></div>
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Running the Subscriber</span><br />
<br />
When EasyNetQ makes a subscription, it creates the queue and automatically binds it to the exchange. We can see the results both in the console output, and in the queues on the management page:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4jsXbgsVgbmZv-Ja0eIvHUxL8-iCY7qfybXXxkGB8WaGZf-I6YCmqLf85YgD2VJnTxg3vCXLt-AjM7Q6qSECiYCZ-gIe5ArAFEKFDSulmmrNFmGtn3GPetUuHmk31nFfadaEezQV4zFY/s1600/Demo+Run.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Showing the sample output from two console apps; one publisher and one subscriber." border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4jsXbgsVgbmZv-Ja0eIvHUxL8-iCY7qfybXXxkGB8WaGZf-I6YCmqLf85YgD2VJnTxg3vCXLt-AjM7Q6qSECiYCZ-gIe5ArAFEKFDSulmmrNFmGtn3GPetUuHmk31nFfadaEezQV4zFY/s320/Demo+Run.png" title="" width="315" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFkTCpv9qiHXjFJgBkBUdKfJSX1sBDnjP3blAY3miTCmvhab1us3hVzmYADFFBey2x8T-ZpTP0dmFIrxUlsI9uArjtFDP4UrVJ7mzS8H5vEBpIO6_g1s3FgdMHVeeqKF451zFlqh6rlAg/s1600/Both+Queues.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Showing the queues with both apps active." border="0" height="31" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFkTCpv9qiHXjFJgBkBUdKfJSX1sBDnjP3blAY3miTCmvhab1us3hVzmYADFFBey2x8T-ZpTP0dmFIrxUlsI9uArjtFDP4UrVJ7mzS8H5vEBpIO6_g1s3FgdMHVeeqKF451zFlqh6rlAg/s320/Both+Queues.png" title="" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Run the Subscriber First</span><br />
<br />
In creating the subscriptions and publishing the message, EasyNetQ handles the creation of the exchanges and queues for you. Be default, RabbitMQ will discard messages for which there is no destination queue. Thus, you will want to ensure that the subscribers are initialized, before you publish a message.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Wrapping It Up</span><br />
<br />
That's about it for creating a simple demo for RabbitMQ. There are a lot of topics which we haven't covered: clustering, federations, high availability to name a few. Although a little dated, Manning's <i><span id="goog_485013907"></span><a href="http://www.amazon.com/RabbitMQ-Action-Distributed-Messaging-Everyone/dp/1935182978" target="_blank">RabbitMQ in Action: Distributed Messenging<span id="goog_485013908"></span> for Everyone</a> </i>is worth a read. The documentation for <a href="http://easynetq.com/" target="_blank">EasyNetQ</a> and <a href="http://masstransit-project.com/" target="_blank">MassTransit</a> are other good references.</div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-20658532924844732902013-03-11T10:00:00.000-07:002013-03-11T10:00:19.538-07:00Building a Service App: Logging<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
In the last post, we saw how to get started hooking things up with Windsor, TopShelf, and NLog. This post will take a look at logging with Windsor and NLog. We'll also look at using a utility called <a href="http://log2console.codeplex.com/">Log2Console </a>to view our log messages as they are generated.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Packages</span><br />
<br />
This post looks at using the following NuGet packages:<br />
<ul>
<li><a href="http://nuget.org/packages/Castle.Windsor-NLog/">Castle.Windsor-NLog</a></li>
<li><a href="http://nuget.org/packages/NLog.Schema/">NLog.Schema</a></li>
</ul>
<div>
Installing Castle.Windsor-NLog ensures that all the appropriate logging dependencies are included in our application. NLog.Schema adds some Intellisense to help with the NLog.config file.</div>
<div>
<br /></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Initializing the Logger</span><br />
<br />
Windsor's behavior can be extended through the use of facilities. A handy one, available out of the box, is the <a href="http://docs.castleproject.org/Windsor.Logging-Facility.ashx">Logging Facility</a>. We'll be setting up to use NLog as our framework. Windsor is configured to use NLog by adding the appropriate facility:<br />
<br />
<pre class="brush:c-sharp;"> container.AddFacility<LoggingFacility>(facility => facility.LogUsing(LoggerImplementation.NLog))
</pre>
<br />
It is possible to specify various options: config file location, log target, etc. We'll be using the default NLog beahvior which looks for a file called <span style="font-family: Courier New, Courier, monospace;">NLog.config</span> in the root directory of the assembly.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Configuring the Logger</span></div>
<div>
<br />
Adding the NLog.Schema package to a project adds a schema file which can aid in editing the NLog.config file. The <a href="https://github.com/nlog/nlog/wiki">NLog wiki</a> is pretty good about documenting the different options. In short, the config is broken into two sections:<br />
<br />
<ol>
<li>Targets. These describe the formatting, content, and destination of the log message.</li>
<li>Rules. These describe what gets logged, and to what target the message is sent.</li>
</ol>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Viewing Logger Messages</span><br />
<br /></div>
<div>
A nifty trick which can be used while you're working on things is to use NLog in conjunction with a utility called Log2Console. To use Log2Console to view log message, you will need to add a receiver. This will allow it to receive messages. First click the Receivers button, then click the Add... button. Add a UDP receiver, leaving the default settings.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbWgVBkqaZ0XnmT9rCyNf014XKWWFNBurssyMB9I_nO-WJ_qEElZBhCbWRjq49I7wb6MQl9ZNS6tLYXEn64EngdFxHsTYIYcxSixEdxAlmrYR4ztDUSXAGSbKwb5DTI7PKynhhj_c_8dI/s1600/receiversdialog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="The receivers dialog box with a UDP receiver added." border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbWgVBkqaZ0XnmT9rCyNf014XKWWFNBurssyMB9I_nO-WJ_qEElZBhCbWRjq49I7wb6MQl9ZNS6tLYXEn64EngdFxHsTYIYcxSixEdxAlmrYR4ztDUSXAGSbKwb5DTI7PKynhhj_c_8dI/s400/receiversdialog.png" title="" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
After adding the receiver, the NLog.config file will need to be updated. A Chainsaw target will need to be added. There will also need to be the corresponding rule created:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe1DoX58469g6mg6qgkBjTMr6fSfir8-Xihn9O8FkKibppXsN-bG_xOgKwR9MqayuhR9f1py29xbFPNmXzzfUV5qkud_NeMvDivmBgCpQ_gY2ufQn93JFIXxjRuWebzaFin8FVqJ36ctQ/s1600/chainsawconfig.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="A snapshot of an NLog.config file highlighting the chainsaw config options." border="0" height="82" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe1DoX58469g6mg6qgkBjTMr6fSfir8-Xihn9O8FkKibppXsN-bG_xOgKwR9MqayuhR9f1py29xbFPNmXzzfUV5qkud_NeMvDivmBgCpQ_gY2ufQn93JFIXxjRuWebzaFin8FVqJ36ctQ/s400/chainsawconfig.png" title="" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Once it's setup, Log2Console should catch the messages sent to NLog by your application.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs_Y7oSqNVGmRG4DoefxuOQ4ufwouPkjpS-5IvY8flAev_mL5oomgQqiSSK2_I5RV6fAl09HpiZtgph9Se6sR0-bTMP6aJWdCgxq2Txqu3g7172pz7oeAWusc-H0ybF_eLpVo8_xj9hSM/s1600/log2consoleexample.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="An example of log output in Log2Console." border="0" height="333" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs_Y7oSqNVGmRG4DoefxuOQ4ufwouPkjpS-5IvY8flAev_mL5oomgQqiSSK2_I5RV6fAl09HpiZtgph9Se6sR0-bTMP6aJWdCgxq2Txqu3g7172pz7oeAWusc-H0ybF_eLpVo8_xj9hSM/s400/log2consoleexample.png" title="" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Conclusion</span></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This showed a quick and dirty way of viewing log messages in real time. It's something that could be useful while working on applications. Next up will be a look at setting up WCF endpoint in our TopShelf app.</div>
<br /></div>
Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-77453863364684493722013-03-07T05:21:00.000-08:002013-03-11T10:00:11.645-07:00Building a Service App: Adding Windsor and TopShelf<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Preface</span><br />
<br />
In the <a href="http://thesenilecoder.blogspot.com/2013/03/building-service-app-intro-unhandled.html">last post</a> we started with a basic exception handling clause in our console application. This time, we'll be dropping in TopShelf, Windsor, and some Logging bits. The example code is available on <a href="https://github.com/caloggins/NhibSamples/tree/master/TopShelfWcfExample">GitHub</a>.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">The Service Class</span><br />
<br />
The service class will be very simple to start. All it will do is write a couple messages to our logger:<br />
<br />
<pre class="brush:c-sharp;"> public interface IExampleService
{
void Start();
void Stop();
}
public class ExampleService : IExampleService
{
private readonly ILogger logger;
public ExampleService(ILogger logger)
{
this.logger = logger;
}
public void Start()
{
logger.Debug("The service was started.");
}
public void Stop()
{
logger.Debug("The service was stopped.");
}
}</pre>
<br />
To make this class available elsewhere, we'll need to register it with our IoC container, Windsor. There are a lot of different ways to register components. This time, we'll use an installer. Installers are a convenient way to segregate the registration of your application's components.<br />
<br />
<pre class="brush:c-sharp;"> public class MyInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IExampleService>().ImplementedBy<ExampleService>()
);
}
}</pre>
<pre class="brush:c-sharp;"></pre>
<br />
We'll need to add other components to this as things go along. But for now, it's a good start.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Updating Program.Main()</span><br />
<br />
Now that we have a service class and an installer we can modify the Program.Main() method.<br />
<br />
<pre class="brush:c-sharp"> static void Main()
{
try
{
var container = ContainerFactory();
RunTheHostFactory(container);
}
catch (Exception exception)
{
var assemblyName = typeof(Program).AssemblyQualifiedName;
if (!EventLog.SourceExists(assemblyName))
EventLog.CreateEventSource(assemblyName, "Application");
var log = new EventLog { Source = assemblyName };
log.WriteEntry(string.Format("{0}", exception), EventLogEntryType.Error);
}
}
</pre>
<br />
The <span style="font-family: Courier New, Courier, monospace;">ContainerFactory()</span> method creates a new instance of the container. It then configures the container with the appropriate services.<br />
<br />
<pre class="brush:c-sharp;"> private static IWindsorContainer ContainerFactory()
{
var container = new WindsorContainer()
.Install(Configuration.FromAppConfig())
.Install(FromAssembly.This());
return container;
}
</pre>
<br />
The next method, <span style="font-family: Courier New, Courier, monospace;">RunTheHostFactory()</span>, covers the bulk of the TopShelf implementation. It uses the TopShelf <span style="font-family: Courier New, Courier, monospace;">HostFactory </span>static class to perform the actual work.<br />
<br />
<br />
<pre class="brush:c-sharp"> private static void RunTheHostFactory(IWindsorContainer container)
{
HostFactory.Run(config =>
{
config.Service<IExampleService>(settings =>
{
// use this to instantiate the service
settings.ConstructUsing(hostSettings => container.Resolve<IExampleService>());
settings.WhenStarted(service => service.Start());
settings.WhenStopped(service =>
{
// stop and release the service, then dispose the container.
service.Stop();
container.Release(service);
container.Dispose();
});
});
config.RunAsLocalSystem();
config.SetDescription("This is an example service.");
config.SetDisplayName("My Example Service");
config.SetServiceName("MyExampleService");
});
}
</pre>
<br />
TopShelf's HostFactory use our container to instantiate our service. It also cleans up when the service is stopped. This is the basic TopShelf implementation. Calls to <span style="font-family: Courier New, Courier, monospace;">.WhenPaused()</span>, and <span style="font-family: Courier New, Courier, monospace;">.WhenContinued()</span> can be added to the HostFactory to handle when the service is paused and resumed in the service control panel.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">First Run</span><br />
<br />
At this point it's possible to build and install our service. A handy thing about TopShelf is that it greatly simplifies using generic services. Running our service from the Visual Studio debugger shows us we have some basic functionality (red tic marks indicate the logger entries made by the service class):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBolPTGUqcRjubzEhNutrPX2yiwTkSfPMD3dRFnuGIYQlcodIzPmLE8nbAwNjRKquJow7NKdksKmwlml-PJLKow_Y6NqYH5bRs9XaFEAg_O3Bm5zH2XNt7_X1YTa9bOzo99owaW3s8V0o/s1600/firstrun.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="The console app being run in the debugger." border="0" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBolPTGUqcRjubzEhNutrPX2yiwTkSfPMD3dRFnuGIYQlcodIzPmLE8nbAwNjRKquJow7NKdksKmwlml-PJLKow_Y6NqYH5bRs9XaFEAg_O3Bm5zH2XNt7_X1YTa9bOzo99owaW3s8V0o/s400/firstrun.png" title="Example run." width="400" /></a></div>
<br />
There are some other basic things we can do with a TopShelf-based application. We can run the executable as any other console app can be run:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigBVGVo_nK04hCQOua4g00jVlo3CP3JRiMmm-7aXVWsiFJ5EyZh2-2sckEAMfo8c9KX3a4GuvqyQSq5Kj-Cwvv3eI3TwSFTM1XuYfQFt08DS9eZzaiUNcnJLiCU_8sUcAX9g04xilcNz4/s1600/runasconsole.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="TopShelf app being run as a console app." border="0" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigBVGVo_nK04hCQOua4g00jVlo3CP3JRiMmm-7aXVWsiFJ5EyZh2-2sckEAMfo8c9KX3a4GuvqyQSq5Kj-Cwvv3eI3TwSFTM1XuYfQFt08DS9eZzaiUNcnJLiCU_8sUcAX9g04xilcNz4/s400/runasconsole.png" title="Run as a console app." width="400" /></a></div>
<br />
Installing the service is pretty done by adding a parameter, install, to the command:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxcA1AtaIKFfpwGXqVSMAbb1Nyr5exA71t6_j9Bcg_hDfbujNhlIOU2GKz7mg5-tbqFIB2KaLe0RUm1K5rKJ6313svWOSmANax4m4vddc_57Q0Ht8eTiPtPZXZQ2HjHIPL3RHUAsDjrvA/s1600/install.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Output of the WcfExample.exe install command." border="0" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxcA1AtaIKFfpwGXqVSMAbb1Nyr5exA71t6_j9Bcg_hDfbujNhlIOU2GKz7mg5-tbqFIB2KaLe0RUm1K5rKJ6313svWOSmANax4m4vddc_57Q0Ht8eTiPtPZXZQ2HjHIPL3RHUAsDjrvA/s400/install.png" title="Install Example" width="400" /></a></div>
<br />
Once a service is installed, it can be started and stopped:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWNQUr71k9euD8rWBhEyGv-3G4M6SjpeXnv5sjup7Vg8i3J-SS8c5umc4boUEE67dC9i3n1ntQDKec2iGvK03KK8Wm-MI1v3LZRa7cliJ5DuMLUweyYIo6TGywD5YDU9vsm8rorSbifNI/s1600/start.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Example of the WcfExample.exe start command." border="0" height="81" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWNQUr71k9euD8rWBhEyGv-3G4M6SjpeXnv5sjup7Vg8i3J-SS8c5umc4boUEE67dC9i3n1ntQDKec2iGvK03KK8Wm-MI1v3LZRa7cliJ5DuMLUweyYIo6TGywD5YDU9vsm8rorSbifNI/s400/start.png" title="" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7EIOEHH31j5MmSVuavyRTSo4JtZwfIx_onO9yJ54NdYz-7rwlT7B2YCxzOGzHyxD9W599VKGx0xKNdHplDr1NdE70ZXoQwF8rvh7oS3j1dgYmnat2ZE-xQocrpRLr9OpFIhVep2O9LAg/s1600/stop.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Example of the WcfExample.exe stop command." border="0" height="81" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7EIOEHH31j5MmSVuavyRTSo4JtZwfIx_onO9yJ54NdYz-7rwlT7B2YCxzOGzHyxD9W599VKGx0xKNdHplDr1NdE70ZXoQwF8rvh7oS3j1dgYmnat2ZE-xQocrpRLr9OpFIhVep2O9LAg/s400/stop.png" title="" width="400" /></a></div>
<br />
Finally, the service may be uninstalled:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjumrW7ClfPF2w6PzgdJOnhEw2HfoslEOEs9roOduCloy8EPq-iXOQYRu68yxzjZDDkskQkYBQqdlWXR29OgvqbA80RKOK8bWE9tBxtOVBGTbYsvJIYtjXTrSuWVziBP9Dv2vRolV1Ibg0/s1600/uninstall.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Example of the WcfExample.exe uninstall command." border="0" height="118" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjumrW7ClfPF2w6PzgdJOnhEw2HfoslEOEs9roOduCloy8EPq-iXOQYRu68yxzjZDDkskQkYBQqdlWXR29OgvqbA80RKOK8bWE9tBxtOVBGTbYsvJIYtjXTrSuWVziBP9Dv2vRolV1Ibg0/s400/uninstall.png" title="" width="400" /></a></div>
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Conclusion</span><br />
<br />
We covered how to get started with TopShelf. We also looked at setting up an IoC to work with a TopShelf-based application. Next we'll look a little more at logging, and how we can use a component to configure our service.Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0tag:blogger.com,1999:blog-8643450826744932654.post-66074125170955857262013-03-05T05:07:00.002-08:002013-03-07T12:42:21.076-08:00Building a Service App: Intro & Unhandled Exceptions<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Introduction</span><br />
<br />
We do a lot of service applications where I work. Most of them are self-hosted. That means a lot of console-style apps. This post is to document some of the stuff we're doing, so we have something of a common template.<br />
<br />
We'll be using a few tools/technologies:<br />
<ul>
<li><a href="http://nuget.org/" target="_blank">NuGet</a></li>
<li><a href="http://docs.castleproject.org/Windsor.MainPage.ashx">Castle.Windsor</a></li>
<li><a href="http://docs.castleproject.org/Windsor.WCF-Integration-Facility.ashx">Castle's WcfIntegration Facility</a></li>
<li><a href="http://nlog-project.org/">NLog</a></li>
<li><a href="http://commonservicelocator.codeplex.com/">CommonServiceLocator</a></li>
</ul>
The example code will be hosted on <a href="https://github.com/caloggins/NhibSamples/tree/master/TopShelfWcfExample" target="_blank">GitHub</a>.<br />
<br />
We'll get started with a basic unhandled exception handler. This will give us a way to capture the error when the application won't even start, and hasn't had time to initialize the logging framework.<br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Program.Main() and Unhandled Exceptions</span><br />
<br />
When everything fails, including your logging mechanism, it's nice to know what happened. There's just a ton of things that can and do go wrong. One way to help catch these errors is to log to the an event log.<br />
<br />
<pre class="brush:c-sharp;"> public class Program
{
static void Main()
{
try
{
// do something
}
catch (Exception exception)
{
var assemblyName = typeof(Program).AssemblyQualifiedName;
if (!EventLog.SourceExists(assemblyName))
EventLog.CreateEventSource(assemblyName, "Application");
var log = new EventLog { Source = assemblyName };
log.WriteEntry(string.Format("{0}", exception), EventLogEntryType.Error);
}
}
}</pre>
<br />
What we've done is place a generic exception handler in the Main() method. It catches generic exceptions, logging them all to the event log. This catches anything that hasn't been caught; your basic unhandled exception handler. Now we have a way to see what happened...<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlr42Eoa4Ud3JQiXXkcrWMcEyBFab5EOgKnOdndPNb7tHf59By5hj7vep3xxXVoU8lqnbhSpC4CkCJxdqI5YYF7hM6SpQ0Gc2qS-_RV8G67uSA1MAl_wcVzx5v21zFVtZbGV_MnsdGGKc/s1600/EventLog.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="An image showing the error in the Application Windows Log." border="0" height="169" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlr42Eoa4Ud3JQiXXkcrWMcEyBFab5EOgKnOdndPNb7tHf59By5hj7vep3xxXVoU8lqnbhSpC4CkCJxdqI5YYF7hM6SpQ0Gc2qS-_RV8G67uSA1MAl_wcVzx5v21zFVtZbGV_MnsdGGKc/s640/EventLog.png" title="" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The EventLog</td></tr>
</tbody></table>
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyt5BRNLsZAKaue0Z0f0WdbtJHVDU-1FqbiKJWD5Bw_UV2vReW0-sN6TAN-i9HYZGflnOB7zEb-7xKPDyPr_npI-pJR9z7vKI-VoyYYLTrGURcRo4Ni9WbdCooFkRu2L98R7IytrmMJew/s1600/EventLog2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="A picture of the actual error, complete with stack trace." border="0" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyt5BRNLsZAKaue0Z0f0WdbtJHVDU-1FqbiKJWD5Bw_UV2vReW0-sN6TAN-i9HYZGflnOB7zEb-7xKPDyPr_npI-pJR9z7vKI-VoyYYLTrGURcRo4Ni9WbdCooFkRu2L98R7IytrmMJew/s640/EventLog2.png" title="" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The captured error message.</td></tr>
</tbody></table>
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: large;">Next...</span><br />
<br />
There you have it. An easy way to capture exceptions when the worst happens. Next up, we'll take a look at dependency injection with Windsor.<br />
<br />
<br />
<br />Chrishttp://www.blogger.com/profile/07050959395523812736noreply@blogger.com0