Skip to main content

Blog

Go Search
Home
  

Categories
Work
Personal
Other
Other Blogs
There are no items in this list.
Blog of Adrian Anttila, containing my thoughts, comments and questions.
Integrating the Silverlight SDK into Visual Studio’s MSDN Library

If you use local MSDN rather than the internet-based version like I do and you are doing Silverlight work, here's how to integrate Silverlight's SDK into Visual Studio's local help.

  1. Open the Microsoft Visual Studio 2008 Documentation start menu item


  2. Go to the Index tab, and type in "combined help", which should navigate you to the combined Help collection [Visual Studio]entry, and press enter


  3. Open the help topic opens, click on the last link named Visual Studio Combined Help Collection Manager


  4. At this point, you should see a list similar to what you see below. Pick the SDKs you'd like to integrate, then press the Update VSCC button.

Once you press the Update VSCC button, you'll be prompted to close the documentation and Visual Studio. The next time you open the documentation, it will spends several minutes integrating the SDK. Once the integration is complete, when you navigate to a class common to .NET and Silverlight, you'll be able to select which SDK you want to navigate to:

For Silverlight, you'll want to select the dv_silverltmref location.

Good luck!

Vista Explorer Search Tips

Quite by accident, I discovered some advanced search options using the built-in search box in Windows Explorer. It's the little box in the top right-hand corner of your Explorer windows:

If you search for something but name but can't find it, you get the option of using Advance Search:

Clicking the Advanced Search link shows quite a few search options that are hidden by default.

What I've managed to find today, quite by accident, is that you can specify most of that information from within the search box itself! You just need to qualify the data your searching for with the right keyword. Here are a few examples:

  • type: C#
  • modified: > 4/28/2008
  • created: >= 4/29/2008

Pretty cool, huh?

TimeZoneInfo : Another reason to love .NET 3.5

One of the new classes in .NET 3.5 is TimeZoneInfo. MSDN's vague and all-encompassing description states "Represents any time zone in the world." Scrolling further down, you'll find a list of actual things that TimeZoneInfo can do:

  • Retrieving a time zone that is already defined by the operating system.
  • Enumerating the time zones that are available on a system.
  • Converting times between different time zones.
  • Creating a new time zone that is not already defined by the operating system.
  • Serializing a time zone for later retrieval.

Personally, I'm using TimeZoneInfo for all of my DateTime conversions to support different time zones. Performing the conversion is as easy as calling ConvertTimeBySystemTimeZoneId. Here are a few examples:

DateTime pstDateTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(utcDateTime, TimeZoneInfo.Utc.Id, "Pacific Standard Time");

DateTime utcDateTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(pstDateTime, "Pacific Standard Time", TimeZoneInfo.Utc.Id);

TimeZoneInfo supports daylight savings time (DST), and makes supporting time zones much easier than rolling your own solution.

Excel and CSV Reference

I've been doing a lot of work with CSV and Excel imports recently. There are a lot of poorly documented or disparate pieces of information that are required to interface with a CSV or Excel data source, so I'm recording it here.

Formatting Overview

There are a few formatting rules that you need to consider when working with CSV files.

  • Double-quotes are escaped with two double-quotes: " becomes ""
  • Fields with reserved characters are escaped with double-quotes; this includes carriage-return and new-line characters

Using a StreamReader is probably a no-no

For simple files, using a StreamReader will work fine. However, if you have any fields that contain carriage-returns or line-feeds, ReadLine() won't get you the full set of data for a single record. I suppose that you could try and read subsequent lines until you read the expected number of fields, but that brings up the next problem: commas. Fields can contain commas, so calling Split() with a comma as the parameter can produce unexpected results.

As an aside, a StreamReader won't work for native Excel files, so you would be stuck with a hybrid approach. So what do you do? Use OLE DB.

System.Data.OleDb to the rescue

There are OLE DB providers for CSV, Excel 97-2003, and Excel 2007. The CSV and Excel 97-2003 drivers seem to be available with either Windows, the Microsoft Data Access Components, or the .NET Framework. The Excel 2007 drivers are part of the 2007 Office System Driver: Data Connectivity Components, a separate download.

Each file format requires a slightly different connection string, as shown below.

CSV

Provider=Microsoft.Jet.OLEDB.4.0;
Data Source={0};
Extended Properties="text;HDR=Yes;FMT=Delimited;";

Excel 97-2003

Provider=Microsoft.Jet.OLEDB.4.0;
Data Source={0};
Extended Properties="Excel 8.0;HDR=Yes;IMEX=1;";

Excel 2007

Provider=Microsoft.ACE.OLEDB.12.0;
Data Source={0};
Extended Properties="Excel 12.0;HDR=Yes;IMEX=1;";

Note: The data source for CSV is the directory where the file can be found, not the full path to the file.

HDR=Yes is required if the first line/row in the file has column names, aka, header row. I recommend that you use header rows whenever possible so you're not depending on the column ordering.

IMEX=1 indicates that columns may have mixed data. This is important in situations where a column may contain both text and numerical data. Without IMEX=1, mixed columns default to decimal, and string values are read as null values. By default, the OLE DB provider only reads the first 8 rows to determine a column's data type when IMEX=1 was specified. To increase the number of rows examined, change the TypeGuessRows value in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Excel and HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\12.0\Access Connectivity Engine\Engines\Excel sections in your registry. Changing the value to 0 will force all columns to be read before the column type will be determined.

The easiest way to determine which connection string to use is to initialize a new System.IO.FileInfo instance with the name of the file you're working with, and use its Extension property.

Querying for data

With CSV, you query against files, not tables. With Excel (any version), you query against sheets, not tables. However, either format works with SQL queries.

The easiest way to translate the file or sheet name into a table name is to use call OleDbConnection.GetOleDbSchemaTable. GetOleDbSchemaTable returns a DataTable with schema information for the OLEDB data source.

DataTable schemaDataTable = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
foreach (DataRow dataRow in schemaDataTable.Rows)
{
    string tableName = (string) dataRow["TABLE_NAME"];
    // Do something important here
}

The other important thing to consider is that the names of columns, files, and sheets can contain spaces. When you build your queries, it's a good idea to escape everything with brackets.

    string commandText = String.Format("SELECT [First Name], [Last Name], [E-Mail Address] FROM [{0}]", tableName);

Example

If a header row is present, you can call GetOrdinal to determine the index of a column by its name. Here is a helper method, GetDataReaderString, to read the column value as a string.

private string GetDataReaderString(IDataReader dataReader, int ordinal)
{
    if (dataReader.IsDBNull(ordinal))
    {
        return null;
    }
    else
    {
        return dataReader.GetValue(ordinal).ToString();
    }
}

Here's an example that reads a file with a header row.

using (OleDbConnection connection = new OleDbConnection(connectionString))
{
    connection.Open();
    
    DataTable schemaDataTable = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
    foreach (DataRow dataRow in schemaDataTable.Rows)
    {
        string tableName = (string) dataRow["TABLE_NAME"];

        if ((extension == ".csv" && tableName.Contains("YourFileNameWithoutExtension")) || extension == ".xls" || extension == ".xlsx")
        {
            // Build the command text
            string commandText = String.Format("SELECT [First Name], [Last Name], [E-Mail Address] FROM [{0}]", tableName);

            // Issue the command and process the results
            using (OleDbCommand command = new OleDbCommand(commandText, connection))
            {
                using (OleDbDataReader dataReader = command.ExecuteReader())
                {
                    int firstNameOrdinal = dataReader.GetOrdinal("First Name");
                    int lastNameOrdinal = dataReader.GetOrdinal("Last Name");
                    int emailOrdinal = dataReader.GetOrdinal("E-Mail Address");

                    while (dataReader.Read())
                    {
                        string firstName = GetDataReaderString(dataReader, firstNameOrdinal);
                        string lastName = GetDataReaderString(dataReader, lastNameOrdinal);
                        string email = GetDataReaderString(dataReader, emailOrdinal);

                        // Do something important here
                    }
                }
            }

            // Only process the first sheet of an Excel 97-2003 or Excel 2007 file; or, only process the CSV that was uploaded by the member
            break;
        }
    }
}

Hope this helps!

.NET Runtime Optimization error on SQL Server 2005

If you're getting an error similar to the following in your Event Log, I've found a solution that may work for you.

NET Runtime Optimization Service (clr_optimization_v2.0.50727_32) - Failed to compile: Microsoft.ReportingServices.QueryDesigners, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91.

In my case, re-installing SQL Server 2005 SP2 didn't work. Neither did rebooting. The only thing that seemed to correct the problem was to install the Microsoft Report Viewer Redistributable 2005. I'm not really sure why that would be required on a server, but things don't always make sense.

Customizing a Windows Service during installation

Recently, I needed to add the ability install multiple instances of a Windows Service we've been developing on a single server. After some initial research (read:Google), I was able to get it working. The basic steps are as follows:

  1. Override Installer.Install
  2. Read the InstallContext for specified parameters
  3. Update your service installer with any parameters you found
  4. Call base.Install

Note: If you modify the ServiceInstaller.ServiceName property during Install, you will need to also modify it during Uninstall.

Here's some simple code to illustrate how to support customizations during installation.

using System;
using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace MyApplication.WindowsServices

    [RunInstaller(true)] 
    public partial class MyServiceInstaller : Installer 
    { 
        private ServiceProcessInstaller processInstaller; 
        private ServiceInstaller serviceInstaller;         

        public MyServiceInstaller() 
        { 
            InitializeComponent();             

            processInstaller = new ServiceProcessInstaller(); 
            processInstaller.Account = ServiceAccount.User; 
            Installers.Add(processInstaller);             

            serviceInstaller = new ServiceInstaller(); 
            serviceInstaller.Description = "Provides functionality for doing something special."
            serviceInstaller.ServiceName = "My Services (Default)"
            serviceInstaller.StartType = ServiceStartMode.Automatic; 
            Installers.Add(serviceInstaller); 
        }

        public override void Install(System.Collections.IDictionary stateSaver) 
        { 
            if (Context.Parameters.ContainsKey("InstanceName")) 
            { 
                string instanceName = Context.Parameters["InstanceName"]; 
                serviceInstaller.ServiceName = String.Format("My Services ({0})", instanceName); 
            }             

            base.Install(stateSaver); 
        }

        public override void Uninstall(System.Collections.IDictionary savedState) 
        { 
            if (Context.Parameters.ContainsKey("InstanceName")) 
            { 
                string instanceName = Context.Parameters["InstanceName"]; 
                serviceInstaller.ServiceName = String.Format("My Services ({0})", instanceName); 
            }

            base.Uninstall(savedState); 
        } 
    }
}

Notice that if nothing is specified when invoking InstallUtil.exe, the installer won't fail. To actually install, type the following command in the directory where your service executable is located:

    InstallUtil /InstanceName=Production MyService.exe

To uninstall, make sure you specify the InstanceName parameter, or it won't find anything to uninstall.

    InstallUtil /u /InstanceName=Production MyService.exe

Pretty easy, huh?

Coming up for air

I've been pretty heads down for the last month or so, working on an application that fills a very interesting niche. Even though the project isn't done, there are a few things that I've been able to come away with.

LINQ is a huge productivity boost
LINQ has saved quite a bit of development time over the last few weeks. Between the quick code generation (I used SqlMetal.exe to create the initial model, which I've modified since then) and compile time checking, I've really been able to cut down on the number of data-access errors that I always encounter during development. Having my queries defined right where I use them has made refactoring a breeze. Additionally, by calling DataContext.SubmitChanges() once all my modifications are complete, I get free transactional support.

Once I get a little more time and figure out an example data model to use, I'm planning on blogging about some of the neat things I've been able to do that you don't get to see in a typical keynote. Most of the examples and demos I've seen only really show how to perform simple reads—I'd like to take things a step further and show more complicated operations like grouping, inserts, updates, and deletes.

SCRUM is fantastic for managing projects
In the past, I've been on projects that either used SCRUM incorrectly (read: only parts of SCRUM were used) or used SCRUM to internally manage work that was externally managed using a waterfall based approach. Having "loosed the chains" has really opened my eyes as to how SCRUM serves the development team AND the client. The ability to keep the work in sprints down to a manageable level, providing working code every few weeks, and adjusting priorities over the lifetime of a project have been very helpful. Another big bonus is being able to see the short-term progress in addition to the long-term progress. It's great motivation to see the backlog get shorter every sprint, and to see the spring burn-down moving along every day; it's also nice to be able to share that information with our clients, their confidence in us to increase continually.

Working at Vertigo is liberating
I've worked at handful of companies over the years that have really stifled my creativity, usually through process or the slow adoption of technology. It's so much fun to work at a place where you can build an application using the newest tools and modern methodologies. I've been at Vertigo for almost 2 years now, and it's been a great ride so far. Wanna join me?

DataContext and Properties?  NO!

I was experimenting with the preview release of the new MVC framework yesterday. I was also using LINQ to perform my data access, and had some trouble when attempting to assign an anonymous type to the ViewData in the controller. As it turns out, you can assign anonymous types to ViewData, but you have to use reflection to access the properties, which stinks. Anyway, the error I kept getting was:

Value cannot be null.
Parameter name: source

Petar came over, and we were able to determine that the problem was with my DataContext class. Here's the definition, which I was using to access a local AdventureWorks database.

    public class AdventureWorks : DataContext 
    { 
        public AdventureWorks(string connectionString) 
            : base(connectionString) 
        { 
        }

        public Table<Contact> Contacts { get; set;} 
    }

What's weird was just changing the signature of the Contacts property to a public field worked!

    public Table<Contact> Contacts;

I opened Reflector and started digging around, only to find that the private method InitTables on the DataContext class only accesses fields, not properties. Best practices always state that fields should be exposed as properties, and at this point, it's just second nature to me to create a property instead of a public field. However, this "requirement" violates that recommendation, and I can't think of a reason why. Petar did suggest that there are hooks that can provide enough information about commands issued against a table, but it still seems a little weird.

Alerting

Introduction

I'd like to introduce you to a new approach (pattern?) to widget communication within a dashboard style application. The basic idea is that a variable number of widgets are bound to a backend data source; each widget should be independent from the other widgets, but there needs to be a way for one widget to notify other widgets when something has changed.

Each widget is implemented as a web user control (ascx) whose contents are wrapped in an UpdatePanel for AJAX support. Since each user control is created dynamically, using delegates and events becomes difficult since event registration is not persisted in ViewState between post backs. That means that each event and its handler(s) would have to be re-wired on each user request. Additionally, the hosting page would have to have advanced knowledge of each control and what events it exposes, which leads to a tightly-coupled design. What we'd like is an approach where the widgets don't know about each other, where the widget container doesn't know about what the widgets can do, but where it's possible for widgets to send messages to each other.

Instead of using events, a different approach could be used involving interfaces to implement a dynamic publisher-subscriber alternative to events; I'll use the term "Alert" instead of "Event" to describe the messages that are passed. Alerts differ from events in that rather than registering for event notifications before the event occurs, the publishing component looks through the entire audience of possible subscribers and identifies the interested ones and calls them directly. The thought here is that classes can implement specific interfaces to identify their desire and capability to receive certain alerts. As long as there is a means to traverse the relevant objects in some sort of hierarchy, we can inspect each object to see if it should be alerted. All of this is a little abstract, so let's take a look at some code to see how this could work.

Implementation

The first thing that will be required is to create a new class that represents the arguments for an alert.

using System;

namespace Vertigo.AlertingExample

    public class AlertArgs 
    { 
        public static readonly AlertArgs Empty;         

        public AlertArgs() 
        { 
        }

        static AlertArgs() 
        { 
            Empty = new AlertArgs(); 
        } 
    }
}

Next, the interface used to identify a class as being interested in a particular type of alert is required. Implementing this interface is analogous to creating an event handler in a class. With generics, we can create a special interface that is extensible and will allow for custom typing to uniquely identify each variation of alert.

using System;

namespace Vertigo.AlertingExample

    public interface IAlertable<T> where T : AlertArgs 
    { 
        void Alert(object sender, T args); 
    }
}

Different subclasses of the AlertArgs class can now be defined and used in conjunction with the IAlertable<T> interface to uniquely identify subscribers based on the alerts they are interested in.

Now that we have a way to define subscribers, we need a way to create and send alerts. Since IAlertable<T> is based on subclasses of the AlertArgs class, we'll just create a class that inherits from AlertArgs. To keep the usage simple, our base alerting AlertArgs class will also provide methods to send alerts.

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Vertigo.AlertingExample

    public class BroadcastingAlertArgs<T> : AlertArgs where T : AlertArgs 
    { 
        public virtual void Broadcast(object sender, Page page) 
        { 
            Broadcast(sender, page.Controls); 
        }

        public virtual void Broadcast(object sender, Control control) 
        { 
            Broadcast(sender, control.Controls); 
        }

        protected virtual void Broadcast(object sender, ControlCollection controls) 
        { 
            foreach (Control control in controls) 
            { 
                IAlertable<T> alertableControl = control as IAlertable<T>; 
                if (alertableControl != null && alertableControl != sender) 
                { 
                    alertableControl.Alert(sender, this as T); 
                }

                Broadcast(sender, control.Controls); 
            } 
        } 
    }
}

Since the alerting is occurring between user controls, we can use recursion to "walk the tree" of a control or page's control hierarchy, as seen in the Broadcast method. The concrete implementation of the Broadcast method iterates over each of the control's child controls, looking for any matches on the IAlertable<T> interface. If a match is found, its Alert method is called, passing in both the sender as well as the AlertArgs instance cast to the appropriate type. In other words, find any matching alert receivers and alert them.

Note that the class inherits from AlertArgs and has its type parameter T restricted to AlertArgs.

Example

Now that the plumbing is in place, here's an example implementation.

using System;

namespace Vertigo.AlertingExample

    [Serializable
    public class ExampleAlertArgs : BroadcastingAlertArgs<ExampleAlertArgs
    { 
        protected string message;

        public ExampleAlertArgs(string message) 
        { 
            this.message = message; 
        }

        public virtual string Message 
        { 
            get { return message; } 
        } 
    }
}

The ExapmleAlertArgs class inherits from BroadcastingAlertArgs<T> (and restricts its type parameter to ExampleAlertArgs) to provide specific alerting.

Note that the signature for this class is very strange! The type being declared is also used as the template type for the class it derives from. Strangely, however, this works just the way we want it to.

Now that we have our custom BroadcastingAlertArgs class, we can start broadcasting.

protected void exampleButton_OnClick(object sender, AlertArgs e)

    // Let all the other controls know that this control changed 
    ExampleAlertArgs args = new ExampleAlertArgs("Test"); 
    args.Broadcast(this, Page);
}


All that's required is that we instantiate the ExampleAlertArgs class and call its Broadcast method. So now we have the alert defined and being broadcast, but no sinks. Creating a control that receives alerts only requires that a subscribing class implement the IAlertable<T> interface.

using System;
using System.Web.UI.WebControls;

using Vertigo.AlertingExample;

namespace Vertigo.AlertingExample.Controls

    public partial class ExampleControl : UserControl, IAlertable<ExampleAlertArgs
    { 
        public void Alert(object sender, ExampleAlertArgs args) 
        { 
            // Do something useful here 
        } 
    }
}

Summary

Using alerting provides a loosely-coupled approach to eventing. Since neither the broadcaster nor the alert receiver know anything about the other, new sinks can be added simply by placing them on the page with the right signature. More alerts can be defined and broadcast without affecting any pre-existing code and two controls can send alerts to each other without introducing any circular dependencies or load order issues. Also, with both the alerting and alertable controls wrapped in UpdatePanels, the screen content will be changed without visible refreshes occurring in the browser.

Disabling the Shutdown Event Tracker

If you're like me, you get annoyed every time you try to shut down or restart Windows Server 2003. It displays a dialog box that requires input before you can actually shut down or restart.

The purpose of this dialog is to create events in the Event Log so that you can track why your server has gone offline. However, for most developers, we couldn't care less, and our comments turn out to be something like "asdf". If you want to get rid of this dialog box, just follow these steps:

  1. Open the Microsoft Management Console (I just press the WindowsKey+R to get the run dialog box and type in "MMC")

  2. The MMC will open, but with no add-ins loaded. You need to load the Group Policy Editor by selecting "Add/Remove Snap-In" from the File menu

  3. Find the "Group Policy Editor" in the list and press Add, followed by Finish on the subsequent dialog box, and finally OK on the Add/Remove Snap-Ins dialog

  4. Navigate down to Local Computer Policy > Computer Configuration > Administrative Templates > System, and double-click the "Display Shutdown Event Tracker" setting in the right pane

  5. Select the "Disabled" option and press OK

That's it! Now you can shut down or restart your server without having to put a reason in.

1 - 10 Next

 ‭(Hidden)‬ Admin Links