wcf, gists, csharp, dotnet comments edit

One of the challenges I’m facing in the project I’m working on is that we want to store configuration values for the system in a central location that can be accessed via a service… but that’s not how most .NET developers are used to working with configuration. Most folks are used to ConfigurationManager or WebConfigurationManager, something like this:

NameValueCollection config = (NameValueCollection)WebConfigurationManager.GetSection("mySection");
this.SomeObject.Value = config["key"];

That’s great if everything is stored in your app.config or web.config, but if you’ve got everything behind a service, it’s trickier. You’ve got to get a proxy to your service, get the approriate values, handle exceptions… it’s a lot messier, and if you’re trying to get a bunch of devs up to speed using that, it’s going to take a bit. Wouldn’t it be nice if they could just use the stuff they’re used to?

There are a couple of ways that can happen.

First, you can use a ProtectedConfigurationProvider implementation. You might be used to seeing these in the form of things like the RsaProtectedConfigurationProvider that you’d use to store settings encrypted in your configuration files. The cool thing is, the ConfigurationManager doesn’t really care what’s stored in the <EncryptedData> element in your config. For example, when you use the RsaProtectedConfigurationProvider, you’ll see something like this in your config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <mySection configProtectionProvider="RsaProtectedConfigurationProvider">
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
      xmlns="http://www.w3.org/2001/04/xmlenc#">
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
          <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <KeyName>Rsa Key</KeyName>
          </KeyInfo>
          <CipherData>
            <CipherValue>(encrypted data here)</CipherValue>
          </CipherData>
        </EncryptedKey>
      </KeyInfo>
      <CipherData>
        <CipherValue>(encrypted data here)</CipherValue>
      </CipherData>
    </EncryptedData>
  </mySection>
</configuration>

But everything inside <EncryptedData/> is entirely up to the configuration provider. Since you can define your own providers, what if you did something like this:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="mySection"
      type="System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
  </configSections>
  <configProtectedData>
    <providers>
      <add name="ServiceConfigurationProvider"
        type="Framework.ServiceConfigurationProvider, Framework"
        endpointName="WSHttpBinding_IConfigurationService"/>
    </providers>
  </configProtectedData>
  <mySection configProtectionProvider="ServiceConfigurationProvider">
    <EncryptedData>
      <values>
        <value key="value1"/>
        <value key="value2"/>
      </values>
    </EncryptedData>
  </mySection>
</configuration>

See what we have there?

  • A custom section that (for simplicity) is just a key/value section like AppSettings.
  • A custom protected config provider that has a special extra configuration property - an endpoint name (that would correspond to something in your <system.serviceModel> configuration).
  • A section that uses the configuration provider you specified… and notice how the contents of the <EncryptedData> are simply keys? These are the values you’d want to retrieve from your configuration service.

So how would you do it? You could implement a provider that looks like this:

using System;
using System.Configuration;
using System.Xml;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.ServiceModel;
using System.Text;

namespace Framework
{
  public class ServiceConfigurationProvider : ProtectedConfigurationProvider
  {
    public string ServiceEndpointName { get; set; }

    public override XmlNode Decrypt(XmlNode encryptedNode)
    {
      List<string> keysToRetrieve = new List<string>();
      foreach (XmlNode value in encryptedNode.SelectNodes("/EncryptedData/values/value"))
      {
        XmlAttribute keyAttrib = value.Attributes["key"];
        if (keyAttrib != null && !String.IsNullOrEmpty(keyAttrib.Value))
        {
          string key = keyAttrib.Value;
          if (!keysToRetrieve.Contains(key))
          {
            keysToRetrieve.Add(key);
          }
        }
      }

      ChannelFactory<IConfigurationService> factory = new ChannelFactory<IConfigurationService>(this.ServiceEndpointName);
      IConfigurationService service = factory.CreateChannel();
      AppSettingsSection section = new AppSettingsSection();
      foreach (string key in keysToRetrieve)
      {
        section.Settings.Add(key, service.GetValue(key));
      }
      XmlDocument doc = new XmlDocument();
      StringBuilder builder = new StringBuilder();
      using (XmlWriter writer = XmlWriter.Create(builder))
      {
        typeof(AppSettingsSection)
        .GetMethod("SerializeToXmlElement", BindingFlags.Instance | BindingFlags.NonPublic)
        .Invoke(section, new object[] { writer, "root" });
      }
      doc.LoadXml(builder.ToString());
      return doc.DocumentElement;
    }

    public override XmlNode Encrypt(XmlNode node)
    {
      throw new NotImplementedException();
    }

    public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
    {
      this.ServiceEndpointName = config["endpointName"];
      base.Initialize(name, config);
    }
  }
}

Note that, in the above, there’s a lot I’m not doing to keep it simple - I’m not properly closing the service channel, I’m not handling errors in the call, etc. It’s for illustration purposes. I’m also doing some reflection magic to get the AppSettingsSection to serialize to XML so I don’t have to manually do it. Wouldn’t that be nice if it was public?

The point is, you can use the protected configuration provider mechanism to store things elsewhere - service, database, etc. Consuming something like this would look exactly like the previous example. You’d literally never know the difference as a consumer of the settings. The problem with this solution is that once the value is read, it’s cached and never re-read. Which is to say, the service will only ever get called once. If the configuration value changes in whatever data store the service is wrapping, you’ll never get it in your app. Also, if you wanted strong typing, you’d have to implement a custom configuration section that handles strong typing and that’s what your provider would return from the Decrypt method. (Like I said, a simple AppSettingsSection keeps it simple.)

A solution that’s chattier but overcomes this caching issue is to implement a special ConfigurationSection. In that section, you can simply have a method that wraps the service call.

Your configuration file might look like this:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="mySection" type="Framework.ServiceConfigurationSection, Framework"/>
  </configSections>
  <mySection endpointName="WSHttpBinding_IConfigurationService"/>
</configuration>

It’s a little shorter, but you can still see there’s a service endpoint name in there that’d correspond to the configuration service you’ll be calling. You can also see that we’re using a custom configuration section rather than one of the standard out-of-the-box ones.

The ConfigurationSection implementation might look like this:

using System;
using System.Configuration;
using System.ServiceModel;

namespace Framework
{
  public class ServiceConfigurationSection : ConfigurationSection
  {
    [ConfigurationProperty("endpointName", IsRequired = true)]
    public string ServiceEndpointName
    {
      get
      {
        return (string)this["endpointName"];
      }
      set
      {
        this["endpointName"] = value;
      }
    }

    public string GetValue(string key)
    {
      ChannelFactory<IConfigurationService> factory =
        new ChannelFactory<IConfigurationService>(this.ServiceEndpointName);
      IConfigurationService service = factory.CreateChannel();
      return service.GetValue(key);
    }
  }
}

Again, there’s a lot I’m not doing in there to keep it simple, but, again, you see the idea - the GetValue method on the section wraps the service call. Consuming this looks very similar to the original example:

ServiceConfigurationSection config = (ServiceConfigurationSection)WebConfigurationManager.GetSection("mySection");
this.SomeObject.Value = config.GetValue("key");

This version retrieves the value every time you ask for it, which gets you around the caching issue. That said, the developer using this mechanism should probably be made aware of what’s going on so he or she doesn’t wonder why performance has gone down the tubes on that page that uses 150 bajillion configuration values.

gaming, xbox comments edit

I blogged a while ago (in my drum comparison entry) that I’d never gotten 100% on a song playing the drums in Rock Band, even on easy difficulty, and I generally play on medium or hard. It was like my own personal Curse of the Bambino going on - no matter what I did, I’d always miss one note. Maybe it was a stupid mistake on my part, maybe it was a double-hit registered, but whatever the reason, never did I get 100%.

The curse has been broken!

100% on Hella
Good

Last night I got 100% on the No Doubt song “Hella Good” on medium difficulty. Interestingly enough, I actually got two 100% songs last night - the other was “My Best Friend’s Girl” by The Cars. The hardest songs in the world? Not by a long shot, but I’m still pretty proud. I’m not afraid to admit I was singing songs about how I’m the King of Drums last night. No, I’m not an awesome drummer, but I was pretty stoked with myself.

And, yes, you’ll see my character’s name is “Alyss.” All of my characters are named based on Frank Beddor’s Looking Glass Wars characters. My guitarist is Hatter Madigan, my band is Wonderland’s Millinery… you get the idea. Here’s Alyss:

Alyss from Wonderland's
Millinery

Coach Hines is a character on MadTV that teaches at a high school for boys. He’s one of my favorite characters on the show. Anyway, I was working on some fairly convoluted process stuff the other day and it reminded me of the choreography from his version of Oliver Twist:

General Ramblings comments edit

I generally don’t make plans to hang out with people during the week. It’s not that I don’t like visiting friends, it’s just that things never seem to quite work out. Folks are rushed getting off work, usually have to take care of some things at home, and you don’t really want to be out too terribly late on a “school night” because you do have to make it to work the next day.

Of course, sometimes I forget and we try. Last night was one of these times.

Earlier this week we got called by the local comedy club offering tickets to the Thursday night show. It sounded like fun, and we hadn’t been out with friends for a while, so we accepted. The show started at 8pm Thursday, but you had to pick up your tickets between 6pm and 7:15pm. No problem, right?

The first issue we ran into was that almost everyone else has adopted the same no-weeknight-events policy we have, so of the 8+ people we invited, two were able to make it. That’s OK, though, because they’re really good friends and fun to hang out with, so we weren’t really sweating the fact it wasn’t as big as we hoped. (It turns out it’s probably a good thing it was small.) As long as we could pick one of them up at home on the way, the other would meet us at the club and all would be well.

The second issue was that Jenn had a chiropractor appointment at 6pm on Thursday. “Don’t worry,” she said, “the chiropractor is really fast and if I’m there early, he always takes me early. I’ll just get there early.” I wasn’t terribly convinced, but hey, if she says she can make it, I’ll believe it.

Here’s how it turned out:

Jenn got out of work a half hour later than she usually does because it got busy. She noticed that her driver’s side headlight might be out and sent me a text message as such. No big deal. Anyway, getting out late put her behind a bit so she couldn’t quite get to the chiropractor as early as she hoped.

The chiropractor had a backlog of people hanging out in the lobby when Jenn arrived, so there was no way she was going to get taken care of early, and may be a few minutes late. It was at this point I was getting worried because I started doing the math:

  • 10 minutes for Jenn to come home from the chiropractor and pick me up.
  • 10 minutes to go pick up one of our friends.
  • 20 minutes to make it downtown in medium traffic.
  • 5 minutes to park if we’re lucky.

So as long as Jenn could leave by 6:30p, we could still barely make it in time to get the tickets. Close, but not a big problem. Plus, since I was sitting at home waiting, it’d give me more Fallout 3 time. I sent a message to our friend to let her know we’d pick her up a little later than we expected, but we’d still make it.

About 6:15p Jenn calls to say she’s locked herself out of the car. Remember that text message earlier about the driver’s side headlight? She turned the car battery on (power on, but not the engine), which locks the car doors, then got out of the car to see if the headlight was out. While she was out “knocking on the headlight” (no, I don’t know what the knocking was for), the car door shut. Locked out. Now I’ve got to bring her the spare keys.

We’re a little behind where I was hoping to be, but we’re still looking OK.

  • 5 minutes to get my shoes on, find the spare key, and leave.
  • 10 minutes for me to take Jenn the spare key and unlock the car.
  • 10 minutes to go get our friend and leave my car at their house.
  • 20 minutes to make it downtown in medium traffic.
  • 5 minutes to park if we’re lucky.

It’s about 6:15p, and with the 50 minutes it’s going to take to get things together, we have a 10 minute window (between 7:05p and 7:15p) where we can still pick up the tickets. Tight.

I make it to Jenn in the expected amount of time, unlock the car, and we both hop in and get ready to go. I say “get ready” because Jenn’s battery is dead and she needs a jumpstart. Now I know we’re not going to make it.

  • 15 minutes to push Jenn’s car to a spot where I can get to it, move my car, give the jump start, and put everything away.
  • 10 minutes to go get our friend and leave my car at their house.
  • 20 minutes to make it downtown in medium traffic.
  • 5 minutes to park if we’re lucky.

It’s about 6:30p and we won’t make it to the ticket booth until 7:20p, and that’s if everything goes right.

“Hey, Jenn, should we just call this off?”

“No, we can make it.”

No, we can’t. I love Jenn to death, but she doesn’t listen to me in situations like this, and she knows it, so it’s best just to go with it, as frustrating as it is. “OK, well, while I’m getting my car moved and getting the jump start going, let our friend know that we’re going to be even later.”

“I don’t have her phone number.”

Now I’m I/O-bound - I’m the only one that can get the cars set up for the jump start,and I’m the only one that can coordinate this whole thing. Does a text message or a call really take that long? No, but when minutes are literally counting, it adds up.

I got Jenn started, we put things away, and we headed off to our friend’s house. I, of course, hit literally every stupid stop light on the way there, so a 10 minute trip took closer to 15 minutes. (Thanks, City of Hillsboro, for having every light be pressure-sensitive instead of timed.) I called Jenn about halfway there to let her know this wasn’t going to happen. By the time I got there, Jenn had already told our friend and we decided to make the best of it and at least get some dinner.

Dinner was good, and it was nice to see our friends, so it all worked out for the most part. Makes me wonder if we shouldn’t have just gone for the smaller plans - just dinner - to begin with. Maybe next time. If there’s a next time. Maybe we should just wait until the weekend like we always do so it won’t go so horribly wrong.