tag:blogger.com,1999:blog-328574182024-03-13T21:28:42.540-07:00Riyad's Technical BlogMy collection of small essays on various technical subjectsUnknownnoreply@blogger.comBlogger46125tag:blogger.com,1999:blog-32857418.post-57689331510185012622011-04-21T22:42:00.000-07:002011-04-21T22:42:43.076-07:00SoCal .NET Architecture PresentationJust finished my presentation on designing enterprise applications for Windows Phone 7. Many thanks to Mike Vincent, David Wells, and everyone who attended. Here are the links to <a href="http://members.cox.net/rmamedov/blog/EnterpriseAppsWinPh7.pdf">slides</a> and <a href="http://members.cox.net/rmamedov/blog/EnterpriseAppsWinPh7.zip">source code</a> of the sample application. Feel free to contact me if you need any help building the solution.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-32857418.post-31010043388863610252011-03-13T21:29:00.000-07:002011-03-13T21:29:04.060-07:00Source Code Comments RevisitedI have to admit I don't get much traffic on this blog - usually a few hits per day, according to Feedjit. That's why I was pleasantly surprised when I saw a steady stream of comments earlier today. Some of them were submitted here on blogger.com, but most went to <a href="http://www.reddit.com/r/programming/comments/g3ck2/heres_what_enterprise_architects_who_dabble_in/">the discussion on reddit.com</a>. Since I can't possibly reply to every single comment, here is a summary response.<br />
<br />
First of all, I'd like to thank everyone who agreed with my view of automated unit tests as a perfectly good substitute of source code comments (of course, unit tests are much much more than a replacement for comments!). I also appreciate the folks who submitted constructive criticism and shared their personal rules of thumb for writing comments.<br />
<br />
<br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">Some readers took offence on my use of terms like "<a href="http://en.wikipedia.org/wiki/Cohesion_(computer_science)">cohesion</a>", "<a href="http://en.wikipedia.org/wiki/Coupling_(computer_science)">coupling</a>", and "<a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a>", calling them buzzwords. My friends, if these terms are just buzzwords to you, then you clearly are missing some important trends in our industry. If you are writing objects with hundreds of methods that pertain to dozens different responsibilities, or if your thousand-line functions have so many <i>if-else</i> statements it makes you dizzy, then no amount of source code comments will hide one simple fact: your code is bad and is in dire need of refactoring.</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">One often-repeated mistake was that I am advocating against ALL source code comments. This is simply not true, and if you read the blog post through the end, you will see a pretty funny example of a very legitimate comment one programmer left in his code.</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">Speaking of examples - I got a few posts saying they are "stupid", "straw-man", and not real. Well, I don't even know what to say... There are just two examples in my blog post, and both are taken verbatim from the StackOverflow discussion called "<a href="http://stackoverflow.com/questions/184618/what-is-the-best-comment-in-source-code-you-have-ever-encountered">What is the best comment in source code you have ever discovered</a>".</div><div><br />
</div><br />
To all people who questioned my credibility, I am happy to say that I have been a professional programmer for over 16 years, used more programming languages than I care to remember, and was involved in the maintenance of large codebases. I do code reviews on a regular basis, and I always enjoyed respect of my colleagues. True, my current job title is no longer a "programmer", and I've been coding in C# exclusively for the last several years, but make no mistake - I am no "dabbler" when it comes to software development.Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-32857418.post-22941762405897243782011-01-11T23:27:00.000-08:002011-01-11T23:27:52.387-08:00Don't Waste Your Time Commenting Source CodeI recently had an argument with a colleague about source code comments. He called it one of software development best practices and suggested that any programmer worth his salt writes extensive comments. You hear this pretty often from people who consider themselves "old school". Well, I have been writing code since early 90s, but I strongly believe that 90% of source code comments are a waste of time. Let's review the arguments...<br />
<blockquote><i>Pro: Comments explain what the program does, so the person maintaining the code can understand it easily.</i></blockquote>Well, it sounds good on the surface, but if you think about it, a well-designed program doesn't need comments to be maintainable. A well-designed program uses classes and design patterns; it has high cohesion, low coupling, and limited cyclomatic complexity. The names of classes and variables are carefully chosen to be self-explanatory. We know that programmers don't generally have unlimited time for development. If the choice is between a well-designed program without comments and a thoroughly commented but poorly architected one, I will choose the former any day of the week. Frankly, I would rather have developers spend time polishing their design skills than technical writing skills.<br />
<blockquote><i>Contra: Automated unit tests explain what the program does just as well, and they never become obsolete.</i></blockquote>The truth about source code comments, and any written documentation for that matter, is that it quickly becomes obsolete. Take a look at this real-life example I took from <a href="http://stackoverflow.com/questions/184618/what-is-the-best-comment-in-source-code-you-have-ever-encountered">StackOverflow discussion</a>:<br />
<span class="Apple-style-span" style="border-collapse: collapse; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px;"></span><br />
<pre style="background-attachment: initial; background-clip: initial; background-color: #eeeeee; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; font-size: 14px; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-height: 600px; overflow-x: auto; overflow-y: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; vertical-align: baseline; width: auto;"><code style="background-attachment: initial; background-clip: initial; background-color: #eeeeee; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; font-size: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; vertical-align: baseline;">/**
* Always returns true.
*/
public boolean isAvailable() {
return false;
}</code></pre><br />
There is no guarantee that the person changing the code will take time to update the comment. There is nothing your integration server can do to enforce this. On the other hand, consider this unit test:<br />
<span class="Apple-style-span" style="border-collapse: collapse; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px;"></span><br />
<pre style="background-attachment: initial; background-clip: initial; background-color: #eeeeee; background-image: initial; background-origin: initial; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; font-size: 14px; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-height: 600px; overflow-x: auto; overflow-y: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; vertical-align: baseline; width: auto;"><code style="background-attachment: initial; background-clip: initial; background-color: #eeeeee; background-image: initial; background-origin: initial; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; font-size: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; vertical-align: baseline;">var result = myobject.isAvailable();
Assert.IsTrue(result);
</code></pre><div>As soon as someone changes the method to return "false" instead of "true" and checks the code in, the unit test will break on next build, and pretty soon the developer will be looking into the issue.</div><blockquote><i>Contra: What makes you think people can write clearly?</i></blockquote><div>Let's face it, not every programmer can write well in English (that goes without saying for us immigrants, but I have seen comments written by native English speakers that were profoundly confusing). On the other hand, unit tests are written in programming languages, so developers can apply their core competencies. Natural language comments can be ambiguous, vague, sarcastic, or humorous. Some may be even fun to read (that StackOverflow discussion has some real gems!), but unit tests are much more practical - they leave no room for different interpretations.</div><blockquote><i>Pro: Sometimes you just need to leave a note...</i></blockquote>This is the only case that I would concede. Here is an example to illustrate this point:<br />
<span class="Apple-style-span" style="border-collapse: collapse; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px;"></span><br />
<pre style="background-attachment: initial; background-clip: initial; background-color: #eeeeee; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; font-size: 14px; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-height: 600px; overflow-x: auto; overflow-y: auto; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px; vertical-align: baseline; width: auto;"><code style="background-attachment: initial; background-clip: initial; background-color: #eeeeee; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; font-size: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; vertical-align: baseline;">//
// Dear maintainer:
//
// Once you are done trying to 'optimize' this routine,
// and have realized what a terrible mistake that was,
// please increment the following counter as a warning
// to the next guy:
//
// total_hours_wasted_here = 39
// </code></pre>Unknownnoreply@blogger.com55tag:blogger.com,1999:blog-32857418.post-58288791455432819582010-12-17T16:40:00.000-08:002010-12-17T16:40:54.127-08:00Mobile Enterprise Application. Step 3: Registering For Push NotificationsThis is a third post in a series. Previous posts:<br />
- Step 1: <a href="http://riyadsthoughts.blogspot.com/2010/11/mobile-enterprise-application-step-1.html">General Architecture</a><br />
- Step 2: <a href="http://riyadsthoughts.blogspot.com/2010/11/mobile-enterprise-application-step-2.html">Authentication</a><br />
<br />
I briefly defined Push Notification Service in the previous post. Here we will take a closer look at implementing notifications. PNS has cloud-based infrastructure maintained by Microsoft; phone application registers with it and assumes a unique endpoint address. That address is sent to the server portion of our system which uses it to forward messages to PNS infrastructure which, in turns, forwards it to the phone. There are three different types of alerts that can be sent:<br />
<br />
<ol><li>Tile notifications. If an application is pinned to the start screen, its image (a.k.a. tile) can change in response to tile notification. We can either change the entire image or just display a number on the default tile.</li>
<li>Toast notifications. These are essentially short text messages that are briefly displayed on top of the phone screen. If user touches the message, associated application opens up.</li>
<li>Raw notifications. If previous two are used to communicate with the phone OS, this one is targeted at the phone application itself. Therefore, message contents and system response will be application-specific.</li>
</ol><div><b>Check User Preferences</b></div><div>According to Microsoft certification requirements, users should be able to opt out of push notifications. The most straightforward approach is to store user preferences in the application setting.</div><div class="csharpcode"><pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">public</span> <span class="kwrd">class</span> AppSettings</pre><pre><span class="lnum"> 2: </span> {</pre><pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> IsolatedStorageSettings _isolatedStore;</pre><pre><span class="lnum"> 4: </span> </pre><pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">public</span> <span class="kwrd">bool</span> CanUsePNS</pre><pre><span class="lnum"> 6: </span> {</pre><pre class="alt"><span class="lnum"> 7: </span> get</pre><pre><span class="lnum"> 8: </span> {</pre><pre class="alt"><span class="lnum"> 9: </span> <span class="kwrd">return</span> GetValueOrDefault<<span class="kwrd">bool</span>>(Constants.Settings.CanUsePNSKey, Constants.Settings.CanUsePNSDefault);</pre><pre><span class="lnum"> 10: </span> }</pre><pre class="alt"><span class="lnum"> 11: </span> set</pre><pre><span class="lnum"> 12: </span> {</pre><pre class="alt"><span class="lnum"> 13: </span> AddOrUpdateValue(Constants.Settings.CanUsePNSKey, <span class="kwrd">value</span>);</pre><pre><span class="lnum"> 14: </span> Save();</pre><pre class="alt"><span class="lnum"> 15: </span> }</pre><pre><span class="lnum"> 16: </span> }</pre><pre class="alt"><span class="lnum"> 17: </span> </pre><pre><span class="lnum"> 18: </span> <span class="kwrd">public</span> AppSettings()</pre><pre class="alt"><span class="lnum"> 19: </span> {</pre><pre><span class="lnum"> 20: </span> _isolatedStore = IsolatedStorageSettings.ApplicationSettings;</pre><pre class="alt"><span class="lnum"> 21: </span> }</pre><pre><span class="lnum"> 22: </span> </pre><pre class="alt"><span class="lnum"> 23: </span> <span class="kwrd">public</span> <span class="kwrd">bool</span> AddOrUpdateValue(<span class="kwrd">string</span> key, Object <span class="kwrd">value</span>)</pre><pre><span class="lnum"> 24: </span> {</pre><pre class="alt"><span class="lnum"> 25: </span> }</pre><pre><span class="lnum"> 26: </span> </pre><pre class="alt"><span class="lnum"> 27: </span> <span class="kwrd">public</span> TValueType GetValueOrDefault<TValueType>(<span class="kwrd">string</span> key, TValueType defaultValue)</pre><pre><span class="lnum"> 28: </span> {</pre><pre class="alt"><span class="lnum"> 29: </span> }</pre><pre><span class="lnum"> 30: </span> </pre><pre class="alt"><span class="lnum"> 31: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> Save()</pre><pre><span class="lnum"> 32: </span> {</pre><pre class="alt"><span class="lnum"> 33: </span> _isolatedStore.Save();</pre><pre><span class="lnum"> 34: </span> }</pre><pre class="alt"><span class="lnum"> 35: </span> }</pre></div><div><b><br />
</b><br />
<b>Register Push Channel.</b><br />
This needs to be done when application starts and after user confirmed he or she wants to use PNS.</div><div class="csharpcode"><pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> RegisterPushChannel()</pre><pre><span class="lnum"> 2: </span> {</pre><pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd">if</span>(!(<span class="kwrd">new</span> AppSettings()).CanUsePNS) <span class="kwrd">return</span>;</pre><pre><span class="lnum"> 4: </span> </pre><pre class="alt"><span class="lnum"> 5: </span> _httpChannel = HttpNotificationChannel.Find(Constants.ChannelName);</pre><pre><span class="lnum"> 6: </span> </pre><pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">if</span> (<span class="kwrd">null</span> != _httpChannel)</pre><pre><span class="lnum"> 8: </span> {</pre><pre class="alt"><span class="lnum"> 9: </span> SubscribeToChannelEvents();</pre><pre><span class="lnum"> 10: </span> SubscribeToService();</pre><pre class="alt"><span class="lnum"> 11: </span> SubscribeToNotifications();</pre><pre><span class="lnum"> 12: </span> }</pre><pre class="alt"><span class="lnum"> 13: </span> <span class="kwrd">else</span></pre><pre><span class="lnum"> 14: </span> {</pre><pre class="alt"><span class="lnum"> 15: </span> _httpChannel = <span class="kwrd">new</span> HttpNotificationChannel(Constants.ChannelName, Constants.Channels.Service);</pre><pre><span class="lnum"> 16: </span> SubscribeToChannelEvents();</pre><pre class="alt"><span class="lnum"> 17: </span> _httpChannel.Open();</pre><pre><span class="lnum"> 18: </span> }</pre><pre class="alt"><span class="lnum"> 19: </span> }</pre></div><br />
<div><br />
Method SubscribeToChannelEvents simply adds application handlers to process various events raised by the HttpNotificationChannel object.</div><br />
<div class="csharpcode"><pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> SubscribeToChannelEvents()</pre><pre><span class="lnum"> 2: </span> {</pre><pre class="alt"><span class="lnum"> 3: </span> <span class="rem">// Register to UriUpdated event - occurs when channel successfully opens</span></pre><pre><span class="lnum"> 4: </span> _httpChannel.ChannelUriUpdated += <span class="kwrd">new</span> System.EventHandler<NotificationChannelUriEventArgs>(HttpChannelChannelUriUpdated);</pre><pre class="alt"><span class="lnum"> 5: </span> </pre><pre><span class="lnum"> 6: </span> <span class="rem">// Subscribe to raw notifications</span></pre><pre class="alt"><span class="lnum"> 7: </span> _httpChannel.HttpNotificationReceived += <span class="kwrd">new</span> System.EventHandler<HttpNotificationEventArgs>(HttpChannelHttpNotificationReceived);</pre><pre><span class="lnum"> 8: </span> </pre><pre class="alt"><span class="lnum"> 9: </span> <span class="rem">// General error handling for push channel</span></pre><pre><span class="lnum"> 10: </span> _httpChannel.ErrorOccurred += <span class="kwrd">new</span> System.EventHandler<NotificationChannelErrorEventArgs>(HttpChannelErrorOccurred);</pre><pre class="alt"><span class="lnum"> 11: </span> </pre><pre><span class="lnum"> 12: </span> <span class="rem">// Subscribe to toast notifications</span></pre><pre class="alt"><span class="lnum"> 13: </span> _httpChannel.ShellToastNotificationReceived += <span class="kwrd">new</span> System.EventHandler<NotificationEventArgs>(HttpChannelShellToastNotificationReceived);</pre><pre><span class="lnum"> 14: </span> }</pre></div><div><br />
Method SubscribeToNotifications binds channel notifications to Windows shell:</div><div class="csharpcode"><pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> SubscribeToNotifications()</pre><pre><span class="lnum"> 2: </span> {</pre><pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd">if</span> (!_httpChannel.IsShellToastBound)</pre><pre><span class="lnum"> 4: </span> {</pre><pre class="alt"><span class="lnum"> 5: </span> _httpChannel.BindToShellToast();</pre><pre><span class="lnum"> 6: </span> }</pre><pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">if</span> (!_httpChannel.IsShellTileBound)</pre><pre><span class="lnum"> 8: </span> {</pre><pre class="alt"><span class="lnum"> 9: </span> _httpChannel.BindToShellTile();</pre><pre><span class="lnum"> 10: </span> }</pre><pre class="alt"><span class="lnum"> 11: </span> }</pre></div><div><br />
<b>Associate User and Channel URI</b><br />
Method SubscribeToService needs to send unique endpoint URI (which can be accessed via _httpChannel.ChannelUri property) to the server portion of the system, e.g., by calling a web service. The service will associate the URI with the ID of the currently logged in user. This is an important consideration: since different users may be using the mobile application (or the same person may have different user accounts), but channel URI will always be the same. If we do not properly associate URI with the current user, he or she will be receiving other person's notifications. By the same rationale, when user logs off from the application, a web service call needs to be made to disassociate her from push notifications URI.</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-54841465735165875682010-11-17T10:57:00.000-08:002010-11-17T10:57:22.672-08:00Mobile Enterprise Application. Step 2: AuthenticationThis is a second post in the series. Previous post:<br />
- <a href="http://riyadsthoughts.blogspot.com/2010/11/mobile-enterprise-application-step-1.html">Step 1: General Architecture</a><br />
<br />
Authentication - as in supplying proper user credentials - is an essential part of any enterprise application. Consumer apps and games usually allow unauthenticated users to execute them, but enterprise systems have higher security requirements. So, your login page is likely to be set in WMAppManifest.xml as default task:<br />
<br />
<pre style="font-family: consolas;"><span style="color: blue;"><span class="Apple-style-span" style="font-size: small;"> <</span></span><span style="color: #a31515;"><span class="Apple-style-span" style="font-size: small;">Tasks</span></span><span style="color: blue;"><span class="Apple-style-span" style="font-size: small;">></span></span><span class="Apple-style-span" style="font-size: small;">
<span style="color: blue;"> <</span><span style="color: #a31515;">DefaultTask</span><span style="color: blue;"> </span><span style="color: red;">Name</span><span style="color: blue;"> =</span>"<span style="color: blue;">_default</span>"
<span style="color: red;">NavigationPage</span><span style="color: blue;">=</span>"<span style="color: blue;">/Views/LoginPage.xaml</span>"<span style="color: blue;">/></span></span></pre><pre style="font-family: consolas;"><span style="color: blue;"><span class="Apple-style-span" style="font-size: small;"> </span></span><span class="Apple-style-span" style="color: blue; font-size: small;"><</span><span class="Apple-style-span" style="color: blue; font-size: small;"><span style="color: #a31515;">Tasks</span><span style="color: blue;">></span></span></pre><br />
It's not difficult to put together a simple page with two text boxes and a button, then make a web service call to verify user credentials and return an object containing user context. However, there are a couple of things to consider.<br />
<br />
<b>Push Notifications Opt-In</b><br />
Push Notification Service (PNS) is a powerful tool that allows your server application to initiate communication with the client even while the client isn't running. There is no equivalent functionality on the desktop or in web applications; it is one of the unique features of the mobile client. I'm sure any enterprise system could use PNS, and in my next post I will show how to implement it. Normally, you would register a user for push notifications as soon as he or she authenticates. However, according to Windows Phone 7 Application Certification Requirements, the application must ask the user for explicit permission to receive a toast notification. Once the opt-in is obtained from the user, it can be saved in isolated storage settings. Below is a code snippet that checks settings and redirects user accordingly:<br />
<pre style="font-family: consolas;"><span class="Apple-style-span" style="font-size: small;"> NavigationService.Navigate(
<span style="color: #2b91af;">IsolatedStorageSettings</span>.ApplicationSettings.Contains(Constants.<span style="color: #2b91af;">Settings</span>.CanUsePNS)
? <span style="color: blue;">new</span> <span style="color: #2b91af;">Uri</span>(Constants.<span style="color: #2b91af;">Urls</span>.LandingPage, <span style="color: #2b91af;">UriKind</span>.Relative)</span></pre><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span class="Apple-style-span" style="font-size: small;"> : </span></span><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span style="color: blue;"><span class="Apple-style-span" style="font-size: small;">new</span></span></span><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span class="Apple-style-span" style="font-size: small;"> </span></span><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span style="color: #2b91af;"><span class="Apple-style-span" style="font-size: small;">Uri</span></span></span><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span class="Apple-style-span" style="font-size: small;">(Constants.</span></span><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span style="color: #2b91af;"><span class="Apple-style-span" style="font-size: small;">Urls</span></span></span><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span class="Apple-style-span" style="font-size: small;">.PNSOptInPage, </span></span><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span style="color: #2b91af;"><span class="Apple-style-span" style="font-size: small;">UriKind</span></span></span><span class="Apple-style-span" style="font-family: consolas; white-space: pre;"><span class="Apple-style-span" style="font-size: small;">.Relative));</span></span><br />
<b><br />
</b><br />
<span class="Apple-style-span" style="font-family: consolas; white-space: pre;"></span><b>Session Management</b><br />
Authentication usually implies a time-limited user session. Unlike ASP.NET, which is a server-side platform, Silverlight doesn't provide session management features out of the box. My recommended approach for mobile application is to implement a dual session management mechanism along these lines:<br />
<br />
<ol><li>Client ask user for a preferred session duration (not to exceed a predefined system limit) before login</li>
<li>Client successfully authenticates, and server returns a unique session token (a GUID, for instance)</li>
<li>Client keeps session state in the isolated storage</li>
<li>Every time the application is activated, it checks if session length has exceeded timeout</li>
<li>Every time the client makes a webservice call, it includes the session token as a parameter. Server uses it to validate the session and optionally create an audit trail of user activity.</li>
</ol><div><i>Restoring Session State On Activation</i></div><div>When application is running, session state is stored in a public static property of the App class (App.xaml.cs), for example:</div><div><pre style="font-family: consolas;"><span style="color: blue;"><span class="Apple-style-span" style="font-size: small;"> public</span></span><span class="Apple-style-span" style="font-size: small;"> <span style="color: blue;">static</span> <span style="color: #2b91af;">UserLogin</span> CurrentUser { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }</span></pre></div><div>However, the value goes away when application becomes inactive (again, this is unique behavior of mobile clients) and we need to restore it as part of reactivation:</div><br />
<div class="csharpcode"><pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">private</span> <span class="kwrd">void</span> Application_Activated(<span class="kwrd">object</span> sender, ActivatedEventArgs e)</pre><pre><span class="lnum"> 2: </span>{</pre><pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd">if</span> (AppController.CurrentUser == <span class="kwrd">null</span>)</pre><pre><span class="lnum"> 4: </span> {</pre><pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">using</span> (var store = IsolatedStorageFile.GetUserStoreForApplication())</pre><pre><span class="lnum"> 6: </span> {</pre><pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">if</span> (store.FileExists(Constants.Files.UserLogin))</pre><pre><span class="lnum"> 8: </span> {</pre><pre class="alt"><span class="lnum"> 9: </span> <span class="kwrd">using</span> (var file = <span class="kwrd">new</span> IsolatedStorageFileStream(Constants.Files.UserLogin, FileMode.Open, store))</pre><pre><span class="lnum"> 10: </span> {</pre><pre class="alt"><span class="lnum"> 11: </span> var serializer = <span class="kwrd">new</span> DataContractSerializer(<span class="kwrd">typeof</span>(UserLogin));</pre><pre><span class="lnum"> 12: </span> AppController.CurrentUser = (UserLogin)serializer.ReadObject(file);</pre><pre class="alt"><span class="lnum"> 13: </span> }</pre><pre><span class="lnum"> 14: </span> }</pre><pre class="alt"><span class="lnum"> 15: </span> }</pre><pre><span class="lnum"> 16: </span> }</pre><pre class="alt"><span class="lnum"> 17: </span>}</pre></div><div><pre><span class="Apple-style-span" style="font-family: 'Times New Roman';"><span class="Apple-style-span" style="white-space: normal;">
</span></span></pre><pre><span class="Apple-style-span" style="font-family: 'Times New Roman';"><span class="Apple-style-span" style="white-space: normal;"><i>(to be continued)</i></span></span></pre></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-20358369472745544602010-11-10T15:03:00.000-08:002010-11-17T10:58:26.493-08:00Mobile Enterprise Application. Step 1: General ArchitectureI decided to follow up on my <a href="http://riyadsthoughts.blogspot.com/2010/10/mobile-clients-of-business-applications.html">previous post</a> and write a series of more practical articles to illustrate various decisions that are specific to mobile enterprise applications. Being is Microsoft platform developer, I am going to stick to Windows Phone 7 in this series. This first blog post discusses general architectural issues.<br />
<br />
<b>Choosing Client Technology</b><br />
WinPhone 7 supports two development paradigms: Silverlight and XNA. The latter targets game developers, providing them with game loop, sprites, and stuff like that. Silverlight, on the other hand, is a subset of the traditional desktop UI platform (WPF). It has a rich set of controls plus the ability to do cool visual effects. Silverlight is a natural choice for a mobile enterprise application.<br />
<br />
<b>Relative Merits of MVVM</b><br />
Model-View-ViewModel design pattern has a widespread adoption in the XAML world, including Silverlight. The question isn't whether or not MVVM <i>can</i> be used in WinPhone 7 applications (it can) but whether or not it <i>should</i> be used. On the negative side, MVVM makes your app larger and slower, which is no small thing on the mobile device. On the positive side, it provides the separation between user interface and logic which is extremely beneficial in two scenarios: unit testing and sharing projects with a designer.<br />
<br />
<i>Unit Testing</i><br />
Generally, I am a big proponent of unit testing - I believe they are essential to building high-quality maintainable programs. However, WinPhone 7 unit testing is a little wobbly at the moment. Test framework built into Visual Studio doesn't support phone applications, so we are supposed to download Silverlight Unit Test framework, which is included into Silverlight Toolkit. Only problem is that latest version of the toolkit supports Silverlight 4, but not WinPhone 7... I'm sure eventually Microsoft will sort everything out, but for the time being it's probably best not to concentrate on unit tests.<br />
<br />
<i>Sharing Projects With Designer</i><br />
If your project team has a dedicated designer who actually works with the same project as developers, MVVM provides a nice clean separation of concerns. If, on the other hand, you do not have a designer, or the one you have prefers exchanging images and screenshots with you over email, MVVM doesn't really give you much of an edge.<br />
<br />
<b>Choosing Server Technology</b><br />
We should try to shift as much logic as possible to the server. This makes sense from several points of view. First of all, mobile client doesn't offer a lot of processing power while server side can be very scalable. Second, if you support more than one client platform, it helps to have as little code to port as possible. Third, your business logic is your intellectual property, and it is definitely more secure on the server.<br />
<br />
<i>SOAP or REST?</i><br />
When it comes to building web services, WCF allows the choice between SOAP and REST. On the high level, SOAP is really a remote procedure call mechanism which can support sophisticated logic and advanced security requirements. REST, on the other hand, operates with a simple set of HTTP verbs and is therefore better suited for simpler CRUD-type logic.<br />
<br />
<i>Secure Communication</i><br />
Mobile clients communicate with web services over 3G or WiFi networks, which makes them vulnerable to security attacks (open public WiFi are especially fertile ground for packet sniffing - read more <a href="http://codebutler.com/firesheep">here</a>). It is therefore essential to encrypt all messages, not just those related to authentication. Using SSL protocol for communication is a good start.<br />
<br />
<i><span class="Apple-style-span" style="color: #666666;">(to be continued)</span></i>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-35372738992247821382010-10-21T23:13:00.000-07:002010-10-21T23:13:37.815-07:00Mobile Clients of Business ApplicationsAs of today, there are over 200,000 applications in Apple AppStore targeting iPhone, iPod Touch, or iPad. Android Market has over 100,000 applications. Windows Phone 7 will start selling in November, and there is already a rush to fill up its Marketplace. Now, overwhelming majority of all these applications are consumer-oriented: games, social networking, news, and much more (even books these days are often made into phone applications). Does that mean that business apps (sometimes they are called "line of business" apps) don't have a place on a mobile client?<br />
<br />
Given the huge popularity and widespread adoption of modern smartphones, combined with changes in the workplace, the answer must be a resounding "no". However, creating a mobile client that really adds value to the system as a whole is not a trivial task and requires careful planning. In this post, I will try to highlight some of the challenges involved in designing a mobile client for a business application.<br />
<br />
<b>Challenge 1. Define a Reasonable Subset of Functionality</b><br />
Typical enterprise app has a very large scope, which tends to grow as business users demand more and more features with each release. Trying to squeeze as much as possible into the mobile client is probably not a good idea. First of all, consider the form-factor: will user be able to accomplish the task with tiny screen and soft keyboard? Then take into account specific needs of the mobile user - they are guaranteed to be different from someone who is comfortably sitting in front of a computer. For example, the latter may need the ability to sift through large sets of data with different search/sort criteria, while the former wants to see just the relevant data - and upfront.<br />
<br />
<b>Challenge 2. Mobile-Specific Features</b><br />
Modern smartphones like iPhone or Windows Phone 7 have advanced hardware, and developers can incorporate such compelling features as multi-touch interface, camera, microphone, location services, and accelerometer. Naturally, applications can also have the ability to place phone calls and send email. These features may or may not be applicable to a specific business system. A mobile client for a customer-relationship management application is likely to take advantage of location services, phone and email, but it's difficult to imagine why it would need an accelerometer.<br />
<br />
<b>Challenge 3. Choose Appropriate Architecture</b><br />
When it comes to choosing a specific technology, there are two main choices: develop mobile client as a web application or a native one. Although a web application is often a better choice for a desktop client, the situation is opposite in the mobile world. Even if the business system already has a website, a special version will be required to support small form-factor of the mobile device. On the other hand, browsers that are included with mobile operating systems vary in their support for various features of HTML, JavaScript, and CSS. The lowest common denominator website will probably not satisfy the users. Another drawback is the inability to tap into the mobile-specific features, such as location services or camera.<br />
<br />
Going native allows full control over application UI, plus it enables access to hardware features, but it's hardly an easy task. Sheer number of available platforms is the main difficulty, with little or no code reuse between them. Android development should be done in Java, iPhone apps are written in Objective C, and Windows Phone 7 relies on C#/.NET.<br />
<br />
<b>Challenge 4. Security and Session Management</b><br />
Pretty much all enterprise systems deal with sensitive data one way or another, and mobile clients will most likely need to work with it, too. Mobile devices have a security disadvantage compared to office computers: they are easily lost or stolen. It is therefore important not to store anything sensitive on the device itself and employ two-way authentication mechanism. User sessions cannot be open-ended and user activity within the application must be logged on the server for auditing purpose. Another potential vulnerability is the network: smartphones communicate over public Wi-Fi and 3G networks. This can be mitigated by using SSL protocol.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-50286748303021351372010-08-09T12:46:00.000-07:002010-08-09T23:00:07.823-07:00Should Software Development Be Regulated?The question of government regulation of business is high on the agenda these days. Over the last couple of years we have witnessed some spectacular events, like the Great Recession of 2008 and Deepwater Horizon explosion (and subsequent Gulf of Mexico oil spill) of 2010. These have already become case studies of the importance of government regulation. New legislation on financial and healthcare reforms will significantly increase the role of government in those areas. So, here is my question: has the time finally come to regulate software development?<div><br /></div><div>I realize a lot of people have a negative knee-jerk reaction to anything that might expand the role of government (I can almost hear them scream!). Personally, coming from a communist country, I tend to be fairly skeptical in this area: I've seen what happens when bureaucrats are given unchecked power over people's lives. But let's consider the matter objectively. After thinking about it for a while I came up with three different areas where regulation can bring positive change.</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>Professionalism</b></span></div><div>It never ceases to amaze me that you cannot work as a plumber without a plumbing license, but no license is required to write software. Mind you, obtaining a plumber's license is far from a formality: it requires four years of job training, and the applicant must pass a written exam. On the other hand, <i>anyone</i> can apply for a software engineer position: it is up to the hiring company whether or not to ask for evidence of some formal training. Some companies administer tests, or ask a bunch of technical questions during interview process, but there aren't any standards.</div><div><br /></div><div>As a direct result, ranks of software developers are full of people who picked programming as a hobby or were attracted to it by higher salaries, but never learned the mathematical foundations of the discipline. I would argue that these people are more likely to use poor coding practices, steer clear of object-oriented programming, and never bother with design patterns. Note that I am not advocating the supremacy of college graduates; all I'm saying that programming requires <i>proper</i> training.</div><div><br /></div><div>By the way, similar observation can be made about businesses. For example, a financial services company may own cars, but is unlikely to have an in-house team of mechanics who fix them. And yet, the same exact company doesn't have second thoughts about maintaining an in-house software development organization.</div><div><br /></div><div><b><span class="Apple-style-span" style="font-size:large;">Quality Control</span></b></div><div>Given the role software is playing in our lives, it's hard to understand why people tolerate low-quality applications. Although there are many reasons for poor quality, the industry pretty much knows how to address this problem. It all starts with a solid design, of course: application architecture should be appropriate for the task. Developers should write automated unit tests and ensure good code coverage, and these tests should be executed as part of every build. Each application should have well-defined white box and black box test cases, and appropriate performance testing should be done before the system goes live.</div><div><br /></div><div>However, good quality control can be expensive: for example, the time used to write unit tests is the time developers do not implement new functionality. Automated testing tools for QA can be very expensive, too. It's no surprise some businesses prefer to save money on quality, given the extraordinary tolerance consumers have towards buggy software. By enforcing standard QA processes, government regulators can make good reliable software a reality and make life easier for the end user.</div><div><br /></div><div><b><span class="Apple-style-span" style="font-size:large;">Security</span></b></div><div>Over the last 15 years, as high-speed internet access became first widespread and then ubiquitous, software applications grew to rely more and more on connectivity. Sadly, this opened the floodgates for an entirely new class of problems: cyber attacks. Let me quote from an excellent book on the subject, <a href="http://www.amazon.com/gp/product/0061962236?ie=UTF8&tag=riystecblo-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0061962236%22%3ECyber%20War:%20The%20Next%20Threat%20to%20National%20Security%20and%20What%20to%20Do%20About%20It%3C/a%3E%3Cimg%20src=%22http://www.assoc-amazon.com/e/ir?t=riystecblo-20&l=as2&o=1&a=0061962236%22%20width=%221%22%20height=%221%22%20border=%220%22%20alt=%22%22%20style=%22border:none%20!important;%20margin:0px%20!important;%22%20/%3E">Richard Clarke's "Cyber War"</a>:</div><div><blockquote>These military and intelligence organizations are preparing the cyber battlefield with things called "logic bombs" and "trapdoors," placing virtual explosives in other countries in peacetime. Given the unique nature of cyber war, there may be incentives to go first. The most likely targets are civilian in nature. The speed at which thousands of targets can be hit, almost anywhere in the world, brings with it the prospect of highly volatile crises.</blockquote>Of course, cyber attackers exploit security weaknesses in software, and of course the system is as secure as its weakest link. But how does software acquire these weaknesses in the first place? One reason is that people who develop it lack the knowledge and expertise to do proper threat modeling. And even if the application was developed with security in mind, has it ever been tested for security vulnerabilities? This is where government regulators could step in, making sure all software has been secured at an appropriate level.</div><div><br /></div><div>In conclusion of this essay, I would like to acknowledge that regulation doesn't always work, and it is entirely possible that a bad appointee will turn the initiative completely upside down. After all, doesn't Great Recession illustrate inability of the SEC to control derivatives market? And didn't oil rig explosion shed light on mass incompetence and corruption at MMS? But software has become such an important aspect of our civilization that we must at least begin a conversation.</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-87584236644220360392010-08-02T22:17:00.000-07:002010-08-09T10:02:33.008-07:00VB or C#? A Personal JourneyLast time I checked LinkedIn group .NET People, there were 435 posts in the "VB or C#?" discussion. That's strange, I said to myself. After ten years and four language iterations are there enough differences to spark the debate? So I started reading...<div><br /></div><div>Well, there were a couple of people who found genuine gaps (like XML literals in VB or <code>yield</code> keyword in C#). There were a couple of trolls, and a couple of people just having a good laugh ("<i>I prefer C# over VB because I am an American!</i>"). But the majority of comments were pure opinion. "<i>Code is cleaner</i>", "<i>more readable</i>", "<i>I hate semicolons</i>", "<i>I love curly braces</i>", "<i>too verbose</i>", "<i>closest to plain English</i>" were some of the statements repeated over and over. IMHO, this entire discussion sheds more light on the .NET development community than on programming languages themselves.</div><div><br /></div><div>It's no secret that people come to software development using [at least] two separate routes. Some study Computer Science in college (even if it's not their major or they never graduate). They are probably taught programming courses in Java or C++, so C# comes naturally to this group. Second category of developers started out in a different line of work and discovered Office automation with VBA somewhere along the way. Or perhaps they learned VBScript in order to maintain their department's ASP page on the intranet. When .NET came along, this group made a transition to VB.NET.</div><div><br /></div><div>Now, I'm not trying to argue which group has better programmers - I've seen extremely bright engineers without CS degree, as well as some dim bulbs who turned out to have a Master of Science in CS. But it's a common knowledge that C# was designed from the ground up as a managed object-oriented language, while VB.NET is essentially the outcome of multiple cosmetic surgeries made to an aging body. First change happened when original BASIC - <i>Beginner's All-purpose Symbolic Instruction Code</i> - was updated to support structural programming. It has acquired the "Visual" prefix, but didn't become fully object-oriented until its VB.NET incarnation. Nowadays, Microsoft works diligently to keep the language on par with C#, adding constructs like generics, lambda expressions, closures, and so on.</div><div><br /></div><div>However, the efforts to modernize VB have little impact on most VB programmers, who probably just aren't familiar enough with contemporary design and programming patterns. So, it's no surprise they tend to get a little bit defensive...</div><div><br /></div><div>Interestingly, I myself managed to travel both paths to software development. My college major was Applied Mathematics and Cybernetics, and I had plenty of instruction on typical CS subjects. We used Turbo Pascal in the classroom, and by the end of school I transitioned to Borland C++. Incidentally, Soviet Union imploded at about the same time, and in the chaos that followed, my aspirations to find a job in IT became laughable (people were lucky if they had any job at all - it was not unusual in those days for a doctor to work as a taxi driver). So, I ended up doing bookkeeping, accounting and then business planning for a big multinational corporation.</div><div><br /></div><div>Before long, I was dabbling in Microsoft Access and creating automated databases and spreadsheets for my team. VB was easy and forgiving, and, more importantly, it was ubiquitous. When I finally managed to switch my career back to IT, I didn't feel comfortable with latest C++ tools and frameworks, so I stuck with VBScript and VB6. When .NET was introduced, my first instinct was to transition to VB.NET. However, I decided that it was time to re-educate myself. I started reading about design patterns (which weren't even on the radar when I was in college), test-driven development and extreme programming. I studied source code and tackled new classes of problems, like multi-threaded services development.</div><div><br /></div><div>Eventually, I realized that C# was a better choice for me, made a switch, and never looked back. This was around 2005, when gap between the two languages was fairly big. Five years later, it is almost gone. But like I said earlier, it's easier to update a compiler than to change people's mindset. Both VB and C# are here to stay, I'm just waiting for someone to port another of my college-era languages, <a href="http://en.wikipedia.org/wiki/Prolog">Prolog</a>, to .NET framework...</div>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-32857418.post-17447189301384913752010-05-20T15:41:00.001-07:002011-11-22T08:12:37.658-08:00Dynamic Connection Strings With SSRS Data Processing Extension<div>
It is my firm opinion that whoever came up with the names for various parts of SQL Server must be fired. "SQL Server Reporting Services", "SQL Server Analysis Services", "SQL Server Service Broker" do not exactly roll off the tongue. Just try using a few of these in a speech - you will immediately realize you need nicknames (SSRS sounds too much like <a href="http://en.wikipedia.org/wiki/Ussr">USSR</a>. Oh, well, I'll just call it <a href="http://www.imdb.com/character/ch0183742/">Kevin</a>). Anyway, this post wasn't supposed to be a rant, so let's move on.</div>
<br />
<div>
</div>
<div>
SSRS supports ten data sources out of the box, including SQL Server (duh!), ODBC, OLE DB, and Oracle. <i>Data Processing Extensions</i> are usually recommended when you need to generate reports from non-standard data sources, for example, files in a proprietary format. You start by creating a .NET assembly with classes that implement a half-dozen or so interfaces defined in Microsoft.ReportingServices.Interfaces.dll. Once everything is working, you deploy the assembly to two separate locations: Visual Studio subfolder on a report developer's workstation, and a Reporting Services subfolder on a server. The process is well documented on <a href="http://technet.microsoft.com/en-us/library/ms154655.aspx">MSDN</a> and there is also a good article on <a href="http://www.codeproject.com/KB/reporting-services/Implementing_a_Data_Proce.aspx">The Code Project</a>.</div>
<br />
<div>
</div>
<div>
However, what if your database is a SQL Server, but you cannot rely on a static connection string? Suppose you maintain separate databases for your various customers and generate connection strings at runtime? Although SSRS allows us to use parameterized connection strings, sometimes this isn't an optimal solution, given the fact that those parameters are passed around openly inside URL. I found that Data Processing Extensions can be used very effectively in this scenario.</div>
<div>
<br /></div>
<div>
Rather than implementing all the interfaces required by DPE, we will encapsulate an existing class SqlConnectionWrapper in the Microsoft.ReportingServices.DataExtensions namespace (it is marked as "sealed", so you can't subclass it):</div>
<div>
<div class="csharpcode">
<br />
<pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">using</span> Microsoft.ReportingServices.DataExtensions;</pre>
<pre><span class="lnum"> 2: </span><span class="kwrd">using</span> Microsoft.ReportingServices.DataProcessing;</pre>
<pre class="alt"><span class="lnum"> 3: </span> </pre>
<pre><span class="lnum"> 4: </span><span class="kwrd">public</span> <span class="kwrd">class</span> MySqlConnection : IDbConnectionExtension</pre>
<pre class="alt"><span class="lnum"> 5: </span>{</pre>
<pre><span class="lnum"> 6: </span> <span class="kwrd">private</span> SqlConnectionWrapper _Connection;</pre>
<pre class="alt"><span class="lnum"> 7: </span> </pre>
<pre><span class="lnum"> 8: </span> <span class="kwrd">public</span> MySqlConnection()</pre>
<pre class="alt"><span class="lnum"> 9: </span> {</pre>
<pre><span class="lnum"> 10: </span> _Connection = <span class="kwrd">new</span> SqlConnectionWrapper();</pre>
<pre class="alt"><span class="lnum"> 11: </span> }</pre>
<pre><span class="lnum"> 12: </span>}</pre>
</div>
</div>
<div>
Right-click IDbConnectionExtension and choose "Implement Interface". This automatically implements three more interfaces, IDbConnection, IDisposable, and IExtension members. Most of the new methods and properties added to our class will be merely wrappers of the respected methods and properties of the _Connection. For example:</div>
<div>
<div class="csharpcode">
<pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">public</span> <span class="kwrd">string</span> Password</pre>
<pre><span class="lnum"> 2: </span> {</pre>
<pre class="alt"><span class="lnum"> 3: </span> set { _Connection.Password = <span class="kwrd">value</span>; }</pre>
<pre><span class="lnum"> 4: </span> }</pre>
<pre class="alt"><span class="lnum"> 5: </span> </pre>
<pre><span class="lnum"> 6: </span> <span class="kwrd">public</span> <span class="kwrd">string</span> UserName</pre>
<pre class="alt"><span class="lnum"> 7: </span> {</pre>
<pre><span class="lnum"> 8: </span> set { _Connection.UserName = <span class="kwrd">value</span>; }</pre>
<pre class="alt"><span class="lnum"> 9: </span> }</pre>
</div>
</div>
<div>
Of course, you still need to add the implementation.</div>
<div>
<br /></div>
<div>
Property LocalizedName should return the string that you want report developers to see in the list of data sources (e.g., on the "Select Data Source" screen of the new report wizard).</div>
<div>
<div class="csharpcode">
<pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">public</span> <span class="kwrd">string</span> LocalizedName</pre>
<pre><span class="lnum"> 2: </span> {</pre>
<pre class="alt"><span class="lnum"> 3: </span> get { <span class="kwrd">return</span> <span class="str">"Dynamic SQL Server Connection"</span>; }</pre>
<pre><span class="lnum"> 4: </span> }</pre>
</div>
</div>
<div>
Arguably the most important implementation is ConnectionString setter. This is where you need to put your proprietary logic that dynamically generates a valid connection string. There are a couple of different approaches. If you don't need any additional information in order to generate the connection string, ignore the "value" and just call necessary methods:</div>
<div>
<div class="csharpcode">
<pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">public</span> <span class="kwrd">string</span> ConnectionString</pre>
<pre><span class="lnum"> 2: </span> {</pre>
<pre class="alt"><span class="lnum"> 3: </span> get</pre>
<pre><span class="lnum"> 4: </span> {</pre>
<pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">return</span> _Connection.ConnectionString;</pre>
<pre><span class="lnum"> 6: </span> }</pre>
<pre class="alt"><span class="lnum"> 7: </span> set</pre>
<pre><span class="lnum"> 8: </span> {</pre>
<pre class="alt"><span class="lnum"> 9: </span> _Connection.ConnectionString = MyDataLayer.GenerateConnectionString();</pre>
<pre><span class="lnum"> 10: </span> }</pre>
<pre class="alt"><span class="lnum"> 11: </span> }</pre>
</div>
</div>
<div>
If, on the other hand, your logic does require parameters, you will need to parse ConnectionString value that client code provided. Example below uses regular expression to extract CustomerID from the value (and skips property getter for brevity):</div>
<div>
<div class="csharpcode">
<pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">public</span> <span class="kwrd">string</span> ConnectionString</pre>
<pre><span class="lnum"> 2: </span> {</pre>
<pre class="alt"><span class="lnum"> 3: </span> set</pre>
<pre><span class="lnum"> 4: </span> {</pre>
<pre class="alt"><span class="lnum"> 5: </span> Match m = Regex.Match(<span class="kwrd">value</span>, <span class="str">"CustomerID=([^;]+)"</span>, RegexOptions.IgnoreCase);</pre>
<pre><span class="lnum"> 6: </span> <span class="kwrd">int</span> custId = 0;</pre>
<pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">if</span> (m.Success</pre>
<pre><span class="lnum"> 8: </span> && <span class="kwrd">int</span>.TryParse(m.Groups[1].Captures[0].Value, <span class="kwrd">out</span> custId))</pre>
<pre class="alt"><span class="lnum"> 9: </span> {</pre>
<pre><span class="lnum"> 10: </span> _Connection.ConnectionString = MyDataLayer.GenerateConnectionString(custId);</pre>
<pre class="alt"><span class="lnum"> 11: </span> }</pre>
<pre><span class="lnum"> 12: </span> <span class="kwrd">else</span></pre>
<pre class="alt"><span class="lnum"> 13: </span> {</pre>
<pre><span class="lnum"> 14: </span> <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentException(<span class="str">"Valid CustomerID is missing"</span>);</pre>
<pre class="alt"><span class="lnum"> 15: </span> }</pre>
<pre><span class="lnum"> 16: </span> }</pre>
<pre class="alt"><span class="lnum"> 17: </span> }</pre>
</div>
</div>
<div>
Now the only thing left to do is deploy assembly containing MySqlConnection to both server and developer workstation.<br />
<br />
*** UPDATED 11/22/2011 ****<br />
<br />
Bad news for those of you using SQL 2008 R2 - the approach of encapsulating Microsoft.ReportingServices.DataExtensions.SqlConnectionWrapper I outlined in this post no longer works. Apparently, they changed class accessibility from "public" to "internal". Looks like the only opportunity is to implement all interfaces manually.</div>Unknownnoreply@blogger.com6tag:blogger.com,1999:blog-32857418.post-25998045685013311942010-05-18T22:09:00.000-07:002010-05-18T22:13:32.394-07:00San Diego .NET User Group PresentationThanks to everyone who attended my presentation at San Diego .NET User Group. As promised, below are the links to slides I used and sample code we wrote.<div><br /></div><div>Slides: <a href="http://members.cox.net/rmamedov/blog/IntroducingWCSF.pdf">http://members.cox.net/rmamedov/blog/IntroducingWCSF.pdf</a></div><div>Visual Studio solution: <a href="http://members.cox.net/rmamedov/blog/SanDiego.zip">http://members.cox.net/rmamedov/blog/SanDiego.zip</a></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-48055856134265331292010-05-02T12:39:00.000-07:002010-05-02T14:11:51.462-07:00Code Generation For Auto-Implemented PropertiesI recently ventured into one of the more obscure areas of .NET framework - code generation. The project involved rules engine manipulating properties of our internal domain objects. Long story short, I had to create a routine that converts our domain objects into .NET classes (derived from System.Workflow.Activity). These generated classes did not have much behavior - all methods were pushed to the base class - but they did carry so many properties that they in turn had to be grouped together into classes.<div><br /></div><div>Writing code generation logic for a property turned out to be a lot of work: first, I had to add declaration for a private backing field, then a property declaration, including code expressions for both getter and setter. Here's sample code similar to what I ended up with:</div><!-- code formatted by http://manoli.net/csharpformat/ --><br /><div class="csharpcode"><br /><pre class="alt">var myType = <span class="kwrd">new</span> CodeTypeDeclaration(<span class="str">"Person"</span>);</pre><pre> </pre><br /><pre class="alt">var field = <span class="kwrd">new</span> CodeMemberField()</pre><pre>{</pre><pre class="alt"> Name = <span class="str">"_LastName"</span>,</pre><pre> Type = <span class="kwrd">new</span> CodeTypeReference(<span class="str">"System.String"</span>),</pre><pre class="alt"> Attributes = MemberAttributes.Private</pre><pre>};</pre><pre class="alt">myType.Members.Add(field);</pre><pre> </pre><pre class="alt">var prop = <span class="kwrd">new</span> CodeMemberProperty()</pre><pre>{</pre><pre class="alt"> Name = <span class="str">"LastName"</span>,</pre><pre> Type = <span class="kwrd">new</span> CodeTypeReference(<span class="str">"System.String"</span>),</pre><pre class="alt"> Attributes = MemberAttributes.Public</pre><pre>};</pre><pre class="alt">prop.GetStatements.Add(</pre><pre> <span class="kwrd">new</span> CodeMethodReturnStatement(</pre><pre class="alt"> <span class="kwrd">new</span> CodeFieldReferenceExpression(</pre><pre> <span class="kwrd">new</span> CodeThisReferenceExpression(), <span class="str">"_LastName"</span>)));</pre><pre class="alt">prop.SetStatements.Add(</pre><pre> <span class="kwrd">new</span> CodeAssignStatement(</pre><pre class="alt"> <span class="kwrd">new</span> CodeFieldReferenceExpression(</pre><pre> <span class="kwrd">new</span> CodeThisReferenceExpression(), <span class="str">"_LastName"</span>), </pre><pre class="alt"> <span class="kwrd">new</span> CodePropertySetValueReferenceExpression()));</pre><pre>myType.Members.Add(prop);</pre><pre><br /></pre></div><div>And here is the code that was generated by the above fragment:</div><!-- code formatted by http://manoli.net/csharpformat/ --><br /><div class="csharpcode"><br /><pre class="alt"><span class="kwrd">private</span> <span class="kwrd">string</span> _LastName;</pre><pre><span class="kwrd">public</span> <span class="kwrd">string</span> LastName</pre><pre class="alt">{</pre><pre> get { <span class="kwrd">return</span> _LastName; }</pre><pre class="alt"> set { _LastName = <span class="kwrd">value</span>; }</pre><pre>}</pre><pre><br /></pre></div><div>Of course, C# 3.0 has introduced a much shorted way of declaring the same property: "<span class="Apple-style-span" style="font-family:'courier new';"><span class="Apple-style-span" style="font-size:small;">public string LastName { get; set; }</span></span>". This syntax is called "auto-implemented properties" and it puts the burden on the compiler to create a backing field and implement getter and setter logic. Naturally, I wanted generated classes to look cleaner, so being an optimist that I am I decided to change code generation logic to create auto-implemented properties instead.</div><div><br /></div><div>That proved to be a mistake: after a while I realized that classes in System.CodeDom namespace do not support auto-implemented properties generation. The best I could come up with was a hack using CodeSnippetTypeMember:</div><!-- code formatted by http://manoli.net/csharpformat/ --><br /><div class="csharpcode"><br /><pre class="alt">var snippet = <span class="kwrd">new</span> CodeSnippetTypeMember(<span class="str">"public string LastName { get; set; }"</span>);</pre><pre>myType.Members.Add(snippet);</pre></div><br /><div>This solution is pretty far from ideal. It goes against the spirit of code generation because it allows me to target just one programming language, C#. Still, it is pragmatic. Hopefully, Microsoft can bring CodeDom up to date in a future release. </div>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-32857418.post-80683101557635422492010-03-29T19:05:00.000-07:002010-04-01T16:33:01.034-07:00Passing Parameters To ClickOnce ApplicationsI was doing some research with ClickOnce deployment architecture and found an unexpected challenge: passing command line parameters. This post summarizes a couple of different approaches; hopefully, it will save someone a few hours of trial and error and frantic googling.<div><br /></div><div><b>Use Query String</b></div><div><br /></div><div>ClickOnce applications can be installed from a website, and they can also be invoked from a webpage. All that's needed is a hyperlink that references the <span class="Apple-style-span" style="font-family:'courier new';">.application</span> file, e.g.: <span class="Apple-style-span" style="font-family:'courier new';">http://www.mywebsite.com/foobar/foobar.application</span>. When user clicks the link, <i>Foobar</i> will launch (actually, the same link will install <i>Foobar</i> on user machine). In this scenario, parameters can be passed to the application by adding query string to the URL: <span class="Apple-style-span" style="font-family:'courier new';">http://www.mysite.com/foobar/foobar.application?param1=value1&param2=value2&...</span> . Here's how to do it:</div><div><br /></div><div><i>Step 1: Enable URL parameters in ClickOnce application</i></div><div><br /></div><div>Open project properties in Visual Studio and click "Publish" tab. Then click "Options" button, which brings up a dialog window. Select "Manifests" from the list, and make sure the checkbox that reads "Allow URL parameters to be passed to application" is checked.</div><div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_J25GU3zvjZY/S7UnGhG3qaI/AAAAAAAACG0/C30n91T0oag/s1600/ClickOnce-1.gif"><img style="cursor:pointer; cursor:hand;width: 320px; height: 195px;" src="http://1.bp.blogspot.com/_J25GU3zvjZY/S7UnGhG3qaI/AAAAAAAACG0/C30n91T0oag/s320/ClickOnce-1.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5455309516549106082" /></a><br /></div><div><i><br /></i></div><div><i>Step 2: Add code to process parameters</i></div><div><br /></div><div>In regular Windows applications written in C#, it is enough to declare <span class="Apple-style-span" style="font-family:'courier new';">static void Main(string[] args)</span> in order to get the list of command line parameters in the args array. Unfortunately, this doesn't work with ClickOnce applications - the args array will be empty whether or not URL had any parameters. In order to access them, we need to analyze <span class="Apple-style-span" style="font-family:'courier new';">AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData</span> property.</div><div><!-- code formatted by http://manoli.net/csharpformat/ --><br /><div class="csharpcode"><br /><pre class="alt">[STAThread]</pre><br /><pre><span class="kwrd">static</span> <span class="kwrd">void</span> Main()</pre><br /><pre class="alt">{</pre><br /><pre> Application.EnableVisualStyles();</pre><br /><pre class="alt"> Application.SetCompatibleTextRenderingDefault(<span class="kwrd">false</span>);</pre><br /><pre> </pre><br /><pre class="alt"> var args = AppDomain.CurrentDomain.SetupInformation.ActivationArguments;</pre><br /><pre> var frm = <span class="kwrd">new</span> MainForm();</pre><br /><pre class="alt"> <span class="kwrd">if</span> (args != <span class="kwrd">null</span></pre><br /><pre> && args.ActivationData != <span class="kwrd">null</span></pre><br /><pre class="alt"> && args.ActivationData.Length > 0)</pre><br /><pre> {</pre><br /><pre class="alt"> var url = <span class="kwrd">new</span> Uri(args.ActivationData[0], UriKind.Absolute);</pre><br /><pre> var parameters = HttpUtility.ParseQueryString(url.Query);</pre><br /><pre class="alt"> <span class="rem">// Process parameters here</span></pre><br /><pre> }</pre><br /><pre class="alt"> </pre><br /><pre> Application.Run(frm);</pre><br /><pre class="alt">}</pre><br /></div><br /></div><div><br /></div><div><b>Add File Type Association</b></div><div><br /></div><div>Another interesting approach is to associate the application with a specific file extension. When a file with this extension is downloaded from a web page or opened in Windows Explorer, application will be launched automatically and file name will be passed to it. Prior SP1 release of .NET 3.5, file type association had to be created programmatically (by creating subkeys for the desired extension and a shell\open\command using Microsoft.Win32.Registry API). Visual Studio 2008 SP1 allows to define association declaratively. In the same Options dialog mentioned above, click "File Associations" and fill in required information in the data grid.</div><div><br /></div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_J25GU3zvjZY/S7UsSekxTDI/AAAAAAAACG8/8gG3_xg6pi4/s1600/ClickOnce-2.gif"><img style="cursor:pointer; cursor:hand;width: 320px; height: 195px;" src="http://2.bp.blogspot.com/_J25GU3zvjZY/S7UsSekxTDI/AAAAAAAACG8/8gG3_xg6pi4/s320/ClickOnce-2.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5455315219585780786" /></a><br /><br /></div><div>Processing logic is very similar to the first scenario - we still need to analyze<span class="Apple-style-span" style="font-family:'courier new';">AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData</span>property. The only difference is that instead of calling HttpUtility.ParseQueryString, we need to extract file name from it.</div><div><br /></div>Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-32857418.post-55735706111049348472010-03-13T17:19:00.000-08:002010-03-14T23:30:15.306-07:00Continuous Integration + Continuous ImprovementLong time ago, in the early days of software development, one person could program entire application. Gary Kildall wrote the <a href="http://en.wikipedia.org/wiki/CP/M">CP/M</a> operating system, and Wayne Ratliff wrote <a href="http://en.wikipedia.org/wiki/DBase">dBASE</a>, one of the first database engines. Nowadays, the project can get started with one or two developers, but eventually ends up with many more (as management often seems to ignore <a href="http://en.wikipedia.org/wiki/Brooks's_law">Brooks's law</a> about adding man-power to a late project).<div><br /></div><div>Once you have several people working on the same codebase, integrating their changes can become a challenge. (<span class="Apple-style-span" style="font-family:georgia;">I remember one project where two developers decided to work independently and did not attempt to integrate until the code-cutoff day. Sadly but unsurprisingly, the solution didn't build, and since there was no time to solve all the issues, they had to deliver two separate applications instead of one.)</span> The solution, known as continuous integration, is to use the common source code repository and integrate frequently. The first part is obvious, the second may require some explanation.</div><div><br /></div><div>Many software companies have Build engineers (or even teams of Build engineers), whose main job is to produce builds. Since "integrate" really means "get latest code and build the system", it is theoretically possible to assign this task to Build engineers. However, I do not think it is such a great idea: first of all, the task is boring, and second, humans may have a problem with the "frequently" part. For some projects, it will be enough to run a nightly build, while other will prefer to integrate every time source code is committed to the repository. There is no way a human could be doing that! The best thing to do is automate the task, and there are commercial and open-source systems that can do the job.</div><div><br /></div><div>A few months ago I installed one such application, open-source product called <a href="http://confluence.public.thoughtworks.org/display/CCNET/Welcome+to+CruiseControl.NET">Cruise Control .NET</a> on a virtual server we use as a build machine. It consists of a Windows service and an ASP.NET web application: service runs integration tasks, web app provides user interface for build status, logs, and reports. Naturally, it supports multiple projects, but project configuration has to be done the old-fashioned way, by manually editing XML in a couple of .config files. Another nice feature is a utility called CCTray; this is a little app that displays an icon in the taskbar. The icon uses traffic light colors to notify user of their project status.</div><div><br /></div><div>Cruise Control is a great application that I highly recommend, but there is one more concept I wanted to describe in this blog post: continuous improvement, or "<a href="http://ja.wikipedia.org/wiki/%E6%94%B9%E5%96%84">Kaizen</a>" in the original Japanese. Kaizen is a philosophy that helps to improve productivity and quality while reducing cost. It applies to different areas: manufacturing, government, banking, healthcare, and its main ideas are individual empowerment and continuous quality cycle.</div><div><br /></div><div>I think we can successfully apply Kaizen ideas to software development. Most straightforward approach in my opinion is encouraging programmers to do three things:</div><div><ul><li>Refactor code to design patterns,</li><li>Increase unit test code coverage,</li><li>Fix <i>all</i> bugs (not just those reported by users).</li></ul></div><div>This of course means that our application's codebase will be continuously updated, and I know there are companies out there that will be really uncomfortable with such perspective. However, when source code is sufficiently covered by unit tests, and all tests are executed as part of every build, I see no reason for concern. </div>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-32857418.post-11416396454431957442010-01-30T18:34:00.001-08:002010-08-09T22:20:55.921-07:00Introducing Web Client Software FactoryEarlier today I gave a talk on <a href="http://www.socalcodecamp.com">Socal Code Camp</a> entitled "Introducing Web Client Software Factory". Thanks to everyone who attended! We ran out of time and didn't cover some of the less important features of WCSF. Perhaps, in the future I will need to split this into two sessions.<div><br /></div><div>Here are the slides I used: <a href="http://members.cox.net/rmamedov/blog/IntroducingWebClientSoftwareFactory.pdf">http://members.cox.net/rmamedov/blog/IntroducingWebClientSoftwareFactory.pdf</a></div><div><br /></div>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-32857418.post-54589590236301435172009-11-13T10:03:00.000-08:002009-11-13T11:49:01.607-08:00Why I Hate Entity FrameworkA few months ago I took over development of an insurance-related system. It was a Windows Forms application created for a small workgroup. Original design utilized ADO.NET Entity Framework and it was my first serious encounter with the technology. Immediately, I sensed that something wasn't right: application was too slow. There were only a dozen or so tables and hardly any data in them, yet forms took whole seconds to load. Database updates were even more problematic - not only they took long time, but sometimes they failed for no apparent reason.<div><br /></div><div>Initially, I tried to write it all off as part of a learning curve. I recreated entity model and ran a SQL Profiler in an effort to better understand the technology. Profiler results were simply shocking: instead of executing a half-dozen or so SELECT statements in response to user opening a record, Entity Framework generated hundreds of them (trace file was over 1Mb in size).</div><div><br /></div><div>So, I remembered the <a href="http://riyadsthoughts.blogspot.com/2008/01/linq-to-sql-performance.html">little performance test</a> I did for LINQ to SQL about two years ago and decided to expand it to include Entity Framework. New method looks similar to the one used to test LINQ to SQL:</div><!-- code formatted by http://manoli.net/csharpformat/ --><pre class="csharpcode"><span class="kwrd">private</span> TimeSpan RunEntityTest()<br />{<br />var swatch = Stopwatch.StartNew();<br />NorthwindEntities db = <span class="kwrd">new</span> NorthwindEntities(<br />ConfigurationManager.ConnectionStrings[<span class="str">"NorthwindEntities"</span>].ConnectionString);<br /><br /><span class="kwrd">for</span> (<span class="kwrd">int</span> orderId = 10248; orderId < 11078; orderId++)<br />{<br />var query = from o <span class="kwrd">in</span> db.Orders<br /> <span class="kwrd">where</span> o.OrderID == orderId<br /> select <span class="kwrd">new</span><br /> {<br /> o.OrderID,<br /> o.OrderDate,<br /> o.Customers.CustomerID,<br /> o.Customers.CompanyName,<br /> ProdCount = o.Order_Details.Count<br /> };<br /><br /><span class="kwrd">foreach</span> (var item <span class="kwrd">in</span> query)<br />{<br /> <span class="kwrd">string</span> s = item.CompanyName;<br />}<br />}<br /><span class="kwrd">return</span> swatch.Elapsed;<br />}<br /></pre><div>By the way, that original blog post has been criticized by an anonymous guest, who pointed out that my test routines for stored procedures, dynamic SQL and parameterized SQL were not equivalent to LINQ test, because I never read any values from SqlDataReader object after opening it. So, I changed the code in all three methods as follows:</div><!-- code formatted by http://manoli.net/csharpformat/ --><pre class="csharpcode">SqlDataReader dr = cmd.ExecuteReader();<br /><span class="kwrd">while</span> (dr.Read())<br />{<br /><span class="kwrd">string</span> s = Convert.ToString(dr[<span class="str">"CompanyName"</span>]);<br />}<br />dr.Close();<br /></pre><div>I'm glad to say that this change didn't make any difference to test results: LINQ to SQL is still 40 times slower than stored procedures or dynamic SQL. But Entity Framework results were much worse: 2.2 times slower than LINQ to SQL. Here is the full table:</div><div><br /></div><table><tbody><tr><td><b>METHOD</b></td><td><b>AVERAGE TIME, ms</b></td></tr><tr><td>Stored Procedure</td><td style="text-align: right;">110</td></tr><tr><td>Dynamic SQL</td><td style="text-align: right;">115</td></tr><tr><td>Parameterized Dynamic SQL</td><td style="text-align: right;">126</td></tr><tr><td>LINQ to SQL</td><td style="text-align: right;">4,699</td></tr><tr><td>Entity Framework</td><td style="text-align: right;">10,547</td></tr></tbody></table><div><br /></div><div>So, in the end, I rewrote the data layer of the application using LINQ to SQL.</div><div>Updated test harness code is available here: <a href="http://members.cox.net/rmamedov/blog/EntityFrameworkTestHarness.zip">http://members.cox.net/rmamedov/blog/EntityFrameworkTestHarness.zip</a></div>Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-32857418.post-33821321455849241962009-09-26T17:18:00.000-07:002009-11-11T16:22:59.311-08:00Two Strategies For Asynchronous Message Processing<h3>Asynchronous Message Processing</h3>Asynchronous message processing is a common pattern in designing highly available web applications. Essentially, it means that certain tasks are not processed immediately within the scope of a HTTP request. Instead, they are handled asynchronously, by a different application unit, which in Microsoft realm is often (but not always) implemented as a Windows service. This helps streamline the web application and make it appear faster to the end user.<div><br /></div><div>There is a special class of tasks that are suitable for asynchronous message processing, and it is different from typical scheduled jobs (also executed by a separate application service). Usually, they are closely related to user interactions with the main web application, but are too process-expensive or slow to be incorporated into the page processing workflow. Dynamic rendering of a multi-page PDF report is a good example since it falls under both categories. Sometimes, the tasks are not necessarily slow, but they do not produce any information for the user, for example keeping an audit trail of user activity within the system.</div><div><br /></div><div>Regardless of the specific task being "outsourced", web application exchanges information with the processing service using discrete messages. In a typical design, messages flow only one way: from web application to the service (although there are scenarios where two-way dialog is preferable). There are two main strategies for implementing this design, MSMQ and SQL Server Service Broker.</div><div><h3>Technologies</h3></div><div>Although I remember the days when you had to buy 3rd party applications (like IBM MQSeries) if you wanted message queuing functionality, Microsoft has incorporated MSMQ 1.0 into Windows NT back in 1994. Fifteen years later, we are now at version 4, and MSMQ is considered to be a proven messaging platform. Even the advent of Windows Communication Foundation did not make it obsolete, since WCF includes special MSMQ binding. Service Broker is a much more recent addition to Microsoft tools lineup; it debuted with SQL Server 2005 and was updated in SQL Server 2008.</div><div><h3>Message Size And Content Validation</h3></div><div>MSMQ uses special memory-mapped files to store messages, while Service Broker relies on SQL Server database engine for storage. Message size limit is 4Mb and 2048Mb, respectively (Service Broker uses varbinary(max) data type to store messages). When it comes to describing the content of the message, MSMQ offers 18 "Body Type" values, such as integer, double, date, ANSI or Unicode strings, etc. but this information is optional: MSMQ doesn't validate message contents. Service Broker, on another hand, has just 3: empty, XML, and XML with schema, but it does validate the contents and rejects messages that don't conform.</div><div><h3>Queue-Server Affinity</h3></div><div>When developing high-performance MSMQ applications, one important best practice is "send remotely, receive locally" (<a href="http://msdn.microsoft.com/en-us/library/ms811053.aspx">here is a link to the article that explains it</a>). What this means is that the process reading from the queue has to exist on the same machine where the queue is located. This impacts overall system scalability, because it makes adding additional processing servers more difficult.</div><div><br /></div><div>Service Broker doesn't have such limitations, although it does require an instance of SQL Server database engine. In enterprise applications, it is generally a good idea to use a dedicated instance and host all message queues there. Applications that send and receive messages will use this instance as a global hub; they can be physically located on different servers.</div><div><h3>Programmability</h3></div><div>There are a number of ways to develop MSMQ applications: you can use native API, COM, or .NET. Programmers can use literally any language, from VB to C# to C++. Service Broker is less accessible: its main language is Transact-SQL and in order to use it in, say, a .NET application, you will need to write an ADO.NET wrapper. SQL Server programming samples include one such wrapper, Microsoft.SqlServer.Broker.dll, which exposes classes like SsbService and SsbMessage that shield developers from Transact-SQL.</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-42908669772582426462009-08-13T12:52:00.000-07:002010-08-09T10:03:32.015-07:00Book Review: "The Wikipedia Revolution"<a href="http://www.amazon.com/Wikipedia-Revolution-Nobodies-Greatest-Encyclopedia/dp/1401303714/ref=sr_1_1?ie=UTF8&qid=1250193338&sr=8-1">"The Wikipedia Revolution"</a> by Andrew Lih tells the short but enchanting story of Wikipedia: how the project conceived as a fairly regular for-profit web enterprise evolved into something dramatically different. In just a few short years after <a href="http://en.wikipedia.org/wiki/Nupedia">Nupedia</a> creators embraced wiki-wiki-web and opened the site to everyone with a browser, Wikipedia grew to be one of the top 10 most visited sites on the Internet. It has unparalleled reach with its 259 supported languages, and at least 25 of these languages include over 100,000 articles. All of this has been achieved with essentially all-volunteer force from around the world.<div><br /></div><div>There are some aspects of the book I didn't like very much. For example, it looks like the author has applied one of the Wikipedia editing principles: "No original research". All the information in the book is compiled from publicly available sources; there are no new interviews. Numerous biographies of geeks are rather boring, and most of the additional material about Linux, Free Software Foundation, Mozilla, etc. belongs in sidebars, not main text. (I was reading Chris Anderson's <a href="http://www.amazon.com/Free-Future-Radical-Chris-Anderson/dp/1401322905/ref=sr_1_1?ie=UTF8&qid=1250195303&sr=8-1">"Free"</a> at the same time and it is amazing how much of that general material is echoed in both books.)</div><div><br /></div><div>That being said, I am positive you will learn something new from "The Wikipedia Revolution" (unless you are a seasoned wikipedian, of course). Like the intricacies of maintaining three different scripts of the same language (check out <a href="http://kk.wikipedia.org/wiki/%D0%91%D0%B0%D1%81%D1%82%D1%8B_%D0%B1%D0%B5%D1%82">Kazakh Wikipedia</a>), for example. Or what roles in the organization are played by <a href="http://en.wikipedia.org/wiki/Wikipedia:Administrators">administrators</a> and <a href="http://en.wikipedia.org/wiki/Wikipedia:Bots">bots</a>. Or what happened when someone googled the word "jew" and didn't like what he saw.</div><div><br /></div><div>But in my opinion, the most interesting part discusses various controversies surrounding Wikipedia. How does a quality of articles produced by countless anonymous contributors compare with the quality of established encyclopedias, such as <a href="http://corporate.britannica.com/about/">Britannica</a>? How does the open system protect itself from vandalism and libel without becoming a closed system? How many articles is too much? (Does every high school need to have an entry? What about elementary schools?) Last but not least, what happened when it was revealed that a prominent Wikipedia contributor and administrator <a href="http://en.wikipedia.org/wiki/Essjay_controversy">falsely pretended to be a university professor</a>?</div><div><br /></div><div>Enjoy the book!</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-16350494957013225892009-07-14T11:59:00.000-07:002009-07-14T16:13:21.870-07:00Exposing EntLib to COM ClientsAll of us (<span class="Apple-style-span" style="font-size:small;">well, most of us</span>) know and appreciate the benefits of Enterprise Library (EntLib) Application Blocks: they solve common problems, encapsulate best practices, implement design patterns. They are easy to use and not hard to extend. What's even better, they ensure consistency across different applications and development teams.<div><br /></div><div>Sadly, but all this goodness is only available to .NET code.</div><div><br /></div><div>I do not have exact statistics, but anecdotal evidence suggests that even software companies firmly committed to .NET platform still have 25-50% of their codebase in C++, VB 6, or some form of VBScript. The ratio will continue to shift but legacy code is unlikely to disappear anytime soon (after all, mainframes and COBOL are still with us). And of course, all that code needs to be maintained.</div><div><br /></div><div>Programmers are rarely enthusiastic about legacy code maintenance. Part of the reason is that such code is often a reverse of EntLib: it doesn't encapsulate best practices, doesn't use design patterns, is difficult to use. Yet, we cannot afford to rewrite the whole thing and have to be content just patching holes. Therefore, I think many will welcome the possibility to somehow plug in Application Blocks into their legacy code. Parts of EntLib aren't useful in the non-.NET world, of course, but things like logging, caching, and cryptography are perfect integration points. </div><div><br /></div><div>In the remaining part of this post, I will describe how this can be done and will use Logging Application Block as an example.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">COM Facade</span></div><div>There are many different ways to expose EntLib functionality to older applications, but COM Interop is probably the most efficient. The idea is to use a "facade" design pattern: create a .NET class that will be exposed to COM clients via Interop and pass through calls to EntLib.</div><div><br /></div><div>I decided to derive this new facade from <span class="Apple-style-span" style="font-size:small;"><span class="Apple-style-span" style="font-family:'courier new';">System.EnterpriseServices.ServicedComponent</span></span> and host it in a COM+ server application. This way we can take advantage of a couple of very useful services provided by COM+ infrastructure.</div><pre class="csharpcode">[ComVisible(<span class="kwrd">true</span>)]<br />[ClassInterface(ClassInterfaceType.None)]<br /><span class="kwrd">public</span> <span class="kwrd">class</span> EntLibAdapter : ServicedComponent, IEntLibAdapter<br /></pre><div>Interface IEntLibAdapter contains a single method:</div><pre class="csharpcode">[ComVisible(<span class="kwrd">true</span>)]<br />[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]<br /><span class="kwrd">public</span> <span class="kwrd">interface</span> IEntLibAdapter<br />{<br /><span class="kwrd">void</span> WriteLog(<span class="kwrd">ref</span> ILogData log, <span class="kwrd">string</span> category, <span class="kwrd">int</span> priority);<br />}</pre><div>Here, ILogData is a name of another interface that defines multiple properties collected for logging. Our COM clients will invoke WriteLog method of the facade class and Logging Application Block will determine whether to log or not (based on category and priority), and which logging trace listener to use. This, however, requires that Application Block be properly initialized.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Initialization</span></div><div>EntLib application blocks rely on XML configuration which is usually stored in the web.config or exe.config file. In our scenario, entry point is not a .NET application, so we cannot rely on default behavior. Fortunately, EntLib supports multiple configuration sources: for example, it can consume a stand-alone file and read XML configuration from it. Here is how this is achieved for Logging Application block:<br /></div><pre class="csharpcode">FileConfigurationSource configSrc = <span class="kwrd">new</span> FileConfigurationSource(fileName);<br />LogWriterFactory factory = <span class="kwrd">new</span> LogWriterFactory(configSrc);<br /><span class="kwrd">this</span>.LogWriter = factory.Create();</pre><div>Because the facade class is a ServicedComponent, we can take advantage of the COM+ Activation service. When object is created, COM+ will invoke Construct method and pass a string that in our case will contain full path to the configuration file:</div><pre class="csharpcode">[ComVisible(<span class="kwrd">true</span>)]<br />[ClassInterface(ClassInterfaceType.None)]<br />[ConstructionEnabled(<span class="kwrd">true</span>, Default = <span class="str">@"C:\EntLibAdapter.config"</span>)]<br /><span class="kwrd">public</span> <span class="kwrd">class</span> EntLibAdapter : ServicedComponent, IEntLibAdapter<br />{<br /><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Construct(<span class="kwrd">string</span> s)<br />{<br /> <span class="kwrd">if</span> (File.Exists(s))<br /> {<br /> FileConfigurationSource configSrc = <span class="kwrd">new</span> FileConfigurationSource(s);<br /> LogWriterFactory factory = <span class="kwrd">new</span> LogWriterFactory(configSrc);<br /> <span class="kwrd">this</span>.LogWriter = factory.Create();<br /> }<br />}<br />}</pre><div><span class="Apple-style-span" style="font-weight: bold;">Object Pooling</span></div><div>In a typical usage scenario, EntLibAdapter object will be constructed, WriteLog method invoked, and then the object will be destroyed. Notice that the initialization step is fairly expensive - it involves reading a file from disk, parsing XML, building up objects. We can improve performance and increase overall system scalability by maintaining a pool of objects. That way EntLibAdater instances do not get destroyed after client releases the reference - they simply go back to the pool. Object pooling is another built-in service in COM+, so all we need to do is mark our class to participate:</div><pre class="csharpcode">[<br />ComVisible(<span class="kwrd">true</span>),<br />ClassInterface(ClassInterfaceType.None),<br />ConstructionEnabled(<span class="kwrd">true</span>, Default = <span class="str">@"C:\Nexsure\Installation\Dlls\EntLibAdapter.config"</span>),<br />EventTrackingEnabled(<span class="kwrd">true</span>),<br />ObjectPooling(<span class="kwrd">true</span>, MinPoolSize = 5)<br />]<br /><span class="kwrd">public</span> <span class="kwrd">class</span> EntLibAdapter : ServicedComponent, IEntLibAdapter</pre><div>Object pooling may not be the best approach if you plan to use flat file logging. In the example above, there will always be 5 instances in the pool, and each will create its own log file (4 of them will have a GUID-based file name). This should not be a problem if your primary target is database or Windows Event Log.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Deployment</span></div><div><div>Since EntLibAdapter is a ServicedComponent, it has to be strongly named and registered using RegSvcs.exe. In addition, EntLib assemblies that it depends on, such as Microsoft.Practices.EnterpriseLibrary.Logging.dll, need to be placed in the GAC.</div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-914399799669068742009-06-04T09:28:00.000-07:002009-07-14T14:02:48.579-07:00Design For Operations, Part III - MMC IntegrationBack in 2006 I started writing about designing applications with IT department in mind. I'm glad to say that my position didn't change since then - I still believe computer software should be friendly to its end users, which are either customers (mobile, desktop and web apps) or IT engineers (web apps and services). Unfortunately, these two groups are not represented equally in the design process: business analyst is a voice of the customer, but who is a voice of IT?<div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">MMC Background</span></div><div>In my previous posts I covered such aspects as <a href="http://riyadsthoughts.blogspot.com/2006/12/design-for-operations-part-i.html">event logging, performance counters</a>, and <a href="http://riyadsthoughts.blogspot.com/2007/02/design-for-operations-part-ii.html">WMI integration</a>. Today I wanted to discuss Microsoft Management Console (MMC) which was originally developed for Windows NT Option Pack. The idea was to create a common interface for managing IIS, Certificate Server, and Transaction Server, so that administrators have fewer tools to learn. This was further extended in the next release, MMC 2.0 (included with Windows XP/Server 2003), when a concept of the snap-in was added. Snap-in was a COM in-process server that MMC would communicate with, thus allowing any third-party application to have a custom management screen within MMC. In order to develop custom snap-ins, you would need to be well-versed in C++ COM development, as there were 30-something interfaces that could be used. Development of snap-ins in managed code was not supported, although there were custom frameworks, for example, an open-source project called <a href="http://sourceforge.net/projects/mmclibrary/">MMC.NET</a>.</div><div><br /></div><div>MMC 3.0, which was shipped with Vista and Server 2008 (but available for download for older platforms), includes a managed layer and thus natively supports snap-in development in any .NET language. Everyone but hard-core C++ programmers would agree that this can be done faster, with fewer lines of code and simplified maintenance. And even they will have to admit that the ability to use WinForms inside MMC is really cool.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Setting Up Solution</span></div><div>In order to develop our custom MMC snap-in using C# 2008, we will create a class library project. However, before you begin, there is one important step: executing<span class="Apple-style-span" style="font-family:'courier new';"> %WINDIR%\System32\MMCPerf.exe</span> from the command prompt. This will put MMC assemblies in the GAC and NGEN them. After creating new project, add a reference to Microsoft.ManagementConsole.dll by browsing to the following folder: \Program Files\Reference Assemblies\Microsoft\mmc\v3.0\. Unfortunately, the assembly doesn't appear in the .NET tab of the "Add Reference" dialog.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Writing Code</span></div><div>We will start by adding two classes to the project: one derived from Microsoft.ManagementConsole.SnapInInstaller, will be used to register custom snap-in with MMC, and another, derived from Microsoft.ManagementConsole.SnapIn, will serve as an entry point.</div><pre class="csharpcode"><br /><span class="kwrd">using</span> System.ComponentModel;<br /><span class="kwrd">using</span> System.Security.Permissions;<br /><span class="kwrd">using</span> Microsoft.ManagementConsole;<br /><br />[assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Unrestricted = <span class="kwrd">true</span>)]<br /><br /><span class="kwrd">namespace</span> Microsoft.ManagementConsole.Samples<br />{<br />[RunInstaller(<span class="kwrd">true</span>)]<br /><span class="kwrd"> public</span> <span class="kwrd">class</span> InstallUtilSupport : SnapInInstaller<br />{<br />}<br /><br />[SnapInSettings(<span class="str">"{9627F1F3-A6D2-4cf8-90A2-10F85A7A4EE7}"</span>,<br />DisplayName = <span class="str">"- Sample SnapIn"</span>,<br />Vendor = <span class="str">"My Company"</span>,<br />Description = <span class="str">"Shows FormView"</span>)]<br /><span class="kwrd"> public</span> <span class="kwrd">class</span> SelectionFormViewSnapIn : SnapIn<br />{<br />}<br />}</pre><div>Note the attribute that decorates SelectionFormViewSnapIn class. All snap-ins are defined in the Registry, so we have to provide a GUID, and also specify metadata which will be displayed in the catalog. We can leave the body of the installer empty, but SnapIn class requires a constructor.</div><pre class="csharpcode"><br /><span class="kwrd">public</span> SelectionFormViewSnapIn()<br />{<br /> <span class="rem">// Create the root node.</span><br /> <span class="kwrd">this</span>.RootNode = <span class="kwrd">new</span> ScopeNode();<br /> <span class="kwrd">this</span>.RootNode.DisplayName = <span class="str">"Selection (FormView) Sample"</span>;<br /><br /> <span class="rem">// Create a form view for the root node.</span><br /> FormViewDescription fvd = <span class="kwrd">new</span> FormViewDescription();<br /> fvd.DisplayName = <span class="str">"Users (FormView)"</span>;<br /> fvd.ViewType = <span class="kwrd">typeof</span>(FormView);<br /> fvd.ControlType = <span class="kwrd">typeof</span>(SelectionControl);<br /><br /> <span class="rem">// Attach the view to the root node.</span><br /> <span class="kwrd">this</span>.RootNode.ViewDescriptions.Add(fvd);<br /> <span class="kwrd">this</span>.RootNode.ViewDescriptions.DefaultIndex = 0;<br />}<br /></pre><div>In the constructor, we are effectively defining the root node of the snap-in. In this example, we will be using a WinForms user control called SelectionControl. This is a regular UserControl that implements a special interface Microsoft.ManagementConsole.IFormViewControl, which really only has a single method: void Initialize(FormView view). This is where we would put our initialization logic.</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Deployment</span></div><div>After successful build of the solution, we will end up with a single DLL. Deploying it is very straightforward: all you need to do is execute InstallUtil.exe against it. Assuming you didn't skip the first step (running MMCPerf.exe), you should see no errors. Start MMC and choose "Add/Remove Snap-in" from the File menu, then click the "Add" button. You should see your custom snap-in appear in the list.</div><div><br /></div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_J25GU3zvjZY/SihUBog5SLI/AAAAAAAABic/WLm3B-mRTTc/s1600-h/SelectSnapIn.jpg"><img style="cursor:pointer; cursor:hand;width: 309px; height: 320px;" src="http://2.bp.blogspot.com/_J25GU3zvjZY/SihUBog5SLI/AAAAAAAABic/WLm3B-mRTTc/s320/SelectSnapIn.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5343613344907086002" /></a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-32608345261146640772009-03-01T20:40:00.000-08:002009-03-01T20:49:34.449-08:00How To Force Partial PostbackASP.NET UpdatePanel control allows us to program web pages with partial postback. The page still goes through most of its lifecycle stages, but only a portion of HTML is updated in the browser. This is a quick and efficient way to improve user experience by reducing page flicker.<br /><br />Usually, the events that trigger partial postback of an UpdatePanel are defined declaratively in .aspx file. For example, events by child controls are considered triggers by default. If a control is located outside UpdatePanel, it can still be declared a trigger using markup:<br /><pre class="csharpcode"><br /><span class="kwrd"><</span><span class="html">asp:UpdatePanel</span> <span class="attr">ID</span><span class="kwrd">="MyUpdatePanel"</span> <span class="attr">runat</span><span class="kwrd">="Server"</span><span class="kwrd">></span><br /><span class="kwrd"><</span><span class="html">Triggers</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">asp:AsyncPostBackTrigger</span> <span class="attr">ControlID</span><span class="kwrd">="Button1"</span> <span class="kwrd">/></span><br /><span class="kwrd"></</span><span class="html">Triggers</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">asp:UpdatePanel</span><span class="kwrd">></span></pre><br />However, sometimes it is necessary to trigger partial postback programmatically. For example, consider an UpdatePanel that is used together with CollapsiblePanelExtender. We want to force postback when user expands the panel. The logical place to do so is inside the "Expanded" event handler, and the code is very simple:<br /><pre class="csharpcode"><br />function onCollapsiblePanelExpanded(sender, args) {<br />__doPostBack(<span class="str">'<%= MyUpdatePanel.ClientID %>'</span>, <span class="str">''</span>);<br />}</pre><br />If we need specific server-side logic to handle partial postback, ScriptManager control offers two properties: bool IsInAsyncPostBack and string AsyncPostBackSourceElementID. The former indicates whether page is processing a partial postback, and the latter contains ID of the UpdatePanel being processed.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-85477241143532701932009-02-13T14:25:00.001-08:002009-02-17T11:35:44.950-08:00Using Web Client Software Factory With Mobile Web FormsAfter I somewhat successfully <a href="http://riyadsthoughts.blogspot.com/2009/02/mobile-web-forms-in-visual-studio-2008.html">solved the problem</a> Visual Studio 2008 has with mobile web forms, I had to tackle another challenge. The website is built with <a href="http://www.codeplex.com/websf">Web Client Software Factory</a>, a powerful and flexible ASP.NET framework from Microsoft Patterns & Practices team. WCSF, or, more specifically, CWAB (composite web application block) provides dependency injection to the application. Unfortunately, the most recent release of WCSF doesn't include any support for mobile web forms. Of course, this release is almost one year old, and I know that good people of P&P are <a href="http://blogs.msdn.com/blaine/archive/2008/12/03/roadmap-for-wcsf.aspx">planning</a> a new release for 2010, so hopefully this will be addressed, but in the meantime here is the solution I came up with.<div><br /></div><div>WCSF guidance package includes a nice set of recipes that automate creation of web forms, master pages and user controls. The boilerplate code that is autogenerated for code-behind classes defines them as derived from Microsoft.Practices.CompositeWeb.Web.UI.Page class instead of standard System.Web.UI.Page:</div><pre class="csharpcode"><br /><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> MySummaryView : Microsoft.Practices.CompositeWeb.Web.UI.Page, IMySummaryView<br />{<br />}</pre><br /><div>The Page class overrides the OnPreInit method, and that is where dependency injection "magic" happens:</div><pre class="csharpcode"><br /><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPreInit(EventArgs e)<br />{<br /> <span class="kwrd">base</span>.OnPreInit(e);<br /> Microsoft.Practices.CompositeWeb.WebClientApplication.BuildItemWithCurrentContext(<span class="kwrd">this</span>);<br />}</pre><div>We can use similar approach for mobile web forms. Of course, there is no class in WCSF that is derived from System.Web.UI.MobileControls.MobilePage, so we will have to create our own base class in App_Code (or in a shared class library):</div><pre class="csharpcode"><br /><span class="kwrd">namespace</span> Microsoft.Practices.CompositeWeb.Web.UI<br />{<br /> <span class="kwrd">public</span> <span class="kwrd">class</span> MobilePage : System.Web.UI.MobileControls.MobilePage<br /> {<br /> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPreInit(EventArgs e)<br /> {<br /> <span class="kwrd">base</span>.OnPreInit(e);<br /> Microsoft.Practices.CompositeWeb.WebClientApplication.BuildItemWithCurrentContext(<span class="kwrd">this</span>);<br /> }<br /> }<br />}</pre><div>Now, as long as we derive our mobile web form from this class, we can declare a Presenter property and let CWAB inject it at runtime. There is one drawback, though: we still need to manually create the presenter class and view interface, something that the guidance package recipe used to do automatically. Unfortunately, I don't know GAT well enough to create my own recipe for mobile web form, so the workaround I am using is this:</div><div><ol><li>Execute "Add page with presenter" recipe<br /></li><li>Modify .aspx file to register "mobile" tag prefix</li><li>Modify code-behind file to change the base class</li></ol><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-16403393177677390162009-02-06T16:14:00.000-08:002009-02-06T16:45:26.383-08:00Mobile Web Forms in Visual Studio 2008I recently discovered that Visual Studio 2008 dropped support for ASP.NET mobile. You can create ASP.NET websites, of course, but try adding a mobile web form or mobile user control - these item templates are no longer there.<br /><br />Omar Khan wrote a <a href="http://blogs.msdn.com/webdevtools/archive/2007/09/17/tip-trick-asp-net-mobile-development-with-visual-studio-2008.aspx">post</a> for Visual Web Developer Team blog which describes a workaround but doesn't explain why this happened in the first place. One big problem with that workaround is that you can't download it due to a broken link.<div><br /></div><div>I found that one way to solve the problem is to copy mobile item templates from Visual Studio 2005 (assuming you still have it installed) to a special folder where VS 2008 will look for user item templates. Here's the detailed how-to:</div><div><br /></div><div>1) Find item templates in VS 2005 folder:</div><div><br /></div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_J25GU3zvjZY/SYzWGc2FwII/AAAAAAAABQ4/26edmd4H8Pk/s1600-h/Image1.jpg"><img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 205px;" src="http://1.bp.blogspot.com/_J25GU3zvjZY/SYzWGc2FwII/AAAAAAAABQ4/26edmd4H8Pk/s320/Image1.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5299846267818852482" /></a><br /></div><div>2) Find user item templates folder:</div><div><br /></div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_J25GU3zvjZY/SYzWoeKLAVI/AAAAAAAABRA/XR5qDYmKX94/s1600-h/Image2.jpg"><img style="cursor:pointer; cursor:hand;width: 320px; height: 190px;" src="http://3.bp.blogspot.com/_J25GU3zvjZY/SYzWoeKLAVI/AAAAAAAABRA/XR5qDYmKX94/s320/Image2.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5299846852287070546" /></a><br /></div><div><br /></div><div>3) Copy MobileWebForm.zip, MobileWebUserControl.zip, and MobileWebConfig.zip to that folder</div><div><br /></div><div>4) Restart VS 2008. Mobile web items now appear in the "Add New Item" dialog under "My Templates":</div><div><br /></div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_J25GU3zvjZY/SYzXkt-lhQI/AAAAAAAABRI/K4bX-GH7O-o/s1600-h/Image3.jpg"><img style="cursor:pointer; cursor:hand;width: 320px; height: 215px;" src="http://2.bp.blogspot.com/_J25GU3zvjZY/SYzXkt-lhQI/AAAAAAAABRI/K4bX-GH7O-o/s320/Image3.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5299847887325594882" /></a><br /></div><div><br /></div><div>One problem still remains: VS 2008 designer doesn't display mobile forms and controls. This isn't a major issue for me because I hardly ever use the designer.</div><div><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-52997270883009225852009-01-25T16:03:00.000-08:002009-03-17T09:42:27.806-07:00Cloud Storage or SDS?Ever since Ray Ozzie has announced Windows Azure on last year's PDC (<a href="http://channel9.msdn.com/pdc2008/KYN01/">watch the keynote</a>) there's been a lot of buzz about new platform. Every recent Microsoft event, it seems, included a session or two on Azure. <a href="http://www.socalcodecamp.com/">SoCal Code Camp</a> that took place this past weekend at CalState Fullerton had an entire track of cloud-related presentations. <div><br /></div><div>One general observation: details of the new platform are still, well, cloudy. Windows Azure is presently in a <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=80e3eabf-0507-4560-aeb6-d31e9a70a0a6&displaylang=en">CTP</a> stage; nobody expects an RTM until the end of 2009. There are a lot of technology-, process-, and cost-related questions that no one yet knows the answers to. What's worse, marketing geniuses at Microsoft decided to slap Azure label on a set of technologies that originated in different parts of the company (and even Microsoft evangelists admit that there is very little coordination).</div><div><br /></div><div>Take a look at the obligatory Azure platform stack slide:</div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_J25GU3zvjZY/SX0GdOxCLBI/AAAAAAAABQw/NXttI0f5F-E/s1600-h/Azure.gif"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 148px;" src="http://2.bp.blogspot.com/_J25GU3zvjZY/SX0GdOxCLBI/AAAAAAAABQw/NXttI0f5F-E/s400/Azure.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5295395836107303954" /></a><div>My initial assumption about SQL Server Data Services (SDS) was that it is somehow built on top of Azure. Apparently, SDS is a completely separate service. In fact, you don't even need to have an Azure application in order to use it.</div><div><br /></div><div>Let's take a closer look at the data support for cloud applications. This is, in my opinion, the biggest paradigm shift for developers and architects. After all, it's easy to understand the concept of deploying your application code to a whole bunch of virtual servers, but how are we going to survive without our beloved connection strings, stored procedures, triggers?</div><div><br /></div><div>There are two options available to us, cloud storage and SDS. Both are going to be reliable, scalable, highly available, and support terabytes of data. On the back end, both will utilize a vast network of SQL Server nodes that use some advanced algorithms to support distributed data storage and replication. Below is a side-by-side comparison.</div><div><br /></div><div><span class="Apple-style-span" style="font-style: italic;"><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-style: normal;">Signup</span></span>. </span>When you sign up for Azure, you receive a separate storage account. To use SDS you will need to get yet another account.</div><div><br /></div><div><span class="Apple-style-span" style=""><span class="Apple-style-span" style="font-weight: bold;">Hierarchy</span></span></div><div><span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-style-span" style="font-style: italic;">Cloud Storage</span>: Provides account/container/entity model for your data.</div><div><span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-style-span" style="font-style: italic;">SDS</span>: The model is similar - authority/container/entity</div><div><br /></div><div><span class="Apple-style-span" style=""><span class="Apple-style-span" style="font-weight: bold;">Data Abstractions</span></span></div><div><span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-style-span" style="font-style: italic;">Cloud Storage</span>: Supports blobs (basically, named files with metadata) up to 50Gb, tables (which are essentially lists of entities, not database tables), and queues with message size up to 8Kb.</div><div><span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-style-span" style="font-style: italic;">SDS</span>: Only works with entities, which are similar to the tables above.<br /></div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Data Access</span></div><div><span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-style-span" style="font-style: italic;">Cloud Storage</span>: Blobs and queues can be accessed via REST, but tables are also exposed via ADO.NET Data Services. This allows for a more convenient API (for example, you can query a table using LINQ). Large blobs can be uploaded by small 4Mb-sized chunks.</div><div><span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-style-span" style="font-style: italic;">SDS</span>: Entities can be queried using REST. Although there is no ADO.NET Data Services support, you can pass a LINQ-style query in the HTTP request (query may even join entities).<br /></div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">*** UPDATE (March 17, 2009)</span></div><div>Someone at Microsoft have finally noticed the striking similarities between Cloud Storage and SDS. Data Platform Insider blog is <a href="http://blogs.technet.com/dataplatforminsider/archive/2009/03/10/what-s-next-for-sql-data-services.aspx">announcing</a> the change to SDS architecture: REST-based interface will be decommissioned and replaced by a service protocol based on Tabular Data Stream (which has been a SQL Server network protocol since SQL 2000). Public CTP of the new architecture will be available in the middle of this year.</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-32857418.post-54420996723490478442008-11-12T10:20:00.000-08:002008-11-12T10:27:37.310-08:00Analytical Approach To Solving Programming ProblemsIn the six months that passed since I updated this blog I've been working on various web application projects, learning a lot about ASP.Net Ajax and Web Client Software Factory. Nevertheless, this posting isn't about any particular technology. In my opinion, software developers already have way too many technologies, frameworks, programming languages, and APIs available to us. It's a challenge just to keep up with all the new stuff that comes out. What I want to discuss instead are the benefits of the analytical approach to programming problems.<br /><br />Here is a sample problem. Imagine there is a virus spreading through the cells of a very large two-dimensional matrix. We start with a relatively healthy matrix with only 10 random cells infected. The virus is spreading by infecting 4 adjacent cells every minute. For example, if "." represents a healthy cell, this is how the epidemic will progress:<br /><table width="100%"><br /> <tr><br /> <td><br />Start<br /><pre><br />.........<br />.........<br />....0....<br />.........<br />.........<br /></pre><br /> </td><br /> <td><br />After first minute<br /><pre><br />.........<br />....1....<br />...101...<br />....1....<br />.........<br /></pre><br /> </td><br /> <td><br />After second minute<br /><pre><br />.........<br />....2....<br />...212...<br />..21012..<br />...212...<br />....2....<br />.........<br /></pre><br /> </td><br /> </tr><br /></table><br />Of course, the virus starts spreading from 10 different places on the surface, so depending on where these cells are, the time it takes to infect entire matrix can vary. Our task is to find that time given 10 initial locations.<br /><br />It may be tempting to rely on a raw processing power of modern computers and concoct a solution that looks like this:<br /><br />while (!matrix_is_fully_infected)<br />{<br /> infect_next_set_of_cells();<br />}<br /><br />The model above simply recreates the behavior of the virus. The obvious drawback here is the sheer inefficiency of the algorithm: we end up scanning entire matrix an unknown number of times. As matrix size increase, the inefficiency will be more evident. Still, this may be a valid approach in some cases, where there is no easy analytical solution. Fortunately, our virus has a primitive DNA and yields itself to mathematical definition.<br /><br />For simplicity, let's assume that we begin with a single infected cell with coordinates (a,b). The number of minutes it takes to infect an arbitrary cell (x,y) can be expressed with this simple formula: |a-x|+|b-y|. Now let's assume we had a second infected cell at the beginning: (c,d). We could use a similar formula to find out how many minutes it will need to infect our arbitrary cell (x,y): |c-x|+|d-y|.<br /><br />Depending on whether (a,b) or (c,d) is located closer to (x,y), one of the above expressions will produce a smaller number of minutes. This will be the answer to the question "how long it takes to infect a single arbitrary cell". As we go from 2 infected cells to the original 10, we can write the answer as a function of (x,y):<br /><br />min(|a<sub>i</sub> - x| + |b<sub>i</sub> - y|), where 1 <= i <= 10<br /><br />Of course, our job is not done yet - the virus doesn't stop until all cells are infected. What we need to find out is how many minutes it will take to infect the last cell. Evidently, this will be the maximum time across the matrix, so our solution will be to take the maximum of the above function:<br /><br />max( min(|a<sub>i</sub> - x| + |b<sub>i</sub> - y|) ), where x and y vary across matrix dimensions<br /><br />As you can easily see, analytical approach provided significant performance improvement - we now only need to scan the matrix once.Unknownnoreply@blogger.com0