tag:blogger.com,1999:blog-91558529045208453762024-03-14T13:57:43.271-04:00like was told to meA very smart person once told me a secret, and I want to share it with you, or something like that.Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-9155852904520845376.post-9636600003200994202021-08-29T21:08:00.031-04:002021-09-15T20:52:47.085-04:00X-ray StoneAssemblies.MassAuth with NDepend<h2 style="text-align: left;">Introduction</h2>
<p style="text-align: justify;">A long time ago, I wrote this post <a href="http://likewastoldtome.blogspot.com/2015/01/why-start-to-use-ndepend.html">Why should you start using
NDepend?</a> which I consider as the best post I have ever written or almost ;)</p>
<p style="text-align: justify;">NDepend is a static analysis tool for .NET, and helps us to analyze code without executing it, and is generally used to ensure conformance with the coding guidelines. As its authors use to say,
it will likely find hundreds or even thousands of issues affecting your codebase.</p>
<p style="text-align: justify;">After the first pre-releases of <a href="https://likewastoldtome.blogspot.com/2021/07/introducing-stoneassemblies-massauth.html">StoneAssemblies.MassAuth</a>
I decided to X-ray it with <a href="https://www.ndepend.com/" target="_blank">NDepend</a>. I attach a new NDepend
project to StoneAssemblies.MassAuth solution, filter out the test and demo assemblies, and hit the analyze button.
</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNosQVgT85PlmbMTcRFm_Xc4NNt09q5epjtX0RrEo6JBuNilDv2w-v_FrlFwAP1wCbA2r_PZ_RUc1-NvZIN1Mx_IAmXtLskFFPAIgpmK2QuaJcmbqi3bd0cBGyC8kvqJju-65RQBbxnGg/s1087/attach-ndepend.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="705" data-original-width="1087" height="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNosQVgT85PlmbMTcRFm_Xc4NNt09q5epjtX0RrEo6JBuNilDv2w-v_FrlFwAP1wCbA2r_PZ_RUc1-NvZIN1Mx_IAmXtLskFFPAIgpmK2QuaJcmbqi3bd0cBGyC8kvqJju-65RQBbxnGg/w640-h416/attach-ndepend.png" width="640" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Attach new NDepend Project to Visual Studio
Solution </td>
</tr>
</tbody>
</table>
<p>Now, I invite you to interpret some results with me. So, let's start.</p>
<h2 style="text-align: left;">Interpreting the NDepend analysis report</h2>
<div style="text-align: left;">One of the outputs of the analysis is a web report. The main page includes a report
summary with Diagrams, Application Metrics, Quality Gates summary, and Rules summary sections.</div>
<div style="text-align: left;"><br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiflj7NgYJuEdT-KvepnSzsX19lLkIDTZI8RB-W1AAwOQcgf9uO-uzqM1bqABsHJsmJYUwFpcuCJ9Tlq73EF6Ob90GqnpwC40BahIBOrqeGkkx_leqP9Rl8DzMB16ExbUYTOmtqGeVP7_c/s1898/ndepend-report-summary.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1649" data-original-width="1898" height="557" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiflj7NgYJuEdT-KvepnSzsX19lLkIDTZI8RB-W1AAwOQcgf9uO-uzqM1bqABsHJsmJYUwFpcuCJ9Tlq73EF6Ob90GqnpwC40BahIBOrqeGkkx_leqP9Rl8DzMB16ExbUYTOmtqGeVP7_c/w640-h557/ndepend-report-summary.png" width="640" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">NDepend Report Summary</td>
</tr>
</tbody>
</table><br />
<div style="text-align: left;">
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPDogtdTW4FjcMhAJSRvWBPtndlvufxl8UtlFtWw9rXQsVvXHisS9K3ixp7FAwGZaC1XxCQoNUG0ouxS4HKplpMJpqYL9hQdypJ-vmpaKmXqmK2C6nFfzbS4USICiSklSj-HmnVmGXh0E/s791/ndepend-report-navigation.png" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto; text-align: right;"><img border="0" data-original-height="724" data-original-width="791" height="211" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPDogtdTW4FjcMhAJSRvWBPtndlvufxl8UtlFtWw9rXQsVvXHisS9K3ixp7FAwGZaC1XxCQoNUG0ouxS4HKplpMJpqYL9hQdypJ-vmpaKmXqmK2C6nFfzbS4USICiSklSj-HmnVmGXh0E/w231-h211/ndepend-report-navigation.png" width="231" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Navigation Menu</td>
</tr>
</tbody>
</table>
<div style="text-align: justify;"><br /></div><div style="text-align: justify;">It also includes a navigation menu to drill through more detailed
information including Quality Gates, Rules, Trend Charts, Metrics, Dependencies, Hot Sports, Object-Oriented
Design, API Breaking Changes, Code Coverage, Dead Code, Code Diff Summary, Build Order, Abstractness vs.
Instability and Analysis Log.</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;"><br /></div><div style="text-align: justify;">But let's take a look at these summary sections.</div></div><div style="text-align: left;"><h3 style="text-align: justify;"><span style="text-align: left;">Diagrams</span></h3>
<div style="text-align: justify;">The diagrams section includes Dependency Graph, Dependency Matrix, Treemap
Metric View and Abstractness vs. Instability. </div>
<div style="text-align: justify;"><br /></div>
<div><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTtDLVO81eXC4bikgaLAhs-eTqrYTf7yIa0eyPLvHhpAuykAIHAr_QANfZEbBwN7d6msvbHOmJ_MY0DotonaV2VRpn7lqFcQ9YH78Pb4x-PbkegPWs65KW5e05Kmza_XirwKu7CUdH5uI/s1280/ComponentDependenciesDiagram.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="435" data-original-width="1280" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTtDLVO81eXC4bikgaLAhs-eTqrYTf7yIa0eyPLvHhpAuykAIHAr_QANfZEbBwN7d6msvbHOmJ_MY0DotonaV2VRpn7lqFcQ9YH78Pb4x-PbkegPWs65KW5e05Kmza_XirwKu7CUdH5uI/w572-h195/ComponentDependenciesDiagram.png" width="572" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Dependency Graph</td>
</tr>
</tbody>
</table><span style="text-align: left;"><br /></span>
</div>
<div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEoJ0lCVPyRltP29uedESJFKPgDkAVQTAXuxKD9M-qoB4VIk89VVpLqtPDBTx4vJ993kkgGgdL8kVJcyyhK32rYo5N9vooUGWg-FRaZ3JPXOkvmqreKjbURk4EulGLEYtARJmbKoM4_DE/s951/ComponentDependenciesMatrix.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="951" data-original-width="762" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEoJ0lCVPyRltP29uedESJFKPgDkAVQTAXuxKD9M-qoB4VIk89VVpLqtPDBTx4vJ993kkgGgdL8kVJcyyhK32rYo5N9vooUGWg-FRaZ3JPXOkvmqreKjbURk4EulGLEYtARJmbKoM4_DE/w512-h640/ComponentDependenciesMatrix.png" width="512" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Dependency Matrix</td>
</tr>
</tbody>
</table><br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii3_OQy3QS9oABLotKMqOjo5_ojJFP06L0bIUZ_VAgeLivAvam0dCeIN-RiMFjbeylglOsxme8FTwzQHrbLu-ivoyBxbxdEquQK8inbHGFK38b5Qz8cpdMjoCbZgJTESBAXN1so_iTgyI/s1280/VisualNDependView.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1280" data-original-width="1280" height="525" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii3_OQy3QS9oABLotKMqOjo5_ojJFP06L0bIUZ_VAgeLivAvam0dCeIN-RiMFjbeylglOsxme8FTwzQHrbLu-ivoyBxbxdEquQK8inbHGFK38b5Qz8cpdMjoCbZgJTESBAXN1so_iTgyI/w525-h525/VisualNDependView.png" width="525" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Treemap Metric View (Color Metric
Coverage)
</td>
</tr>
</tbody>
</table>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">So far I understand these metrics, actually, I can interpret
them relatively easily. </div>
<div style="text-align: justify;"><span style="text-align: center;"><br /></span></div>
<div style="text-align: justify;"><span style="text-align: center;">But, wait for a
second. </span>What is this Abstractness versus Instability? </div><div style="text-align: justify;"><br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRy0Cr_59QCcIosg2yM0RR7CD8aoGJIvKZKUGG6tOcWittxN2JJGUhmQkCmwpWnfWpzbRnonXXzupd2hImqNz6EXLaznlCK0H8VuqgLHI9s_16B91KBxRP0Jj6h2X4ykYbs9XdTBLec5I/s1000/abstracness.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="894" data-original-width="1000" height="539" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRy0Cr_59QCcIosg2yM0RR7CD8aoGJIvKZKUGG6tOcWittxN2JJGUhmQkCmwpWnfWpzbRnonXXzupd2hImqNz6EXLaznlCK0H8VuqgLHI9s_16B91KBxRP0Jj6h2X4ykYbs9XdTBLec5I/w603-h539/abstracness.png" width="603" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;"><span style="text-align: justify;">Abstractness
versus Instability</span></td>
</tr>
</tbody>
</table><br />
<div style="text-align: justify;">According to the documentation the Abstractness versus Instability diagram helps to detect which assemblies are potentially painful to maintain (i.e concrete and stable) and
which assemblies are potentially useless (i.e abstract and instable).</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;"><b>Abstractness</b>: If an assembly contains many abstract types (i.e
interfaces and abstract classes) and few concrete types, it is considered as abstract.</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;"><b>Instability</b>: An assembly is considered stable if its types are used by a lot of types from other assemblies. In this context stable means painful to modify.</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;"><br /></div>
</div>
</div>
<table style="border-collapse: collapse; border: 1px solid rgb(179, 173, 173); margin-left: auto; margin-right: auto; padding: 5px;">
<thead>
<tr>
<th style="background: rgb(240, 240, 240); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px;">
Component</th>
<th style="background: rgb(240, 240, 240); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px;">
Abstractness (A)</th>
<th style="background: rgb(240, 240, 240); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px;">
Instability (I)</th>
<th style="background: rgb(240, 240, 240); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px;">
Distance (D)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.96</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.03</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Rules</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
1</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.4</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.28</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Messages</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.43</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.62</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.04</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Hosting</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.14</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.99</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.09</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Rules.SqlClient</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.17</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
1</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0.12</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Server</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
1</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Proxy</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
1</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
0</td>
</tr>
</tbody>
</table>
<br />
<div style="text-align: justify;">None of StoneAssemblies.MassAuth's components seem <span style="text-align: justify;">potentially painful to maintain or </span><span style="text-align: justify;">potentially useless. But, </span>I
have to keep my eyes on StoneAssemblies.MassAuth.Rules, because of the distance (D) from the main sequence. Actually, another candidate to review is StoneAssemblies.MassAuth.Messages since ideal assemblies are either completely abstract and stable (I=0, A=1) or completely concrete and instable (I=1, A=0).</div>
<div>
<h3><br /></h3><h3>Application Metrics </h3>
</div>
<div>The application metrics section shows the following summary.</div>
<div><br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlJ_bo1Hcqeua-8zADkacHXFOzdRJM97oikwOyk5w_rLb4t_SIdzMdXDUh60NtvCgbFufH8sV25xIM98lwHiUatsGWzYBiFbEy7llGaM1VgpxLhOfEPcTllTA7NpKvpjyWeiFVa2Pf5uM/s1313/app-metrics.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="709" data-original-width="1313" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlJ_bo1Hcqeua-8zADkacHXFOzdRJM97oikwOyk5w_rLb4t_SIdzMdXDUh60NtvCgbFufH8sV25xIM98lwHiUatsGWzYBiFbEy7llGaM1VgpxLhOfEPcTllTA7NpKvpjyWeiFVa2Pf5uM/w640-h346/app-metrics.png" width="640" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Application Metrics</td>
</tr>
</tbody>
</table><br />
<div style="text-align: justify;">Looks like some metrics depend on a codebase. Since this is the first I run NDepend's analysis over StoneAssemblies.MassAuth code, it hasn't noticed any difference with previous executions. But this
help me to be alert about the low 66.99% value for the tests coverage, the 3 failures for quality gates, the
violations of 2 critical rules and 15 high issues.</div>
<div style="text-align: justify;">
<h3 style="text-align: left;"><br /></h3><h3 style="text-align: left;">Quality Gates</h3>
<div>In this section is possible to view more details on the failing quality gates. The percentage of coverage, the
critical rules violated and the debt rating per namespace.</div>
<div><br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFqmJNcaTPbf1JfBeScL7jBCePANT3dpmCaxLBIQkNlHwa0mbfImzdNbE-ZLF_cq_cXLEg1lKci0zQDKj0p_nIdHnEH_q7l5OGaK7ghWvPXX7euWsfFDNmLxSZ8GX6x5q4LXY4m0FsuLU/s1315/quality-gates.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="496" data-original-width="1315" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFqmJNcaTPbf1JfBeScL7jBCePANT3dpmCaxLBIQkNlHwa0mbfImzdNbE-ZLF_cq_cXLEg1lKci0zQDKj0p_nIdHnEH_q7l5OGaK7ghWvPXX7euWsfFDNmLxSZ8GX6x5q4LXY4m0FsuLU/w640-h242/quality-gates.png" width="640" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Quality Gates</td>
</tr>
</tbody>
</table><br />
<div class="separator" style="clear: both; text-align: justify;">Wait for a second again. What is debt rating per
namespace means? </div>
<div class="separator" style="clear: both; text-align: justify;"><br /></div>
<div class="separator" style="clear: both; text-align: justify;">According to the documentation the rule is about to forbid namespaces with a poor debt rating. By default, a value greater than 20% is considered a poor debt
rating.</div>
<div class="separator" style="clear: both; text-align: justify;"><br />
<table style="border-collapse: collapse; border: 1px solid rgb(179, 173, 173); margin-left: auto; margin-right: auto; padding: 5px;">
<thead>
<tr>
<th style="background: rgb(240, 240, 240); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px;">
Namespaces</th>
<th style="background: rgb(240, 240, 240); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px;">
Debt Ratio</th>
<th style="background: rgb(240, 240, 240); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px;">
Issues</th>
</tr>
</thead>
<tbody>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Services</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
39.01</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
8</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Services.Attributes</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
37.62</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
3</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Server</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
23.67</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
6</td>
</tr>
<tr>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
StoneAssemblies.MassAuth.Rules.SqlClient .Rules</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
36.24</td>
<td style="background: rgb(255, 255, 255); border: 1px solid rgb(179, 173, 173); color: #313030; padding: 5px; text-align: center;">
3</td>
</tr>
</tbody>
</table>
</div><div style="text-align: justify;"><br /></div>
<div>
<h3 style="text-align: left;">Rules summary</h3>
</div>
<div>The final section is the Rules summary. It listed the issues per rules in the following table. </div>
<div><br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc7a0ZAsMgnzvmSZBqQNq3F_tcu5bb5Wbd_A3ksviAMBr2Bgd7WvYZCsmsyGp3GMMAQQSUVjGx1nOOXtVPu5kHWbX_q-V5CYZcb7Y0zfJbnxPq3fCiZZOdI-BW6s5kgmOrHT_drI7_gE0/s1475/rules.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="986" data-original-width="1475" height="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc7a0ZAsMgnzvmSZBqQNq3F_tcu5bb5Wbd_A3ksviAMBr2Bgd7WvYZCsmsyGp3GMMAQQSUVjGx1nOOXtVPu5kHWbX_q-V5CYZcb7Y0zfJbnxPq3fCiZZOdI-BW6s5kgmOrHT_drI7_gE0/w640-h428/rules.png" width="640" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Rules summary</td>
</tr>
</tbody>
</table><br />
<div>NDepend indicates to me that I violated 2 critical rules. One to avoid namespaces mutually dependent and the other to avoid having different types with the same name. That sounds weird, but who knows, even I can make mistakes ;)
</div>
<h2><br /></h2><h2>What's next?</h2>
<div>I the near future, I will be integrating the NDepend analysis as part of the build process, therefore I could easily share with you the evolution of this library in terms of quality. If you are interested in such an experience wait for the next post.</div>
<div><br /></div>
<div>As you already know, <a href="https://github.com/stoneassemblies/StoneAssemblies.MassAuth">StoneAssemblies.MassAuth</a> is a work in progress, which includes some unresolved technical debts. But, as I told you once, it is possible to make mistakes
(critical or not), but be aware of your code quality constantly makes the difference between the apparent and intrinsic quality of your sources. If you are a dotnet developer, NDepend is a great tool to be aware of your code quality. </div>
<div><br /></div>
<div>
<div>Yeah, you are right, I have some work to do here in order to fix this as soon as possible but also remember, StoneAssemblies.MassAuth is also an open-source project, so
you are welcome to contribute ;)</div>
</div>
</div>Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0Havana, Cuba23.1135925 -82.3665956-5.1966413361788462 -117.5228456 51.423826336178848 -47.2103456tag:blogger.com,1999:blog-9155852904520845376.post-81994240202494062172021-08-22T15:25:00.043-04:002021-09-15T20:57:21.402-04:00StoneAssemblies.MassAuth Hands-on Lab<p>A few days ago, I introduced you <a href="http://likewastoldtome.blogspot.com/2021/07/introducing-stoneassemblies-massauth.html">StoneAssemblies.MassAuth</a> as a <a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/gatekeeper">Gatekeeper</a> implementation.</p><p>Today, as promised, I bring you a hands-on lab that consists of the following steps:</p><p></p><ol style="text-align: left;"><li><a href="#samhol-step1">Set up the workspace</a></li><li><a href="#samhol-step2">Contract first</a></li><li><a href="#samhol-step3">Implementing rules</a></li><li><a href="#samhol-step4">Implementing services</a></li><li><a href="#samhol-step5">Hosting rules</a></li><li><a href="#samhol-step6">Build, run and test</a></li></ol><div>So, let’s do this straightforward. </div><p></p><h2 style="text-align: left;">Prerequisites</h2><p></p><ul style="text-align: left;"><li>Visual Studio 2019 (16.9.3)</li><li>Docker (2.3.0.4)</li><li><a href="https://cakebuild.net/" target="_blank">Cake</a> (1.1.0)</li><li><a href="https://github.com/dotnet/tye/blob/main/docs/getting_started.md">Tye</a> (0.9.0-alpha.21380.1)</li></ul><h2 id="samhol-step1">Step 1: Set up the workspace</h2><div><span style="text-align: justify;">To set up the workspace, open a PowerShell console and run the following commands:</span></div><div><br />
<script src="https://gist.github.com/alexfdezsauco/998e4f86c347c9b9d8da1cae9a2841bf.js"></script>
</div><div><br /></div><div style="text-align: justify;">After executing these commands, <i><b>StoneAssemblies.MassAuth.QuickStart.sln </b></i>Visual Studio solution file is created, which includes the following projects:</div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"></blockquote><span style="text-align: justify;"><ul><li style="text-align: justify;"><b style="text-align: justify;"><i style="text-align: left;">StoneAssemblies.<span style="text-align: justify;">MassAuth</span><span style="text-align: justify;">.</span>QuickStart.Messages</i>:</b><span style="text-align: justify;"> </span><span style="text-align: justify;">C</span><span style="text-align: justify;">lass library for messages specification. </span></li><li style="text-align: justify;"><b style="text-align: justify;"><i style="text-align: left;">StoneAssemblies.<span style="text-align: justify;">MassAuth</span><span style="text-align: justify;">.</span>QuickStart.Rules</i>: </b><span style="text-align: justify;">C</span><span style="text-align: justify;">lass library to implement rules for messages.</span></li><li style="text-align: justify;"><b style="text-align: justify;"><i style="text-align: left;">StoneAssemblies.<span style="text-align: justify;">MassAuth</span><span style="text-align: justify;">.</span>QuickStart.Services</i>: </b><span style="text-align: justify;">Web API to host the services that require to be authorized by rules.</span></li><li style="text-align: justify;"><span style="text-align: justify;"><span style="text-align: left;"><i><b>StoneAssemblies.<span style="text-align: justify;">MassAuth</span><span style="text-align: justify;">.</span>QuickStart.<span style="text-align: justify;">AuthServer</span></b></i></span><b>: </b></span><span style="text-align: justify;">Authorization server to host the rules for messages. </span></li></ul></span><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"></blockquote><div><div><span style="text-align: justify;">The commands also add the required NuGet packages and project references.</span></div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><div>If you review the content of the <i><b>StoneAssemblies.MassAuth.QuickStart.AuthServer.csproj</b></i> project file, you should notice a package reference to <i><a href="https://www.nuget.org/packages/StoneAssemblies.Extensibility/">StoneAssemblies.Extensibility</a></i>. This is required because all rules will be provisioned as plugins for the authorization server. </div><div><br /></div><div style="text-align: justify;">The extensibility system is NuGet based, so we need to set up the build to provision the rules and messages as NuGet packages. For that is the purpose, this workspace configuration includes two more files.<span style="text-align: left;"> The</span><i> build.cake, </i>a cake based build script to ensure the required package output, <i> </i></div></div></div><div><br /></div>
<script src="https://gist.github.com/alexfdezsauco/581187a11cb49cec591d2ab7a81e4db5.js"></script>
<div style="text-align: justify;"><br /></div><div style="text-align: justify;">and the <i>tye.yaml</i> that will help us to run and debug the solution.</div><div style="text-align: justify;"> </div>
<script src="https://gist.github.com/alexfdezsauco/761885e61409f5b62c8ce2feb844ce4b.js"></script>
<div><br /></div><div><br /></div><div><h2 id="samhol-step2">Step 2: Contract first</h2></div><div style="text-align: justify;">Let's add a bit of complexity to the generated problem, related to the weather forecast. For instance, let's say we will allow requesting forecasts from a certain date, as some forecasts may not be available due to the complexity of the calculations.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">For that purpose, we will add the following class to the message project, to request the weather forecast with the start date as an argument.</div>
<script src="https://gist.github.com/alexfdezsauco/52e10bdad84c154a35cfd2be104d7333.js"></script>
<div style="text-align: justify;"><br /></div><div><h2 id="samhol-step3">Step 3: Implementing rules</h2></div><div style="text-align: justify;">Now we are ready to implement some rules for such a message. Continuing with our scenario, let's say the forecast data is only available from today and up to 10 days. This operation could be more complex through a query to an external database, but for simplicity, it will be implemented as follows.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><br /></div>
<script src="https://gist.github.com/alexfdezsauco/6b5d4d0b37c3351cb34ddb2f008a3c76.js"></script>
<div><h2 id="samhol-step4">Step 4: Implementing services</h2></div><div style="text-align: justify;">It's time to complete the <i>WeatherForecastController </i>implementation in the service project. It should look like this. </div><div><br /></div>
<script src="https://gist.github.com/alexfdezsauco/cfde54e975924aaf39ff3d7664b7fdb2.js"></script>
<div><br /></div><div><div style="text-align: justify;">Notice the usage of <i>AuthorizeByRule </i>attribute on the <i>Get</i> method, to indicate that the input message <i>WeatherForecastRequestMessage</i> must be processed and validated by the authorization engine before the method execution.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">We also have to update the <i>Startup </i>class implementation.</div><div style="text-align: justify;"><br /></div>
<script src="https://gist.github.com/alexfdezsauco/86b681686642537c8d945149031a2302.js"></script>
<div style="text-align: justify;"> </div><div style="text-align: justify;">Basically, the <i>AddMassAuth</i> service collection extension method is called to register the library services and also ensure communication through the message broker. Remember, StoneAssemblies.MassAuth is built on top of <a href="https://masstransit-project.com/" target="_blank">MassTransit</a>. <span style="text-align: left;">Finally, to read the configuration via environment variables we must update the </span><i style="text-align: left;">Program </i><span style="text-align: left;">class to this</span><i style="text-align: left;">.</i><span style="text-align: left;"> </span></div><div style="text-align: justify;"><span style="text-align: left;"><br /></span></div>
<script src="https://gist.github.com/alexfdezsauco/2d6e33f15ee7077577727498a387e8c3.js"></script>
<h2 id="samhol-step5">Step 5: Hosting rules</h2></div><div style="text-align: justify;">To host rules, we provide a production-ready of <i>StoneAssemblies.MassAuth.Server</i> as docker image available in <a href="https://hub.docker.com/r/stoneassemblies/massauth-server">DockerHub</a>. But for debugging or even for customization purpose could be useful build your own rule host server. So, in the server project, we also have to update the <i>Startup </i>class implementation, to initialize the extensibility system and load rules. </div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><br /></div>
<script src="https://gist.github.com/alexfdezsauco/6384b11ed441d6efb06950e5e6babdc9.js"></script>
<div style="text-align: justify;"><div style="text-align: left;">Again, to read the configuration via environment variables the <i>Program</i> file must be updated like this. </div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div>
<script src="https://gist.github.com/alexfdezsauco/9cd40c62c6efba8fc164d73dafe3b117.js"></script>
<h2 id="samhol-step6" style="text-align: left;">Step 6: Build, run and test</h2><div>Let's see if this works. So, cross your fingers first ;)</div><div><br /></div><div>To build and run the project, open a PowerShell terminal in the working directory and run the following commands.</div><div><br /></div><div><script src="https://gist.github.com/alexfdezsauco/86ae93d5d612700483e96d3b66655e6d.js"></script></div><div><br /></div><div>Open your browser and navigate to <a href="http://localhost:8000">http://localhost:8000</a> to display the Tye user interface. </div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZZ2-qOgL9SWx3Qf5rlVBsK4qEeJp8tTeRYh_z-m3fQOAdHiV7O6o3IiJbOR-WLHtKOYEy9smGgNLINDZBgogTv2mgok1My2PWwUTa8cmN07ddp6gndL5bU_3LiWEi-ruvIgUbPDdngtw/s16000/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="588" data-original-width="1567" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZZ2-qOgL9SWx3Qf5rlVBsK4qEeJp8tTeRYh_z-m3fQOAdHiV7O6o3IiJbOR-WLHtKOYEy9smGgNLINDZBgogTv2mgok1My2PWwUTa8cmN07ddp6gndL5bU_3LiWEi-ruvIgUbPDdngtw/s16000/image.png" width="640" /></a></div><div><br /></div>You can see the logs of the rules host server to notice how extensibility works.</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbVFQo2lR165ZbHDjNBcoPp_RKEVUZh-pT5qb_0frxQTFiRtDpq1gygGdqUukBz_E0HaodboFJwqa5lk8q9af9M9F0NMOiWFUizdcmMwWd71WwPd81RGyusXjC5GNlnlWUylK7aqKNKoE/s16000/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="798" data-original-width="1457" height="350" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbVFQo2lR165ZbHDjNBcoPp_RKEVUZh-pT5qb_0frxQTFiRtDpq1gygGdqUukBz_E0HaodboFJwqa5lk8q9af9M9F0NMOiWFUizdcmMwWd71WwPd81RGyusXjC5GNlnlWUylK7aqKNKoE/s16000/image.png" width="640" /></a></div><br /><div style="text-align: left;">Let's do some weather forecast requests. For instance with a valid request</div><div style="text-align: left;"><br /></div>
<script src="https://gist.github.com/alexfdezsauco/9966d93bb853f9ac761127d7e262dd91.js"></script>
<div style="text-align: left;"><div class="separator" style="clear: both; text-align: justify;">the output looks like this</div><div class="separator" style="clear: both; text-align: justify;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrhlDjrvUiL_MRKIpx8ZYctQVsiT-VwImCj8L2sG3HRDmA6056jkmrQjPeFWX_Ly8UQrJI6J1y7FCxQNxt79RIno5I0yRNO2riungNhci0JGSqVTCaJbjDJFkr_yl6V62wrftIvNpdgEM/s16000/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="439" data-original-width="1593" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrhlDjrvUiL_MRKIpx8ZYctQVsiT-VwImCj8L2sG3HRDmA6056jkmrQjPeFWX_Ly8UQrJI6J1y7FCxQNxt79RIno5I0yRNO2riungNhci0JGSqVTCaJbjDJFkr_yl6V62wrftIvNpdgEM/s16000/image.png" width="640" /></a></div><br /><span style="text-align: left;">but with an out of range request</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div></div><script src="https://gist.github.com/alexfdezsauco/08f5afd91c8216b87cef1ceff6b26aa4.js"></script><div style="text-align: left;"><br /></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">the output shows an unauthorized response.</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicpEOat2pTYBPD8WtnEjFKLi_Tv_MHcAvxwBrbLavpnNafDdsGNDwcuxkTHJushQfHW-juUT6UJhxedXPEHarU77hTnzaFcvEC9lzgPFj1WjAqmRb1TeDriZp-ubT-Blv4TvesjS2EOHs/s16000/image.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="151" data-original-width="1592" height="61" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicpEOat2pTYBPD8WtnEjFKLi_Tv_MHcAvxwBrbLavpnNafDdsGNDwcuxkTHJushQfHW-juUT6UJhxedXPEHarU77hTnzaFcvEC9lzgPFj1WjAqmRb1TeDriZp-ubT-Blv4TvesjS2EOHs/s16000/image.png" width="640" /></a></div><br /><br /></span></div><div style="text-align: left;">So, as expected, it works ;)</div><h2 style="text-align: left;"><br /></h2><h2 style="text-align: left;">Closing</h2><div style="text-align: justify;">In case it doesn't work for you, you can always try to review the final and complete source code of this hands-on lab is in the <a href="https://github.com/stoneassemblies/StoneAssemblies.MassAuth.QuickStart">StoneAssemblies.MassAuth.QuickStart</a> repository is available on GitHub. </div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">Remember <i style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; text-align: justify;"><a href="https://github.com/stoneassemblies/StoneAssemblies.MassAuth">StoneAssemblies.MassAuth</a></i> is a work in progress, we are continuously releasing new versions, so your feedback is welcome. Also, remember that it is an open-source project, so you can contribute too.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">Enjoy «authorizing» with pleasure and endless possibilities.</div></div></div></div></div>Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0Havana, Cuba23.1135925 -82.3665956-5.1966413361788462 -117.5228456 51.423826336178848 -47.2103456tag:blogger.com,1999:blog-9155852904520845376.post-32974886458843064092021-07-21T16:23:00.017-04:002022-01-01T19:04:45.878-05:00Introducing StoneAssemblies MassAuth<h2 style="clear: both; text-align: left;">What is Stone Assemblies in the first place?</h2>
<div>
<div style="text-align: justify;">It has been a long way before making this decision. I worked for state-owned
companies for years, in fact, I still do, but now I try to see this from a different perspective. I did not keep any of the things that I built or designed in the years of work. Maybe just professional experience.</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">Now, I decided to start over again, by creating something more personal. <a href="https://stoneassemblies.github.io/" target="_blank">Stone Assemblies</a> is a new software development and consulting group or organization or project. Actually, if you are running a software business or starting a
new one, you probably need us ;).</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">I cannot say that Stone Assemblies is a company or a small and medium businesses
(a.k.a. PYMES). There are many regulations here in Cuba and probably I will need some legal assistance to reach that point. So, let's keep this simple. I just founded Stone Assemblies and of course, I'm the lead software engineer. <span style="text-align: left;">That sounds great, doesn't it? </span></div>
<div style="text-align: justify;"><span style="text-align: left;"><br /></span></div>
<div style="text-align: justify;">The story of the name is quite funny, so I will probably tell you one day about
it, but not today.</div>
</div>
<h2 style="text-align: justify;"><br /></h2>
<h2 style="text-align: justify;">Some background and context</h2>
<div>
<div style="text-align: justify;">Last year I was outlining strategies to modernize the systems of an organization,
implementing proofs of concepts, which would allow their legacy system to support more workload. </div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">This particular system is in fact a database-centric large monolithic one. There
are several options to scale this kind of system. </div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">One of these options is vertical scaling, but they could eventually reach the same state. In fact, the database provider may have limitations to use all the resources, even those limitations could be expressed in the use license. But the main reason is that computational resources are finite.</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">The other option is horizontal scaling, but even when the database vendor has options for horizontal scaling, it doesn’t solve the fact that the system is actually a monolithic system with all the well-known issues of this kind of architecture. Again, this option could also have limitations expressed
in the license.</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">Our research led us to review some well-known patterns, and we started with:
</div>
<div style="text-align: justify;"><br /></div>
</div>
<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;">
<div>
<div style="text-align: justify;"><b>Command and Query Responsibility Segregation (CQRS)</b>: CQRS stands for
Command and Query Responsibility Segregation, a pattern that separates read and update operations for a data
store. Implementing CQRS in your application can maximize its performance, scalability, and security. The
flexibility created by migrating to CQRS allows a system to better evolve over time and prevents update
commands from causing merge conflicts at the domain level.</div>
</div>
</blockquote>
<div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">In combination with a migration approach from the:</div>
<div style="text-align: justify;"><br /></div>
</div>
<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;">
<div>
<div style="text-align: justify;"><b>Strangler Fig</b>: Incrementally migrate a legacy system by gradually
replacing specific pieces of functionality with new applications and services. As features from the legacy
system are replaced, the new system eventually replaces all of the old system's features, strangling the old
system and allowing you to decommission it. </div>
</div>
</blockquote>
<div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">and looking to maximize the added value for a minimum viable product (MVP), we
identified one key feature of the legacy system, so, we decided to also include this one:</div>
<div style="text-align: justify;"><br /></div>
</div>
<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;">
<div>
<div style="text-align: justify;"><b>Gatekeeper</b>: Protect applications and services by using a dedicated host
instance that acts as a broker between clients and the application or service, validates and sanitizes
requests, and passes requests and data between them. This can provide an additional layer of security, and
limit the attack surface of the system.</div>
</div>
</blockquote>
<h2 style="text-align: justify;"><br /></h2>
<h2 style="text-align: justify;">What is Stone Assemblies MassAuth?</h2>
<div style="text-align: justify;">The key feature I mentioned earlier, is an extensive, exhaustive validation subsystem that is executed before any attempt of command execution. But all these validations - query base operations - are executed in the main single database demanding computing resources, to the detriment of the performance of the other commands that could be executing at the same time. Remember, this is a very high
concurrency system.</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">The diagram below shows the monolithic shape of the system. </div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBZKbwE-UlHeDZb1cAAkV1FSx035kIPpRpFsLcN8IhwKz_ikzHBZBC-cjUtdejWO1N4AfsMkTpGul7LSkrtCZLUJznyW-J7HhdVV29F2CgGi-O2eJMK43c33c9UhjXCPmcZPMi9MBtBBU/s16000/image.png" style="margin-left: auto; margin-right: auto;"><img alt="" data-original-height="101" data-original-width="587" height="87" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBZKbwE-UlHeDZb1cAAkV1FSx035kIPpRpFsLcN8IhwKz_ikzHBZBC-cjUtdejWO1N4AfsMkTpGul7LSkrtCZLUJznyW-J7HhdVV29F2CgGi-O2eJMK43c33c9UhjXCPmcZPMi9MBtBBU/s16000/image.png" width="508" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Monolithic shape </td>
</tr>
</tbody>
</table><br />So, why not move all those validations to an isolated subsystem? The idea is to replicate all the slowly changing data, which is used in validation queries. With this only action, all validation workloads are executed in isolation, with the advantage that is also possible to assign dedicated resources to run these tasks.
The following diagram depicts this scenario.
</div>
<div style="text-align: justify;"><br /></div>
<div style="text-align: justify;">
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3-4dn1bjrOBGrnNPPI2KYp90P3yloUnT9AkunQCkfdww3u9pBsWpO95P58KfWyJtzL26xdxQ1bEMSDliv8izUqJhUOIeV47kYcRvELaVZ-0DqR36zExsQySSolj-08EdefEVIakutBxw/s16000/image.png" style="margin-left: auto; margin-right: auto;"><img alt="" data-original-height="290" data-original-width="588" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3-4dn1bjrOBGrnNPPI2KYp90P3yloUnT9AkunQCkfdww3u9pBsWpO95P58KfWyJtzL26xdxQ1bEMSDliv8izUqJhUOIeV47kYcRvELaVZ-0DqR36zExsQySSolj-08EdefEVIakutBxw/s16000/image.png" width="493" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Validation workloads run in isolation (CQRS)</td>
</tr>
</tbody>
</table><br />
<div>With this idea in mind, is not hard to generalize a solution that intercepts any message, and executes a
preflight without impact the core system. This is the idea behind <i>StoneAssemblies.MassAuth</i>.</div>
<div><br /></div>
<div><a href="https://github.com/stoneassemblies/StoneAssemblies.MassAuth"><i>StoneAssemblies.MassAuth</i></a> is a
free, open-source distributed, extensible message-based authorization framework built on top of <a href="https://masstransit-project.com/"><i>MassTransit</i></a>. Actually, it allows you to improve the responsiveness and throughput, from a loosely coupled and message-driven approach. </div>
<div><br /></div>
<div>The following diagram shows, the result of starting to strangulate the monolithic system, segregate the
responsibility of command and queries and the usage of <i>StoneAssemblies.MassAuth</i>.</div><div><br /></div><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDPh21U0Ien-PjRBCIEu4OD7CiWfc5h7w6La5iXCGV4i0rgyCJEdA46rX-P9BHLaAlJttSwgPN7r8B34MeuOfQ8cnBOInPpNE9FCWkWQngZ8iiyHjon1ONrRpKWVYnIm_7dglh-8XCj2A/s1191/gatekeeper.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="518" data-original-width="1191" height="278" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDPh21U0Ien-PjRBCIEu4OD7CiWfc5h7w6La5iXCGV4i0rgyCJEdA46rX-P9BHLaAlJttSwgPN7r8B34MeuOfQ8cnBOInPpNE9FCWkWQngZ8iiyHjon1ONrRpKWVYnIm_7dglh-8XCj2A/s1191/gatekeeper.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Result of system modernization and evolution</td></tr></tbody></table><br /><div class="separator" style="clear: both; text-align: center;"><br /></div></div>
<div>By the way, if you didn't notice yet, <i>StoneAssemblies.MassAuth</i> is a <a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/gatekeeper" target="_blank">Gatekeeper</a> implementation. </div>
<div><br /></div>
<div><i>StoneAssemblies.MassAuth</i> is also built on top of powerful and insane extensibility system <a href="https://github.com/stoneassemblies/StoneAssemblies.Extensibility" target="_blank"><i>StoneAssemblies.Extensibility</i></a>. So, basically, all authorization rules can be provisioned as plugins for the authorization engine, but that's part of another story. I will
tell you more about this in the future.</div>
<div><br /></div>
<h2>Send us your feedback</h2>
<div>
<div>This is a work in progress and we are continuously releasing new versions. Sources and sample codes,
are available in <a href="https://github.com/stoneassemblies/StoneAssemblies.MassAuth" target="_blank">GitHub</a> including some <a href="https://github.com/stoneassemblies/StoneAssemblies.MassAuth.Benchmarks">Benchmarks</a>. Packages
as usual, are available in <a href="https://www.nuget.org/packages?q=stoneassemblies" target="_blank">NuGet</a> gallery and we also provide production-ready
of <i>StoneAssemblies.MassAuth.Server (</i>a.k.a. authorization engine<i>)</i> as docker image
available in <a href="https://hub.docker.com/r/stoneassemblies/massauth-server">DockerHub</a>.
</div>
<div><br /></div>
<div>Without too much to say, I just invite you to use <i>StoneAssemblies.MassAuth</i> and let me know what you think. You can also look forward to the next post where I will explain how to use
<i>StoneAssemblies.MassAuth</i> from a quick start.</div>
<div><br /></div>
<div>Remember, this is an open-source project, so, you are welcome to contribute. There are a lot of work to do, so
you can contribute by creating tickets, with pull requests, or just by inviting me to a <a href="https://paynest.app/alexfdezsauco">coffee</a> ;)</div>
<div><br /></div>
<div>
<div>Enjoy «authorizing» with pleasure.</div>
</div>
</div>
</div>Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com1Havana, Cuba23.1135925 -82.3665956-8.1571350848989184 -117.5228456 54.384320084898917 -47.2103456tag:blogger.com,1999:blog-9155852904520845376.post-83232535295123464362020-09-26T20:24:00.069-04:002021-09-15T21:02:47.392-04:00Stressless in the new jungleThis is my personal journey buying in <a href="https://www.tuenvio.cu/" rel="nofollow" target="_blank">TuEnvio</a>. <div><br /></div><h3 style="text-align: left;">What is TuEnvio?</h3><div style="text-align: justify;">Described by <a href="http://www.cimex.cu/" target="_blank">CIMEX</a> itself, TuEnvio is an “E-Commerce platform created by the CIMEX corporation for the national customer, which allows online purchases from the comfort of your home”. </div><div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">But you may wonder: Why is this new? The fact is that the expansion of Internet access in Cuba is actually a new phenomenon. From almost zero, without infrastructure, in a couple of years, Internet access for many Cubans is almost a reality. Right, it is very expensive thanks to <a href="http://www.etecsa.cu/" rel="nofollow" target="_blank">ETECSA</a>, but it continues to expand, which is good.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">Since Cubans had no internet access, “no one” worried about selling products online. At least, not for Cubans that live in Cuba. Therefore, they “invented” a service called <a href="https://www.envioscuba.ca/en/" rel="nofollow" target="_blank">EnviosCuba</a> for foreign families could buy products for their national’s relatives. A kind of favor-based business model, which is very sad. An approach to only capture foreign currency instead also think in the prosperity and comfort of Cubans that live in Cuba.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">But the <a href="https://en.wikipedia.org/wiki/Severe_acute_respiratory_syndrome_coronavirus_2" target="_blank">SARS-Cov-2</a> arrived. They would be forced to launch a service on a scale for which they were neither technologically nor logistically prepared. Its name <b>TuEnvio</b>.</div></div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1IcuhptQi9DSZdy7MOyZ9KwaP5XczN0OsGujG_jecQb7FShT33y7F3Jye_Ws1ZgsmQGZrdSBnOn0JQD96a61DJPL0MjloJGpHSQnzGxd8_P4rXFCE-aC2hu0jm3zYitfKqX2YPSuUX20/s1290/TuEnvio.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="810" data-original-width="1290" height="402" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1IcuhptQi9DSZdy7MOyZ9KwaP5XczN0OsGujG_jecQb7FShT33y7F3Jye_Ws1ZgsmQGZrdSBnOn0JQD96a61DJPL0MjloJGpHSQnzGxd8_P4rXFCE-aC2hu0jm3zYitfKqX2YPSuUX20/w640-h402/TuEnvio.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><h3 style="text-align: justify;">The new jungle</h3><div><div style="text-align: justify;">TuEnvio looked promising. Several instances of the store, distributed in some physical stores, showed its “stock” online. Users were able to navigate, search and buy. But somewhat was not right. Buying what you needed wasn't exactly that easy. Eventually, you could catch a thing but the stress began to increase. As a vigilante, to buy a high demanded product, you had to stay up late at night.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">TuEnvio doesn't have a native notification system, so I started implementing something to help me stay tuned. I was at home (remember COVID19), I was bored, but most importantly I had to buy.</div></div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">That was the birth of <a href="https://github.com/alexfdezsauco/YourShipping.Monitor">YourShipping.Monitor</a> as a project. </div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs-biYNm1B9mNRq2rWVu6H7QtyvcXzVanEO8m9FlfrI-wkMyYjwZ5Ubua_0sFHvLySaH-zHdQK1CWwZLmxhixCjdPnD4qqjdGe3qhFsMbAk0-77qvIYjs1Hk_EKQlUI0AoAkuePtkoCoM/s1882/YSM.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="890" data-original-width="1882" height="302" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs-biYNm1B9mNRq2rWVu6H7QtyvcXzVanEO8m9FlfrI-wkMyYjwZ5Ubua_0sFHvLySaH-zHdQK1CWwZLmxhixCjdPnD4qqjdGe3qhFsMbAk0-77qvIYjs1Hk_EKQlUI0AoAkuePtkoCoM/w640-h302/YSM.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div>The first step was implementing a basic scraping system to be notified of the availability of products, including some searches by keywords. To improve the notification system, I also implemented a personal <a href="https://core.telegram.org/bots" target="_blank">Telegram Bot</a>, that also allows me some basic interactions.</div><div>
<blockquote class="twitter-tweet"><p dir="ltr" lang="en"><a href="https://twitter.com/cimex_cuba?ref_src=twsrc%5Etfw">@cimex_cuba</a> <a href="https://twitter.com/hashtag/TuEnvio?src=hash&ref_src=twsrc%5Etfw">#TuEnvio</a> <a href="https://twitter.com/hashtag/Telegram?src=hash&ref_src=twsrc%5Etfw">#Telegram</a> <a href="https://twitter.com/hashtag/Bot?src=hash&ref_src=twsrc%5Etfw">#Bot</a> <a href="https://twitter.com/hashtag/Demo?src=hash&ref_src=twsrc%5Etfw">#Demo</a> 😉<br /><br />/search agua <a href="https://t.co/3fTR2z3hIp">pic.twitter.com/3fTR2z3hIp</a></p>— Alexánder Fernández (@alexfdezsaucoCU) <a href="https://twitter.com/alexfdezsaucoCU/status/1266963015850696704?ref_src=twsrc%5Etfw">May 31, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
</div><div><br /></div><div style="text-align: justify;">So, the idea was to create an application similar to <a href="https://camelcamelcamel.com/" rel="nofollow" target="_blank">CamelCamelCamel</a> with target TuEnvio. But everything would change when <a href="http://www.vanguardia.cu/opinion-de-periodistas/17737-la-nueva-jungla" target="_blank">The new jungle</a> arises. </div><div style="text-align: justify;"><br /></div><h3 style="text-align: justify;">Shoot first, ask later</h3><div style="text-align: justify;">The best description of the situation was published in this video. A "parodied" scene from <a href="https://www.imdb.com/title/tt0898266/" target="_blank">The Big Bang Theory</a> television series. By the way, to understand what is happening you need to read the subtitles in Spanish ;). I'm not sure who the original author is. But it rocks. If you know him, please just let me know to update this post.</div><div style="text-align: justify;"><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dx_QWiJeKrVDX876Gdz4ypg67gM2dCgkfFc35-bMa1AJAEYyne7gX5qfKZD-IUGaJzb4COms-EOlMFDuTDHGw' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div><br /><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><div>It turns out that shopping at TuEnvio wasn't too easy. Only a few viewed the products because they accessed them at the right time. Links leak?</div><div><br /></div><div>On the other hand, the workload generated by the simultaneous access of thousands of people was handled by <a href="http://www.datacimex.cu/">DATACIMEX</a>'s developers with an incorrect caching approach. If someone doesn't see a product at the right time, should wait for the cache to be invalidated within the next 3 minutes.</div><div><br /></div><div>This, combined with the limited offer, meaning that the majority of TuEnvio's users were unable to purchase a thing. Worse still, they didn't even see a single product.</div></div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">Under these circumstances YourShipping.Monitor's goals changed. I needed the notifications. But actually, I needed to interact with the store in light speed mode to add products to the shopping cart. </div><div style="text-align: justify;"> </div><div style="text-align: justify;">I almost forget that this is also a technical post. So, here we go.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><h3>Parallel web scraping</h3><div><div>YourShipping.Monitor is being implemented using the <a href="https://dotnet.microsoft.com/learn/aspnet/what-is-aspnet-core" target="_blank">NetCore</a> full stack including the frontend with <a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor">Blazor</a>. It allows me to track stores, departments, and products from its uniform resource locator (URL). The user must enter the link and a background process extracts the information and also tries to interact with the options of the store with a single rule: add a product to the cart at first sight. </div><div><br /></div><div>But what if I'm looking to the wrong department? What if one product is available in the very same second as another. This is why it was important to send as many requests as possible at the same time. Using the asynchronous capabilities of C# in combination with <a href="https://github.com/Dasync/AsyncEnumerable" target="_blank">AsyncEnumerable</a> library, I was able to do it, just like this. </div></div><div><h3><br /></h3><div><script src="https://gist.github.com/alexfdezsauco/3b6a22b93beb91adc68059bf6d01bd0e.js"></script></div><div><br /></div><div>But it wasn't just me. A community of Cuban developers launched several applications to help people to buy. Even when such applications required user interaction, the workload affected the store's servers a lot. So, CIMEX responded with an anti-scraping approach.</div><div><br /></div><h3>Fighting against the anti-scraping system</h3></div><div><h3><span style="font-size: small;"><span style="font-weight: 400;">One day the scraper stopped working. All requests were redirected to a page to execute this JavaScript code.</span></span></h3><div><span style="font-size: small;"><span style="font-weight: 400;"><br /></span></span></div>
<div><script src="https://gist.github.com/alexfdezsauco/0ff7cde1f73cf8df01a37bb28951d6c5.js"></script></div>
<div><span style="font-size: small;"><span style="font-weight: 400;"><br /></span></span></div><h3><span style="font-size: small;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; font-weight: 400; text-align: justify;"><span>It could be easy to figure out what is happening. They expect a cookie, with a value generated in that JavaScript. I'm already using </span><a href="https://anglesharp.github.io/" target="_blank">AngleSharp</a><span> to explore the DOM elements. It might be possible to evaluate such a function, to acquire the value of the cookie, using the same library? The answer is yes. AngleSharp.Js is an experimental extension that allows you to run simple JavaScript functions. So, after capturing the parameters with regex, I was able to call the function to capture the cookie value as well.</span></div></div></div></span></h3><div><br /></div><div><script src="https://gist.github.com/alexfdezsauco/7935045536e7df3d4b32a0d8bf0b2b2a.js"></script></div><h3>Moving to unattended mode </h3><h3><span style="font-size: small;"><span style="font-weight: 400;">At this point, I was creating the session with the browser, saving the <a href="https://chrome.google.com/webstore/detail/cookiestxt/njabckikapfpffapmjgojcnbfjonfjfg" target="_blank">cookies.txt</a> file, and making it available to the scraping server (a.k.a. YourShipping.Monitor.Server). The main reason, the captcha. But TuEnvio's captcha looks like this.</span></span></h3><div><span style="font-size: small;"><span style="font-weight: 400;"><br /></span></span></div><h3><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTqZO24AZFPEzDRJ9LgpNFo6le70Am9pjUD3pg22F4mb2hchpjntMFSRQKYRrr6W25rUNoWM51VUuTeyRVXzlvnuJg9WflutJlq-MLIM0CXlm-h5l7ozCSFfoTOj8iutE4Ts1f_43_pGE/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="31" data-original-width="140" height="89" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTqZO24AZFPEzDRJ9LgpNFo6le70Am9pjUD3pg22F4mb2hchpjntMFSRQKYRrr6W25rUNoWM51VUuTeyRVXzlvnuJg9WflutJlq-MLIM0CXlm-h5l7ozCSFfoTOj8iutE4Ts1f_43_pGE/w400-h89/6VH8E.jpg" width="400" /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /></a></div></h3><h3><span style="font-size: small;"><span style="font-weight: 400;">Actually, it doesn't look like a very hard captcha. Nothing that has not been broken before with <a href="https://github.com/tesseract-ocr">tesseract-ocr</a>. So, just added the reference to a .NET <a href="https://github.com/charlesw/tesseract/" target="_blank">wrapper</a> of tesseract and wrote down this</span></span></h3><div><span style="font-size: small;"><span style="font-weight: 400;"><br /></span></span></div><div><script src="https://gist.github.com/alexfdezsauco/6c734074d077c505d4971b0bffc6b44c.js"></script></div><div>and you know what? It worked.</div><div><br /></div><h3>Final thoughts </h3></div><div><h3><span style="font-size: small;"><span><span style="font-weight: 400;">I know, this doesn't seem a bit stressful, but yeah, now it is. With </span><span style="font-weight: normal;">YourShipping.Monitor</span><span style="font-weight: 400;"> and a bit of luck, I have been able to capture something in TuEnvio's stores. There is no guarantee, so I always insist that ETECSA should not charge for access to virtual stores. Someone can spend more money trying to buy than buying.</span></span></span></h3><div><span style="font-size: small;"><span><span style="font-weight: 400;"><br /></span></span></span></div><div><span style="font-size: small;"><span style="font-weight: 400;">Recently, CIMEX released the store's opening schedule. So now, with the effective combination of my command-line tool </span></span><a href="https://github.com/alexfdezsauco/Nothing.Nauta" target="_blank">nauta-session</a>, <span style="font-size: small;"><span>to manage <a href="http://www.etecsa.cu/internet_conectividad/internet/#nauta_hogar">Nauta Hogar</a> sessions, </span></span><span>I can already go to sleep, stressless </span>😉.</div></div><div><blockquote class="twitter-tweet" data-conversation="none"><p dir="ltr" lang="es">Me cuadró. Ya me puedo acostar a dormir 😉. <a href="https://t.co/Xe1UwFYnPC">pic.twitter.com/Xe1UwFYnPC</a></p>— Alexánder Fernández (@alexfdezsaucoCU) <a href="https://twitter.com/alexfdezsaucoCU/status/1309565616295219201?ref_src=twsrc%5Etfw">September 25, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script></div></div><div><br /></div>Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com6tag:blogger.com,1999:blog-9155852904520845376.post-34206163259242581752020-01-07T23:54:00.001-05:002020-10-01T09:28:32.782-04:00Getting started with Blorc.PatternFly<div style="text-align: right;">
<i>Original Published on <a href="https://medium.com/patternfly/getting-started-with-blorc-patternfly-tutorial-cc71fed4bef6" target="_blank">PatternFly Medium Publication</a></i></div>
<div style="text-align: right;">
<br /></div>
<div style="text-align: center;">
<img src="https://miro.medium.com/max/558/1*9V18BNri35XiwnRhNrMz-Q.png" /></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: justify;">
If you’re a developer who loves hands-on tactical tutorials, then read on. Today, we’re covering Blorc.PatternFly.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
First off, the basics: What is Blorc.PatternFly? Standing for <a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor">Blazor</a>, <a href="https://opensource.wildgums.com/">Orc</a>, and <a href="https://www.patternfly.org/v4/">PatternFly</a>, Blorc.PatternFly is a library with the ultimate goal of wrapping all PatternFly components and making them available as Blazor components.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now let’s jump into a tutorial. Keep in mind that this tutorial isn’t meant as an overview of Blazor — you’ll need some basic knowledge of Blazor before diving in.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
You’ll also need to have these tools handy:</div>
<ul>
<li style="text-align: justify;">Visual Studio 2019 (16.4.2)</li>
<li style="text-align: justify;">Blazor (3.1.0-preview4.19579.2)</li>
</ul>
<br />
<h2 style="text-align: justify;">
Step 1: Creating the project</h2>
<div style="text-align: justify;">
<div>
First, go through the <a href="https://docs.microsoft.com/en-us/aspnet/core/blazor/get-started?view=aspnetcore-3.1&tabs=visual-studio" target="_blank">Get started with ASP.NET Core Blazor tutorial</a> for Blazor WebAssembly experience. You’ll create the Blazor project in this tutorial, and you’ll only have to convert the Bootstrap to PatternFly. For the purpose of this guide, use <b>Blorc.PatternFly.QuickStart</b> as the project name.</div>
<div>
<br /></div>
<div>
Follow the on-screen instructions of the Visual Studio project:</div>
<div>
<br /></div>
<div>
Create a new project.</div>
<div>
<img height="425" src="https://miro.medium.com/max/1440/1*uGdrCfoaad-fCzCl88mChg.png" width="640" /></div>
<div>
<br /></div>
<div>
Configure your new project.</div>
<div>
<img height="425" src="https://miro.medium.com/max/1440/1*1WteQF4NJZZ5c9vlMzE8lw.png" width="640" /></div>
<div>
<br /></div>
<div>
Create a new Blazor app with Blazor WebAssembly experience.</div>
<div>
<img height="444" src="https://miro.medium.com/max/1440/1*OrSJU1VgzR1ij19BZJBNxA.png" width="640" /></div>
<div>
<br />
The Blazor template is built on top of <a href="https://getbootstrap.com/" target="_blank">Bootstrap</a>. So the resulting app looks like this:</div>
<div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td><img height="150" src="https://miro.medium.com/max/2156/1*TGAKHv7Utk-diitcMnv1YQ.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr>
<tr><td class="tr-caption">Index.razor and SurveyPrompt.razor</td></tr>
</tbody></table>
</div>
<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;"><img height="123" src="https://miro.medium.com/max/2145/1*bKz7TuBYGedgkyWI2DjhSg.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Counter.razor</td></tr>
</tbody></table>
</div>
<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;"><img height="194" src="https://miro.medium.com/max/2141/1*Nz9ZTr2cNpvKegmj6RQmsQ.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">FetchData.razor</td></tr>
</tbody></table>
From here, you’ll replace the Bootstrap look and feel with the PatternFly one.
<br />
<br />
<h2>
Step 2: Startup configuration</h2>
<div style="text-align: justify;">
Once the project has been created, add <b>Blorc.PatternFly</b> as a package reference via NuGet. At the time of writing this article (which I hope you’re enjoying!), this package is only available as prerelease. To install the latest prerelease version, check the <b>Include prerelease</b> option in the <b>Package Manager</b>.</div>
<div style="text-align: justify;">
<br /></div>
<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;"><img height="431" src="https://miro.medium.com/max/1468/1*rGy94hHv9TmQ_Zg3SWRefw.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Adding latest prerelease of Blorc.PatternFly package</td></tr>
</tbody></table>
<div style="text-align: justify;">
Also, it’s mandatory to register the <b>Blorc.Core</b> services in the <b>ConfigureServices</b> method of the <b>Startup</b> class, shown below:</div>
<div style="text-align: justify;">
<br /></div>
<script src="https://gist.github.com/alexfdezsauco/979a6760659d1dab2ce1007c8e3d1ef4.js"></script>
<br />
<div style="text-align: justify;">
Once the Blorc services are registered, it’s time to start replacing the UI elements, starting with the content of the <b>index.html</b> and <b>site.css</b> files.</div>
<div style="text-align: justify;">
<br /></div>
<script src="https://gist.github.com/alexfdezsauco/ac843a6498d66f037463b81f6840360c.js"></script>
<script src="https://gist.github.com/alexfdezsauco/8b2075d55c5a12c7840af56248ddb8d1.js"></script>
<br />
<div style="text-align: justify;">
To make sure that no unused dependencies are being deployed, remove the <b>bootstrap </b>and <b>open-iconic</b> directories from the <b>wwwroot/css</b> directory.<br />
<br />
<h2>
Step 3: Updating pages and components</h2>
The time has come to update the components. You should be able to update the content of the razor files with references to the available <b>Blorc.PatternFly</b> components.<br />
<br />
You can do this yourself by following the steps below or you can clone the repository with the <a href="https://github.com/alexfdezsauco/Blorc.PatternFly.QuickStart" target="_blank">source code of this tutorial</a>.<br />
<br />
For instance, the <b>MainLayout</b> component must inherit from <b>PatternFlyLayoutComponentBase</b>, and you can use the <b>Page</b> component as follows:<br />
<br />
<script src="https://gist.github.com/alexfdezsauco/9715febfbbc441698a56581a48de6d80.js"></script>
For the <b>NavMenu</b>, you could use the <b>Navigation</b> component and update the razor file as shown below:
<br />
<br />
<script src="https://gist.github.com/alexfdezsauco/79ecacee09395bd3a42c073d6aabb613.js"></script>
Finally, update the content of the <b>Counter</b> and <b>FetchData</b> pages.
<br />
<br />
<script src="https://gist.github.com/alexfdezsauco/328b457d26b93da778f82898db18ec3d.js"></script>
<script src="https://gist.github.com/alexfdezsauco/5c70a416c61b405d03f9098772d7bf72.js"></script>
<br />
And that’s it! Great work. Your application should now look like the screenshots below:
<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;"><img height="168" src="https://miro.medium.com/max/2158/1*r7E63S_wD9H7vSOo5aK7_A.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Index.razor and SurveyPrompt.razor</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;"><img height="180" src="https://miro.medium.com/max/2159/1*guYexfTBXznHhiHRLStngQ.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Counter.razor</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;"><img height="273" src="https://miro.medium.com/max/2158/1*703nnQ-dtTJWr-x9abp58A.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">FetchData.razor</td></tr>
</tbody></table>
<br />
<h2>
Send us your feedback</h2>
Keep in mind that the library is a work in progress, and there are still a few PatternFly components being implemented. We are continuously releasing new versions. The good news is that <a href="https://github.com/WildGums/Blorc.PatternFly">Blorc.PatternFly</a> is open source, and the sources are available on GitHub.<br />
<br />
If you would like support for any new component, contribute to the Blorc.PatternFly library on GitHub. You can get in touch by:<br />
<ul>
<li>Creating tickets.</li>
<li>Contributing by pull requests.</li>
<li>Contributing via Open Collective.</li>
</ul>
<br />
Finally, if you want to see the latest develop branch of Blorc.PatternFly in action, you can browse to <a href="http://blorc-patternfly.wildgums.com/">the live demo</a> with a full overview of all the PatternFly components already available for Blazor. And you’ll probably agree: PatternFly and Blazor are awesome — and combined, they are a beautiful pair.<br />
<br />
<i>Interested in contributing an article to the PatternFly Medium publication? Great! Submit <a href="https://docs.google.com/forms/d/e/1FAIpQLSenoFuNp_GoW9gDxA5s8uklvZuGcYRMpwTfiTc0nXaG3Z3tEQ/viewform?usp=sf_link">your topic idea</a>, and we’ll be in touch.</i></div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-52234047846514746062019-12-16T20:23:00.002-05:002021-09-16T09:14:56.048-04:00How to avoid copying movies that you will never play?<div class="separator" style="clear: both; text-align: center;">
</div>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQwpFqFKeKhi4HU7Z_lUcQCXiwRUAf895NFsnNYCBaIzvq0FAibIKeJrwqXAI4e1PNdRAzu5DzjFYE9ioq7tXF2QlzKZCJvk2Pg9U3A2qIJLHMCHomHv2ABYRxsDVPfX1B7cncPjQlIks/s1600/IMG_20191217_230156.jpg" style="display: none;" />
<br />
<h2>
Introduction</h2>
<div style="text-align: justify;">
This is a kind of odd title for a technical post. But yes, it is a technical post. Actually, doesn't look like a real problem. But yes, it is a real one. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
It turns out that I have a compulsion and obsession to watch movies. It is better to say, to copy and organize movies on my personal storage. But some of those movies will be never played.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Recently, I also noticed that I am running out of space. A well-known approach to solve this situation could be to eliminate all those movies that I never played or all that I really don't like.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But I could also try something else and take some advantage of this situation, something more productive for a Sunday afternoon because at some point I will be in the same position again.</div>
<h2>
<span class="tlid-translation translation" lang="en"><span title=""><br /></span></span></h2>
<h2>
<span class="tlid-translation translation" lang="en"><span title="">The root of all evil</span></span></h2>
<div style="text-align: justify;">
In Cuba, Internet access is very expensive. You can check the prices by yourself on the official website of only one Internet service provider (a.k.a. <a href="http://www.etecsa.cu/" target="_blank">ETECSA</a>). Therefore, regular Cubans don't use <a href="https://www.netflix.com/" target="_blank">Netflix</a>, nor use the Internet to download large multimedia files (at least not from home).<br />
<br />
Such a situation has created a unique business model, that probably only works in Cuba. An offline alternative of media service provider, code name "<a href="http://paquetedecuba.com/" target="_blank">El paquete</a>" (the package).<br />
<br />
I will not give you too many details about this service. All you need to know is that the package distributes a lot of movies every week via USB drives. The media content includes the latest premiers as pirates cinema copies, improved cinema copies, HD copies with Chinese subtitles, Full-HD versions, classics movies, animated movies, a specific actor's cycle, and so on. The package also includes some television programs, series, sports, contests, etc. About 1 TB per week in media files.<br />
<br />
But my personal <a href="https://en.wikipedia.org/wiki/Obsessive%E2%80%93compulsive_disorder" target="_blank">OCD</a> is about movies, and I copy them all. This is not exactly a healthy approach for my very limited personal storage.<br />
<br />
<h2>
Everything gets "worse" when I meet Emby</h2>
<a href="https://emby.media/">Emby</a> is a media server designed to organize, play, and stream audio and video to a variety of devices as you can read <a href="https://en.wikipedia.org/wiki/Emby" target="_blank">here</a>. Therefore, my copy movies routine now includes the download of all movie metadata with the original title, the tag line, poster and backdrop images, the cast, community rating, critical rating, genres, all the information available from sites like <a href="https://www.imdb.com/" target="_blank">IMDb</a> or <a href="https://www.themoviedb.org/?language=en-US" target="_blank">TheMovieDB</a> that is stored in the server database and also in <a href="https://kodi.wiki/view/NFO_files/Movies" target="_blank">nfo</a> local files next to each movie file.<br />
<br />
These metadata enrich the user experience and are displayed when someone browses the media content from a client like <a href="https://emby.media/emby-for-roku.html" target="_blank">Emby for Roku</a> direct from the TV.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio7S2QyBmFcuUyKtQEuX67qWtDZ8I2s4keiFjgAf29zM-sXFQjI4bNLKu9MD3kWibdcYqhKU4qKpahWtBM843Vr3uf9sSUuXBxjVLNe7-8s0vy2yN6cIQ1rlO6SAJtBRlOD_tlfNssdUI/s1600/IMG_20191217_230134.jpg" style="clear: left; float: left; margin-right: 1em;"><img border="0" data-original-height="942" data-original-width="1600" height="116" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio7S2QyBmFcuUyKtQEuX67qWtDZ8I2s4keiFjgAf29zM-sXFQjI4bNLKu9MD3kWibdcYqhKU4qKpahWtBM843Vr3uf9sSUuXBxjVLNe7-8s0vy2yN6cIQ1rlO6SAJtBRlOD_tlfNssdUI/s200/IMG_20191217_230134.jpg" width="200" /></a>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV0Kbn77qWJHlVmgHzEHqIh32sJbaj0CO6nWP1AULfYktP7TIBCyJXW3Bt7MSqwWiybamj6UO8ZR1W9t2TZ_0XT09SUmzOK9G4WEKwO63DgGxShQyq-BByklTT-73GiY9EEiU80Mqz8Eg/s1600/IMG_20191217_230211.jpg" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQwpFqFKeKhi4HU7Z_lUcQCXiwRUAf895NFsnNYCBaIzvq0FAibIKeJrwqXAI4e1PNdRAzu5DzjFYE9ioq7tXF2QlzKZCJvk2Pg9U3A2qIJLHMCHomHv2ABYRxsDVPfX1B7cncPjQlIks/s1600/IMG_20191217_230156.jpg" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="930" data-original-width="1600" height="116" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQwpFqFKeKhi4HU7Z_lUcQCXiwRUAf895NFsnNYCBaIzvq0FAibIKeJrwqXAI4e1PNdRAzu5DzjFYE9ioq7tXF2QlzKZCJvk2Pg9U3A2qIJLHMCHomHv2ABYRxsDVPfX1B7cncPjQlIks/s200/IMG_20191217_230156.jpg" width="200" />
</a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV0Kbn77qWJHlVmgHzEHqIh32sJbaj0CO6nWP1AULfYktP7TIBCyJXW3Bt7MSqwWiybamj6UO8ZR1W9t2TZ_0XT09SUmzOK9G4WEKwO63DgGxShQyq-BByklTT-73GiY9EEiU80Mqz8Eg/s1600/IMG_20191217_230211.jpg" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="912" data-original-width="1600" height="113" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV0Kbn77qWJHlVmgHzEHqIh32sJbaj0CO6nWP1AULfYktP7TIBCyJXW3Bt7MSqwWiybamj6UO8ZR1W9t2TZ_0XT09SUmzOK9G4WEKwO63DgGxShQyq-BByklTT-73GiY9EEiU80Mqz8Eg/s200/IMG_20191217_230211.jpg" width="200" /></a>
</div>
<div>
<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/AVvXsEhQwpFqFKeKhi4HU7Z_lUcQCXiwRUAf895NFsnNYCBaIzvq0FAibIKeJrwqXAI4e1PNdRAzu5DzjFYE9ioq7tXF2QlzKZCJvk2Pg9U3A2qIJLHMCHomHv2ABYRxsDVPfX1B7cncPjQlIks/s1600/IMG_20191217_230156.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="930" data-original-width="1600" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQwpFqFKeKhi4HU7Z_lUcQCXiwRUAf895NFsnNYCBaIzvq0FAibIKeJrwqXAI4e1PNdRAzu5DzjFYE9ioq7tXF2QlzKZCJvk2Pg9U3A2qIJLHMCHomHv2ABYRxsDVPfX1B7cncPjQlIks/s400/IMG_20191217_230156.jpg" width="400" /></a></td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;"><span style="font-size: small; text-align: start;">Spider-Man: Into the Spider-Verse (Emby for
Roku)</span></td>
</tr>
</tbody>
</table>
</div>
<br />
As you can also notice in the picture above, Emby also tracks the movies that I already played. Wait a second. That looks like a perfect ground truth to be used to solve a <a href="https://en.wikipedia.org/wiki/Statistical_classification" target="_blank">classification</a> problem.<br />
<br />
<h2>
Deep learning to the rescue</h2>
Sundays are good days to spend time with the family and watch movies. But, I couldn't find the right one yesterday. I'm also near to zero space for the next release of the package.<br />
<br />
So, I just needed to try something deep ;). Something that could work as a long-term approach.<br />
<br />
Yes, I know. I haven't written too much on this blog for a while. But remember I'm training <a href="https://likewastoldtome.blogspot.com/2018/07/introducing-myself-into-deep-learning.html">Alexa</a> every day, and she demands a lot of my time ;). She only left me time to publish <a href="https://link.springer.com/chapter/10.1007/978-3-030-13469-3_28">Computing Anomaly Score Threshold with Autoencoders Pipeline</a> and then I completely forgot to comment about it here. But that will be the subject of the next post (or the next one). So, let's go back to the movies.<br />
<br />
The Emby server has an <a href="https://www.sqlite.org/index.html">SQLite</a> database (library.db). I explored the data all around and extracted all the useful information to solve my problem with a simple join of two tables <i>MediaItems</i> and <i>UserDatas</i>. <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/AVvXsEj9ozHeTr2vA7sCASqOXlURb2d3d09buNF8KWWzWkNeI3_9lcra3T9yIXR1B_aM5SjpT41mCcR4ZsHc5JVStscmjzoA-52usWhe1Kl71TdIpxA3d9xLio_0oRlhwc1OjlLGghWoWI0B4fY/s1600/2019-12-16_195253.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="731" data-original-width="1600" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ozHeTr2vA7sCASqOXlURb2d3d09buNF8KWWzWkNeI3_9lcra3T9yIXR1B_aM5SjpT41mCcR4ZsHc5JVStscmjzoA-52usWhe1Kl71TdIpxA3d9xLio_0oRlhwc1OjlLGghWoWI0B4fY/s400/2019-12-16_195253.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Sample of extracted data from Emby database</td></tr>
</tbody></table>
At this point, I <span class="tlid-translation translation" lang="en"><span title="">thought that was good timing to try the </span></span><a href="http://marketplace.visualstudio.com/items?itemName=MLNET.07">ML.NET Model Builder (Preview)</a> but the extension size is about 150 MB. Too large for a Sunday at home. The .NET solution to this problem has to wait until I finish writing this post, or maybe the next weekend.
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<a href="https://deeplearning4j.org/">Deeplearning4j</a> (DL4J) is already cached on my local <a href="https://www.sonatype.com/product-nexus-repository" target="_blank">nexus</a>. So, here we go.<br />
<br /></div>
<div style="text-align: justify;">
<h2>
</h2>
<h2>
Let's do this straightforward</h2>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
There is enough documentation about DL4J, even a book <a href="https://www.amazon.com/Deep-Learning-Practitioners-Josh-Patterson/dp/1491914254" target="_blank">Deep Learning: A Practitioner's Approach</a>. So, this will be fast. I will try don't repeat any step available online, but probably you notice some resemblance with the excellent <a href="https://twitter.com/dot_treo?lang=en" target="_blank">Paul Dubs</a> quick-start <a href="https://www.dubs.tech/guides/quickstart-with-dl4j/" target="_blank">tutorial</a>, since this, is exactly a classification problem.</div>
<br />
<div style="text-align: justify;">
Yes, if you didn't notice yet. This is a classification problem and is a quite simple one. <span style="text-align: center;">I have to predict if I will play a movie from the following features</span><i style="text-align: center;">: </i><span style="text-align: center;"><i>Official Rating</i>, <i>Community Rating</i>, <i>Critic Rating, and </i><i>Genres</i> in correlation with my own playback action.</span></div>
<br />
First, I split the existing data. I created the training data set with 80% and the evaluation data set with 20% from the full data set. I stored the local analysis of the full data set to normalize each one using the same analysis.<br />
<br />
Then I transformed the data using DataVect as follow:<br />
<br />
<script src="https://gist.github.com/alexfdezsauco/950f7fe2096e343ba99a6159f204e24b.js"></script><br />
Followed by this network configuration:<br />
<br /></div>
<script src="https://gist.github.com/alexfdezsauco/ea10164ade7ab81bb124d379ee899421.js"></script><br />
Finally, I set up the early stopping trainer to save the best model: <br />
<br />
<script src="https://gist.github.com/alexfdezsauco/3b891a03fe0c50b6baf2df2c0217bdc0.js"></script><br />
<h2>
<span style="font-size: small; font-weight: 400;">And done.</span></h2>
<div>
<span style="font-size: small; font-weight: 400;"><br /></span></div>
<h2>
The results</h2>
Well, the results are quite impressive and also suspect. <span style="text-align: justify;">But there is no problem at all. </span>The network <span class="tlid-translation translation" lang="en"><span title="">perfectly</span></span> isolates the movies that I already played on the evaluation data set.<br />
<br />
<script src="https://gist.github.com/alexfdezsauco/ef6bcbbfd67044587d90bdf2c56c76eb.js"></script>
<script src="https://gist.github.com/alexfdezsauco/131c1dff829631827580c6eaa32e0edd.js"></script>
<br />
<div style="text-align: justify;">
<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/AVvXsEgMKkRYfu6FyWhyEXRgPYejM5SeJzdUXCP9RP_k8GATLKujc8mARlqkDc-wjoYUDeCS_B2LCKR0Q_19xu6FE5J524Lit7hyphenhyphenrc4auPk2nl0efsTs2XKhGVZNJrXf30W91yIAHAlK0qL9ugc/s1600/Evaluation.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="523" data-original-width="1600" height="130" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMKkRYfu6FyWhyEXRgPYejM5SeJzdUXCP9RP_k8GATLKujc8mARlqkDc-wjoYUDeCS_B2LCKR0Q_19xu6FE5J524Lit7hyphenhyphenrc4auPk2nl0efsTs2XKhGVZNJrXf30W91yIAHAlK0qL9ugc/s400/Evaluation.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="font-size: 10.4px;">Played movies from the evaluation data set.</td></tr>
</tbody></table>
Now, I'm ready for the next release of the package. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Wait a second. I just remember, that I have an isolated copy of the last week's package with 58 movies in the inbox and already processed by Emby. After running the prediction program, the assistant neural network (the result of the training process) recommends that I copy only 7 movies. Yes, I can deal with that.<br />
<br /></div>
<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/AVvXsEhWW-seZQ_kUoNoVHLtCIrRSZxi6B1OYmiY26ztymtJhLh9JJ_PbuspcOUHxLFnG08iv9R5W-jrK4IP_aFlbcY9jcgW7TlSMdVV46GMVTV4q3Xap68OCDtkIg8_37-GyEuIaGO-pzXgtfA/s1600/2019-12-16_201952.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="297" data-original-width="690" height="137" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWW-seZQ_kUoNoVHLtCIrRSZxi6B1OYmiY26ztymtJhLh9JJ_PbuspcOUHxLFnG08iv9R5W-jrK4IP_aFlbcY9jcgW7TlSMdVV46GMVTV4q3Xap68OCDtkIg8_37-GyEuIaGO-pzXgtfA/s320/2019-12-16_201952.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Prediction over the last week package</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Not too bad for a Sunday, right? But probably it requires some tuning (or watching more movies). <span class="tlid-translation translation" lang="en"><span title="">I'm not sure that the adversary network (myself) allows ignoring</span></span> <a href="https://www.youtube.com/watch?v=P6AaSMfXHbA" target="_blank">Ad Astra</a>. Or yes? ;)</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/P6AaSMfXHbA" width="560"></iframe></div>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com1Havana, Cuba23.1135925 -82.36659559999998222.646048 -83.012042599999987 23.581137 -81.721148599999978tag:blogger.com,1999:blog-9155852904520845376.post-39928689005572795932018-07-11T14:53:00.004-04:002021-09-16T09:16:53.502-04:00Introducing myself into Deep Learning<h2>
</h2>
<h3>
Overview</h3>
<div style="text-align: justify;">
It has been some time since my last blog <a href="http://likewastoldtome.blogspot.com/2016/01/introducing-sharepoint-package-manager.html" target="_blank">post</a>. Actually, it has been more than two years. The main reason is that something changed in my life when I started to train a neural network. Her name is Alexa.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Just to avoid confusion let me clarify that I am not a member of Amazon Alexa team. Alexa is the female version of my own name and it is the name of my little girl ;)</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
She is one of the reasons for this deep learning journey.</div>
<br />
<h3>
How did the journey begin?</h3>
<div class="MsoNormal" style="text-align: justify;">
Every journey has a motivation and this one is not the exception. It started on September 19 of 2016 when I carried her for the very first time. After saw her for a while I asked myself: How is possible that she can learn something in the future?</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="MsoNormal" style="text-align: justify;">
Months passed, and I saw her learning so fast effortless without too much “computational power” (apparently). She learned to walk, to dance, to almost talk, to solve a puzzle, to play basketball, to solve pyramid-piling rings puzzle, and even to scramble a Rubik’s cube ;)<br />
<br />
<table align="center">
<tbody>
<tr>
<td style="text-align: center;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoIOEnU1ngkdu07lERK_avc5Vk8Vy2FGA9PjdjC5z7SHf5mmV6CqkfswnbmV6EDUQnQvxScUyPIo934Ducb80sIT4rcC5Izs0nBmG3NsSV559Mudy36Wlh-YMplJYXiDAP7LkShfvhUN8/s1600/IMG_20180505_100533.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1600" data-original-width="1200" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoIOEnU1ngkdu07lERK_avc5Vk8Vy2FGA9PjdjC5z7SHf5mmV6CqkfswnbmV6EDUQnQvxScUyPIo934Ducb80sIT4rcC5Izs0nBmG3NsSV559Mudy36Wlh-YMplJYXiDAP7LkShfvhUN8/s200/IMG_20180505_100533.jpg" width="150" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Solving puzzle</td></tr>
</tbody></table>
</td>
<td style="text-align: center;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiWs-3FIfDI1lIkl_gXNFtrm2mB9CxoJQnyg5hxs8Bh0TRWu-EJqBNX_aLU6whBbZLEg637F_00F-7xPla2iCvC_3QAL2YGSJPB9hz5nWrYhJ-QzdmAksm_D5lEIMwEvIgTI-kbNh9Etc/s1600/IMG_20180429_135636.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1600" data-original-width="1200" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiWs-3FIfDI1lIkl_gXNFtrm2mB9CxoJQnyg5hxs8Bh0TRWu-EJqBNX_aLU6whBbZLEg637F_00F-7xPla2iCvC_3QAL2YGSJPB9hz5nWrYhJ-QzdmAksm_D5lEIMwEvIgTI-kbNh9Etc/s200/IMG_20180429_135636.jpg" width="150" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"> Defending vs. Elizabeth</td></tr>
</tbody></table>
</td>
<td style="text-align: center;"><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcrgzz605AR1-UL2PCzXuLEeGvb-5hDqtuhqTRf58O-wlnj5bDBTxbKfx4yob456KkKTaasQstSkULhavtgpCpmcF2AAN3s2Uk42GsicjLl5JAhhK8k85U1_MITFSz71-msWmeTrNAmC4/s1600/IMG_20171023_210317.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1600" data-original-width="1200" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcrgzz605AR1-UL2PCzXuLEeGvb-5hDqtuhqTRf58O-wlnj5bDBTxbKfx4yob456KkKTaasQstSkULhavtgpCpmcF2AAN3s2Uk42GsicjLl5JAhhK8k85U1_MITFSz71-msWmeTrNAmC4/s200/IMG_20171023_210317.jpg" width="150" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Scrambling a Rubik's cube</td></tr>
</tbody></table>
</td>
</tr>
</tbody></table>
Beyond the obvious answers that she will learn by design, there is a lot of trial and error in her learning process. Several attempts to look for the best fit before she can learn something. I love to see her “computing the distance” from the expected result and her attempts at solving the pyramid-piling rings puzzle by removing a wrong ring and replacing it with the right one.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0HKpreZHg7RoIcc4KaYVtpgXfvh3R2aYGExRitcdWvKTJXuk6zJkc4mT1jNI3-Pi9_dvpUvjytCUqEht34JmEMgiyDL-4Eg6TooOHMXA5nnlIMT7iRfm7Kx50kiJO5AB_52evkyqp4m4/s1600/20180317_173332.jpg" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1600" data-original-width="900" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0HKpreZHg7RoIcc4KaYVtpgXfvh3R2aYGExRitcdWvKTJXuk6zJkc4mT1jNI3-Pi9_dvpUvjytCUqEht34JmEMgiyDL-4Eg6TooOHMXA5nnlIMT7iRfm7Kx50kiJO5AB_52evkyqp4m4/s320/20180317_173332.jpg" width="177" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Dad is trying to build something<br />
with blocks but I'm interested<br />
in the neighbor’s dog ;)</td></tr>
</tbody></table>
What really happened is that her learning process motivated me to explore something “new”. A discipline that is called to be (if it is not really is) the new toolset for every single software developer. It turns out that the new hobby came with a practitioner approach but it required to be found first.<br />
<br />
<h3>
What happened next?</h3>
At this point, I started to watch the machine learning course videos of <a href="https://en.wikipedia.org/wiki/Andrew_Ng">Andrew Ng</a> using alternatives sources. Cubans (that live in Cuba) are not able to access the certification program at Coursera. In some way, the USA embargo to Cuba – (specifically the USA exportation laws) – also affects the deep learning global democratization process.<br />
<br />
However, it doesn't worry me too much, actually never does. I can't get the certification but I can get the knowledge. Andrew’s course is actually motivating and didactically insuperable. It was able to bring back to life some math and algebra that I thought was dead in my brain and made me felt very comfortable implementing a vectorized version of the <a href="https://en.wikipedia.org/wiki/Stochastic_gradient_descent">Stochastic Gradient Descent</a> algorithm with <a href="https://www.gnu.org/software/octave/">Octave</a>.<br />
<br />
<blockquote class="twitter-tweet tw-align-center" data-lang="en">
<div dir="ltr" lang="en">
"We apologize for the inconvenience" said a <a href="https://twitter.com/coursera?ref_src=twsrc%5Etfw">@coursera</a> message because also <a href="https://twitter.com/hashtag/block?src=hash&ref_src=twsrc%5Etfw">#block</a> us, <a href="https://t.co/vsmxsoaMop">https://t.co/vsmxsoaMop</a> <a href="https://twitter.com/hashtag/Cuba?src=hash&ref_src=twsrc%5Etfw">#Cuba</a> <a href="https://twitter.com/cubavsbloqueo?ref_src=twsrc%5Etfw">@cubavsbloqueo</a> <a href="https://t.co/4JpDtas3PH">pic.twitter.com/4JpDtas3PH</a></div>
— Alexánder Fernández (@alexfdezsauco) <a href="https://twitter.com/alexfdezsauco/status/895344991333216256?ref_src=twsrc%5Etfw">August 9, 2017</a></blockquote>
<script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
<br />
After understand how this works (almost just like Andrew used to say), and what kind of problems were possible to solve, just I wanted to put this in practice at the production level. Some researchers (friends of mine) sold me <a href="https://www.tensorflow.org/" target="_blank">Tensorflow</a> as the Holy Grail but I had some doubts about Python performance (still have).<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZuIITuzyNSxczNwrqV_TAjtJ5Z20PHRe4OAFytBzu3NOtA-MkqTyFcPE3IkZLwrdm8NTDo97-gHhgjBDi8iwGVKXUKpcINZGTFMjmu7yN1QoEmM-tucxqVBojHfR_qjf8W3Cm8VV36lw/s1600/IMG_20171023_221812.jpg" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1200" data-original-width="1600" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZuIITuzyNSxczNwrqV_TAjtJ5Z20PHRe4OAFytBzu3NOtA-MkqTyFcPE3IkZLwrdm8NTDo97-gHhgjBDi8iwGVKXUKpcINZGTFMjmu7yN1QoEmM-tucxqVBojHfR_qjf8W3Cm8VV36lw/s200/IMG_20171023_221812.jpg" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The new hobby comes with the<br />
practitioner approach</td></tr>
</tbody></table>
After some research, I found exactly what I was looking for. A deep learning library for JVM. <a href="http://deeplearning4j.org/" target="_blank">Deeplearnig4j</a> (DL4j) is an excellent library and comes with this excellent book <a href="https://www.amazon.com/_/dp/1491914254" target="_blank">Deep Learning: A Practitioner's Approach</a> from <a href="https://github.com/agibsonccc">Adam Gibson</a> and <a href="https://github.com/jpatanooga" target="_blank">Josh Patterson</a>. I just needed to read the preface, to identify me as a deep learning practitioner. It wasn't to hard notice that was the right book for me. I'm pretty sure that is also the right book for you.<br />
<br />
DL4j also comes with a lot of helpful features and tools to assist the training process including <a href="https://deeplearning4j.org/visualization" target="_blank">Training UI</a>, <a href="https://deeplearning4j.org/overview#datavec" target="_blank">datavec</a>, <a href="https://deeplearning4j.org/earlystopping" target="_blank">early stopping</a>, even <a href="https://deeplearning4j.org/gpu" target="_blank">GPU</a> support, and more, but we can talk about this in forthcoming posts.<br />
<table align="center"><tbody>
<tr><td style="text-align: center;"><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/AVvXsEj41h9wmIWPjZhPhSGXiKIBb3AEqUZGmQt2MYzRd6B10DCj14lOW0LbJ36XQVIsLt7LuA54YqMjiAmNasCOwlCJudKm0ZNXuqrOC88pzEi9ec_TR3lpof9zyDbwBklPBTy4tJr2AEsjmIg/s1600/Clipboard+-+April+19%252C+2018+9-26+AM.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="463" data-original-width="1119" height="129" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj41h9wmIWPjZhPhSGXiKIBb3AEqUZGmQt2MYzRd6B10DCj14lOW0LbJ36XQVIsLt7LuA54YqMjiAmNasCOwlCJudKm0ZNXuqrOC88pzEi9ec_TR3lpof9zyDbwBklPBTy4tJr2AEsjmIg/s320/Clipboard+-+April+19%252C+2018+9-26+AM.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">DL4J Performance - examples/sec on Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz (No GPU required in this case)</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
</td>
<td style="text-align: center;"><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/AVvXsEgIIhCiVDUT-GkbwiDakKqQO_2MPbN2dnDsRdiaGGJaB0iTqqqEU1uUw524AjhSOIAsqW_f9GL2W9bbt-trt93OGdAM9vqS_I-5hClibX0fSPQtybiwhl7rknXQlEDSu38dmfZrOLUBDR4/s1600/Clipboard+-+May+3%252C+2018+1-54+PM.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="403" data-original-width="906" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIIhCiVDUT-GkbwiDakKqQO_2MPbN2dnDsRdiaGGJaB0iTqqqEU1uUw524AjhSOIAsqW_f9GL2W9bbt-trt93OGdAM9vqS_I-5hClibX0fSPQtybiwhl7rknXQlEDSu38dmfZrOLUBDR4/s320/Clipboard+-+May+3%252C+2018+1-54+PM.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Nice normal distribution shape for weights in the Layer Parameters Histogram (So, no regularization issues)</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
</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/AVvXsEjDor9hyWhzzI9Hw8zhqykxwKkDBYEOvn4kbkl0wVKUTF3FaK1TaIVHB7wh404jT_KJ1aRVz5l6PFQhwhONB4ENkbHdffXMKY9Xb-0pT1m12R0pzFhwYYXVWNnika6_Njw6MlIfr47te3M/s1600/Clipboard+-+April+19%252C+2018+10-17+AM.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="609" data-original-width="1111" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDor9hyWhzzI9Hw8zhqykxwKkDBYEOvn4kbkl0wVKUTF3FaK1TaIVHB7wh404jT_KJ1aRVz5l6PFQhwhONB4ENkbHdffXMKY9Xb-0pT1m12R0pzFhwYYXVWNnika6_Njw6MlIfr47te3M/s320/Clipboard+-+April+19%252C+2018+10-17+AM.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span face=", "blinkmacsystemfont" , "roboto" , "helvetica neue" , "arial" , sans-serif , "apple color emoji" , "segoe ui" , "segoe ui emoji" , "segoe ui symbol" , "meiryo ui"" style="background-color: white; color: #444444; display: inline; float: none; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;">Some network details</span></td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
</div>
Recently, I also started to work in build a proof of concept of an anomaly detection system built on top of DL4j, specifically by using Autoencoder networks with promising results but I can't give you anything in advance yet (just wait for it).<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/AVvXsEgk6M_LLJfIOsagFZoHCdRirWslPMrWE0nwQB9ZXzSxXquhJGQhDx43IpCExss2lI5PrxGl5rX7OmjUHCT8Zd-vWVo0qp8YKEO7Ji8Ef18yCZmozUUVK4t2cVlvOWHH8s9eyqta5e9RbkA/s1600/autoencoders.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="613" data-original-width="828" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk6M_LLJfIOsagFZoHCdRirWslPMrWE0nwQB9ZXzSxXquhJGQhDx43IpCExss2lI5PrxGl5rX7OmjUHCT8Zd-vWVo0qp8YKEO7Ji8Ef18yCZmozUUVK4t2cVlvOWHH8s9eyqta5e9RbkA/s320/autoencoders.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Autoencoders are supported by DL4j</td></tr>
</tbody></table>
<h3>
Conclusions</h3>
<div style="text-align: justify;">
I have a lot to learn about deep learning, but the journey has already begun and I have the intention to share it with you.</div>
<div style="text-align: justify;">
<br /></div>
</div>
<div class="MsoNormal" style="text-align: justify;">
</div>
<div style="text-align: justify;">
Btw, if you are not motivated to go “deep” with machine learning yet, be a father (or mother) first, and then let me know. I'm sure you will find the same "biological" inspiration when you witness how to "train a neural network" looks like ;)</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center">
<tbody>
<tr><td><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/AVvXsEieIzF6uor1FWIKMeJODUjt7MpaoUyqAjDjtEp_IGU6fx_r6UhLAKXGlDjxC1yqjy3UdcxUawijsva6A2Wog1C9Xs3qZyKjldHw5TAiFTLrYvBCdBaFbmSVQP4c2yRtAfQghGMvAv7CIYA/s1600/IMG_20180216_123425.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1200" data-original-width="1600" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieIzF6uor1FWIKMeJODUjt7MpaoUyqAjDjtEp_IGU6fx_r6UhLAKXGlDjxC1yqjy3UdcxUawijsva6A2Wog1C9Xs3qZyKjldHw5TAiFTLrYvBCdBaFbmSVQP4c2yRtAfQghGMvAv7CIYA/s200/IMG_20180216_123425.jpg" width="200" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGfnCWfVyBEsTMyjqFd2y532zA0Fx6LY9-N1zGj78p54j2HQctWhQjLvKkab442XW7EYTJ3R3lhs5efNCOFkXYp55VRovfz2X7uhlzbJKJ64e3AZXghqMrayiYWE_jRK4aBL9Y0Zu03pw/s1600/IMG_20180216_123341.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1200" data-original-width="1600" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGfnCWfVyBEsTMyjqFd2y532zA0Fx6LY9-N1zGj78p54j2HQctWhQjLvKkab442XW7EYTJ3R3lhs5efNCOFkXYp55VRovfz2X7uhlzbJKJ64e3AZXghqMrayiYWE_jRK4aBL9Y0Zu03pw/s200/IMG_20180216_123341.jpg" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Alexa talking with a large predator cat of stone</td></tr>
</tbody></table>
<div class="separator" style="clear: both;">
</div>
</td></tr>
</tbody></table>
<br />Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com5Havana, Cuba23.1135925 -82.36659559999998222.646048 -83.012042599999987 23.581137 -81.721148599999978tag:blogger.com,1999:blog-9155852904520845376.post-55009584426268123002016-01-28T13:27:00.000-05:002016-02-02T12:59:44.220-05:00Introducing SharePoint Package Manager<div style="text-align: justify;">
<h3>
Introduction</h3>
Half a year ago, I announced – in this <a href="http://likewastoldtome.blogspot.com/2015/08/state-machine-approach-to-handle-and.html">post</a> – the forthcoming release of a new secret weapon. I apologize for the delay, but I entertained myself doing other things and I couldn't find a way to spend a couple of days on formulating it.<br />
<br />
I could even tell you: ‘I had no time to do it’, but I learned the lesson – maybe I'm still learning – from my father. He always insisted me: ‘Alex, the time is the same’. So, what actually happened was a matter of time management and prioritization.<br />
<i><br /></i> The true is, I also expected that something like this already exists at this time, but it doesn’t. So, I recalled this, wrote the minimal working code, push the sources and <a href="https://github.com/alexfdezsauco/PackageManager.SharePoint">here</a> it is.<br />
<br />
<br />
<h3>
What is SharePoint Package Manager? </h3>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNTJOMhMJRQ3sFxeRe9zyEKjGWiuHyEaLUUvgiDk3ljlVhrjuLfL-2Hi1Jc-yyEJWooh7Z_rEuugwCfDzdRoWQIpXUfOHzFdcPXtQoZ8col1Z1jdmfzAvp_mbe8i5oCgotljj9c500aIw/s1600/2016-01-29_120155.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNTJOMhMJRQ3sFxeRe9zyEKjGWiuHyEaLUUvgiDk3ljlVhrjuLfL-2Hi1Jc-yyEJWooh7Z_rEuugwCfDzdRoWQIpXUfOHzFdcPXtQoZ8col1Z1jdmfzAvp_mbe8i5oCgotljj9c500aIw/s320/2016-01-29_120155.png" width="280" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">SharePoint Package Manager</td></tr>
</tbody></table>
The SharePoint Package Manager is a NuGet-based distribution and deployment system for SharePoint's solutions.<br />
<br />
Basically, it's an extension of the SharePoint Central Administration site that automates the process for install or update solution packages from package sources (regular NuGet repositories).<br />
<br />
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
Why NuGet?</h3>
Why not? NuGet is the widely accepted and popular package manager among .net developers.<br />
<br />
There are also a lot of custom solutions and initiatives that use NuGet as the backend, for instance, <a href="https://resharper-plugins.jetbrains.com/">ReSharper</a> extension manager, <a href="https://octopus.com/">OctopusDeploy</a>, <a href="https://chocolatey.org/">Chocolatey</a>, <a href="https://github.com/Squirrel">Squirrel</a>, you know, even <a href="http://likewastoldtome.blogspot.com/2013/10/catel-extends-prism-modularity-options.html">Catel extending the modularity options of Prism</a>.<br />
<br />
<br />
There are only a few rules in order to use this package manager, starting with this 'new' concept: solution package.<br />
<br />
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
What is a solution package?</h3>
<div>
A solution package is a regular NuGet package with its name ending in '.wsp' and with following structure:<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/AVvXsEgTyfoBQkxqB4wEUwyQp1yzWnJgAWnLegYFqNqUesXTBnrkP-Xk_b_6PlF_mPY1yyWUhfnws_XHue3pWsqoHP5wi0Nx0FdjyHQHjpqDURHLYZqcqA2on-agdjhNsTMS_BUSv53t7hhCsqI/s1600/2016-01-29_155531.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="154" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTyfoBQkxqB4wEUwyQp1yzWnJgAWnLegYFqNqUesXTBnrkP-Xk_b_6PlF_mPY1yyWUhfnws_XHue3pWsqoHP5wi0Nx0FdjyHQHjpqDURHLYZqcqA2on-agdjhNsTMS_BUSv53t7hhCsqI/s320/2016-01-29_155531.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8000001907349px;">A sample of solution package for SignalR.</span></td></tr>
</tbody></table>
Notice how the folder 'content' contains a <b><i>wsp</i></b> file with the same name of the solution package and that’s it.</div>
<div>
<br />
A solution package can also have declared dependencies, but only between solution packages.<br />
<br />
Maybe the naming convention looks weak, but there is only one package in the gallery with name <i><a href="https://www.nuget.org/packages/Digst.OioIdws.Wsp">Digst.OioIdws.Wsp</a>, </i>so, for me, is enough. Eventually, the package manager could also track non-solution packages through an ignore list.<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/AVvXsEi7tHX-1OKWkEP25H7o49N2Set3DPk8PZwtUtaZujbts6rnniOBtMklsImA3sCqi_8CJXbT1WrU_l_JYe-ryok2Mu5iNPWx6PnuOuxXt88Iy1J27YflAWyRMU0D4_hNtaXGhnsDmIhLdIc/s1600/2016-01-29_122437.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="81" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7tHX-1OKWkEP25H7o49N2Set3DPk8PZwtUtaZujbts6rnniOBtMklsImA3sCqi_8CJXbT1WrU_l_JYe-ryok2Mu5iNPWx6PnuOuxXt88Iy1J27YflAWyRMU0D4_hNtaXGhnsDmIhLdIc/s320/2016-01-29_122437.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i style="font-size: 12.8000001907349px;">Solution packages from NuGet Gallery. The Digst.OioIdws.Wsp isn't a solution package.</i></td></tr>
</tbody></table>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
Managing package sources</h3>
</div>
<div>
The SharePoint Package Manager includes a page to manage the package source. You are able to add, remove, edit, enable or disable a package source.<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/AVvXsEgr061ZuSPEpx6FtYP3J8GQqV1kLarOsTeoztCIQ7km8D7b6dONaoxjoWCZswb-94YF6D5_AR-Lx10AH8t3RllKoe-xhN6EPK3JdFpgmMNvZe2GYeu1GGLn5YPuUI99z8hV8RrY25Hnojo/s1600/2016-01-30_234533.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr061ZuSPEpx6FtYP3J8GQqV1kLarOsTeoztCIQ7km8D7b6dONaoxjoWCZswb-94YF6D5_AR-Lx10AH8t3RllKoe-xhN6EPK3JdFpgmMNvZe2GYeu1GGLn5YPuUI99z8hV8RrY25Hnojo/s320/2016-01-30_234533.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8000001907349px;">Creating a new package source</span></td></tr>
</tbody></table>
<br />
<br /></div>
The default package source is the NuGet Gallery.<br />
<br />
<h3>
Installing or updating solution packages</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<div>
The SharePoint Package Manager also includes a page to manage the farm packages. Looking for the installed solutions in the SharePoint solution storage and making a join with available solution packages from the package sources, the page shows the available solution packages to install or update.<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/AVvXsEjWdp1WXFUVgjDCTaYhuPLd_d34JjOeKhMMwjfbMJSWBWcAnkCxpy9pzZbmB6sIwh67YjPySg7AX7M-9et5EQQgkNTdldQl0XeyK1bL2df4S3eqYEENMUlYWPYdSTx_ByYRy12Mlp2l29o/s1600/2016-01-29_115706.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWdp1WXFUVgjDCTaYhuPLd_d34JjOeKhMMwjfbMJSWBWcAnkCxpy9pzZbmB6sIwh67YjPySg7AX7M-9et5EQQgkNTdldQl0XeyK1bL2df4S3eqYEENMUlYWPYdSTx_ByYRy12Mlp2l29o/s320/2016-01-29_115706.png" width="268" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8000001907349px;">Managing the farm packages</span></td></tr>
</tbody></table>
</div>
<div>
Sorry about the name of the solution package in Spanish on the image above but was client choice and the picture was taken from real life scenario.</div>
<br />
The SharePoint Package Manager provides an option to install or update solution packages. After clicking the button – on the right of the solution package info – the system will schedule a job to install or update the last available version of the selected solution package. If the selected package has dependencies, the package manager will also install or update all dependencies in the right order.<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/AVvXsEh0gUy_ETt-V6e0X07bSllJCyACLBDAkoGR0hCIaUn5NS8aaG6Cst8bdaCH9dMh-mw7TkIdHTgBad8dqKQDvkGyXo18ogdG3KwsqJVBmTI9iVj3xqsg8F4GjhG0fi8fgdsEN7P3gTFt4GQ/s1600/2016-01-30_235341.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="60" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0gUy_ETt-V6e0X07bSllJCyACLBDAkoGR0hCIaUn5NS8aaG6Cst8bdaCH9dMh-mw7TkIdHTgBad8dqKQDvkGyXo18ogdG3KwsqJVBmTI9iVj3xqsg8F4GjhG0fi8fgdsEN7P3gTFt4GQ/s320/2016-01-30_235341.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Tracking the install or update process.</td></tr>
</tbody></table>
<br /></div>
<div style="text-align: justify;">
<div>
<h3>
What's next?</h3>
This is almost a draft or a proof of concept, remember just the minimal working code. So, you can try. I also published the <a href="https://www.nuget.org/packages/SignalR.SharePoint.WSP/">SignalR.SharePoint.WSP</a> solution package at NuGet gallery, so, you should see it as an available solution package.</div>
<div>
<br />
Enjoy it, and let me know what you think. Even better, we can do this together, just fork the source on <a href="https://github.com/alexfdezsauco/PackageManager.SharePoint">GitHub</a>. There are a lot of things to do, including better user interface, REST services, a better approach for settings storage, ignore list, performance issues, msbuild extension, Visual Studio extension, and so on. You tell me.<br />
<br />
In the meantime, I’m already working to turn more Catel’s <a href="https://github.com/Catel/Catel/tree/feature/XamarinForms">rumors</a> in true.<br />
<br />
Talking about rumors, if everything goes right, I might update my resume in about seven months. Yes, your assumption is correct, I'm a father candidate ;).</div>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0Havana, Cuba23.1135925 -82.36659559999998222.646047499999998 -83.012042599999987 23.5811375 -81.721148599999978tag:blogger.com,1999:blog-9155852904520845376.post-37204211198266071312016-01-12T14:51:00.000-05:002016-01-25T11:01:50.154-05:00'The Force Awakens' or How awake the communication channels on a development team?<h3 style="text-align: justify;">
Introduction</h3>
<div style="text-align: justify;">
I’m actually not a follower of the Star Wars saga even when I saw all the seven movies – the last one as a cinema pirate copy – plus some episodes of animated series and also including some TV movies with the Ewoks when I was younger.</div>
<div style="text-align: justify;">
<br /></div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggeOZcRaVKZQl5CxGtLX87Aq-qwEAOk9Kyrnp34XXavAPw2A1bIAedVCJLr0ugk9mpvDPTkTRJNbO9u6Tn0YGY7BKFZhjYgacGZcPUH6zL0hx_l8fPUzjJOyHLSC3g2QUz9O3220dZbvs/s1600/375px-Ewok_SWExhibition.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggeOZcRaVKZQl5CxGtLX87Aq-qwEAOk9Kyrnp34XXavAPw2A1bIAedVCJLr0ugk9mpvDPTkTRJNbO9u6Tn0YGY7BKFZhjYgacGZcPUH6zL0hx_l8fPUzjJOyHLSC3g2QUz9O3220dZbvs/s200/375px-Ewok_SWExhibition.jpg" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">An Ewok</td></tr>
</tbody></table>
<div style="text-align: justify;">
Who didn’t heard the story about Anakin Skywalker? The boy that was trained as Jedi by Obi-Wan Kenobi who eventually was turned – by his trend to the dark side of the force and also influenced by a Sith – into Darth Vader, who also was the father of Luke – the new hope to get the balance of the force – and the princess Leia and so on.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Probably I missed something, some of these movies are too long and actually, some characters make me sick. But the true is that these movies were a turning point in the world of the visual effects.</div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJAdKr1N5l3ZOfVPk-eHQ5I86svyc0WQYc2gRpAWawiXeUXy7b60tWTUBQw3OFB9MKFMg7NW01VpO3MhJJxu_ijEYKCiszZX8nN4qOeZ6qlOJMSjcREmHojtvbSCoVP1jU7mznhziva3w/s1600/star_wars_poster_full.0.0.jpg" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJAdKr1N5l3ZOfVPk-eHQ5I86svyc0WQYc2gRpAWawiXeUXy7b60tWTUBQw3OFB9MKFMg7NW01VpO3MhJJxu_ijEYKCiszZX8nN4qOeZ6qlOJMSjcREmHojtvbSCoVP1jU7mznhziva3w/s320/star_wars_poster_full.0.0.jpg" width="212" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8000001907349px;">Star Wars - The Force Awakens poster</span></td></tr>
</tbody></table>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I won’t talk about the movies but the title of the seven episode “The Force Awakens” inspired me to write a new post. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The concept of the force, such energy field with source even genetic - cell with something call “midi-chlorian” - that empower the <i class="">jedies</i> knights to move objects with his mind, get great reflex and anticipation, and also great skills as pilots, is actually unreal but in some scenarios could reveal its presence. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Let me show you the way you can found an expression of the force as a result of an approach that allow you awake the team communication channel from a hypothetical scenario. </div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Common communication channels</h3>
<div style="text-align: justify;">
On software development teams the communication is a key factor. Not a few agile practice talk about it including informative workspace, release the plan, sit together, pair programming, ubiquitous language or even poker planning. I have no doubt that every single agile practice is about to improve the communication in the team.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
From a real life scenario communication channels could look like this way:</div>
<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/AVvXsEg8A2JovSQ30lLhznA2HRiSYVVHzzCamEZLj-vUBjxliuKPFfRWiw8YIXE4-lp4B-NeA6KDOPU-FfgtrPTLl6c4MXxcNBP_G_9VXyoJzQvXP4trWnaxPTJtQZAPGJzw_VE_xmHKxkvJJBs/s1600/Picture01.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="456" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8A2JovSQ30lLhznA2HRiSYVVHzzCamEZLj-vUBjxliuKPFfRWiw8YIXE4-lp4B-NeA6KDOPU-FfgtrPTLl6c4MXxcNBP_G_9VXyoJzQvXP4trWnaxPTJtQZAPGJzw_VE_xmHKxkvJJBs/s640/Picture01.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Common communication channels</td></tr>
</tbody></table>
<div style="text-align: justify;">
The client tells to the product owner what he wants. The product owner can create a vision of the final product – optionally with a consultant - and share the expected result to the project lead in terms of requirements and also prioritize such requirements. Then project lead and the team should be able to create a roadmap in term of features and small increments to cover all client’s expectation.</div>
<div style="text-align: justify;">
<div>
<br /></div>
<div>
The project lead must share systematically all his knowledge or the vision with the team looking for an effective and integrated solution. Notice that the project lead should be the only communication channel between each developer and the people that really knows what the client wants. </div>
<div>
<br /></div>
<div>
But the world isn’t perfect and the project lead also should be ready to manage the changes on requirements including say <b>NO</b> or defers some requirements. There is a single rule, every single decision must be taken in collective with the team.</div>
<div>
<br /></div>
<div>
Actually, as a developer, I always expect an effective communication system. It could be done through public the iteration plan, plus daily meetings, retrospective, and demos, everything that allow the whole team get an integrated view of the thing that they are building. An informative workspace where they can share the issues or impediments and, of course, enjoy the progress.</div>
<div>
<br /></div>
<div>
Such approach should work and actually does.</div>
<div>
<br /></div>
<div>
But sometimes something happens that drive the team to a complete failure of the communication system.</div>
<div>
<br /></div>
<h3>
Breaking the communication channels</h3>
<div>
Allow me to twist a bit the previous scenario.<br />
<br />
Assume that suddenly the product owner and the external consultant start to manage the team in a very odd way. They do direct tasks and components assignments in private instead thought the project lead. From another side, but not less important the project lead always saying <b>YES </b>to each the product owner request without team consulting. At some point, the product lead also stops to communicate with the team at all, probably just a few emails or comments about some new client expectation, but not in real team dynamics.<br />
<br />
The issue here is about product owner and consultant vision. They don't want to know about small increments. They want the final solution and production ready now. They don't know about the team dynamics or how they manage the source or about components integration. They also expect for some magical entity do the coordination work. But such thing doesn’t exist in software development.<br />
<br />
The result: a completely broken communication system.<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/AVvXsEijJl1SYWdSXWOttw4ckM5qtx-_NFDLeS_Anfh7UzEpy_C8qPkENGd9GnqCEB3K4SnJL7OQhGN4MkKRpA9fGhSDRhfVeGEDTHg1HjdmOsi5CYzAyJsF-uZPu0rB2tF7fKHM1vCcznz6fKo/s1600/Picture02.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="403" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijJl1SYWdSXWOttw4ckM5qtx-_NFDLeS_Anfh7UzEpy_C8qPkENGd9GnqCEB3K4SnJL7OQhGN4MkKRpA9fGhSDRhfVeGEDTHg1HjdmOsi5CYzAyJsF-uZPu0rB2tF7fKHM1vCcznz6fKo/s640/Picture02.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Broken communication channels</td></tr>
</tbody></table>
<div style="text-align: center;">
<br /></div>
</div>
<div>
<h3>
Awaking the communication channels</h3>
</div>
<div>
<div>
Could be spent some time before you really notice the disaster. The bug corrections lead to other incongruousness or to regressions. Even worse, people sitting together can't found a real way to coordinate their work. But something remains immutable, no one talk about the system beyond a few individuals' virtual chatting sessions. </div>
<div>
<br /></div>
<div>
At this point, some practices could save them all. So, also assume that the team have a full dependency in a build automated system (just a build server), and have a well configured a deployment pipeline that run unit and integration tests and also run the deployment routines into quality assurance servers (including product owner's server). </div>
</div>
<div>
<br /></div>
<div>
You as team member could ask yourself: <i>Why don't use this to trigger the communication back?</i></div>
<div>
<br /></div>
<div>
So, you as a team member with integration needs can start to write a lot of integration test. For instance, for each disagreement, for each incongruousness, every assumption, every of non-final decisions, everything that anyone told aloud, you can translate it into an executable code that immediately will run on the build server, and eventually this approach will lead to stopping the deployment pipeline due by the tons of errors.</div>
<div>
<br /></div>
<div>
This is a point when a sort of energy field (a.k.a 'the force') should start to play its role. The product owner needs upgrades. But the upgrades are locked because the deployment pipeline is locked. So, eventually, someone would need to start talking again.<br />
<br /></div>
<div>
<h3>
Conclusion</h3>
</div>
<div>
There aren’t nothing more effective to improve – not only to awake – the communication in your team than the integration tests. That is because coding is actually the communication channel that never dies. Even better if you really use practice like continuous integration you are already empowered – without “midi-chlorian” – to awake you communication channels at any time.<br />
<br /></div>
<div>
By the way, while I´m writing this lines, I noticed that Multivision channel - on Cuba - started to broadcast the saga again. So, if you never saw it, it's a good timing ;)</div>
<div>
<br /></div>
<div style="text-align: center;">
<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/AVvXsEjYNJmhq-oiff6qHUZoqIJFvAy1DN8w-D8YUgwviZ0phwI9j-DjahM13mcEka6g1FJsl28zSaRRyCwWdb7u1a4sC8RYx8f2f3Qp9q4JCBZ5tO2M5bBnFU1ljQujK0Dn45FnOn3GuSxbMyE/s1600/Picture04.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYNJmhq-oiff6qHUZoqIJFvAy1DN8w-D8YUgwviZ0phwI9j-DjahM13mcEka6g1FJsl28zSaRRyCwWdb7u1a4sC8RYx8f2f3Qp9q4JCBZ5tO2M5bBnFU1ljQujK0Dn45FnOn3GuSxbMyE/s320/Picture04.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Star Wars Episode I: The Phantom Menace at Multivision</td></tr>
</tbody></table>
<i></i></div>
<div>
<br /></div>
<div>
<i>Remember: Your focus determines your reality. </i><br />
<i>May the force be with you.</i></div>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com1Havana, Cuba23.1135925 -82.36659559999998222.646048 -83.012042599999987 23.581137 -81.721148599999978tag:blogger.com,1999:blog-9155852904520845376.post-20908578170950742552015-08-13T16:03:00.000-04:002016-08-05T10:05:09.121-04:00Simplest way to implement a state machine approach for SharePoint list items<h3>
Introduction</h3>
<div>
<div style="text-align: justify;">
As you can read in <a href="https://en.wikipedia.org/wiki/Finite-state_machine">Wikipedia</a> “<i>A finite-state machine (FSM) or finite-state automaton (plural: automata), or simply a state machine, is a mathematical model of computation used to design both computer programs and sequential logic circuits. It is conceived as an abstract machine that can be in one of a finite number of states. The machine is in only one state at a time; the state it is in at any given time is called the current state. It can change from one state to another when initiated by a triggering event or condition; this is called a transition. A particular FSM is defined by a list of its states, and the triggering condition for each transition.</i>”</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
SharePoint developers frequently face to state machine problems and the typical solution includes a workflow implementation. Actually, SharePoint includes default workflows for common scenarios, for instance Approval (route a document or item for approval or rejection), Collect Feedback (route a document or item for feedback), Collect Signatures (route a document, workbook, or form for digital signatures), Three-State (track an issue, project, or task through three states or phases) and Publishing Approval (automate content routing for review and approval) workflows.</div>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But sometimes such workflows doesn’t fit exactly to your scenario or worse, the workflow usage is just an overkill.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Next, I’ll introduce you a clean state machine (also personal) approach to handling state transitions of SharePoint list items without workflows.</div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
Event receivers as workflows alternative</h3>
<div>
<div>
<div style="text-align: justify;">
As you should suppose the only way implement this is by using event receivers (a.k.a. event handlers) instead workflows. But how make a clean solution event handler based to implement a state machine. </div>
</div>
<div>
<br /></div>
<div>
Allow me show you how the final code looks like for a customized publication process based on this approach:</div>
</div>
<div>
<br /></div>
<div>
<pre class="brush: csharp">[StateMachine("State", typeof(PublicationRequestStateMachineValidator))]
public sealed class PublicationRequestStateMachineItemEventReceiver : StateMachineItemEventReceiverBase
{
[State("Approved")]
private void OnApproved(SPItemEventProperties properties)
{
/*...*/
}
[State("Rejected")]
private void OnRejected(SPItemEventProperties properties)
{
/*...*/
}
[State("ReadyToBePublished")]
private void OnReadyToBePublished(SPItemEventProperties properties)
{
/*...*/
}
[State("ReadyToBeUnpublished")]
private void OnReadyToBeUnpublished(SPItemEventProperties properties)
{
/*...*/
}
}
</pre>
<br />
<span style="text-align: justify;">Notice the introduction of a few new classes:</span></div>
<div>
<ul>
<li style="text-align: justify;"><b><i>StateMachineAttribute</i></b>: To indicate the column to be monitored and its validator class. The example above indicates that the column name is "State" and the validator class is typeof(PublicationRequestStateMachineValidator). </li>
</ul>
<ul>
<li style="text-align: justify;"><b><i>StateAttribute</i></b>: To indicate the event method that will be called when the state change to the specified value. For instance, the usage of [State("Approved")] means that the method OnApproved will be called when the item change to the "Approved" state.</li>
</ul>
<ul>
<li><b><i>StateMachineItemEventReceiverBase</i></b>: Implements the base behavior of the state machine (invokes the validation to avoid not allowed transitions also call the event methods).</li>
</ul>
<div>
<div style="text-align: justify;">
To make this work properly you must register you state machine item event receiver on the list that you want to monitor for state change. This must be done via <i>RegisterEventReceiverIfRequired </i>extension method for <i>SPList. </i>This method not only registers the event receiver the list, it also adds a custom column to the list to implement the change detection approach whether the event receiver inherits from <i>StateMachineItemEventReceiverBase. </i><br />
<br />
This could be done with the follow code in a feature activation for instance.<br />
<br />
<pre class="brush:csharp">publicationRequestList.RegisterEventReceiverIfRequired(SPEventReceiverType.ItemUpdating, typeof(PublicationRequestStateMachineItemEventReceiver).Assembly.FullName, typeof(PublicationRequestStateMachineItemEventReceiver).FullName);
publicationRequestList.RegisterEventReceiverIfRequired(SPEventReceiverType.ItemUpdated, typeof(PublicationRequestStateMachineItemEventReceiver).Assembly.FullName, typeof(PublicationRequestStateMachineItemEventReceiver).FullName);
</pre>
<br /></div>
<h3 style="text-align: justify;">
How validate state transitions?</h3>
</div>
<div style="text-align: justify;">
Support transition validation is also a cool feature of this library. In order to validate the transition, you can inherit from <i><b>StateMachineValidator</b></i> class and type your own. Our custom publication request example the state machine validator looks like this:</div>
<div>
<span style="text-align: justify;"><br /></span></div>
<div>
<br /></div>
<pre class="brush:csharp">public sealed class PublicationRequestStateMachineValidator : StateMachineValidator<string>
{
public PublicationRequestStateMachineValidator()
{
this.AddAllowedTransition("WaitingForApproval", "Approved");
this.AddAllowedTransition("WaitingForApproval", "Rejected");
this.AddAllowedTransition("Approved", "ReadyToBePublished");
this.AddAllowedTransition("ReadyToBePublished", "Published");
this.AddAllowedTransition("Published", "ReadyToBeUnpublished");
this.AddAllowedTransition("ReadyToBeUnpublished", "Unpublished");
}
}
</pre>
<div>
<br />
<div style="text-align: justify;">
Now if someone tries to change the state from <i>WaitingForApproval</i> to <i>Published</i> - for instance - the change will be reverted automatically.<br />
<br />
This is also useful to enable or disable some actions. Here are couple of pictures that depicts the enable state of the ribbon button depends on an allowed transition validation implemented in javascript in combination with a REST service.<br />
<br />
<table>
<tbody>
<tr>
<td><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/AVvXsEgfNqCIsOuBHRw2eYBIoppPj5KO2Fj_st-ddRNZ3DsWk2f-_-wZ-bk1FHhj270txuICq7n7WQdlL6U6I0Iqvbq1hRtNYHAT0GelcO8GOrcmZ1OYQAbui5yuyg_JUfDe3lM8aAG9Azc45Sc/s1600/2015-08-13_153006.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="87" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfNqCIsOuBHRw2eYBIoppPj5KO2Fj_st-ddRNZ3DsWk2f-_-wZ-bk1FHhj270txuICq7n7WQdlL6U6I0Iqvbq1hRtNYHAT0GelcO8GOrcmZ1OYQAbui5yuyg_JUfDe3lM8aAG9Azc45Sc/s320/2015-08-13_153006.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Example A: Enabled because transitions are allowed</td></tr>
</tbody></table>
</td>
<td><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/AVvXsEgOqyV4soXU5wdH5qC9aBc9Eqj8cBeZEvh3YbyPNCYnv4K4F-aAcaFwIkpHR8At66VCinez0Pd2wR0of-GqzCz5Ow_FA7V-mQ4bMYfCTM8SJZ1xVsv5JcL8tyP1W7cNGTpFvGJISGzX4zo/s1600/2015-08-13_153148.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="82" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOqyV4soXU5wdH5qC9aBc9Eqj8cBeZEvh3YbyPNCYnv4K4F-aAcaFwIkpHR8At66VCinez0Pd2wR0of-GqzCz5Ow_FA7V-mQ4bMYfCTM8SJZ1xVsv5JcL8tyP1W7cNGTpFvGJISGzX4zo/s320/2015-08-13_153148.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8000001907349px;">Example B: Disabled because transitions are not allowed</span></td></tr>
</tbody></table>
</td>
</tr>
</tbody></table>
<br />
<h3>
Conclusions</h3>
</div>
</div>
<div style="text-align: justify;">
This post is an introduction to the new <i><a href="https://github.com/alexfdezsauco/StateMachine.SharePoint">StateMachine.SharePoint</a> </i>library. This library allows you simplify the implementation of a state machine based approach to monitor and validate the states of SharePoint list items.</div>
<br />
<div style="text-align: justify;">
For now, you can build this library from its <a href="https://github.com/alexfdezsauco/StateMachine.SharePoint">sources</a> and deploy directly into your SharePoint farm or wait for the "top secret" weapon and forthcoming project <i><a href="https://github.com/alexfdezsauco/PackageManager.SharePoint">PackageManager.SharePoint</a> </i><i>;)</i></div>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-36719035173525139212015-07-08T10:24:00.001-04:002015-07-13T17:03:13.982-04:00Can NDepend 6 and SONAR work together?<h3>
Introduction</h3>
<div>
<div style="text-align: justify;">
As I wrote in this <a href="http://likewastoldtome.blogspot.com/2015/01/why-start-to-use-ndepend.html" rel="nofollow">post</a>, one of the greatest feature of NDepend were its “<i>great Visual Studio integration in order to display your technical debt directly inside the IDE</i>”.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
NDepend can also be integrated as part of your continuous integration pipeline in order to make the analysis of technical debt results public for the whole team (or just break the build under certain conditions). There are a lot of official documentation about how integrate NDepend 6 with <a href="http://www.ndepend.com/docs/teamcity-integration-ndepend">Team City</a> (as a build server) or <a href="http://www.ndepend.com/docs/sonarqube-integration-ndepend">SONAR</a> (as a quality metric tool).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But let’s start with my own experience setting up NDepend 6 and SONAR and checks the benefits of integrates both tools.<br />
<br /></div>
<h3>
</h3>
<h3>
Integrating NDepend with SONAR</h3>
<div>
NDepend 6 comes with support for SONAR integration. The process is pretty forward and is well described on the <a href="http://www.ndepend.com/docs/sonarqube-integration-ndepend">documentation</a>. After follow such steps you will get all NDepend’s rules imported into SONAR and you can activate them into a <i>Quality Profile</i> for instance the <i>Full Analysis for C#</i>. </div>
</div>
<div>
<br /></div>
<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/AVvXsEiBiBsmczjkXi04aNxzuaEtKIV4FTSRzA7GQtflk9MeJeWAavScxmFEoR3RaYlwZ1O7gDPX7GqiPP6X4nfYSxiOk5U0xwBsTGKCdSwRB0j4GwWcBpt-Pa11SEcmwU8Fh7TnZw8oTUWBTgM/s1600/1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBiBsmczjkXi04aNxzuaEtKIV4FTSRzA7GQtflk9MeJeWAavScxmFEoR3RaYlwZ1O7gDPX7GqiPP6X4nfYSxiOk5U0xwBsTGKCdSwRB0j4GwWcBpt-Pa11SEcmwU8Fh7TnZw8oTUWBTgM/s320/1.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">NDepend rules imported in SONAR</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The issues could start when you run an analysis for large projects with several violations. If you run (the runner) with –X the stack trace will show you the <i>java.lang.OutOfMemoryError</i> as the exception. But nothing that can’t be solved following this recommendations: </div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<ol>
<li>Run sonar-runner with x64 JRE. </li>
<li>Increase the heap size by turn this line:</li>
</ol>
<br />
<div class="separator" style="clear: both; text-align: left;">
%JAVA_EXEC% %SONAR_RUNNER_OPTS% -cp "%SONAR_RUNNER_HOME%\lib\sonar-runner-dist-2.4.jar" "-Drunner.home=%SONAR_RUNNER_HOME%" "-Dproject.home=%PROJECT_HOME%" org.sonar.runner.Main %*</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
into this one</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
%JAVA_EXEC% <b>-Xmx3062m -XX:MaxPermSize=512m -XX:ReservedCodeCacheSize=128m</b> %SONAR_RUNNER_OPTS% -cp "%SONAR_RUNNER_HOME%\lib\sonar-runner-dist-2.4.jar" "-Drunner.home=%SONAR_RUNNER_HOME%" "-Dproject.home=%PROJECT_HOME%" org.sonar.runner.Main %*</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
in the sonnar-runner.bat file.</div>
<div style="text-align: justify;">
<br /></div>
<h3 style="text-align: justify;">
</h3>
<h3 style="text-align: justify;">
The results</h3>
<div style="text-align: justify;">
SONAR is an isolated server that receive the results from “<i>inspection agents</i>”. Actually the inspection results are committed directly into SONAR database and the SONAR web application or dashboard displays the results in a centralized way. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
So, as you expected (and so do I), after run an inspection via sonar-runner, the NDepend's rules violations are displayed as SONAR's issues, just like this.</div>
<div style="text-align: justify;">
<br /></div>
<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/AVvXsEiDBdclwz0uWgMDez7xixDoKuI3q6MRsrouk3lNj7Cbiipd2zRNLl7JqpE98UDGzl9XsYiCkUVxeZ_Fq4DW1aala1Q4ZU5RV5CR2gS1VdQ2X4N_oMlibL77xDw4nzXavR0dpBt7nwtZIws/s1600/2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDBdclwz0uWgMDez7xixDoKuI3q6MRsrouk3lNj7Cbiipd2zRNLl7JqpE98UDGzl9XsYiCkUVxeZ_Fq4DW1aala1Q4ZU5RV5CR2gS1VdQ2X4N_oMlibL77xDw4nzXavR0dpBt7nwtZIws/s320/2.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">NDepend's violations as SONAR's issues</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So, now you can manage (assign, resolve, or comment) such issues trougth SONAR interface. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3 style="clear: both; text-align: justify;">
Conclusions</h3>
<div style="text-align: justify;">
As you should know at this point, the answers is yes. NDepend 6 can work together with SONAR. But as you can also see I have a lot of work to do. So, I’m not sure what I’m doing writing this blog post ;).<br />
<br /></div>
<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/AVvXsEieYtI0v9yM5xToLD0lH89XoZKBjWLGtDDdYef0C0A0r-SQCzM4ElDYF2Cg9U3AoayUF32JUB-5zPPc-sT5fD6k7_FTpMNrvdL3XDjMfDXlgXUiVeimQGE5DkspCWJ4jtNNVro-5Wx-4Kg/s1600/3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="116" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieYtI0v9yM5xToLD0lH89XoZKBjWLGtDDdYef0C0A0r-SQCzM4ElDYF2Cg9U3AoayUF32JUB-5zPPc-sT5fD6k7_FTpMNrvdL3XDjMfDXlgXUiVeimQGE5DkspCWJ4jtNNVro-5Wx-4Kg/s320/3.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">SONAR dashboard</td></tr>
</tbody></table>
<div style="text-align: justify;">
PS: This is not a <i>"Do as I say, not as I do"</i> post. As I also said, the "<i>important thing is, not to accumulate technical debt and fix it as soon as it is detected</i>". The sample reports shown on this post intentionally includes source with a tons of defects. Most of them comes from tests / PoC assemblies and auto-generated code.</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-47847598320819043122015-02-16T13:08:00.001-05:002015-02-24T11:37:50.985-05:00Self-disciplined Agile Monitoring<i>Note for readers: I wrote this post over a year ago (even more), but for some reason I forgot to post it, so here it is.</i><br />
<h3>
Introduction</h3>
<div>
<div style="text-align: justify;">
Now days, we are improving our development process laying-out our organization strategies, development process and methodologies. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Our experiences point to a mixed approach, with the self-organization from Scrum and self-discipline from eXtreme Programming (XP). But about this kind of “mixed martial arts” for software development approach I will talk in forthcoming blog post. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
As you can read in one of my previous blog <a href="http://likewastoldtome.blogspot.com/2013/08/if-you-cant-defeat-them-just-join-them.html">post</a>, we use Team Foundation Server (TFS) as issue tracker and thanks to Scrum for Team System v3 (STSv3) process template, we have an “excellent” implemented guidance to execute Scrum “as is”.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But the existing day by day sprint monitoring’s tools around this process template hides the real behavior of the team in the iteration. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
On the other hand, we also have some needs about monitoring. Indeed against the theoretical practice of monitor the whole team we have to track individuals.</div>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Some projects leads (me included) want to track theirs developers work against the importance of monitor the whole team behavior. Sam Guckenheimer (with Juan J. Perez), in his book “<a href="http://www.amazon.com/Software-Engineering-Microsoft-Visual-Studio/dp/0321278720" target="_blank">Software Engineering with Microsoft Visual Studio Team System</a>”, aims us to use descriptive metrics rather than prescriptive. But here such measurement method “doesn’t work”, we need more control and also need a single view. </div>
<h3 style="text-align: justify;">
Tracking the daily work in STSv3</h3>
<div>
<div style="text-align: justify;">
<a href="http://scrumforteamsystem.codeplex.com/" target="_blank">Scrum for Team System</a> (v3) is a great process template. Its major advantage of this implementation for TFS is about the usage of the server side event notification API. This allows updating all of computable fields for instance: start and end time for sprints (summarized from team start and end sprint dates), remaining hours for sprints and team sprints, and so on.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Scrum for Team System also comes with a lot of reports, but about daily work sprint monitoring comes with only one (maybe two). This report is known as <a href="http://www.scrumforteamsystem.co.uk/ProcessGuidance/v3/sprint%20burndown%20chart" target="_blank">Sprint Burn Down</a>. </div>
</div>
<div style="text-align: justify;">
<br /></div>
<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/AVvXsEgKVRs101yL0GuuZg3lBhBl6d2hhBt0wllvNaNevbsAYj82e5rtOaf1_NB2J7dkLG573cfDNwyNdNSy9NKdUFwx1Cm5CUnAufDH2ityZCGl3k1lIwfGN6NHNsD915haPZbjNo-T7Yc0aiw/s1600/BurnDown.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKVRs101yL0GuuZg3lBhBl6d2hhBt0wllvNaNevbsAYj82e5rtOaf1_NB2J7dkLG573cfDNwyNdNSy9NKdUFwx1Cm5CUnAufDH2ityZCGl3k1lIwfGN6NHNsD915haPZbjNo-T7Yc0aiw/s1600/BurnDown.jpg" height="211" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.7272720336914px;">The burn down metric</span></td></tr>
</tbody></table>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<div>
The Sprint Burn Down is good metric but it’s incomplete. Such single line indeed hides the real behavior of iteration. </div>
<div>
<br /></div>
<div>
Please, try to answer these questions:</div>
<div>
<ul>
<li>How can you notice if some tasks where moved out of the current sprint?</li>
<li>How can you notice if some user stories where moved out of the current sprint?</li>
<li>How can you notice if some tasks where added to the current sprint?</li>
<li>How can you notice if some user stories where added to the current sprint?</li>
</ul>
</div>
<div>
The fact is that as this chart doesn’t display the planned work so it hides these behaviors. </div>
<div>
<br /></div>
<div>
Notice:</div>
<div>
<ol>
<li>If you see an ideal chart, an straight down line from an amount of hours as remaining work (at some point of the sprint) to zero (at the end of the sprint), doesn’t mean that everything is fine. May some tasks were moved of the sprint.</li>
<li>If you see a horizontal line doesn’t mean that everything is wrong. May some tasks were added at the same time that others were actually done. </li>
</ol>
</div>
<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/AVvXsEgSP9i4JP-nXPyfayWwXhGNnXuM9lb_mV3AYE0Iehcl0T-P02SST6IQMXq49ttoui-wzAsdcJ8pCexLCpwO0HE_4Cg0tG-Cc32CyWdGH8W-UVhkb6YKYbSP2BmGL4zbpWfEddS7C3CbRN4/s1600/What.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSP9i4JP-nXPyfayWwXhGNnXuM9lb_mV3AYE0Iehcl0T-P02SST6IQMXq49ttoui-wzAsdcJ8pCexLCpwO0HE_4Cg0tG-Cc32CyWdGH8W-UVhkb6YKYbSP2BmGL4zbpWfEddS7C3CbRN4/s1600/What.jpg" height="217" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.7272720336914px;">The burn down metric</span></td></tr>
</tbody></table>
<div>
<br /></div>
</div>
<div style="text-align: justify;">
The fact is that you are not able to answer this question: <i>What had really happened here?</i></div>
<h3>
Complementary tools to track the daily work</h3>
<div>
<div style="text-align: justify;">
One of my favorites tools to track iterations, and also share the iteration status with the whole team is <a href="http://scrumsprintmonitor.codeplex.com/" target="_blank"><i>ScrumSprintMonitor</i></a>. Yes, the multi-process template screen saver. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The effect of the usage of this tool in the team’s focus is incredible and of course, more over the “guys in red” ;-).</div>
</div>
<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/AVvXsEhZ6M5_FxgdkUph3OATtQ-vltml0oZehhNj4QdBajLy-3KbERrOG-0ZOoTKZsvlRxmfahgMmwrIjS8UYOrSq2pBzg-0lCP06H94-rPtj_5QYkH0k0lzCN5BYlwmeJ1IfdAj0hWn1GHjk3g/s1600/Monitor.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZ6M5_FxgdkUph3OATtQ-vltml0oZehhNj4QdBajLy-3KbERrOG-0ZOoTKZsvlRxmfahgMmwrIjS8UYOrSq2pBzg-0lCP06H94-rPtj_5QYkH0k0lzCN5BYlwmeJ1IfdAj0hWn1GHjk3g/s1600/Monitor.png" height="208" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Demo screenshot of S<span style="font-size: 12.7272720336914px;">crumSprintMonitor </span><span style="font-size: 12.7272720336914px;">from codeplex and </span><span style="font-size: 12.7272720336914px;">S</span><span style="font-size: 12.7272720336914px;">crumSprintMonitor </span><span style="font-size: 12.7272720336914px;">in action but in planning mode in a lab</span></td></tr>
</tbody></table>
<div style="text-align: justify;">
<div>
I like the Scrum Sprint Monitor and have been using it for years, even when I had no longer available the TV in the picture above. But again, the main metric is the Burn Down.</div>
<div>
<br /></div>
<div>
This tool includes a lot of info so I get inspired and wrote my own, just like I thought that it should be written ;-).</div>
<div>
<br /></div>
<h3>
Self disciplined agile monitoring</h3>
</div>
<div>
<div style="text-align: justify;">
Well, the thing actually started some years ago when I found this chart in the book “<a href="http://www.amazon.com/The-Agile-Development-James-Shore/dp/B00CVDWRA0" target="_blank">The Art of Agile Programming</a>” from James Shore and Shane Warden. Its name is Burn Up. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Basically consist of a couple of lines. One to show the total of planned work and the second to display the progress.</div>
</div>
<div>
<br /></div>
<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/AVvXsEjG-KFmN8gfxcVRc49EdVCtq55Ma-3-FECdvHflxL9BN_rUA8yQCUbQXyQFOBNnjcZuOlZf4o6Ub2n6RtX0zdPzGJoBDpv7PtGG1cUJvAOvTfkwF-Y8Y4E08jC3HaaKiHl-xHKmDV7k3xk/s1600/BurnUp.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjG-KFmN8gfxcVRc49EdVCtq55Ma-3-FECdvHflxL9BN_rUA8yQCUbQXyQFOBNnjcZuOlZf4o6Ub2n6RtX0zdPzGJoBDpv7PtGG1cUJvAOvTfkwF-Y8Y4E08jC3HaaKiHl-xHKmDV7k3xk/s1600/BurnUp.jpg" height="212" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.7272720336914px;">The burn up metric</span></td></tr>
</tbody></table>
<div>
<br /></div>
<div style="text-align: justify;">
In the context of a project to help my own organization to get the right way in terms of software development practices, I bought some time in order to port this metric into this monitoring application.</div>
<div style="text-align: justify;">
<br /></div>
<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/AVvXsEjxrrTM9dNKmPpPJsQLDsOJJVrdUMKqQbiBZs833X1OObaSE-O5tGqIzYyVPVi6hJwexinJFsT-jf6Kzofn9r6sVtKM1B5OH4hQsfmtvd8GYSxLJF9yW4RiEihDgwODivmhRxvs8Ka7o-k/s1600/DisciplinedScrumMonitor.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxrrTM9dNKmPpPJsQLDsOJJVrdUMKqQbiBZs833X1OObaSE-O5tGqIzYyVPVi6hJwexinJFsT-jf6Kzofn9r6sVtKM1B5OH4hQsfmtvd8GYSxLJF9yW4RiEihDgwODivmhRxvs8Ka7o-k/s1600/DisciplinedScrumMonitor.jpg" height="211" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">My own ScrumSprintMonitor in action with the burn up metric</td></tr>
</tbody></table>
<div style="text-align: justify;">
As I said before it was inspired in Scrum Sprint Monitor but it was re-written from scratch to focus in the Burn Up metric. The current version it’s only compatible with STSv3.</div>
<div style="text-align: justify;">
<h3>
Conclusion</h3>
<div>
<ol>
<li>Now we have a very cool monitoring application with a very meaningful metric. The Burn Up. </li>
<li>In order to distribute as fast as possible this tool and its updates across my organization, I also implemented a draft of NuGet based automatic update system. After done, someone told me about something called <a href="https://github.com/Squirrel/Squirrel.Windows">Shimmer</a>. I have to review it ;-).</li>
<li>I almost forget. This application is powered by <a href="http://www.catelproject.com/">Catel</a> and <a href="http://compositewpf.codeplex.com/">Prism</a> in combination (a.k.a. <a href="http://www.nuget.org/packages/Catel.Extensions.Prism/3.6">Catel.Extensions.Prism</a>). </li>
</ol>
Happy sprinting and monitoring ;-)</div>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-52724051062006412912015-01-19T12:24:00.002-05:002021-12-17T23:04:21.964-05:00Why should you start using NDepend?<h3>
<b>Introduction</b></h3>
This weekend I finished painting my apartment. Then I laid on the floor, looking at the ceiling, started taking some shots and talking to myself:<br />
<br />
<table style="text-align: center;">
<tbody>
<tr>
<td><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMLdIkQSlfRmOWjECs4wgbfnujfwl2MNZ1z98pxbgccEcUzyaXOWQh9jKwyCCIldFiY-NUv7-R7lqhSLG0GMR5lWxswHn6uLhixIYlJzx5JRbwu1mEkHUiTgn4QP7YSWTPUG5RrVWfNPY/s1600/IMG_20150118_135621.jpg"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMLdIkQSlfRmOWjECs4wgbfnujfwl2MNZ1z98pxbgccEcUzyaXOWQh9jKwyCCIldFiY-NUv7-R7lqhSLG0GMR5lWxswHn6uLhixIYlJzx5JRbwu1mEkHUiTgn4QP7YSWTPUG5RrVWfNPY/s200/IMG_20150118_135621.jpg" /></a></td>
<td><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdlvvnqqmkPosQ4rg4B0J2litnOVGewbprFkt9U3cOLejDabe0lgx1RZGJPqtn4iTcY6iJsP1HSSmpqZRJNfPa8XX-jspqgqwn1-y77ssHI9RzVNVmxQ2C5YiShWGbPIOAktKlrdHERoI/s1600/IMG_20150118_135638.jpg"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdlvvnqqmkPosQ4rg4B0J2litnOVGewbprFkt9U3cOLejDabe0lgx1RZGJPqtn4iTcY6iJsP1HSSmpqZRJNfPa8XX-jspqgqwn1-y77ssHI9RzVNVmxQ2C5YiShWGbPIOAktKlrdHERoI/s200/IMG_20150118_135638.jpg" /></a></td>
<td><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVKfvRIMMDF0IWkUbt4C1AM8GFZlfyn5Nj-ELYSwle7tiBYE8d7pYtQE6SKWwRvTMdvf92pLUDcsTKEV9EyItQJvhIctG0ANuk0yBwZPYn9mdX6EvDZ4IM2X8unQaiP61mcJG6q8kwhtY/s1600/IMG_20150118_135721.jpg"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVKfvRIMMDF0IWkUbt4C1AM8GFZlfyn5Nj-ELYSwle7tiBYE8d7pYtQE6SKWwRvTMdvf92pLUDcsTKEV9EyItQJvhIctG0ANuk0yBwZPYn9mdX6EvDZ4IM2X8unQaiP61mcJG6q8kwhtY/s200/IMG_20150118_135721.jpg" /></a></td>
</tr>
<tr>
<td style="vertical-align: top;">A) Yes, it looks great and with this new lamp in the middle of the living room, everything looks perfect.</td>
<td style="vertical-align: top;">B) But what is that I see at the corner? Let me get a closer shot.</td>
<td style="vertical-align: top;">C) Oops!!! I made a mistake, I need to fix it ASAP ;)</td>
</tr>
</tbody></table>
<div style="text-align: center;">
<br /></div>
<div>
<div style="text-align: center;">
<div style="text-align: justify;">
Yes, I know, I’m not a professional painter. Therefore, I don't have the right tools to alert me about these technical debts while I’m painting. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Such experience reminded me that I’m a software developer and recently acquired the right tool to detect such “dark spots” – a.k.a technical debt – of the source code while I’m<span class="Apple-tab-span" style="white-space: pre;"> </span>coding. Its name is <a href="http://www.ndepend.com/" target="_blank">NDepend</a>.</div>
<div style="text-align: justify;">
<br />
<h3>
What is NDepend?</h3>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYee6Oc0QrZfgkzsZQc2avvNEolRIKmqCdr70PLn_JNVlM-iyb96tRcCpxsGyq2IQeIyj_zZNcM5ImN1gfpSquWIc8ZuiVUE7Es_6A5vWnbZY1wQ6uaAMfCYRKdN288xRgpThrLloEaaA/s1600/SONAR.png" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto; text-align: center;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYee6Oc0QrZfgkzsZQc2avvNEolRIKmqCdr70PLn_JNVlM-iyb96tRcCpxsGyq2IQeIyj_zZNcM5ImN1gfpSquWIc8ZuiVUE7Es_6A5vWnbZY1wQ6uaAMfCYRKdN288xRgpThrLloEaaA/s1600/SONAR.png" width="175" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>SONAR Web Report</i></td></tr>
</tbody></table>
<a href="http://www.ndepend.com/"><span style="background: white;">NDepend</span></a><span style="background: white;"> is a static analysis tool for .NET managed code. As you should know static analysis is about a</span>nalyzing code without executing it and is generally used to ensure conformance with the coding guidelines.<br />
<br />
<div>
</div>
<div>
<a href="http://www.ndepend.com/"><span style="background: white;">NDepend</span></a><span style="background: white;"> is not the only tool available for static analysis code for .NET, there are several tools including <b>Code Violation Detection Tools</b> like </span><a href="http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=917023f6-d5b7-41bb-bbc0-411a7d66cf3c"><span style="background: white;">Fxcop</span></a>, <a href="http://www.clocksharp.com/"><span style="background: white;">Clocksharp</span></a>, <a href="http://www.mono-project.com/Gendarme"><span style="background: white;">Mono.Gendarme</span></a><span style="background: white;"> or </span><a href="http://submain.com/codeit.right"><span style="background: white;">CodeIt.Right</span></a><span style="background: white;">, </span><b>Quality Metric Tools </b><span style="background: white;">like<b><span face=""calibri" , "sans-serif"" style="border: 1pt none; padding: 0in;"> </span></b></span><a href="http://www.nitriq.com/"><span style="background: white;">Nitriq</span></a><span style="background: white;">, </span><a href="http://www.sonarqube.org/"><span style="background: white;">SONAR</span></a><span style="background: white;"> or </span><a href="http://www.ndepend.com/"><span style="background: white;">NDepend</span></a><span style="background: white;"> </span><span style="background: white;">itself, or just <b>Checking Style Tools </b>like<b><span face=""calibri" , "sans-serif"" style="border: 1pt none; padding: 0in;"> </span></b></span><a href="http://code.msdn.microsoft.com/sourceanalysis"><span style="background: white; border: 1pt none; color: #4a6b82; padding: 0in;">StyleCop</span></a><b><span face=""calibri" , sans-serif" style="background: white; border: 1pt none; padding: 0in;">, </span></b><a href="https://code.google.com/p/agentsmithplugin/"><span style="background: white; border: 1pt none; color: #4a6b82; padding: 0in;">Agent Smith</span></a><b><span face=""calibri" , sans-serif" style="background: white; border: 1pt none; padding: 0in;">.</span></b><br />
<span style="background: white;"></span></div>
<br />
<div>
<span style="background: white;">Actually, I currently use </span><a href="http://www.sonarqube.org/"><span style="border: 1pt none; color: #4a6b82; padding: 0in;">SONAR</span></a><span style="background: white;"> with its seamless integration with the build process in order to </span><span style="background-color: white;">continuously</span><span style="background-color: white;"> </span><span style="background-color: white;">manage code quality in centralized reports of technical debts.</span><br />
<br />
<a href="http://www.ndepend.com/"><span style="background: white;">NDepend</span></a> also has integration with the build process, but from my point of view, one of its key features is the great Visual Studio integration in order to display your technical debt directly inside the IDE.<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/AVvXsEiyXWJRU5-dm6XD2X4tBNl7dTOZuswmOY1HHnKPtTHRBAwhAgcWsEV4a_rH7_Rfpy4YZ0aStRmBdPFKBSmPV8Y8c1SpIpY52N6yW8zCvmTCnjRkhWl_Dbz3dGlGMZPbpUR2loCQ9xh8HQs/s1600/NDepend.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="306" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyXWJRU5-dm6XD2X4tBNl7dTOZuswmOY1HHnKPtTHRBAwhAgcWsEV4a_rH7_Rfpy4YZ0aStRmBdPFKBSmPV8Y8c1SpIpY52N6yW8zCvmTCnjRkhWl_Dbz3dGlGMZPbpUR2loCQ9xh8HQs/s1600/NDepend.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>NDepend Dashboard in Visual Studio</i></td></tr>
</tbody></table>
<span style="font-size: small; font-weight: normal;">Let's take a look at a very quick start with </span><span style="background: white;"><a href="http://www.ndepend.com/">NDepend</a></span><span style="font-size: small; font-weight: normal;">.</span><br />
<h3>
A very quick start with NDepend</h3>
<div>
<br /></div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0ylaEruevssQfSkU82RJPieXnUfJfnivLRNXq1yTlc80ED8F3qwvxi7U2wLvM3ZysPFQBG3BXDKXCPeqj_LwM7gIcdsf5eFkvZlCyxF6bwcs_i3AnD0Dm0EOIYOZTB27bEEahADdUWy8/s1600/NDependFirstResults.png" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0ylaEruevssQfSkU82RJPieXnUfJfnivLRNXq1yTlc80ED8F3qwvxi7U2wLvM3ZysPFQBG3BXDKXCPeqj_LwM7gIcdsf5eFkvZlCyxF6bwcs_i3AnD0Dm0EOIYOZTB27bEEahADdUWy8/s1600/NDependFirstResults.png" width="83" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Quick access </i><br />
<i>to the violation results</i></td></tr>
</tbody></table>
<div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZscmjNwRuG4ShcFKxcMasb0GbNv-TUPy1z81kjtzSbTXHGWJCdkYuY16RdQ2lPI3sdulLFIxfAaWfyorAyiw-KPvKDbP6rTaJBZM8XSd6OFfHAHdJa0HW4U-zE01FkswHDlZsjj1Q5GQ/s1600/NDependFirstRun.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="88" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZscmjNwRuG4ShcFKxcMasb0GbNv-TUPy1z81kjtzSbTXHGWJCdkYuY16RdQ2lPI3sdulLFIxfAaWfyorAyiw-KPvKDbP6rTaJBZM8XSd6OFfHAHdJa0HW4U-zE01FkswHDlZsjj1Q5GQ/s1600/NDependFirstRun.png" width="200" /></a>After installing a <a href="https://visualstudiogallery.msdn.microsoft.com/EF4E8DB0-2079-4819-BA1C-51E5EB53E8C7" target="_blank">plugin</a> and setting up your project, you should run a code analysis just by clicking the option from the menu NDEPEND => Analyze => Run Analysis or moving de mouse over a circle in the notification bar and click in Run a First Analysis on this NDepend Project.</div>
<div>
<br /></div>
<div>
If you move the mouse again - once the analysis finished - over the circle in the notification bar you should see the <b>Code Queries and Rules Summary</b>, with fast access to the <b>Critical and Rules Violated</b>. </div>
<div>
<br /></div>
<div>
Such results, categorized into <b>Code Quality</b>, <b>Object Oriented Design</b>, <b>Design</b>, <b>Architecture</b>, <b>Layering</b>, <b>Dead Code</b>, and so on, are displayed on the Query and Rules Explorer panel and allow us to navigate from the violation directly to the source.</div>
<table 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/AVvXsEjoht7wOSd_S3p_6PxivARFaA_vPdiQ2BTThVmuRd5i_KlXYolZuP0_6bJ6hrmFNULEwqrB5PmHUMmQO6povZySmiRxVIdNhW4pzUJbgGKIJmojjA-lLxaCMAaAnaYo-_0VvPmARfc6g6M/s1600/NDependFirstResults01.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="281" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoht7wOSd_S3p_6PxivARFaA_vPdiQ2BTThVmuRd5i_KlXYolZuP0_6bJ6hrmFNULEwqrB5PmHUMmQO6povZySmiRxVIdNhW4pzUJbgGKIJmojjA-lLxaCMAaAnaYo-_0VvPmARfc6g6M/s1600/NDependFirstResults01.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Categorized violation query results on the Query and Rules Explorer</i></td></tr>
</tbody></table>
<div>
For instance, let me check from <b>Code Quality </b>category, the rule <b>Methods with too many parameters - critical</b>. </div>
<div>
<br /></div>
<div>
The rule description is the following: <i>Methods with more than 8 parameters might be painful to call and might degrade performance. You should prefer using additional properties/fields to the declaring type to handle numerous states. Another alternative is to provide a class or structure dedicated to handle arguments passing.</i></div>
<div>
<i><br /></i></div>
<div>
The analysis found 16 violations of this rule, by clicking it you can navigate to the method. In this case, I selected one with 9 parameters and found out that indeed, it must be refactored. Now, thanks to the integration of Visual Studio and Git, you can also see who's the author of this violation. </div>
<div>
<br /></div>
<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/AVvXsEhIZaRtx7vA5uw99XA2qGG2tz5JHyC9eYPZflzMO095xDi5sQUm5E6cRwcB0jHpyv_iYknoWVuEQLRbWNJXDwATm0Vkhan4zeEgrBMhZrgbC3fujbwiHdiOkjbhIEQjy_KlSAks98nqNsU/s1600/NDependMethodsWithParameters.png" style="margin-left: auto; margin-right: auto; text-align: center;"><img border="0" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIZaRtx7vA5uw99XA2qGG2tz5JHyC9eYPZflzMO095xDi5sQUm5E6cRwcB0jHpyv_iYknoWVuEQLRbWNJXDwATm0Vkhan4zeEgrBMhZrgbC3fujbwiHdiOkjbhIEQjy_KlSAks98nqNsU/s1600/NDependMethodsWithParameters.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Navigating from rule 'Methods with too many parameters - critical' result to StartSiteCreationProcess method</i></td></tr>
</tbody></table>
<div style="text-align: left;">
<span style="text-align: justify;">Let me take a closer shoot to see who that is:</span></div>
<div style="text-align: left;">
<span style="text-align: justify;"><br /></span></div>
<div style="text-align: left;">
<span style="text-align: justify;"></span><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/AVvXsEjJRdeIzDTqZ4KC7CThG_g2R9POOnpvhYIewGncTSSaMFNbka7ZYYw3WHON7tI43_XpUVOReJPhGgmEW_yT0sqGMJ5Gty_2edkhSpKI2ek-Wucj4J-QdttCFv1v8boq6H6Onv7l8vraOdo/s1600/Alexander.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="83" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJRdeIzDTqZ4KC7CThG_g2R9POOnpvhYIewGncTSSaMFNbka7ZYYw3WHON7tI43_XpUVOReJPhGgmEW_yT0sqGMJ5Gty_2edkhSpKI2ek-Wucj4J-QdttCFv1v8boq6H6Onv7l8vraOdo/s1600/Alexander.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: small;">Oops!!!</span><span style="font-size: small; text-align: justify;"> it's me, I need to fix this ASAP ;)</span></td></tr>
</tbody></table>
<span style="text-align: justify;"> </span></div>
<h3>
Conclusion</h3>
<div>The important thing is, not to accumulate technical debt and fix it as soon as it is detected. For .NET developers, <span style="background: white;"><a href="http://www.ndepend.com/">NDepend</a> is the right tool to </span>start with.</div>
<div>
<br /></div>
<div>
You can make mistakes (critical or not), but being aware of your code quality constantly makes the difference between the apparent and intrinsic quality of your sources and consequently your products; even when untrained eyes may only see the beautiful lamp.<br />
<br />
Btw, It seems like I've got similar skills as a painter than as a software developer ;)</div>
</div>
</div>
</div>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-57422252643976731502014-09-23T09:54:00.000-04:002015-03-23T17:00:30.600-04:00How setup SharePoint web application to write SignalR based application pages?<div style="text-align: justify;">
There are few steps to enable <a href="http://signalr.net/" rel="nofollow" target="_blank">SignalR</a> into a web application. But how do this for a SharePoint based web application? </div>
<br />
The goal of this post is provide you a SharePoint deployment package to is automate such steps for a SharePoint web application.<br />
<br />
The only thing you have to do is:<br />
<div style="text-align: justify;">
<br />
1) Download <a href="https://onedrive.live.com/redir?resid=ADEB7E738B27F26C!123&authkey=!AB7lL3MQVas4LNw&ithint=file%2cwsp" rel="nofollow" target="_blank">SignalR.SharePoint.wsp</a>.</div>
<br />
<div style="text-align: justify;">
2) Install the SignalR distributed assemblies the web application bin directory from Powershell console:</div>
<div style="text-align: justify;">
<br />
<pre class="brush: ps; gutter:false">>Add-PSSnapin Microsoft.SharePoint.PowerShell
>Add-SPSolution (Resolve-Path .\SignalR.SharePoint.wsp)
>Install-SPSolution SignalR.SharePoint.wsp -WebApplication $WebAppUrl -GACDeployment -FullTrustBinDeployment -Force
</pre>
<br />
3) Enable [SignalR SharePoint Configuration Feature] - in the web application scope - in order to modify the web.config for run-time assembly binding redirection, set <a href="http://msdn.microsoft.com/en-us/library/vstudio/tkscy493(v=vs.100).aspx" target="_blank">legacyCasModel</a> to <i>false </i>(allow dynamic calls) and set the <i>owin:AutomaticAppStartup</i> application setting key to <i>false</i>.<br />
<br />
<pre class="brush: plain; gutter:false">...
<trust level="Full" originUrl="" legacyCasModel="false" />
...
<runtime>
<assemblyBinding>
...
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
...
<appSettings>
...
<add key="owin:AutomaticAppStartup" value="false" />
</appSettings>
</pre>
<div style="text-align: justify;">
<br />
4) Create and deploy your hub based assembly into the web application. The easy way to do this is by writing the hub in a SharePoint based project and set the “Assembly Deployment Target” to WebApplication. You can also try with this simple chat <a href="https://onedrive.live.com/redir?resid=ADEB7E738B27F26C!122&authkey=!ABvr991lcrcDUEQ&ithint=file%2czip" rel="nofollow" target="_blank">example</a> by deploying it into your web application.<i></i></div>
<div style="text-align: justify;">
<br />
5) Enable the [SignalR SharePoint Enable AutomaticAppStartup Feature] - in the web application scope - in order turn the <i>owin:AutomaticAppStartup</i> application setting key to <i>true</i>.<br />
<br />
<pre class="brush:plain; gutter:false"> <appSettings>
...
<add key="owin:AutomaticAppStartup" value="true" />
</appSettings>
</pre>
<br />
<div style="text-align: justify;">
6)<i> </i>Just open your browser and navigates to the application page. If you deployed the chat <a href="https://onedrive.live.com/redir?resid=ADEB7E738B27F26C%21122&authkey=%21ABvr991lcrcDUEQ&ithint=file%2czip" rel="nofollow" target="_blank">example</a>, you can try with <i>%WebApplicationUrl%/_layouts/15/_layouts/15/SignalR.SharePoint.Demo/Chat.aspx </i>application page<i>.</i> </div>
</div>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-21096809845579434382014-08-11T08:49:00.001-04:002021-09-27T22:18:48.431-04:00What about Catel.Fody and computed read-only properties change notifications?<br />
<div style="text-align: justify;">
In my last <a href="http://likewastoldtome.blogspot.com/2014/06/implementing-notify-property-changed.html" rel="nofollow">post</a>, I covered the implementation of INotifyPropertyChanged interface when using <a href="http://sheepaspect.codeplex.com/" rel="nofollow">SheepAspect</a> as an AOP library. In the end, I also implemented an approach to notify changes of computed read-only properties. This approach has a downside, the dependent properties discovering process must be done in run-time. </div>
<div style="text-align: justify;">
<br />
Such a journey recalls us that <a href="https://github.com/Catel/Catel.Fody">Catel.Fody</a> didn’t have support for notifying property changes of computed read-only properties. How could such a thing ever be possible? Obvious, “the shoemaker's son always goes barefoot” ;). But don’t worry: the feature is here, moving the dependent properties discovering process to build-time, thanks to <a href="https://github.com/Fody/Fody">Fody</a>.<br />
<br /></div>
As you probably know by now, <a href="https://github.com/Catel/Catel.Fody">Catel.Fody</a> will rewrite all properties on the DataObjectBase and ViewModelBase. So, if a property is written like this:<br />
<br />
<pre class="brush: csharp; gutter:false">public string FirstName { get; set; }
</pre>
<br />
will be weaved into<br />
<br />
<pre class="brush: csharp; gutter:false">public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName", typeof(string));
</pre>
<br />
<br />
But now we added a new feature to <a href="https://github.com/Catel/Catel.Fody">Catel.Fody</a>. If a read-only computed property like this one exists:<br />
<br />
<pre class="brush: csharp; gutter:false">public string FullName
{
get { return string.Format("{0} {1}", FirstName, LastName).Trim(); }
}
</pre>
<br />
the OnPropertyChanged method will be also weaved into<br />
<br />
<pre class="brush: csharp; gutter:false">protected override void OnPropertyChanged(AdvancedPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.PropertyName.Equals("FirstName"))
{
base.RaisePropertyChanged("FullName");
}
if (e.PropertyName.Equals("LastName"))
{
base.RaisePropertyChanged("FullName");
}
}
</pre>
<br />
<br />
This feature is already available in the latest beta <a href="https://www.nuget.org/packages/Catel.Fody/2.3.0-unstable0018">package</a> of <a href="https://github.com/Catel/Catel.Fody" rel="nofollow">Catel.Fody</a>. <br />
<br />
Try yourself and let us <a href="https://catelproject.atlassian.net/">know</a>.Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com1tag:blogger.com,1999:blog-9155852904520845376.post-54970268377266984132014-06-30T14:27:00.003-04:002021-09-27T22:17:31.624-04:00Implementing notify property changed with SheepAspect<h3>
Introduction</h3>
<div style="text-align: justify;">
I spend some time looking for <a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming" target="_blank">AOP</a> options for .NET. All references point to <a href="http://www.postsharp.net/" target="_blank">PostSharp</a> as the coolest option - even when you have to pay to use it - due to its features, starting from the way it works – in build time and static – plus a lot of build-in “advice” and extensions points. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
There are also several run time and dynamic options such as <a href="http://www.castleproject.org/" target="_blank">Castle</a>, Unity, etc., but I prefer the build time and static approach. Indeed I use <a href="https://github.com/Fody/Fody" target="_blank">Fody</a> - as an alternative to <a href="http://www.postsharp.net/" target="_blank">PostSharp</a> - even when I have to write down custom plugins directly in IL.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But all of these <a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming" target="_blank">AOP</a>-like libraries and tools for .NET do not allow you to handle exactly the all the <a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming" target="_blank">AOP</a> concepts such as pointcut, join-point, and advice.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But recently I found a project in CodePlex, named <a href="http://sheepaspect.codeplex.com/" target="_blank">SheepAspect</a> with an introductory statement that includes the following words “<i>…was inspired in <a href="http://www.eclipse.org/aspectj/" target="_blank">AspectJ</a></i>”. So, I just installed the package from <a href="https://www.nuget.org/packages/SheepAspect/" target="_blank">NuGet</a> and started to write in C# a notify property changed proof of concept with a friend of mine (<a href="http://www.linkedin.com/in/leoriano86/" target="_blank">Leandro</a>).</div>
<br />
<h3>
Introducing NotifyPropertyChanged aspect</h3>
<div style="text-align: justify;">
The very first step is to write a NotifyPropertyChangedAspect class. It’s important to get related with <a href="http://hendryluk.wordpress.com/2011/05/09/sheepaop-part-2-pointcut-and-saql-basics/" target="_blank">SAQL</a> in order to query the right properties from the right types, and with the usage of the <a href="http://sheepaspect.codeplex.com/" target="_blank">SheepAspect</a> attributes. For this particular example the pointcut includes “all public property setters of types that implement System.ComponentModel.INotifyPropertyChanged” and look like this:</div>
<pre class="brush: csharp; gutter:false">[Aspect]
public class NotifyPropertyChangedAspect
{
[SelectTypes("ImplementsType:'System.ComponentModel.INotifyPropertyChanged'")]
public void NotifiedPropertyChangedTypes()
{
}
[SelectPropertyMethods("Public & Setter & InType:AssignableToType:@NotifiedPropertyChangedTypes")]
public void PublicPropertiesOfTypesThatImplementsINotifyPropertyChangedInterfacePointCut()
{
}
}
</pre>
<br />
Now, I just needed to add the notify property changed behavior as around advice just as follow:<br />
<br />
<pre class="brush: csharp; gutter:false">[Around("PublicPropertiesOfTypesThatImplementsINotifyPropertyChangedInterfacePointCut")]
public void AdviceForPublicPropertiesOfTypesThatImplementsINotifyPropertyChangedInterface(PropertySetJointPoint jp)
{
object value = jp.Property.GetValue(jp.This);
if (!object.Equals(value, jp.Value))
{
jp.Proceed();
jp.This.RaiseNotifyPropertyChanged(jp.Property);
}
}
</pre>
<br />
<div style="text-align: justify;">
As you should notice, to implement this, I also introduce a couple of extension methods TryGetPropertyChangedField and of course the RaiseNotifyPropertyChanged itself:</div>
<br />
<pre class="brush: csharp; gutter:false">public static bool TryGetPropertyChangedField(this Type type, out FieldInfo propertyChangedEvent)
{
propertyChangedEvent = null;
while (propertyChangedEvent == null && type != null && type != typeof(object))
{
propertyChangedEvent = type.GetField("PropertyChanged", BindingFlags.Instance | BindingFlags.NonPublic);
if (propertyChangedEvent == null)
{
type = type.BaseType;
}
else if (!typeof(MulticastDelegate).IsAssignableFrom(propertyChangedEvent.FieldType))
{
propertyChangedEvent = null;
}
}
return propertyChangedEvent != null;
}
/*...*/
public static void RaiseNotifyPropertyChanged(this object instance, PropertyInfo property)
{
FieldInfo propertyChangedEvent;
if (instance.GetType().TryGetPropertyChangedField(out propertyChangedEvent))
{
var propertyChangedEventMulticastDelegate = (MulticastDelegate)propertyChangedEvent.GetValue(instance);
var invocationList = propertyChangedEventMulticastDelegate.GetInvocationList();
foreach (var handler in invocationList)
{
MethodInfo methodInfo = handler.GetMethodInfo();
methodInfo.Invoke(handler.Target, new[] { instance, new PropertyChangedEventArgs(property.Name) });
}
}
}
</pre>
<br />
Now, if a class that implements or inherits from a class that implements INotifyPropertyChanged interface is added, just like this one:<br />
<br />
<pre class="brush: csharp; gutter:false">public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get
{
return string.Format(CultureInfo.InvariantCulture, "{0} {1}", this.FirstName, this.LastName).Trim();
}
}
}
</pre>
<br />
and a program like this one is written:<br />
<br />
<pre class="brush: csharp; gutter:false">this.person.PropertyChanged += (sender, args) =>
{
object value = sender.GetType().GetProperty(args.PropertyName).GetValue(sender);
Console.WriteLine("Property Changed => '{0}' = '{1}'", args.PropertyName, value);
};
this.person.FirstName = "Igr Alexánder";
this.person.LastName = "Fernández Saúco";
</pre>
<br />
then the output will be:<br />
<br />
Property Changed => 'FirstName' = 'Igr Alexánder'<br />
Property Changed => 'LastName' = 'Fernández Saúco' <br />
<br />
Uhmm! But what about with the computed read-only properties like FullName?<br />
<br />
<h3>
Notifying property changes of computed read-only properties.</h3>
<div style="text-align: justify;">
In order to notify changes of computed read-only properties, an inspection of the IL code is required. The .NET native reflection API is limited. From the PropertyInfo is only possible to get the IL byte array from the get method body, and nothing more. Therefore, I just switched to the Mono.Cecil reflection API to be able to complement the existing RaiseNotifyPropertyChanged extension method with the following extension methods:</div>
<div style="text-align: justify;">
<br /></div>
<pre class="brush: csharp; gutter:false">public static bool ExistPropertyDependencyBetween(this Type type, PropertyInfo dependentProperty, PropertyInfo propertyInfo)
{
AssemblyDefinition assemblyDefinition = new DefaultAssemblyResolver().Resolve(type.Assembly.FullName);
TypeDefinition typeDefinition = assemblyDefinition.MainModule.GetType(type.FullName);
PropertyDefinition dependentPropertyDefinition = typeDefinition.Properties.FirstOrDefault(definition => definition.Name == dependentProperty.Name);
bool found = false;
if (dependentPropertyDefinition != null)
{
MethodDefinition definition = dependentPropertyDefinition.GetMethod;
if (definition.HasBody)
{
ILProcessor processor = definition.Body.GetILProcessor();
int idx = 0;
while (!found && idx < processor.Body.Instructions.Count)
{
Instruction instruction = processor.Body.Instructions[idx];
MethodDefinition methodDefinition;
if (instruction.OpCode == OpCodes.Call && (methodDefinition = instruction.Operand as MethodDefinition) != null && methodDefinition.DeclaringType.IsAssignableFrom(typeDefinition) && methodDefinition.Name == string.Format(CultureInfo.InvariantCulture, "get_{0}", propertyInfo.Name))
{
found = true;
}
else
{
idx++;
}
}
}
}
return found;
}
/*...*/
public static IEnumerable<PropertyInfo> GetDependentPropertiesFrom(this Type type, PropertyInfo property)
{
List<PropertyInfo> dependentPropertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(dependentProperty => property != dependentProperty && dependentProperty.CanRead && type.ExistPropertyDependencyBetween(dependentProperty, property)).ToList();
for (int i = 0; i < dependentPropertyInfos.Count; i++)
{
foreach (PropertyInfo info in type.GetDependentPropertiesFrom(dependentPropertyInfos[i]))
{
if (!dependentPropertyInfos.Contains(info))
{
dependentPropertyInfos.Add(info);
}
}
}
return dependentPropertyInfos;
}
</pre>
just like this:<br />
<pre class="brush: csharp; highlight:[15,16,17,18,19,20,21,22]; gutter:false">public static void RaiseNotifyPropertyChanged(this object instance, PropertyInfo property)
{
FieldInfo propertyChangedEvent;
if (instance.GetType().TryGetPropertyChangedField(out propertyChangedEvent))
{
var propertyChangedEventMulticastDelegate = (MulticastDelegate)propertyChangedEvent.GetValue(@this);
var invocationList = propertyChangedEventMulticastDelegate.GetInvocationList();
foreach (var handler in invocationList)
{
MethodInfo methodInfo = handler.GetMethodInfo();
methodInfo.Invoke(handler.Target, new[] { instance, new PropertyChangedEventArgs(property.Name) });
}
foreach (PropertyInfo propertyInfo in instance.GetType().GetDependentPropertiesFrom(property))
{
foreach (var handler in invocationList)
{
MethodInfo methodInfo = handler.GetMethodInfo();
methodInfo.Invoke(handler.Target, new[] { instance, new PropertyChangedEventArgs(propertyInfo.Name) });
}
}
}
}
</pre>
<br />
So, now the program output is:<br />
<br />
Property Changed => 'FirstName' = 'Igr Alexánder'<br />
Property Changed => 'FullName' = ' Igr Alexánder' <br />
Property Changed => 'LastName' = 'Fernández Saúco' <br />
Property Changed => 'FullName' = ' Igr Alexánder Fernández Saúco' <br />
<br />
<h3>
Conclusion</h3>
<div style="text-align: justify;">
At this point, you should be worried about the performance and a lot of reflection API calls. I'm pretty sure that this issue could be handle with the right <a href="http://likewastoldtome.blogspot.com/2013/01/cache-storage-explained.html" target="_blank">caching</a> approach ;).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I didn’t know why I never heard about <a href="http://sheepaspect.codeplex.com/" target="_blank">SheepAspect</a> before. Probably no one trust in something called “Sheep”, but believe me <a href="http://sheepaspect.codeplex.com/" target="_blank">SheepAspect</a> rocks!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Wait for a second! Right now I'm reading about something called <a href="http://hendryluk.wordpress.com/2012/03/09/sheepaspect-mixin/" target="_blank">mixing</a>. Probably I can get a more declarative approach to implement this, just like the <a href="https://github.com/Fody/Fody" target="_blank">Fody</a> or <a href="http://www.postsharp.net/" target="_blank">PostSharp</a> home page examples. But I'm not sure right now, so, you have to wait for my next post to know about it ;).</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-15596791925534281172014-02-21T10:36:00.001-05:002014-02-21T15:21:22.194-05:00Developing a ReSharper Plugin – The backward compatibility approach<h3>
Introduction</h3>
<div style="text-align: justify;">
We have being developed a ReSharper plugin for Catel framework also known as <a href="http://www.catelproject.com/tools/catel-resharper/">CatelR#</a> for a while, following an interesting approach in order support the new R# version and also keep the backward compatibility.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
If you want to know how we made it, just take a look.</div>
<div style="text-align: justify;">
<br /></div>
<h3>
Visual Studio solution setup </h3>
<div style="text-align: justify;">
1) Create project per supported R# version, which means that the output of each project is targeting to the specific version of R# and references the specific version of the SDK.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPpSf1xq6sZOnWJCUEOaMdNaaAOp1aBqFkr_lUAPYqNV2v7TfZOnUERMEqy-hXqIYdxb5GkGCcfAVal7wwOD6lIgUwqy8vtr4payk3AW4We1sX7wpv9EVJa6DWHbDFyOW6ubTna_spk0Q/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPpSf1xq6sZOnWJCUEOaMdNaaAOp1aBqFkr_lUAPYqNV2v7TfZOnUERMEqy-hXqIYdxb5GkGCcfAVal7wwOD6lIgUwqy8vtr4payk3AW4We1sX7wpv9EVJa6DWHbDFyOW6ubTna_spk0Q/s1600/1.png" /></a></div>
<br />
<br />
<div style="text-align: justify;">
2) Keep in mind, that could be several breaking changes between R# SDK versions, but nothing that couldn’t be handled with pre-processor directives.</div>
<br />
<pre class="brush: csharp; gutter: false; toolbar:false">#if R70 || R71 || R80
protected override void Process(CSharpGeneratorContext context)
#elif R61
public override void Process(CSharpGeneratorContext context)
#endif
{
CSharpElementFactory factory = CSharpElementFactory.GetInstance(context.Root.GetPsiModule());
#if R80
IDeclaredType viewModelToModelAttributeClrType = TypeFactory.CreateTypeByCLRName(CatelMVVM.ViewModelToModelAttribute, context.PsiModule, UniversalModuleReferenceContext.Instance);
#else
IDeclaredType viewModelToModelAttributeClrType = TypeFactory.CreateTypeByCLRName(CatelMVVM.ViewModelToModelAttribute, context.PsiModule);
#endif
/*...*/
#if R80
var fixedArguments = new List<AttributeValue> { new AttributeValue(ClrConstantValueFactory.CreateStringValue(model.ShortName, context.PsiModule, UniversalModuleReferenceContext.Instance)) };
#else
var fixedArguments = new List<AttributeValue> { new AttributeValue(ClrConstantValueFactory.CreateStringValue(model.ShortName, context.PsiModule)) };
#endif
if (propertyName != modelProperty.ShortName)
{
#if R80
fixedArguments.Add(new AttributeValue(ClrConstantValueFactory.CreateStringValue(modelProperty.ShortName, context.PsiModule, UniversalModuleReferenceContext.Instance)));
#else
fixedArguments.Add(new AttributeValue(ClrConstantValueFactory.CreateStringValue(modelProperty.ShortName, context.PsiModule)));
#endif
}
/*...*/
}
}
}
}
</pre>
<br />
3) Keep all these entire project sources synchronized. Could be very easy thanks to <a href="http://visualstudiogallery.msdn.microsoft.com/079b3fca-e2b1-4fbc-8992-6b3f4134fea9">Caitlyn</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNLj9BTGyD36cy2XAHkRg_H3PAxfIHgosOtxZk73jpnFts_JNMPLGLld4UAcxvUanL6OOiedMI47gihv7temAcpkmGIjrhzHS3wohuaal2haZfnK1nH-Ja_DP8vYBa8paYMYGRBBVXnnY/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNLj9BTGyD36cy2XAHkRg_H3PAxfIHgosOtxZk73jpnFts_JNMPLGLld4UAcxvUanL6OOiedMI47gihv7temAcpkmGIjrhzHS3wohuaal2haZfnK1nH-Ja_DP8vYBa8paYMYGRBBVXnnY/s1600/4.png" height="315" width="320" /></a></div>
<br /><div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmHCbSOkMpMBXxFjCEaXgXER8b9zyFjY4tqPd_gPYzzApXZr1-9o0OTWxzrTh4jNYspqae2-TgT0cE-Cc5-xsc4MP0t-b2TthLsLqDC16jKn4yXvRg4A-PcWTYRI9PQqTpTva-h9eHr0w/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmHCbSOkMpMBXxFjCEaXgXER8b9zyFjY4tqPd_gPYzzApXZr1-9o0OTWxzrTh4jNYspqae2-TgT0cE-Cc5-xsc4MP0t-b2TthLsLqDC16jKn4yXvRg4A-PcWTYRI9PQqTpTva-h9eHr0w/s1600/2.png" /></a></div>
<br />
<br />
<div style="text-align: justify;">
4) Finally redirect the build projects outputs to dealing with ease with the packaging of the deployment units.</div>
<br />
<h3>
Building the deployment units</h3>
<div style="text-align: justify;">
The R# plugin build process indeed an heterogeneous one as any build process. Even though this build could be handled via msbuild tasks, we actually recommend the usage of tools with intuitive GUI in order to quickly creating and debugging such build "scripts", such as <a href="http://www.finalbuilder.com/">FinalBuilder</a> or <a href="http://www.kinook.com/VisBuildPro/">VisualBuild</a>.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY003bpY0L0_KeEG6-wMgjM7iznVm208TBVcJRhFc_gx_b4Gjku42V4PHcGqRYk0oEgSE9B754lP8fCuahNFaykLZNjGCMZNHMhevbhyphenhyphenraCENysGbLhL1wQwa1tZ_Xt2vKVu96TpVmlOo/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY003bpY0L0_KeEG6-wMgjM7iznVm208TBVcJRhFc_gx_b4Gjku42V4PHcGqRYk0oEgSE9B754lP8fCuahNFaykLZNjGCMZNHMhevbhyphenhyphenraCENysGbLhL1wQwa1tZ_Xt2vKVu96TpVmlOo/s1600/3.png" height="489" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
1) Since 8.0 R# version the NuGet based extension manager is available. Therefore one of the build output could be a NuGet package to distribute your plugin through the ReSharper extension gallery.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
2) But NuGet based extension manager is not available for all R# versions. Therefore a second build output could also be classic deployment unit built on top of any of the existing installer system. For instance <a href="http://www.jrsoftware.org/isinfo.php">InnoSetup</a> or <a href="http://nsis.sourceforge.net/Main_Page">NSIS</a>.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The following are the code snippets from the install and uninstall sections of CatelR# setup. Notice how we deal with build output to support all R# versions.</div>
<br />
<b></b><br />
<pre class="brush: plain; gutter: false; toolbar:false"># ...
# Installer section
# ...
Push "v6.1"
Push "v7.0"
Push "v7.1"
Push "v8.0"
Push "v8.1"
${Do}
Pop $0
ReadRegStr $1 HKLM "Software\JetBrains\ReSharper\$0" InstallDir
${If} $1 != ''
DetailPrint "Installing Catel.ReSharper for JetBrains ReSharper $0"
SetOutPath "$1\Plugins\$(^Name)"
${If} $0 == 'v6.1'
File /r "..\..\output\Debug\v6.1\*.dll"
${ElseIf} $0 == 'v7.0'
File /r "..\..\output\Debug\v7.0\*.dll"
${ElseIf} $0 == 'v7.1'
File /r "..\..\output\Debug\v7.1\*.dll"
${ElseIf} $0 == 'v8.0'
File /r "..\..\output\Debug\v8.0\*.dll"
${ElseIf} $0 == 'v8.1'
File /r "..\..\output\Debug\v8.1\*.dll"
${EndIf}
Push true
Pop $3
WriteRegStr HKLM "${REGKEY}" "$0" 1
${EndIf}
${LoopUntil} $0 == "v6.1"
# ...
# ...
# Uninstaller section
# ...
Push "v6.1"
Push "v7.0"
Push "v7.1"
Push "v8.0"
Push "v8.1"
${Do}
Pop $0
ReadRegStr $1 HKLM "${REGKEY}" "$0"
${If} $1 == '1'
ReadRegStr $2 HKLM "Software\JetBrains\ReSharper\$0" InstallDir
${If} $2 != ''
RMDir /r /REBOOTOK "$2\Plugins\$(^Name)"
DeleteRegValue HKLM "${REGKEY}" "$0"
${EndIf}
${EndIf}
${LoopUntil} $0 == "v6.1"
# ...
</pre>
<br />
<h3>
Conclusions </h3>
<h3>
</h3>
<div style="text-align: justify;">
Just a few minutes ago, I read the notification about the release of R#8.2 EAP. It’s a good moment to revalidate this approach. Let’s see,… creating a new project with post-fix 82, …installing the SDK package, ..., ...time out, sorry…slow connection…,…,…,..updating the build script, …, …, … reviewing for breaking changes, good news, there are no breaking changes,… updating setup script…., committing source modifications, … running the build script and it’s done.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now you can update the extension from the <a href="https://resharper-plugins.jetbrains.com/packages/Catel.ReSharper/">extension gallery</a> or download the <a href="http://1drv.ms/1gnWx4w">full installer</a> of CatelR# with support for <a href="http://confluence.jetbrains.com/display/ReSharper/ReSharper+8.2+EAP">R#8.2 EAP</a> ;)</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-62111344635451932612013-10-22T19:42:00.002-04:002013-10-23T11:27:16.585-04:00Catel extends Prism modularity options through NuGet<h3>
Introduction</h3>
<br />
<div style="text-align: justify;">
Prism provides a lot of options regarding modularity by default. Fact is that most of the stuff you need to build a modularized application is available on Prism. Prism contains several modularity options including ways to retrieve modules from a directory, set them up through the configuration file, and even options to create modularized Silverlight applications.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
On the other hand, Catel provides support for module catalog composition in order to enable more than one modularity options into a single application.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Nowadays, initiatives around NuGet come from everywhere, such as <a href="https://github.com/github/Shimmer" target="_blank"><i>Shimmer</i></a> with the same goal of <i>ClickOnce</i> (but works), <a href="http://octopusdeploy.com/" target="_blank"><i>OctopusDeploy</i></a> for release promotion and application deployment or even the recently released <i><a href="http://blogs.jetbrains.com/dotnet/2013/05/resharper-8-eap-nuget-based-extension-manager/" target="_blank">extension manager</a></i> of <i>ReSharper 8.0</i>. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
So, the Catel team comes with a new one and the fact is that we wondered why no one told about this before: </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: center;">
<span style="background-color: white;"><span style="font-size: large;">What if you would be able to distribute your application's modules through NuGet?</span></span> </div>
<div style="text-align: center;">
<br /></div>
If you want to know how, take a look.<br />
<br />
<br />
<h3>
Enabling NuGet based modularity option</h3>
<br />
<div style="text-align: justify;">
With the forthcoming 3.8 version of Catel you will be able to install and load modules from a NuGet repository. The only thing you have to do is:</div>
<ol style="text-align: justify;">
<li>Write a module as you know with Prism (or better in combination with Catel).</li>
<li>Create a NuGet package for the module and publish it into your favorite gallery. </li>
<li>Use and configure the <i>NuGetBasedModuleCatalog </i>in the application’s bootstrapper.</li>
</ol>
<div style="text-align: justify;">
The first two steps are well documented. For details see <a href="http://docs.nuget.org/docs/creating-packages/creating-and-publishing-a-package" target="_blank">creating and publishing a package</a> and <a href="https://catelproject.atlassian.net/wiki/display/CTL/Declaring+modules" target="_blank">declaring modules</a> from NuGet and Catel documentation.</div>
<br />
<br />
So, now we can focus on the third one.<br />
<br />
<h3>
Use and configure the <i>NuGetBasedModuleCatalog</i> in the application’s bootstrapper</h3>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-weight: normal;">In order to simplify the following explanation we published a package into the official NuGet Gallery named <a href="http://www.nuget.org/packages/Catel.Examples.WPF.Prism.Modules.NuGetBasedModuleA">Catel.Examples.WPF.Prism.Modules.NuGetBasedModuleA</a>. Such package contains an assembly with a single class like this one:</span></div>
<span style="font-weight: normal;"> </span>
<br />
<pre class="brush: csharp; gutter: false;">public class NuGetBasedModuleA : ModuleBase
{
public NuGetBasedModuleA(IServiceLocator container):base("NuGetBasedModuleA", null, container)
{
}
protected virtual void OnInitialized()
{
var messageService = this.Container.ResolveType<IMessageService>();
messageService.Show("NuGetBasedModuleA Loaded!!");
}
}
</pre>
<br />
<div style="text-align: justify;">
<span style="font-weight: normal;">Let’s start writing an application that will use this public packaged module. Indeed, the main point of interest here is about the usage and configuration of the <i>NuGetBasedModuleCatalog</i>. Therefore just write the bootstrapper as follow:</span></div>
<div style="text-align: justify;">
<br /></div>
<pre class="brush: csharp; gutter: false ; highlight:[10]">public class Boot : BootstrapperBase<MainWindow, NuGetBaseModuleCatalog>
{
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
this.ModuleCatalog.AddModule(new ModuleInfo
{
ModuleName = "NuGetBasedModuleA",
ModuleType = "Catel.Examples.WPF.Prism.Modules.NuGetBasedModuleA.NuGetBasedModuleA, Catel.Examples.WPF.Prism.Modules.NuGetBasedModuleA",
Ref = "Catel.Examples.WPF.Prism.Modules.NuGetBasedModuleA, 1.0.0-BETA",
InitializationMode = InitializationMode.OnDemand
});
}
}
</pre>
<br />
<div style="text-align: justify;">
<span style="font-weight: normal;">Notice how the <i>Ref </i>property of <i>ModuleInfo</i> is used to specify the package id and optionally the version number. If the version number is not specified then the application always will try to download the latest version keeping the modules up to date.</span><br />
<br />
<span style="font-weight: normal;">Finally, to make this demo work, just put in the XAML<i> </i>of the main window the <i>ModuleManagerView </i>control, run</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHi4GgqQkJgIOjm4quQIjkdChOSfFBnKEYbRQ55F6rLY9o9RKhvuSi1gx5GjHhr8obzJwMKLC1TA05EHQMBEnu3QXbbx9wi4_zEV2K-aC6CPX7xrIy_9N8PdPynOv_VJkG9A1lFOjwGcc/s1600/Demo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="76" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHi4GgqQkJgIOjm4quQIjkdChOSfFBnKEYbRQ55F6rLY9o9RKhvuSi1gx5GjHhr8obzJwMKLC1TA05EHQMBEnu3QXbbx9wi4_zEV2K-aC6CPX7xrIy_9N8PdPynOv_VJkG9A1lFOjwGcc/s320/Demo.png" width="320" /></a></div>
<br />
and click the check box.<br />
<br />
<h3>
Conclusions</h3>
<br />
<div style="text-align: justify;">
<b><span style="font-weight: normal;">Yes, we did it <a href="http://likewastoldtome.blogspot.com/2012/11/more-about-catel-and-prism-in.html">again</a>. Catel keeps working </span></b>alongside Prism<b><span style="font-weight: normal;">. Now, we extended Prism’s modularity options through NuGet </span></b><span style="font-weight: normal;">in order to </span><b><span style="font-weight: normal;">provide a powerful mechanism of application module distribution. </span></b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b><span style="font-weight: normal;">If you want to try, just get the latest beta package of <a href="http://www.nuget.org/packages/Catel.Extensions.Prism">Catel.Extensions.Prism</a> and discover by yourself all </span></b><span style="font-weight: normal;">scena</span><b><span style="font-weight: normal;">rios </span></b><span style="font-weight: normal;">that</span><b><span style="font-weight: normal;"> you can handle with this <a href="http://www.catelproject.com/">Catel</a><b> </b></span></b><span style="font-weight: normal;">exclusive</span><b><span style="font-weight: normal;"> feature.</span></b></div>
<h3>
</h3>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com5tag:blogger.com,1999:blog-9155852904520845376.post-4326012979816678702013-09-28T03:11:00.000-04:002013-09-28T09:15:40.806-04:00Keep updated CatelR# with ReSharper 8.0<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIW_aaCjzMgSaS1LF-TIsZrlQI_l_YprWRlMa7-L1GWqkeZX__FRlAv6hPAk7XJkCzmNpJJRDfGIUfM1XKiltloxgFxgp_CbhfVIhxuyd9Bz1A0Tr6qYNV6CvHP2qczlEEtRV1cOXoYT0/s1600/CatelR%25232.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIW_aaCjzMgSaS1LF-TIsZrlQI_l_YprWRlMa7-L1GWqkeZX__FRlAv6hPAk7XJkCzmNpJJRDfGIUfM1XKiltloxgFxgp_CbhfVIhxuyd9Bz1A0Tr6qYNV6CvHP2qczlEEtRV1cOXoYT0/s200/CatelR%25232.png" width="200" /></a></div>
<div style="text-align: justify;">
CatelR# is now compatible with the latest version of <a href="http://www.jetbrains.com/resharper/download/" target="_blank">ReSharper </a>(R#).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
We also keep the compatibility with the most recent R# versions
including 6.0, 7.0 and 7.1. The full installer, that also includes the R# 8.0
assemblies, of the latest beta of CatelR# is available to download <a href="http://sdrv.ms/15AIdW6">here</a>.</div>
<br />
<div style="text-align: justify;">
R# 8.0 includes a <a href="http://blogs.jetbrains.com/dotnet/2013/05/resharper-8-eap-nuget-based-extension-manager/">NuGet based Extension Manager</a> and the <a href="http://www.catelproject.com/">Catel</a> Team started to publish the CatelR# extension in the <a href="https://resharper-plugins.jetbrains.com/packages/Catel.ReSharper/">Extension Gallery</a>.</div>
<br />
<div style="text-align: justify;">
Yes, CatelR# is alive. We keep working in more features and also are
waiting for your ideas. You got one? Let us <a href="https://catelproject.atlassian.net/">know</a>!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-weight: normal;">So, ensure yourself to install the latest version of R# and you will no miss any of the forthcoming CatelR#'s cool features.</span></div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com3tag:blogger.com,1999:blog-9155852904520845376.post-48499647447680069432013-09-27T15:43:00.002-04:002021-04-09T09:44:33.066-04:00How Configure HTTP Access to Analysis Services on Internet Information Services from Powershell<h3 style="text-align: justify;">
Introduction</h3>
<div>
<br />
<div style="text-align: justify;">
“<i>You can enable HTTP access to Analysis Services by configuring MSMDPUMP.dll, an ISAPI extension that runs in Internet Information Services (IIS) and pumps data to and from client applications and an Analysis Services server. This approach provides an alternative means for connecting to Analysis Services when your BI solution calls for the following capabilities:</i></div>
<ul>
<li style="text-align: justify;"><i>Client access is over Internet or extranet connections, with restrictions on which ports can be enabled.</i></li>
</ul>
<ul>
<li style="text-align: justify;"><i>Client connections are from non-trusted domains in the same network. {…}</i>"</li>
</ul>
<div style="text-align: justify;">
The text above, is the way of the “<a href="http://technet.microsoft.com/en-us/library/gg492140.aspx" target="_blank">Configure HTTP Access to Analysis Services on Internet Information Services (IIS)</a>” guide start. Such steps are typical to setup the development environment or production server of a BI solution that move data over HTTP directly from an instance of SQL Server Analysis Services.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Repeat these steps over and over again encourage me to write the script to automate most of the steps of this guide with Powershell.</div>
</div>
<div style="text-align: justify;">
<br /></div>
<h3>
The Code</h3>
<div>
<div style="text-align: justify;">
So, without more introduction here is the source:<br />
<br />
1) <span style="text-align: start;">Import or load the WebAdministration Module or PSSnapin (depends on IIS version)</span></div>
</div>
<pre class="brush: powershell; toolbar:false; first-line:11">$webAdminModule = Get-Module -ListAvailable | Where-Object { $_.Name -eq "WebAdministration" }
if ($webAdminModule -ne $null)
{
Write-Host "Importing WebApplication Module..."
Import-Module -ModuleInfo $webAdminModule
}
else
{
Write-Host "Loading WebApplication PSSnapin..."
Add-PSSnapin WebAdministration
}
</pre>
<br />
<span style="text-align: justify;">2) </span>Create and setup application pool<br />
<pre class="brush: powershell; toolbar:false; first-line:23">Write-Host "Creating application pool OLAP..."
New-WebAppPool -Name OLAP -ErrorAction SilentlyContinue
Set-ItemProperty IIS:\AppPools\OLAP -Name ManagedRuntimeVersion -Value v2.0.50727
Set-ItemProperty IIS:\AppPools\OLAP -Name ManagedPipelineMode -Value 1
</pre>
<br />
3) Set application pool credentials<br />
<pre class="brush: powershell; toolbar:false; first-line:27">Write-Host "Enter application pool credentials"
$userName = Read-Host "UserName"
$securedPassword = Read-Host "Password" -AsSecureString
$userName = $credential.UserName
$password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securedPassword));
Set-ItemProperty IIS:\AppPools\OLAP -Name ProcessModel -Value @{ userName="$userName"; password="$password"; IdentityType=3 }
</pre>
<br />
3) Create the web application<br />
<pre class="brush: powershell; toolbar:false; first-line:35">Write-Host "Creating OLAP Application in Default Web Site..."
New-Item 'IIS:\Sites\Default Web Site\OLAP' -Type Application -PhysicalPath "C:\Program Files\Microsoft SQL Server\MSAS10_50.MSSQLSERVER\OLAP\bin\isapi"
Set-ItemProperty "IIS:\Sites\Default Web Site\OLAP" -Name ApplicationPool -Value OLAP
Set-WebConfiguration system.web/authentication 'IIS:\Sites\Default Web Site\OLAP' -value @{ mode = 'None' }
</pre>
<br />
4) Add the handler mapping (it can't be done with the available command-lets, so)<br />
<pre class="brush: powershell; toolbar:false; first-line:40">Write-Host "Adding the handler mapping..."
[System.Reflection.Assembly]::LoadFrom("C:\windows\system32\inetsrv\Microsoft.Web.Administration.dll")
$isapiPath = "C:\Program Files\Microsoft SQL Server\MSAS10_50.MSSQLSERVER\OLAP\bin\isapi\msmdpump.dll"
$isapiConfiguration = Get-WebConfiguration "/system.webServer/security/isapiCgiRestriction/add[@path='$isapiPath']/@allowed"
if (-not($isapiConfiguration -eq $null -or $isapiConfiguration.value))
{
Write-Host "Enabling ISAPI Module - $isapiPath"
Set-WebConfiguration "/system.webServer/security/isapiCgiRestriction/add[@path='$isapiPath']/@allowed" -value "True" -PSPath:IIS:\
}
$serverManager = New-Object Microsoft.Web.Administration.ServerManager
if ($isapiConfiguration -eq $null)
{
Write-Host "Adding and enabling ISAPI Module - $isapiPath"
$appHostConfig = $serverManager.GetApplicationHostConfiguration();
$isapiCgiRestrictionSection = $appHostConfig.GetSection("system.webServer/security/isapiCgiRestriction");
$isapiCgiRestrictionCollection = $isapiCgiRestrictionSection.GetCollection();
$cgiRestrictionElement = $isapiCgiRestrictionCollection.CreateElement("add");
$cgiRestrictionElement.SetAttributeValue("path", "C:\Program Files\Microsoft SQL Server\MSAS10_50.MSSQLSERVER\OLAP\bin\isapi\msmdpump.dll");
$cgiRestrictionElement.SetAttributeValue("allowed", "true");
$cgiRestrictionElement.SetAttributeValue("groupId", "");
$isapiCgiRestrictionCollection.AddAt(0, $cgiRestrictionElement);
}
$webConfig = $serverManager.GetWebConfiguration("Default Web Site", "OLAP");
$handlersSection = $webConfig.GetSection("system.webServer/handlers");
$handlersCollection = $handlersSection.GetCollection();
$handlerElement = $handlersCollection.CreateElement("add");
$handlerElement.SetAttributeValue("name", "OLAP");
$handlerElement.SetAttributeValue("path", "msmdpump.dll");
$handlerElement.SetAttributeValue("verb", "*");
$handlerElement.SetAttributeValue("modules", "IsapiModule");
$handlerElement.SetAttributeValue("scriptProcessor", "C:\Program Files\Microsoft SQL Server\MSAS10_50.MSSQLSERVER\OLAP\bin\isapi\msmdpump.dll");
$handlersCollection.AddAt(0, $handlerElement);
$serverManager.CommitChanges();</pre>
<div style="text-align: justify;">
<b><br /></b>
<b>The main differences with the original non-automated guide are: </b><br />
<ul>
<li>Doesn’t create a copy of the files in ‘C:\Program Files\Microsoft SQL Server\MSAS10_50.MSSQLSERVER\OLAP\bin\isapi’ to a ‘c:\inetpub\wwwroot\olap’ just publishes directly the original directory as application. Our deployments (production or workstation) typically involve a single instance of SQL Server Analysis Service.</li>
<li>Doesn’t modify the archive msmdpump.ini because the default configuration is enough.</li>
<li>Doesn't grant data access permissions. Assumes that the application pool’s credentials have the right data access permissions.</li>
</ul>
<br />
<h3>
<span style="text-align: start;">Conclusions</span></h3>
</div>
<div style="text-align: justify;">
<div>
<div>
I’m agree with you. This script can be more parameterized. But with this simple “coded” blog post I just want to send you a message. </div>
<div>
<br /></div>
<div>
When you have to face automation tasks of your daily work follow this tips:</div>
<div>
<ul>
<li>Just do a small step at once.</li>
<li>Don’t add complexity to the solution more than your needs.</li>
<li>Don’t overwhelm you, do it for fun. </li>
<li>The code will be better tomorrow. </li>
<li>One day as result of your small improvements the solution will look just like you ever wanted. </li>
</ul>
</div>
<div>
<br />
But if I you have something to automate just start NOW ;-). </div>
</div>
</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com3tag:blogger.com,1999:blog-9155852904520845376.post-61711456101308895022013-08-14T23:46:00.000-04:002013-08-18T08:48:05.726-04:00If you can’t defeat them, just “join” them – Part I<h3>
Introduction </h3>
<div style="text-align: justify;">
I spend a lot of time using Subversion as the Version Control System for my development team. The fact is I love Subversion and strongly think that there is no a centralized version control system (CVCS) like Subversion. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
On the other hand, my organization promotes the usage of Microsoft Team Foundation Server (TFS) as Application Life-Cycle Management (ALM) and I also think TFS is a great integrated environment. However some of its services are in disadvantage mainly in terms of usability against some third party software. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But I’m not here to talk about TFS vs. Subversion, even when the user experience of the Visual SVN is better than Team Explorer (even in VS2012).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I just want to share how I committed to the indication of shutting down my local team Subversion, and move my entire sources to the centralized TFS, keeping all my “non-integrated” development environment’s cool features. </div>
<br />
<h3>
What features will I miss if I’ll move to TFS version control system?</h3>
<div style="text-align: justify;">
I received a lot of critics because I don’t use the integration features of Visual Studio Team System. Actually I have a non-fully integrated environment for ALM (TFS and Subversion) but always keeping traces between sources and tasks. I know that TFS has built-in support for this and also have a check-in policy system to “force” some team disciplines.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
On the other hand, I needed move my team into some of self-discipline development practices to control the existing “chaos”: uncommented commits, unplanned or non-well-reported work, and more. In such scenario, I was “forced” to ensure the Subversion and TFS integration and also “route” my team into the right direction. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I thought that I would able to handle this situation starting from the Subversion with relative ease and I was right. I implemented a hook to enforce the usage of these practices and also solve some integration issues. The continuous integration server (Team City) also helps me in track task with sources, listing all related tasks from the TFS. The fact is I also modified the existing TFS integration plugin to work as I expected, but this is part of another history. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Therefore with a simple Subversion hook I get a centralized or server side “check-in” polices system to:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Avoid empty commit messages:</b> Every single commit must contain a description.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Avoid unplanned work:</b> Every single commit message must contain the id of the work item of type <i>“Sprint Backlog Item”</i> in <i>“In Progress”</i> state. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Automatically track the task history:</b> As every single commit message contains a work item id then all commit messages are attached as history of the work item.<b> </b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Accept some relevant commit comments or messages:</b> A "relevant" commit comment is about a commit comment that indicates a feature completion. It should be related with addition, modification, removal or bug fixing, but just when those goals are actually "<i>Done, Done"</i>. The usage of this pattern also turn automatically to the <i>“Done”</i> the state of the related work items. This messages can also use to generate the <a href="http://likewastoldtome.blogspot.com/2012/06/release-notes-generation-puzzle.html" rel="nofollow" target="_blank">release notes</a> document for a specific version</div>
<br />
<h3>
Migrating from SVN to TFS version control system</h3>
<div style="text-align: justify;">
My support team started with some existing migration tools but the outcome was incomplete (with runtime errors included). On the other hand, I actually thought in move from SVN to GIT, because the next version of TFS comes with built-in support for GIT repositories but apparently “they” can’t wait and yes, I have to move my source to TFS.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Therefore, with the GIT idea in my mind, I came across a couple of GIT extensions and I started to type the follow commands:</div>
<br />
<pre class="brush: text; toolbar:false;">> git svn clone http://svn.mydivsion:3690/repository
> git tfs init http://tfs.mycompany:8080/tfs/DefaultCollection/MyDivision $/MyDivision
> git tfs fetch
> git rebase /remotes/default/tfs master
> git tfs rcheckin –authors="authors.txt"
</pre>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Everything works like charm. The full migration can be done. Now, after years of discussions, I lose and “they" win. Now, I have to start over again.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The fact is that I think TFS was built on top of one of the best
Business Intelligence Platform (BI) ever made and can be configured to
produce a lot of multidimensional metrics very useful for ALM. But this migration to TFS version control system are backwards steps, at least for me.</div>
<br />
<br />
<h3>
Hook the TFS commits from the server side</h3>
<div style="text-align: justify;">
As I wrote before, TFS has its own check-in policy system. Actually it is a “client side evaluation” check-in policy system, and I don’t like them. Such policies can also be overridden by the developers. TFS check-in policy system looks more like a warnings system.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But TFS comes with a server side event handling system and can be plugged-in deploying an assembly into the web service plugins directory of the application tier of the current installation of TFS.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I started to re-write all my useful check-in polices, referencing the right TFS assemblies. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
For instance, the “<b>Avoid empty commit messages</b>” policy looks like this:</div>
<br />
<pre class="brush: csharp; toolbar: false; highlight=[24,25]">public class AvoidEmptyCommitMessagePolicy : ISubscriber
{
public string Name
{
get { return " AvoidEmptyCommitMessagePolicy"; }
}
public SubscriberPriority Priority
{
get { return SubscriberPriority.Normal; }
}
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
{
statusCode = 0;
properties = null;
statusMessage = string.Empty;
var eventNotificationStatus = EventNotificationStatus.ActionPermitted;
if (notificationType == NotificationType.DecisionPoint)
{
var checkinNotification = notificationEventArgs as CheckinNotification;
if (checkinNotification != null && string.IsNullOrEmpty(checkinNotification.Comment))
{
statusMessage = "Your commit has been blocked because you didn't give any log message.\n Please write a log message describing the purpose of your changes and \n then try committing again.";
eventNotificationStatus = EventNotificationStatus.ActionDenied;
}
}
return eventNotificationStatus;
}
}
</pre>
The “<b>Avoid unplanned work</b>” looks like this: <br />
<br />
<pre class="brush: csharp; toolbar: false;highlight=[12,13,22,23]">public class AvoidUnplannedWorkPolicy : ISubscriber
{
/*...*/
if (checkinNotification != null)
{
CheckinNotificationInfo notificationInfo = checkinNotification.NotificationInfo;
CheckinNotificationWorkItemInfo[] workItemInfos = notificationInfo.WorkItemInfo;
if (notificationType == NotificationType.DecisionPoint)
{
if (workItemInfos == null || workItemInfos.Length == 0)
{
statusMessage = "Your commit has been blocked because you didn't give any work item linked to this changeset.";
eventNotificationStatus = EventNotificationStatus.ActionDenied;
}
var teamFoundationLocationService = requestContext.GetService<TeamFoundationLocationService>();
var uri = new Uri(teamFoundationLocationService.ServerAccessMapping.AccessPoint + "/" + requestContext.ServiceHost.Name);
TfsTeamProjectCollection tfsTeamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(uri);
var workItemStore = tfsTeamProjectCollection.GetService<WorkItemStore>();
if (workItemInfos.Exists(workItem => workItem.Type != "Sprint Backlog Item" || workItem.State != "In Progress"))
{
statusMessage = "Your commit has been blocked because you didn't give any “Sprint Backlog Item” in state "In Progress" linked to this changeset.";
eventNotificationStatus = EventNotificationStatus.ActionDenied;
}
}
}
/*...*/
}
</pre>
and so on.<br />
<br />
<div style="text-align: center;">
<i>The AvoidUnplannedWorkPolicy is very Scrum for Team System process template related. It can be done more generic and cross process template support, but it’s just an example. </i> </div>
<br />
That fact is I’m now thinking about a lot of policies to improve my team practices, but if tell you I have to kill you ;-) <br />
<br />
<h3>
Conclusions</h3>
Seems like I can live with such
transition (to TFS version control system), but it isn’t all happiness. Now I
have to wait for an approval process to deploy my server side policies in the
main TFS server. But if “they” don’t like such intrusion then probably I will
also back into the “chaos”.
<br />
<br />
In the meantime I just wrote this blog post.<br />
<br />
<div style="text-align: center;">
<i>PD: Yes I'm back in the game again, but now without Subversion, with my ankle ligaments broken as outcome of a basketball game, and with my team Villa Clara as the new Champion of the Cuban National Baseball League ;-)</i></div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com4tag:blogger.com,1999:blog-9155852904520845376.post-86785799115512628432013-01-17T14:12:00.005-05:002022-02-12T12:01:57.481-05:00Cache storage explained<h3 style="text-align: justify;">
Introduction </h3>
<div style="text-align: justify;">
Caching is about improving applications performance. The most expensive performance costs of the applications are related to the data retrieving, typically when this data requires to be moved across the network or loaded from disk. But some data have a slow changing behavior (a.k.a nonvolatile) and don't require to be re-read with the same frequency of the volatile data. </div>
<br />
<div style="text-align: justify;">
So, to improve your application performance and handle this "nonvolatile" data from a pretty clean approach, <a href="https://github.com/Catel/Catel" target="_blank">Catel</a> comes with a CacheStorage<TKey, TValue> class. Notice that the first generic parameter is the type of the key and the second the type of the value that will be stored, just like a Dictionary<TKey, TValue> but CacheStorage isn't it just a Dictionary. </div>
<br />
<div style="text-align: justify;">
This class allows you to retrieve data and store it into the cache with a single statement and also helps you to handle the expiration policy if you need it. </div>
<br />
<div style="text-align: justify;">
Let’s take a look into these features: </div>
<br />
<h3 style="text-align: justify;">
Initializing a cache storage</h3>
<div style="text-align: justify;">
To initialize a cache storage field into your class use the following code:<br />
<br />
<pre class="brush:csharp; first-line: 10; toolbar: false;">/*...*/
private readonly CacheStorage<string, Person> _personCache = new CacheStorageCacheStorage<string, Person>(allowNullValues: true);
</pre>
</div>
<br />
<h3 style="text-align: justify;">
Retrieve data and store it into the cache with a single statement</h3>
<div style="text-align: justify;">
To retrieve data and storing into a cache with a single statement use the following code:<br />
<br />
<pre class="brush:csharp; first-line: 35; toolbar: false;">/*...*/
var person = _personCache.GetFromCacheOrFetch(Id, () => service.FindPersonById(Id));</pre>
<br />
When this statement is executed more than once with the same key, the value will be retrieved from the cache storage instead of from the service call (notice the usage of a lambda expression). The service call will be executed just the first time or if the item is removed from the cache manually or automatically due to the expiration policy.</div>
<br />
<h3>
Using cache expiration policies</h3>
<div style="text-align: justify;">
The cache expiration policies add a removal behavior to the cache storage items. A policy signals that an item is expired to make that cache storage remove the item automatically.</div>
<div style="text-align: justify;">
<br />
A default cache expiration policy initialization code can be specified during cache storage initialization constructor:<br />
<br />
<pre class="brush:csharp; first-line: 10; toolbar: false;">/*...*/
private readonly CacheStorage<string, Person> _personCache = new CacheStorageCacheStorage<string, Person>(() => ExpirationPolicy.Duration(TimeSpan.FromMinutes(5)), true);</pre>
<br />
You can specify a specific expiration policy for an item when it's stored:<br />
<br />
<pre class="brush:csharp; first-line: 35; toolbar: false;">/*...*/
var person = _personCache.GetFromCacheOrFetch(id, () => service.GetPersonById(id), ExpirationPolicy.Duration(TimeSpan.FromMinutes(10)));</pre>
<br />
The default cache policy specified at cache storage initialization will be used if during item storing the expiration policy is not specified.</div>
<br />
<h3>
Build-in expiration policies</h3>
<div style="text-align: justify;">
<a href="http://catel.codeplex.com/" target="_blank">Catel</a> comes with build-in expiration policies. They are listed in the following table:<br />
<br />
<table border="1" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td style="background-color: #cccccc;" valign="top" width="30%"><b>Expiration policy</b>
</td>
<td style="background-color: #cccccc;" valign="top" width="20%"><b>Type</b>
</td>
<td style="background-color: #cccccc;" valign="top" width="50%"><b>Description</b>
</td>
<td style="background-color: #cccccc;" valign="top" width="20%"><b>Initialization code sample</b>
</td>
</tr>
<tr>
<td valign="top" width="30%">AbsoluteExpirationPolicy
</td>
<td valign="top" width="20%">Time-base
</td>
<td style="text-align: left;" valign="top" width="50%">The cache item will expire on the absolute expiration DateTime
</td>
<td valign="top" width="20%"><pre class="brush:csharp; toolbar: false;">ExpirationPolicy.
Absolute(new DateTime(21, 12, 2012))</pre>
</td>
</tr>
<tr>
<td valign="top" width="30%">DurationExpirationPolicy
</td>
<td valign="top" width="20%">Time-base
</td>
<td style="text-align: left;" valign="top" width="50%">The cache item will expire using the duration TimeSpan to calculate the absolute
expiration from DateTime.Now
</td>
<td valign="top" width="20%"><pre class="brush:csharp; toolbar: false;">ExpirationPolicy.
Duration(TimeSpan.FromMinutes(5))</pre>
</td>
</tr>
<tr>
<td valign="top" width="30%">SlidingExpirationPolicy
</td>
<td valign="top" width="20%">Time-base
</td>
<td style="text-align: left;" valign="top" width="50%">The cache item will expire using the duration TimeSpan to calculate the absolute
expiration from DateTime.Now, but every time the item is requested, it is expanded
again with the specified TimeSpan
</td>
<td valign="top" width="20%"><pre class="brush:csharp; toolbar: false;">ExpirationPolicy.
Sliding(TimeSpan.FromMinutes(5))</pre>
</td>
</tr>
<tr>
<td valign="top" width="30%">CustomExpirationPolicy
</td>
<td valign="top" width="20%">Custom
</td>
<td style="text-align: left;" valign="top" width="50%">The cache item will expire using the expire function and execute the reset action
if is specified. The example shows how to create a sliding expiration policy with
a custom expiration policy.
</td>
<td valign="top" width="20%"><pre class="brush:csharp; toolbar: false;">var startDateTime = DateTime.Now;
var duration = TimeSpan.FromMinutes(5);
ExpirationPolicy.
Custom(() => DateTime.Now >
startDateTime.Add(duration),
() => startDateTime = DateTime.Now);
</pre>
</td>
</tr>
<tr>
<td valign="top" width="20%">CompositeExpirationPolicy
</td>
<td valign="top">Custom
</td>
<td style="text-align: left;" valign="top" width="50%">Combines several expiration policies into a single one. It can be configured to expire
when any or all policies expire.
</td>
<td valign="top" width="20%"><pre class="brush:csharp; toolbar: false;">new CompositeExpirationPolicy().
Add(ExpirationPolicy.
Sliding(TimeSpan.FromMinutes(5))).
Add(ExpirationPolicy.
Custom(()=>...))</pre>
</td>
</tr>
</tbody></table>
</div>
<br />
<h3 style="text-align: justify;">
Implementing your own expiration cache policy
</h3>
If the CustomExpirationPolicy is not enough, you can implement your own expiration policy to makes that cache item expires triggered from a custom event. You are also able to add some code to reset the expiration policy if the item is read from the cache before it expires (just like SlidingExpirationPolicy does).<br />
<br />
<div style="text-align: justify;">
To implement an expiration cache policy use the following code template:<br />
<br />
<pre class="brush:csharp; first-line: 5; toolbar: false;">public class MyExpirationPolicy : ExpirationCachePolicy
{
public MyExpirationPolicy():base(true)
{
}
public override bool IsExpired
{
get
{
// Add your custom expiration code to detect if the item expires
}
}
public override void OnReset()
{
// Add your custom code to reset the policy if the item is read.
}
}
</pre>
<br />
Notice that the base constructor has a parameter to indicate if the policy can be reset. Therefore, if you call the base constructor false then the OnReset method will never be called.</div>
<br />
<h3 style="text-align: justify;">
Conclusion</h3>
<div style="text-align: justify;">
If you are using caching in your current projects, you are probably using a different caching strategy. Now you have learned about the caching possibilities in <a href="https://github.com/Catel/Catel" target="_blank">Catel</a>, you should definitely try it out and be amazed at the possibilities :)</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-69461478366059836122012-11-02T13:57:00.002-04:002012-11-02T16:20:18.071-04:00More about Catel and Prism in combination<h3>
Introduction </h3>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
Since <a href="http://catel.codeplex.com/" target="_blank">Catel</a> 3.2 the support of <a href="http://compositewpf.codeplex.com/" target="_blank">Prism</a> was enhanced. The fact is that several classes were introduced into <a href="http://nuget.org/packages/Catel.Extensions.Prism/3.2">Catel.Extensions.Prism</a> to simplify the modules and bootstrapper implementation, and thanks to dependency injection <a href="http://catel.catenalogic.com/?IoC_Dependency_injection.htm" target="_blank">support</a> of the <a href="http://catel.catenalogic.com/?gen_ioc.htm" target="_blank">ServiceLocator</a> everything can be done with <a href="http://catel.codeplex.com/" target="_blank">Catel</a> without the usage of third party containers. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But now, with 3.4, a lot of improvements were introduced and the Prism <a href="http://nuget.org/packages/Catel.Extensions.Prism">extension</a> is working like charm.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Lets take a look to a couple of scenarios.<br />
</div>
<h3>
Modularity with Catel explained
</h3>
<div style="text-align: justify;">
Probably you actually noticed the close resemblance of the UI with the Prism's Quick Start examples (with <a href="http://www.nuget.org/packages/Prism.MEFExtensions">MEF</a> or <a href="http://www.nuget.org/packages/Prism.UnityExtensions">Unity</a>). Actually this example is an adaptation of the original sources in order to show how use the <a href="http://compositewpf.codeplex.com/" target="_blank">Prism</a> features in combination with <a href="http://catel.codeplex.com/" target="_blank">Catel</a>. </div>
<h3>
<b> </b><b> </b><object data="data:application/x-silverlight-2," height="620" type="application/x-silverlight-2" width="100%">
<param name="source" value="http://silverlightdemos.catenalogic.com/modularity/ClientBin/ModularityWithCatel.Silverlight.xap"/>
<!--<param name="onError" value="onSilverlightError" />-->
<param name="background" value="white" />
<param name="minRuntimeVersion" value="4.0.50401.0" />
<param name="autoUpgrade" value="true" />
<!-- <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>-->
</object> </h3>
Here are some implementation details:<br />
<br />
<div style="text-align: justify;">
1) Catel comes with two versions of generic classes, named BootstrapperBase, that helps to initialize with ease the shell and the module catalog. There are several methods that you are able to override, such as <em>ConfigureContainer</em> or <em>ConfigureModuleCatalog</em>, in order to setup the IoC container (a.k.a <a href="http://catel.catenalogic.com/?gen_ioc.htm" target="_blank">ServiceLocator</a>) and the module catalog respectively, just like this:</div>
<br />
<pre class="brush:csharp; first-line: 22"> /// <summary>
/// Initializes Prism to start this quickstart Prism application to use Catel.
/// </summary>
public class QuickStartBootstrapper : BootstrapperBase<Shell, CompositeModuleCatalog>
{
#region Fields
/// <summary>
/// The callback logger.
/// </summary>
private readonly CallbackLogger callbackLogger = new CallbackLogger();
#endregion
#region Methods
/// <summary>
/// Configures the <see cref="IServiceLocator"/>. May be overwritten in a derived class to add specific
/// type mappings required by the application.
/// </summary>
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterTypeIfNotYetRegistered<IModuleTracker, ModuleTracker>();
LogManager.AddListener(callbackLogger);
Container.RegisterInstance<CallbackLogger>(callbackLogger);
}
/// <summary>
/// Configures the <see cref="IModuleCatalog"/> used by Prism.
/// </summary>
protected override void ConfigureModuleCatalog()
{
ModuleCatalog.Add(Catel.Modules.ModuleCatalog.CreateFromXaml(new Uri("/ModularityWithCatel.Silverlight;component/ModulesCatalog.xaml", UriKind.Relative)));
var moduleCatalog = new ModuleCatalog();
// Module A is defined in the code.
Type moduleAType = typeof(ModuleA.ModuleA);
moduleCatalog.AddModule(new ModuleInfo(moduleAType.Name, moduleAType.AssemblyQualifiedName, "ModuleD"));
// Module C is defined in the code.
Type moduleCType = typeof(ModuleC.ModuleC);
moduleCatalog.AddModule(new ModuleInfo { ModuleName = moduleCType.Name, ModuleType = moduleCType.AssemblyQualifiedName, InitializationMode = InitializationMode.OnDemand });
ModuleCatalog.Add(moduleCatalog);
}
#endregion
}
</pre>
<br />
2) Catel also comes with the CompositeModuleCatalog class to deal with many catalog as one. The current implementation actually "allow" cross module catalog's module dependencies.<br />
<br />
3) For a module implementation the common approach is inherit from ModuleBase just like this:<br />
<br />
<br />
<pre class="brush:csharp; first-line: 34"> /// <summary>
/// A module for the quickstart.
/// </summary>
public class ModuleA : ModuleBase
{
/// <summary>
/// Initializes a new instance of the <see cref="ModuleA"/> class.
/// </summary>
/// </param name="moduleTracker">The module tracker.</param>
public ModuleA(IModuleTracker moduleTracker) : base("ModuleA", moduleTracker)
{
}
}
</pre>
<br />
4) The common implementation of the application class is about the instantiation of the Bootstrapper and making a call to the Run method. <br />
<br />
<pre class="brush:csharp; first-line: 34">var bootstrapper = new QuickStartBootstrapper();
bootstrapper.Run();
</pre>
<br />
But, what will happend if you call RunWithSplashScreen instead? Try with the latest beta and discover the feature by your self or just take a look into <a href="http://orchesta.codeplex.com/" target="_blank">orchesta</a>.<br />
<br />
<h3>
Enhanced working with regions</h3>
<div style="text-align: justify;">
Some time ago, I <a href="http://likewastoldtome.blogspot.com/2012/05/catel-creates-perfect-combination-with.html" target="_blank">wrote</a> about a feature where your were able to inject a view from a view model from it's view model:<br />
</div>
<pre class="brush:csharp; first-line: 43">
var employeeViewModel = new EmployeeViewModel();
var uiVisualizerService = GetService<IUIVisualizerService>();
uiVisualizerService.Activate(viewModel, "MainRegion");</pre>
<b></b><br />
1) But now you can deal with more than one shell and do this:<br />
<br />
<pre class="brush:csharp; first-line: 45"> uiVisualizerService.Activate(employeeViewModel, this, "MainRegion");
</pre>
<br />
Where the second parameter is the parent view-model.<br />
<br />
2) Actually you are able to inject views (referencing it's view models) in any window. Just like the previous example but in combination with the experimental extension method <em>Show</em>:<br />
<br />
<pre class="brush:csharp; first-line: 49"> var uiVisualizerService = GetService<IUIVisualizerService>();
var windowViewModel = new WindowWithRegionViewModel();
uiVisualizerService.Show(windowViewModel, () => { uiVisualizerService.Activate(new EmployeeViewModel(), windowViewModel, "WindowMainRegion") });</pre>
<h3>
Conclusions</h3>
<div style="text-align: justify;">
1) The usage of third party Prism Extensions like <a href="http://www.nuget.org/packages/Prism.MEFExtensions">MEF</a> or <a href="http://www.nuget.org/packages/Prism.UnityExtensions">Unity</a> is no longer required. Catel Service Locator support dependency injection and is actually configured to work just as Prism expect, the fact is that the ServiceLocatorAdapter do this job.</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
2) Now, you are able to have a nice programming session with <a href="http://compositewpf.codeplex.com/" target="_blank">Prism</a> & <a href="http://catel.codeplex.com/" target="_blank">Catel</a>. </div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-91369539926413157162012-08-23T10:28:00.000-04:002012-08-23T13:14:50.319-04:00Creating a view model with a model and mappings with CatelR#<div style="text-align: justify;">
There are tons of yarns based on MVVM developer’s experiences behind <a href="http://catel.codeplex.com/" target="_blank">Catel</a> framework. Some of them are well documented on Catel <a href="http://catel.catenalogic.com/" target="_blank">docs</a> and one of my favorites is the named "<a href="http://catel.catenalogic.com/?creating_a_view_model_with_a_2.htm" target="_blank">Creating a view model with a model and mappings</a>". </div>
<div style="text-align: justify;">
<br />
When I started to read it I identified myself as one of those developers that map all the view model properties back to the model. </div>
<div style="text-align: justify;">
<br />
I will remember you how it started:</div>
<div style="text-align: justify;">
<br />
<i>"During the use of the MVVM pattern, we noticed that lots and lots of developers have a model, and map the values of the model to all properties of the view model. When the UI closes, the developers map all the properties back to the model. All this redundant code is not necessary when using the view models of Catel." <a href="http://catel.catenalogic.com/?creating_a_view_model_with_a_2.htm" target="_blank">More...</a></i></div>
<div style="text-align: justify;">
<br />
This only feature makes that my interest about <a href="http://catel.codeplex.com/" target="_blank">Catel</a> grown until I became one of the <a href="http://catel.codeplex.com/team/view" rel="nofollow" target="_blank">members</a> of the development team. But this is part of the other history. </div>
<div style="text-align: justify;">
<br />
Let’s go back to the <a href="http://catel.codeplex.com/" target="_blank">Catel</a> feature again. If you don’t remember how it works, here is a summary. </div>
<div style="text-align: justify;">
<br />
Basically if you want to create a model the only thing that you have to do is decorate a view model property with the <a href="http://catel.catenalogic.com/?t_catel_mvvm_modelattribute.htm" target="_blank">ModelAttribute</a>. So if you want to expose the model property as view model one, and don’t write the mapping back code you must decorate the exposed property with the <a href="http://catel.catenalogic.com/?t_catel_mvvm_viewmodeltomodelattribute.htm" target="_blank">ViewModelToModelAttribute</a> just like this: </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<pre class="brush:csharp"> /// <summary>
/// The person view model.
/// </summary>
public class PersonViewModel : ViewModelBase
{
#region Static Fields
/// <summary>Register the FirstName property so it is known in the class.</summary>
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName", typeof(string));
/// <summary>Register the Person property so it is known in the class.</summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person", typeof(Person));
#endregion
#region Public Properties
/// <summary>
/// Gets or sets the first name.
/// </summary>
[ViewModelToModel("Person")]
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
public Person Person
{
get { return GetValue<Person>(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
#endregion
}
</pre>
</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
This example will automatically create a mapping between Person.FirstName and PersonViewModel.FirstName.</div>
<div style="text-align: justify;">
<br />
This feature is amazing and <a href="http://catel.codeplex.com/" target="_blank">Catel</a> distributes some code snippets to accelerate writing such code:</div>
<ul>
<li><b>vm</b> - declare a view model</li>
<li><b>vmpropmodel</b> - declare a property as model on a view model</li>
<li><b>vmpropviewmodeltomodel</b> - declare a property as a pass-through property on a view model</li>
</ul>
<div style="text-align: justify;">
<br />
But could you imagine to yourself writing this code (and more) as fast as is possible (near to the speed of light). Don't you believe me?</div>
<div style="text-align: justify;">
<br />
Watch the movie, and believe me, it is in slow motion ;)</div>
<div style="text-align: justify;">
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dyT8280l9NOQy8JWqqBvytIwc8lMhalsTD8jCl9a6LPkybuDfbutfBfsOXHoZB4eWDB-tIh9TYeFqCZ9YfGOw' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
This is a <a href="http://catelresharper.codeplex.com/releases/view/93095" target="_blank">forthcoming</a> feature of <a href="http://catelresharper.codeplex.com/" target="_blank">CateR#</a>, now powered by <a href="http://nuget.org/packages/Catel.Core/3.2" target="_blank">Catel</a> itself. </div>
<div style="text-align: justify;">
<br />
You got more ideas? <a href="http://catelresharper.codeplex.com/discussions" target="_blank">Let us know</a>!</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0tag:blogger.com,1999:blog-9155852904520845376.post-85166554630386875002012-08-14T13:26:00.001-04:002012-08-14T13:49:00.571-04:00When use the "View Model First" approach?<h3>
Introduction</h3>
<div style="text-align: justify;">
I have been waiting for <a href="http://catel.codeplex.com/" target="_blank">Catel</a> 3.2 to write about some features, especially about the all new modularity stuff (a.k.a. the Prism extension) and how it works in the second part of "<a href="http://likewastoldtome.blogspot.com/2012/05/catel-creates-perfect-combination-with.html" target="_blank">Catel creates a perfect combination with Prism</a>". But, always there is an excuse, we are still working on some <a href="http://compositewpf.codeplex.com/" target="_blank">Prism </a>features and improvements, therefore the second part will have to wait.</div>
<br />
<div style="text-align: justify;">
So, this post will be about an interesting approach and how transform "untestable" code, from the code-behind, as "testable" view model code. The name is "View Model First". I will try to illustrate it transforming a "View First" implementation into a "View Model First" one.</div>
<br />
<h3>
The problem</h3>
<div style="text-align: justify;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0XWAVTF_DcihZ0F0r6o-rFCmuwxO5kHx-_h8GTiaq1l73LuqzfGBsKqpE6L0LJ4Zs3fgrs1iAxUJ_93t2DvOOuVszcSV2vKWjIj6vO4r8bSz5ViQbuPn7B5gNNjkHmgF4Z1zT64lIvqs/s1600/2012-08-14_100503.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0XWAVTF_DcihZ0F0r6o-rFCmuwxO5kHx-_h8GTiaq1l73LuqzfGBsKqpE6L0LJ4Zs3fgrs1iAxUJ_93t2DvOOuVszcSV2vKWjIj6vO4r8bSz5ViQbuPn7B5gNNjkHmgF4Z1zT64lIvqs/s320/2012-08-14_100503.png" width="320" /></a>"Digesting" the sample codes of <a href="http://www.telerik.com/" target="_blank">Telerik</a> components (<a href="http://www.telerik.com/products/wpf/overview.aspx" target="_blank">WPF</a>/<a href="http://www.telerik.com/products/silverlight.aspx" target="_blank">SL</a>) I noticed that some of them, as part of its name, contain the tag "MVVM". The fact is that most of these components have MVVM support but several examples of this suite are written in code-behind. I know it is a demo application but some of the <a href="http://www.telerik.com/" target="_blank">Telerik</a> components are actually written to be used in code-behind, therefore some logic that could be easy to test becomes hard to test.</div>
<br />
<br />
Let's take a look into the "Tree to Grid Drag" drag and drop example. I will remove some part of the code for simplification.<br />
<br />
<pre class="brush:csharp;first-line:5">public partial class Example : System.Windows.Controls.UserControl
{
public Example()
{
// Allow dropping into the ListBox and GridView only if the
// dragged items are all products:
RadDragAndDropManager.AddDropQueryHandler(wishlistView, OnDropQuery);
RadDragAndDropManager.AddDropQueryHandler(orderView, OnDropQuery);
// Change the drag cue and choose an action for the sucessful drop
// in the Wishlist:
RadDragAndDropManager.AddDropInfoHandler(wishlistView, OnWishlistDropInfo);
// Change the drag cue and choose an action for the sucessful drop
// in the Order GridView:
RadDragAndDropManager.AddDropInfoHandler(orderView, OnGridViewDropInfo);
// Allow dragging of the Wishlist and Order items:
RadDragAndDropManager.AddDragQueryHandler(wishlistView, OnWishListDragQuery);
RadDragAndDropManager.AddDragQueryHandler(orderView, OnOrderDragQuery);
// Handle the case when items are dragged away from the ListBox
// and the Order:
RadDragAndDropManager.AddDragInfoHandler(wishlistView, OnWishListDragInfo);
RadDragAndDropManager.AddDragInfoHandler(orderView, OnOrderDragInfo);
}
}
</pre>
<br />
<div style="text-align: justify;">
You should notice that everything is about the <a href="http://www.telerik.com/help/wpf/raddraganddrop-getting-started-with-drag-and-drop.html" target="_blank">RadDragAndDropManager</a>. This static class needs a control reference to setup the drag and drop stuff. This operation forces us to write code that could be part of the VM code on the code-behind. At least the highlighted code could be part of the logic of the view model of Example control removing the access to the list of elements via ListBox control reference.</div>
<br />
<pre class="brush:csharp; first-line:22; highlight: [42,43,44,45,46,47,48,49]">private void OnWishlistDropInfo(object sender, DragDropEventArgs e)
{
System.Windows.Controls.ItemsControl wishlist = e.Options.Destination as System.Windows.Controls.ItemsControl;
ICollection draggedItems = e.Options.Payload as ICollection;
// Get the drag cu that the TreeView or we have created
TreeViewDragCue cue = e.Options.DragCue as TreeViewDragCue;
if (e.Options.Status == DragStatus.DropPossible)
{
// Set a suitable text:
cue.DragActionContent = String.Format("Add {0} item{1} to Wishlist", draggedItems.Count, draggedItems.Count > 1 ? "s" : String.Empty);
cue.IsDropPossible = true;
wishlist.Background = this.Resources["DropPossibleBackground"] as Brush;
}
else if (e.Options.Status == DragStatus.DropImpossible)
{
cue.DragActionContent = null;
cue.IsDropPossible = false;
}
else if (e.Options.Status == DragStatus.DropComplete)
{
IList items = wishlist.ItemsSource as IList;
foreach (object draggedItem in draggedItems)
{
items.Add(draggedItem);
}
}
if (e.Options.Status != DragStatus.DropPossible)
{
wishlist.Background = new SolidColorBrush(Colors.White);
}
}
</pre>
<br />
<br />
So how to transform the code above into MVVM "compatible" code? That is the problem that I will try to solve in this post.<br />
<br />
<br />
<h3>
The solution</h3>
<div style="text-align: justify;">
The approach to solve this problem is quite simple and has a name "View Model First". The only thing we have to do is visualize the solution from the view model point of view.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The very first steps to re-write the drag and drop example with view model support is to install the Catel.MVVM nuget <a href="http://nuget.org/packages/Catel.MVVM/3.2.1208121328-beta" target="_blank">package</a>, at least for me ;).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Using the <a href="http://catel.codeplex.com/" target="_blank">Catel</a> naming <a href="http://catel.catenalogic.com/?mvvm_naming_conventions.htm" target="_blank">conventions</a> the Example control will be renamed as ExampleView (now it inherits from Catel.Windows.Controls.UserControl) and the ExampleViewModel will be introduced (inheriting from Catel.MVVM.ViewModelBase).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I will also rename the ProductViewModel and CategoryViewModel as Product and Category and now inherits from DataObjectBase. They are actually model classes instead view model ones.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The ExampleViewModel class looks like this:</div>
<br />
<pre class="brush:csharp;first-line:5">public class ExampleViewModel : ViewModelBase
{
public static readonly PropertyData OrdersProperty = RegisterProperty("Orders", typeof(ObservableCollection<Product>));
public static readonly PropertyData SelectedOrdersProperty = RegisterProperty("SelectedOrders", typeof(ObservableCollection<Product>));
public static readonly PropertyData SelectedWishesProperty = RegisterProperty("SelectedWishes", typeof(ObservableCollection<Product>));
public static readonly PropertyData WishesProperty = RegisterProperty("Wishes", typeof(ObservableCollection<Product>));
public ObservableCollection<Product> Wishes
{
get { return this.GetValue<ObservableCollection<Product>>(WishesProperty); }
set { this.SetValue(WishesProperty, value); }
}
public ObservableCollection<Product> SelectedWishes
{
get { return this.GetValue<ObservableCollection<Product>>(SelectedWishesProperty); }
set { this.SetValue(SelectedWishesProperty, value); }
}
public ObservableCollection<Product> Orders
{
get { return this.GetValue<ObservableCollection<Product>>(OrdersProperty); }
set { this.SetValue(OrdersProperty, value); }
}
public ObservableCollection<Product> SelectedOrders
{
get { return this.GetValue<ObservableCollection<Product>>(SelectedOrdersProperty); }
set { this.SetValue(SelectedOrders, value); }
}
}</pre>
<br />
<br />
<div style="text-align: justify;">
With this transformation we are able to attach or bind the ItemsSource property of the wishlistView (ListBox) and orderView (<a href="http://www.telerik.com/help/wpf/gridview-overview2.html" target="_blank">RadGridView</a>) to Wishes and Orders view model properties respectively. I will also add some logic to fill the SelectedWishes and SelectedOrders properties with an event to command <a href="http://catel.catenalogic.com/?events_to_commands.htm" target="_blank">approach</a> to be synchronized with the selected elements on the UI.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
At this point I will introduce a service named IDragAndDropService, in order to "map" a property of the view model with a control that have it attached to the ItemsSource property. The interface of this service will be defined as follow:</div>
<br />
<pre class="brush: csharp;first-line:5">public interface IDragAndDropService
{
void AddDragInfoHandler(IViewModel viewModel, Expression<Func<IList>> propertyExpression, EventHandler<DragDropEventArgs> eventHandler, string dependencyPropertyName = "ItemsSourceProperty");
void AddDragQueryHandler(IViewModel viewModel, Expression<Func<IList>> propertyExpression, EventHandler<DragDropQueryEventArgs> eventHandler, string dependencyPropertyName = "ItemsSourceProperty");
void AddDropInfoHandler(IViewModel viewModel, Expression<Func<IList>> propertyExpression, EventHandler<DragDropEventArgs> eventHandler, string dependencyPropertyName = "ItemsSourceProperty");
void AddDropQueryHandler(IViewModel viewModel, Expression<Func<IList>> propertyExpression, EventHandler<DragDropQueryEventArgs> eventHandler, string dependencyPropertyName = "ItemsSourceProperty");
}
</pre>
<br />
<br />
<div style="text-align: justify;">
The code above was the first thing that came to my mind with the more pure style of the <a href="http://catel.codeplex.com/" target="_blank">Catel</a> <a href="http://catel.codeplex.com/team/view" target="_blank">developers</a> ;)</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now during the initialization of the example view model we can use it, resolving it instance from the ServiceLocator, to setup the drag and drop operations.</div>
<br />
<pre class="brush:csharp;first-line:11">protected override void Initialize()
{
var dragAndDropService = this.GetService<IDragAndDropService>();
// Allow dropping into the Wishlist and Order only if the dragged items are all products:
dragAndDropService.AddDropQueryHandler(this, () => this.Wishes, this.OnDropQuery);
dragAndDropService.AddDropQueryHandler(this, () => this.Orders, this.OnDropQuery);
// Choose an action for the sucessful drop in the Wishlist via Wishes property:
dragAndDropService.AddDropInfoHandler(this, () => this.Wishes, this.OnWishesDropInfo);
// Choose an action for the sucessful drop in the Order GridView via Orders property:
dragAndDropService.AddDropInfoHandler(this, () => this.Orders, this.OnOrdersDropInfo);
// Allow dragging of the Wishlist and Order items:
dragAndDropService.AddDragQueryHandler(this, () => this.Wishes, this.OnWishesDragQuery);
dragAndDropService.AddDragQueryHandler(this, () => this.Orders, this.OnOrdersDragQuery);
// Handle the case when items are dragged away from the Wishlist and the Order:
dragAndDropService.AddDragInfoHandler(this, () => this.Wishes, this.OnWishesDragInfo);
dragAndDropService.AddDragInfoHandler(this, () => this.Orders, this.OnOrdersDragInfo);
}
</pre>
<br />
<br />
Then we are able to move some code from code-behind to our view model just like this:<br />
<br />
<pre class="brush: csharp;first-line:32">private void OnWishesDragQuery(object sender, DragDropQueryEventArgs e)
{
List<ProductModel> productModels = this.SelectedWishes.ToList();
e.QueryResult = productModels.Count > 0;
if ((bool)e.QueryResult)
{
e.Options.Payload = productModels;
}
}
private void OnWishesDragInfo(object sender, DragDropEventArgs e)
{
if (e.Options.Status == DragStatus.DragComplete)
{
IEnumerable<ProductModel> productModels = (e.Options.Payload as IEnumerable).Cast<ProductModel>();
foreach (ProductModel draggedItem in productModels)
{
this.Wishes.Remove(draggedItem);
this.SelectedWishes.Remove(draggedItem);
}
}
}
private void OnOrdersDropInfo(object sender, DragDropEventArgs e)
{
if (e.Options.Status == DragStatus.DropComplete)
{
IEnumerable<ProductModel> productModels = (e.Options.Payload as IEnumerable).Cast<ProductModel>();
foreach (ProductModel draggedItem in productModels)
{
this.Orders.Add(draggedItem);
}
}
}
</pre>
<br />
<br />
<div style="text-align: justify;">
The code that we moved from the code-behind is quite ease to test using any mock library, mocking the IDragAndDropService interface.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
But we have to implement the RadDragAndDropService to make the UI controls works as we expected.</div>
<br />
<h3>
Implementing the RadDragAndDropService</h3>
<div style="text-align: justify;">
The only issue here is about get the active view(s) from the view model instance. Here is where <a href="http://catel.codeplex.com/" target="_blank">Catel</a> 3.3 comes to save us with the introduction of the ViewManager. The logic inside the MVVM logic of <a href="http://catel.codeplex.com/" target="_blank">Catel</a> carries with the auto-registration of the control and its association with its view models. So the only thing that we have to do is get the active view(s) using the GetViewsOfViewModel method and lookup the first control.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Basically the search is a wide search through the visual tree a returns the first one dependency object that commits the condition (the dependencyProperty is attached to the view model property) and call the <a href="http://www.telerik.com/help/wpf/raddraganddrop-getting-started-with-drag-and-drop.html" target="_blank">RadDragAndDropManager</a> as usual, just like this:</div>
<br />
<pre class="brush:csharp;;first-line:15;highlight: [29, 33]">public void AddDragInfoHandler(IViewModel viewModel, Expression<Func<IList>> propertyExpression, EventHandler<DragDropEventArgs> eventHandler, string dependencyPropertyName = "ItemsSourceProperty")
{
Argument.IsNotNull("viewModel", viewModel);
Argument.IsNotNull("propertyExpression", propertyExpression);
Argument.IsNotNull("eventHandler", eventHandler);
Argument.IsNotNullOrWhitespace("dependencyPropertyName", dependencyPropertyName);
Argument.IsOfType("propertyExpression.Body", propertyExpression.Body, typeof(MemberExpression));
var memberExpression = (MemberExpression)propertyExpression.Body;
if (memberExpression.Member.MemberType != MemberTypes.Property)
{
throw new ArgumentException(MemberExpressionShouldBeAPropertyErrorMessage);
}
IView[] activeViews = this.ServiceLocator.ResolveType<IViewManager>().GetViewsOfViewModel(viewModel);
foreach (IView activeView in activeViews)
{
DependencyObject dependencyObject = FindChildDependencyObjectAttachedToProperty(activeView, propertyExpression, dependencyPropertyName);
RadDragAndDropManager.AddDragInfoHandler(dependencyObject, eventHandler);
}
}
</pre>
<br />
<br />
The highlighted code shows you the usage of the ViewManager and the <a href="http://www.telerik.com/help/wpf/raddraganddrop-getting-started-with-drag-and-drop.html" target="_blank">RadDragAndDropManager</a>. <br />
<br />
To review the details of the implementation grab the code sample <a href="https://skydrive.live.com/redir?resid=ADEB7E738B27F26C%21109" rel="nofollow" target="_blank">here</a>.<br />
<br />
<h3>
Conclusions</h3>
<div style="text-align: justify;">
1) There is "always" a way to re-write a "View First" approach as "View Model First" one. Sometimes could be hard but is a win-win situation when you invest time to write custom services because you will gain testability and control of your code. So use the "View Model First" as much as you can.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
2) Now with the <a href="http://catel.codeplex.com/" target="_blank">Catel</a> ViewManager is almost possible write any services that allow you to "interact" with "untestable" components without referencing it directly from your view model code.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
3) An update of <a href="http://compositewpf.codeplex.com/" target="_blank">Prism</a> <a href="http://catel.catenalogic.com/?catel_extensions_prism.htm" target="_blank">extension</a> of <a href="http://catel.codeplex.com/" target="_blank">Catel</a> using the ViewManager will come as soon as possible, planned for <a href="http://catel.codeplex.com/" target="_blank">Catel</a> 3.4.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
4) Writing about code testability remembered me that I have to start to write about my experience using <a href="http://www.ncover.com/" target="_blank">NCover</a> 4, but this will part of my next blog post, I think, at least for now ;).</div>
Igr Alexánder Fernández Saúcohttp://www.blogger.com/profile/04026074392368938570noreply@blogger.com0