Sunday, March 13, 2011

Source Code Comments Revisited

I 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 the discussion on reddit.com. Since I can't possibly reply to every single comment, here is a summary response.

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.


Some readers took offence on my use of terms like "cohesion", "coupling", and "cyclomatic complexity", 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 if-else 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.

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.

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 "What is the best comment in source code you have ever discovered".


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.

Tuesday, January 11, 2011

Don't Waste Your Time Commenting Source Code

I 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...
Pro: Comments explain what the program does, so the person maintaining the code can understand it easily.
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.
Contra: Automated unit tests explain what the program does just as well, and they never become obsolete.
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 StackOverflow discussion:

/**
 * Always returns true.
 */
public boolean isAvailable() {
    return false;
}

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:

var result = myobject.isAvailable();
Assert.IsTrue(result);
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.
Contra: What makes you think people can write clearly?
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.
Pro: Sometimes you just need to leave a note...
This is the only case that I would concede. Here is an example to illustrate this point:

// 
// 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
// 

Friday, December 17, 2010

Mobile Enterprise Application. Step 3: Registering For Push Notifications

This is a third post in a series. Previous posts:
 - Step 1: General Architecture
 - Step 2: Authentication

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:

  1. 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.
  2. 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.
  3. 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.
Check User Preferences
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.
   1:      public class AppSettings
   2:      {
   3:          private readonly IsolatedStorageSettings _isolatedStore;
   4:   
   5:          public bool CanUsePNS
   6:          {
   7:              get
   8:              {
   9:                  return GetValueOrDefault<bool>(Constants.Settings.CanUsePNSKey, Constants.Settings.CanUsePNSDefault);
  10:              }
  11:              set
  12:              {
  13:                  AddOrUpdateValue(Constants.Settings.CanUsePNSKey, value);
  14:                  Save();
  15:              }
  16:          }
  17:   
  18:          public AppSettings()
  19:          {
  20:              _isolatedStore = IsolatedStorageSettings.ApplicationSettings;
  21:          }
  22:   
  23:          public bool AddOrUpdateValue(string key, Object value)
  24:          {
  25:          }
  26:   
  27:          public TValueType GetValueOrDefault<TValueType>(string key, TValueType defaultValue)
  28:          {
  29:          }
  30:   
  31:          public void Save()
  32:          {
  33:              _isolatedStore.Save();
  34:          }
  35:      }


Register Push Channel.
This needs to be done when application starts and after user confirmed he or she wants to use PNS.
   1:          public void RegisterPushChannel()
   2:          {
   3:              if(!(new AppSettings()).CanUsePNS) return;
   4:   
   5:              _httpChannel = HttpNotificationChannel.Find(Constants.ChannelName);
   6:   
   7:              if (null != _httpChannel)
   8:              {
   9:                  SubscribeToChannelEvents();
  10:                  SubscribeToService();
  11:                  SubscribeToNotifications();
  12:              }
  13:              else
  14:              {
  15:                  _httpChannel = new HttpNotificationChannel(Constants.ChannelName, Constants.Channels.Service);
  16:                  SubscribeToChannelEvents();
  17:                  _httpChannel.Open();
  18:              }
  19:          }


Method SubscribeToChannelEvents simply adds application handlers to process various events raised by the HttpNotificationChannel object.

   1:          private static void SubscribeToChannelEvents()
   2:          {
   3:              // Register to UriUpdated event - occurs when channel successfully opens
   4:              _httpChannel.ChannelUriUpdated += new System.EventHandler<NotificationChannelUriEventArgs>(HttpChannelChannelUriUpdated);
   5:   
   6:              // Subscribe to raw notifications
   7:              _httpChannel.HttpNotificationReceived += new System.EventHandler<HttpNotificationEventArgs>(HttpChannelHttpNotificationReceived);
   8:   
   9:              // General error handling for push channel
  10:              _httpChannel.ErrorOccurred += new System.EventHandler<NotificationChannelErrorEventArgs>(HttpChannelErrorOccurred);
  11:   
  12:              // Subscribe to toast notifications
  13:              _httpChannel.ShellToastNotificationReceived += new System.EventHandler<NotificationEventArgs>(HttpChannelShellToastNotificationReceived);
  14:          }

Method SubscribeToNotifications binds channel notifications to Windows shell:
   1:          private static void SubscribeToNotifications()
   2:          {
   3:              if (!_httpChannel.IsShellToastBound)
   4:              {
   5:                  _httpChannel.BindToShellToast();
   6:              }
   7:              if (!_httpChannel.IsShellTileBound)
   8:              {
   9:                  _httpChannel.BindToShellTile();
  10:              }
  11:          }

Associate User and Channel URI
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.

Wednesday, November 17, 2010

Mobile Enterprise Application. Step 2: Authentication

This is a second post in the series. Previous post:
 - Step 1: General Architecture

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:

    <Tasks>
      <DefaultTask Name ="_default"
            NavigationPage="/Views/LoginPage.xaml"/>
    <Tasks>

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.

Push Notifications Opt-In
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:
   NavigationService.Navigate(
      IsolatedStorageSettings.ApplicationSettings.Contains(Constants.Settings.CanUsePNS)
         ? new Uri(Constants.Urls.LandingPage, UriKind.Relative)
: new Uri(Constants.Urls.PNSOptInPage, UriKind.Relative));


Session Management
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:

  1. Client ask user for a preferred session duration (not to exceed a predefined system limit) before login
  2. Client successfully authenticates, and server returns a unique session token (a GUID, for instance)
  3. Client keeps session state in the isolated storage
  4. Every time the application is activated, it checks if session length has exceeded timeout
  5. 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.
Restoring Session State On Activation
When application is running, session state is stored in a public static property of the App class (App.xaml.cs), for example:
   public static UserLogin CurrentUser { get; set; }
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:

   1:  private void Application_Activated(object sender, ActivatedEventArgs e)
   2:  {
   3:      if (AppController.CurrentUser == null)
   4:      {
   5:          using (var store = IsolatedStorageFile.GetUserStoreForApplication())
   6:          {
   7:              if (store.FileExists(Constants.Files.UserLogin))
   8:              {
   9:                  using (var file = new IsolatedStorageFileStream(Constants.Files.UserLogin, FileMode.Open, store))
  10:                  {
  11:                      var serializer = new DataContractSerializer(typeof(UserLogin));
  12:                      AppController.CurrentUser = (UserLogin)serializer.ReadObject(file);
  13:                  }
  14:              }
  15:          }
  16:      }
  17:  }

(to be continued)

Wednesday, November 10, 2010

Mobile Enterprise Application. Step 1: General Architecture

I decided to follow up on my previous post 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.

Choosing Client Technology
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.

Relative Merits of MVVM
Model-View-ViewModel design pattern has a widespread adoption in the XAML world, including Silverlight. The question isn't whether or not MVVM can be used in WinPhone 7 applications (it can) but whether or not it should 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.

Unit Testing
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.

Sharing Projects With Designer
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.

Choosing Server Technology
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.

SOAP or REST?
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.

Secure Communication
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 here). It is therefore essential to encrypt all messages, not just those related to authentication. Using SSL protocol for communication is a good start.

(to be continued)

Thursday, October 21, 2010

Mobile Clients of Business Applications

As 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?

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.

Challenge 1. Define a Reasonable Subset of Functionality
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.

Challenge 2. Mobile-Specific Features
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.

Challenge 3. Choose Appropriate Architecture
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.

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.

Challenge 4. Security and Session Management
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.

Monday, August 09, 2010

Should 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?

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.

Professionalism
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, anyone 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.

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 proper training.

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.

Quality Control
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.

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.

Security
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, Richard Clarke's "Cyber War":
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.
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.

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.

Monday, August 02, 2010

VB or C#? A Personal Journey

Last 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...

Well, there were a couple of people who found genuine gaps (like XML literals in VB or yield keyword in C#). There were a couple of trolls, and a couple of people just having a good laugh ("I prefer C# over VB because I am an American!"). But the majority of comments were pure opinion. "Code is cleaner", "more readable", "I hate semicolons", "I love curly braces", "too verbose", "closest to plain English" 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.

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.

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 - Beginner's All-purpose Symbolic Instruction Code - 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.

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...

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.

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.

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, Prolog, to .NET framework...

Thursday, May 20, 2010

Dynamic Connection Strings With SSRS Data Processing Extension

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 USSR. Oh, well, I'll just call it Kevin). Anyway, this post wasn't supposed to be a rant, so let's move on.

SSRS supports ten data sources out of the box, including SQL Server (duh!), ODBC, OLE DB, and Oracle. Data Processing Extensions 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 MSDN and there is also a good article on The Code Project.

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.

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):

   1:  using Microsoft.ReportingServices.DataExtensions;
   2:  using Microsoft.ReportingServices.DataProcessing;
   3:   
   4:  public class MySqlConnection : IDbConnectionExtension
   5:  {
   6:      private SqlConnectionWrapper _Connection;
   7:   
   8:      public MySqlConnection()
   9:      {
  10:          _Connection = new SqlConnectionWrapper();
  11:      }
  12:  }
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:
   1:      public string Password
   2:      {
   3:          set { _Connection.Password = value; }
   4:      }
   5:   
   6:      public string UserName
   7:      {
   8:          set { _Connection.UserName = value; }
   9:      }
Of course, you still need to add the implementation.

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).
   1:      public string LocalizedName
   2:      {
   3:          get { return "Dynamic SQL Server Connection"; }
   4:      }
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:
   1:      public string ConnectionString
   2:      {
   3:          get
   4:          {
   5:              return _Connection.ConnectionString;
   6:          }
   7:          set
   8:          {
   9:              _Connection.ConnectionString = MyDataLayer.GenerateConnectionString();
  10:          }
  11:      }
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):
   1:      public string ConnectionString
   2:      {
   3:          set
   4:          {
   5:              Match m = Regex.Match(value, "CustomerID=([^;]+)", RegexOptions.IgnoreCase);
   6:              int custId = 0;
   7:              if (m.Success
   8:                 && int.TryParse(m.Groups[1].Captures[0].Value, out custId))
   9:              {
  10:                  _Connection.ConnectionString = MyDataLayer.GenerateConnectionString(custId);
  11:              }
  12:              else
  13:              {
  14:                  throw new ArgumentException("Valid CustomerID is missing");
  15:              }
  16:          }
  17:      }
Now the only thing left to do is deploy assembly containing MySqlConnection to both server and developer workstation.

*** UPDATED 11/22/2011 ****

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.

Tuesday, May 18, 2010

San Diego .NET User Group Presentation

Thanks 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.

Sunday, May 02, 2010

Code Generation For Auto-Implemented Properties

I 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.

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:


var myType = new CodeTypeDeclaration("Person");
 

var field = new CodeMemberField()
{
    Name = "_LastName",
    Type = new CodeTypeReference("System.String"),
    Attributes = MemberAttributes.Private
};
myType.Members.Add(field);
 
var prop = new CodeMemberProperty()
{
    Name = "LastName",
    Type = new CodeTypeReference("System.String"),
    Attributes = MemberAttributes.Public
};
prop.GetStatements.Add(
    new CodeMethodReturnStatement(
        new CodeFieldReferenceExpression(
            new CodeThisReferenceExpression(), "_LastName")));
prop.SetStatements.Add(
    new CodeAssignStatement(
        new CodeFieldReferenceExpression(
            new CodeThisReferenceExpression(), "_LastName"), 
        new CodePropertySetValueReferenceExpression()));
myType.Members.Add(prop);

And here is the code that was generated by the above fragment:


private string _LastName;
public string LastName
{
    get { return _LastName; }
    set { _LastName = value; }
}

Of course, C# 3.0 has introduced a much shorted way of declaring the same property: "public string LastName { get; set; }". 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.

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:


var snippet = new CodeSnippetTypeMember("public string LastName { get; set; }");
myType.Members.Add(snippet);

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.

Monday, March 29, 2010

Passing Parameters To ClickOnce Applications

I 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.

Use Query String

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 .application file, e.g.: http://www.mywebsite.com/foobar/foobar.application. When user clicks the link, Foobar will launch (actually, the same link will install Foobar on user machine). In this scenario, parameters can be passed to the application by adding query string to the URL: http://www.mysite.com/foobar/foobar.application?param1=value1&param2=value2&... . Here's how to do it:

Step 1: Enable URL parameters in ClickOnce application

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.



Step 2: Add code to process parameters

In regular Windows applications written in C#, it is enough to declare static void Main(string[] args) 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 AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData property.


[STAThread]

static void Main()

{

    Application.EnableVisualStyles();

    Application.SetCompatibleTextRenderingDefault(false);

 

    var args = AppDomain.CurrentDomain.SetupInformation.ActivationArguments;

    var frm = new MainForm();

    if (args != null

    && args.ActivationData != null

    && args.ActivationData.Length > 0)

    {

        var url = new Uri(args.ActivationData[0], UriKind.Absolute);

        var parameters = HttpUtility.ParseQueryString(url.Query);

        // Process parameters here

    }

 

    Application.Run(frm);

}



Add File Type Association

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.



Processing logic is very similar to the first scenario - we still need to analyzeAppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationDataproperty. The only difference is that instead of calling HttpUtility.ParseQueryString, we need to extract file name from it.

Saturday, March 13, 2010

Continuous Integration + Continuous Improvement

Long time ago, in the early days of software development, one person could program entire application. Gary Kildall wrote the CP/M operating system, and Wayne Ratliff wrote dBASE, 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 Brooks's law about adding man-power to a late project).

Once you have several people working on the same codebase, integrating their changes can become a challenge. (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.) 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.

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.

A few months ago I installed one such application, open-source product called Cruise Control .NET 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.

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 "Kaizen" 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.

I think we can successfully apply Kaizen ideas to software development. Most straightforward approach in my opinion is encouraging programmers to do three things:
  • Refactor code to design patterns,
  • Increase unit test code coverage,
  • Fix all bugs (not just those reported by users).
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.

Saturday, January 30, 2010

Introducing Web Client Software Factory

Earlier today I gave a talk on Socal Code Camp 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.


Friday, November 13, 2009

Why I Hate Entity Framework

A 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.

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).

So, I remembered the little performance test 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:
private TimeSpan RunEntityTest()
{
var swatch = Stopwatch.StartNew();
NorthwindEntities db = new NorthwindEntities(
ConfigurationManager.ConnectionStrings["NorthwindEntities"].ConnectionString);

for (int orderId = 10248; orderId < 11078; orderId++)
{
var query = from o in db.Orders
where o.OrderID == orderId
select new
{
o.OrderID,
o.OrderDate,
o.Customers.CustomerID,
o.Customers.CompanyName,
ProdCount = o.Order_Details.Count
};

foreach (var item in query)
{
string s = item.CompanyName;
}
}
return swatch.Elapsed;
}
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:
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
string s = Convert.ToString(dr["CompanyName"]);
}
dr.Close();
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:

METHODAVERAGE TIME, ms
Stored Procedure110
Dynamic SQL115
Parameterized Dynamic SQL126
LINQ to SQL4,699
Entity Framework10,547

So, in the end, I rewrote the data layer of the application using LINQ to SQL.
Updated test harness code is available here: http://members.cox.net/rmamedov/blog/EntityFrameworkTestHarness.zip

Saturday, September 26, 2009

Two Strategies For Asynchronous Message Processing

Asynchronous Message Processing

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.

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.

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.

Technologies

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.

Message Size And Content Validation

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.

Queue-Server Affinity

When developing high-performance MSMQ applications, one important best practice is "send remotely, receive locally" (here is a link to the article that explains it). 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.

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.

Programmability

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.

Thursday, August 13, 2009

Book Review: "The Wikipedia Revolution"

"The Wikipedia Revolution" 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 Nupedia 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.

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 "Free" at the same time and it is amazing how much of that general material is echoed in both books.)

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 Kazakh Wikipedia), for example. Or what roles in the organization are played by administrators and bots. Or what happened when someone googled the word "jew" and didn't like what he saw.

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 Britannica? 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 falsely pretended to be a university professor?

Enjoy the book!

Tuesday, July 14, 2009

Exposing EntLib to COM Clients

All of us (well, most of us) 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.

Sadly, but all this goodness is only available to .NET code.

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.

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. 

In the remaining part of this post, I will describe how this can be done and will use Logging Application Block as an example.

COM Facade
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.

I decided to derive this new facade from System.EnterpriseServices.ServicedComponent 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.
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class EntLibAdapter : ServicedComponent, IEntLibAdapter
Interface IEntLibAdapter contains a single method:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IEntLibAdapter
{
void WriteLog(ref ILogData log, string category, int priority);
}
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.

Initialization
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:
FileConfigurationSource configSrc = new FileConfigurationSource(fileName);
LogWriterFactory factory = new LogWriterFactory(configSrc);
this.LogWriter = factory.Create();
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:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ConstructionEnabled(true, Default = @"C:\EntLibAdapter.config")]
public class EntLibAdapter : ServicedComponent, IEntLibAdapter
{
protected override void Construct(string s)
{
if (File.Exists(s))
{
FileConfigurationSource configSrc = new FileConfigurationSource(s);
LogWriterFactory factory = new LogWriterFactory(configSrc);
this.LogWriter = factory.Create();
}
}
}
Object Pooling
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:
[
ComVisible(true),
ClassInterface(ClassInterfaceType.None),
ConstructionEnabled(true, Default = @"C:\Nexsure\Installation\Dlls\EntLibAdapter.config"),
EventTrackingEnabled(true),
ObjectPooling(true, MinPoolSize = 5)
]
public class EntLibAdapter : ServicedComponent, IEntLibAdapter
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.

Deployment
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.

Thursday, June 04, 2009

Design For Operations, Part III - MMC Integration

Back 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?

MMC Background
In my previous posts I covered such aspects as event logging, performance counters, and WMI integration. 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 MMC.NET.

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.

Setting Up Solution
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 %WINDIR%\System32\MMCPerf.exe 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.

Writing Code
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.

using System.ComponentModel;
using System.Security.Permissions;
using Microsoft.ManagementConsole;

[assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Unrestricted = true)]

namespace Microsoft.ManagementConsole.Samples
{
[RunInstaller(true)]
public class InstallUtilSupport : SnapInInstaller
{
}

[SnapInSettings("{9627F1F3-A6D2-4cf8-90A2-10F85A7A4EE7}",
DisplayName = "- Sample SnapIn",
Vendor = "My Company",
Description = "Shows FormView")]
public class SelectionFormViewSnapIn : SnapIn
{
}
}
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.

public SelectionFormViewSnapIn()
{
// Create the root node.
this.RootNode = new ScopeNode();
this.RootNode.DisplayName = "Selection (FormView) Sample";

// Create a form view for the root node.
FormViewDescription fvd = new FormViewDescription();
fvd.DisplayName = "Users (FormView)";
fvd.ViewType = typeof(FormView);
fvd.ControlType = typeof(SelectionControl);

// Attach the view to the root node.
this.RootNode.ViewDescriptions.Add(fvd);
this.RootNode.ViewDescriptions.DefaultIndex = 0;
}
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.

Deployment
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.