Customer-extensible configuration

While playing around with custom resources I wondered what ways there are to configure which IResourceManager is used for those generated classes.

As I mentioned before I’m not particularly fond of XML for configuration purposes. But the *.config files are still the most commonly used means to configure a .NET application.

My goal was to allow a developer to configure which of a set of predefined resource managers to use (an obvious choice would be the file based approach with the .NET ResourceManager and maybe a database based implementation) while allowing him to add his own implementations later on. That kind of extensibility calls for an abstract factory approach.

The config file should look something like this

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="i18n" type="Playground.I18nSettingsSection, Playground" />
  </configSections>
  <connectionStrings>
    <clear />
    <add name="DEFAULT" connectionString="localhost"/>
  </connectionStrings>
  <i18n>
    <resxManager>
      <db connectionStringName="DEFAULT" />
    </resxManager>
  </i18n>
</configuration>

File 1: What I wanted my App.config to look like

The code behind that solution should be quite simple. Along the lines of:

public class I18nSection : ConfigurationSection
{
  [ConfigurationProperty("resxManager")]
  public ResourceManagerSettings ResourceManager
  {
    get { return (ResourceManagerSettings) base["resxManager"]; }

    set { base["resxManager"] = value; }
  }
}

public abstract class ResourceManagerSettings : ConfigurationElement
{
  public abstract IResourceManager GetResourceManager(Type resourceFileType);
}

File 2: What I thought might be a good idea for the code behind

When was anything ever that easy? The whole thing blew up in my face. The underlying problem being that the .NET configuration system cannot create an instance of an abstract class (the ResourceManagerSettings) and you can neither get access to the code where the instantiation happens (it’s a private method somewhere inside ConfigurationElement) nor can you handle it via overriding OnDeserializeUnrecognizedElement in your section class. The element is not truly unrecognized if you decorate the ResourceManager property with the ConfigurationPropertyAttribute so the method would never be triggered. You can remove the attribute but then where do you store the created object? You can’t call base["resxManager"] anymore because there is no longer a ConfigurationProperty with that name. And what if you had more than one “unrecognized element” in that section? You couldn’t assume that you where to create a concrete implementation of your abstract ResourceManagerSettings which would make figuring out which class to instantiate quite a bit harder (remember that you want the developer to be able to extend that solution later).

So I had to figure out another approach. What eventually worked was moving the whole concept up one level in the hierarchy of the config system. Where I formerly used a ConfigurationSection I had to use a ConfigurationSectionGroup as base class. And the ConfigurationElement became a ConfigurationSection.

What I ended up with was an App.config that looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="i18n" type="Playground.I18nSettingsSectionGroup, Playground">
      <!--<section name="file" type="Playground.FileResourceManagerSettings, Playground"/>-->
      <!--<section name="null" type="Playground.NullResourceManagerSettings, Playground"/>-->
      <section name="db" type="Playground.DbResourceManagerSettings, Playground"/>
    </sectionGroup>
  </configSections>
  <connectionStrings>
    <clear />
    <add name="DEFAULT" connectionString="localhost"/>
  </connectionStrings>
  <i18n>
    <db connectionStringName="DEFAULT" />
  </i18n>
</configuration>

File 3: Actual App.config

And the code behind to match the .config file:

public class I18nSettingsSectionGroup : ConfigurationSectionGroup
{
  public const string NAME = "i18n";

  private ResourceManagerSettings _ResourceManagerSettings;

  public ResourceManagerSettings ResourceManager
  {
    get
    {
      if (this._ResourceManagerSettings != null)
      {
        return this._ResourceManagerSettings;
      }

      if ((this._ResourceManagerSettings = this.Sections.OfType<ResourceManagerSettings>().SingleOrDefault()) == null)
      {
        this._ResourceManagerSettings = new FileResourceManagerSettings();
        this.Sections.Add(FileResourceManagerSettings.NAME, this._ResourceManagerSettings);
      }

      return this._ResourceManagerSettings;
    }

    set
    {
      ResourceManagerSettings resourceManagerSettings = this.Sections.OfType<ResourceManagerSettings>().SingleOrDefault();

      if (resourceManagerSettings != null && !Equals(resourceManagerSettings, value))
      {
        this.Sections.Remove(resourceManagerSettings.SectionInformation.SectionName);
      }

      this.Sections.Add(value.SectionInformation.Name, value);
    }
  }
}

public abstract class ResourceManagerSettings : ConfigurationSection
{
  public abstract IResourceManager GetResourceManager(Type resourceFileType);
}

public class FileResourceManagerSettings : ResourceManagerSettings
{
  public const string NAME = "file";

  public override IResourceManager GetResourceManager(Type resourceFileType)
  {
    return new ResourceManagerWrapper(new ResourceManager(resourceFileType.FullName, resourceFileType.Assembly));
  }
}

File 4: Actual implementation

In the <configSections> part of the .config file I configure the I18nSectionGroup with at most one (!) implementation of the ResourceManagerSettings. If you add multiple implementations the .NET configuration system will instantiate all of them when you read from the file. And now you would have to figure out which one you actually wanted to use. So (by design!) the code above will fail in case you configured more than one ResourceManagerSetting.

If you don’t configure anything the I18nSectionGroup will fall back to the FileResourceManagerSettings. I believe that’s an acceptable default.

When you set the I18nSectionGroup.ResourceManager property at run-time and save the configuration back to disk the correct section type will be persisted in the <configSections> part of your .config file.

So what I got is not exactly what I wanted. If the .NET framework weren’t as uptight about the object creation (the configuration system is by no means the only part of the framework that behaves like that!) the whole exercise would have been a lot easier. To MS’ defense: From the comments in the code of the ConfigurationElement they seemed to have some security considerations going on. Still, they might (at least) have provided a way to influence what type of object should be created if they couldn’t/didn’t want to let you handle the instantiation itself.

Anyway. You now have a means to configure where your resources are loaded from and if you want to add another source (like RavenDB for example) you can always do so with little effort. If you either mark your resource classes with an interface or a custom Attribute or decide on a naming convention it is really easy to brew up a little reflection code that sets the static ResourceManager property at application start-up.

Advertisement

Testing custom StyleCop rules

StyleCop is the preferred way to enforce consistency in your project’s coding style. Code guidelines in printed or electronic form are always inferior to automatic validation of said guidelines as part of your build process. You get compiler warnings or errors with (hopefully) helpful and descriptive explanations of why what you did is a bad idea. StyleCop even contains a ReSharper plugin that adds quick-fixes for many rule violations.

But StyleCop can do more than just notify you that someone forgot an empty line after a closing curly bracket. As a proof of concept I wrote rules that should prevent faulty re-throws (catch-blocks in the form of catch(Exception ex) { throw ex; }) that swallow the StackTrace or constructors with more than 4 parameters (which is considered a code smell that indicates a component has too many responsibilities).

The point of this post however is not to show you how to write such rules but how you can make sure that they really work by testing them as part of your regular unit testing process. If you are looking for samples on how to write custom rules check out this post or use the search engine of your choice. There are lots of samples.

Posts like this one explain how to setup tests for custom StyleCop rules using the Visual Studio test-runner and VS’ Test View. In my opinion that thing gives you the worst possible user-experience. It makes running your tests as convenient as reading a paper about quantum physics. ReSharper or TestDriven.Net are way more easy to handle. But the given examples don’t work properly with those tools or alternative test-runners (e.g. NUnit or xUnit). I love my tools and I hate to be forced to use something inferior by circumstances that I can influence. So I set out to remove that particular bump in the road.

I did not want to fumble with files and how and where to deploy them for test-runs with different test frameworks or tools. Instead I wanted to make these files embedded resources that are just there when I run my tests. I started with the sample mentioned above and made several changes to it.

  1. Use the StyleCopObjectConsole instead of the StyleCopConsole.
  2. Create a class derived from SourceCode that handles loading code from embedded resources (I called mine ResourceBasedSourceCode. Samples for that can be found in the StyleCop source code. Search for StringBasedSourceCode).
  3. The StyleCopObjectConsole requires an instance of ObjectBasedEnvironment which in turn requires a delegate that creates SourceCode instances for given file names. Make that delegate create instances of your ResourceBasedSourceCode.
  4. Hook up the handlers for output and violations to the events of StyleCopObjectConsole.Core instead of the events of the console object.

Lets have a look at the source code of the tests for which I use xUnit.

public class CodeQualityAnalyzerFixture
{
  private readonly StyleCopObjectConsole console;
  private readonly ICollection output;
  private readonly ICollection violations;
  private readonly CodeProject codeProject;

  public CodeQualityAnalyzerFixture()
  {
    this.violations = new List<string>();
    this.output = new List<string>();
    ObjectBasedEnvironment environment = new ObjectBasedEnvironment(ResourceBasedSourceCode.Create, GetProjectSettings);
    ICollection<string> addinPaths = new[] { "." };
    this.console = new StyleCopObjectConsole(environment, null, addinPaths, true);
    CsParser parser = new CsParser();
    parser.FileTypes.Add("CS");
    this.console.Core.Environment.AddParser(parser);
    this.console.Core.ViolationEncountered += (s, e) =&gt; this.violations.Add(e.Violation);
    this.console.Core.OutputGenerated += (s, e) =&gt; this.output.Add(e.Output);
    this.codeProject = new CodeProject(0, null, new Configuration(null));
  }

  [Fact]
  public void Should_Flag_TooManyCtorParameters()
  {
    this.AnalyzeCodeWithAssertion("TooManyConstructorArguments.cs", 1);
  }

  [Fact]
  public void Should_Flag_IncorrectRethrow()
  {
    this.AnalyzeCodeWithAssertion("IncorrectRethrow.cs", 1);
  }

  private Settings GetProjectSettings(string path, bool readOnly)
  {
    return null;
  }

  private void AnalyzeCodeWithAssertion(string codeFileName, int expectedViolations)
  {
    this.AddSourceCode(codeFileName);
    this.StartAnalysis();
    this.WriteViolationsToConsole();
    this.WriteOutputToConsole();
    Assert.Equal(expectedViolations, this.violations.Count);
  }

  private void WriteOutputToConsole()
  {
    foreach (var o in this.output)
    {
      Console.WriteLine(o);
    }
  }

  private void WriteViolationsToConsole()
  {
    foreach (var violation in this.violations)
    {
      Console.WriteLine(violation.Message);
    }
  }

  private void AddSourceCode(string resourceFileName)
  {
    bool sourceCodeSuccessfullyLoaded = this.console.Core.Environment.AddSourceCode(this.codeProject, resourceFileName, null);
    if (sourceCodeSuccessfullyLoaded == false)
    {
      throw new InvalidOperationException(string.Format("Source file '{0}' could not be added.", resourceFileName));
    }
  }

  private void StartAnalysis()
  {
    IList projects = new[] { this.codeProject };
    this.console.Start(projects);
  }
}

What does it do? Lets start with the test setup in the constructor.

  1. Initialize the collections for the output generated by StyleCop.
  2. Instantiate the ObjectBasedEnvironment providing it with the required delegates to create SourceCode and Settings. The SourceCodeFactory delegate is a static method of my ResourceBasedSourceCode class so we will come to that in a moment. The ProjectSettingsFactory delegate always returns null.
  3. Define a path to the add-in under test (which is the assembly that contains our custom rules). So the dot stands for the “current working folder” where said add-in will be copied to by the build by default.
  4. Create the console object and add a CsParser to the console. As the name indicates it is responsible for parsing C# code files. Don’t forget to register the file extension for C# code files when you create the parser or it just won’t work. The extension name is case-sensitive. Use upper-case.
  5. Register the eventhandlers that will write output and rule violations to the respective collections that will be evaluated after StyleCop is done processing your code files.
  6. Create a new CodePoject. The code files you want analyzed will be added to that project during your tests.

The test methods are simple. They call the AnalyzeCodeWithAssertion method with the name of the file you want to analyze and the number of violations you expect. This is the most basic validation possible. You can make it arbitrarily complex if you want to (e.g. by asserting the type of the expected violation or message texts or …).

Note that I made my ResourceBasedSourceCode class handle incomplete file names. I didn’t want to have to deal with all the namespaces that are added as prefixes to embedded resources so I decided to go with “EndsWith” semantics. As long as the name of the resource ends with the file name provided as a parameter it works just fine.

The AnalyzeCodeWithAssertion method is responsible for

  1. Adding the source code to the project that will be analyzed.
  2. Running the actual analysis using StyleCop.
  3. Writing the output generated during the analysis to the console so you can explore it at leisure after the test is run.
  4. Asserting your expectations.

Nothing spectacular there. Now lets have a look at the code for the ResourceBasedSourceCode.

public class ResourceBasedSourceCode : SourceCode
{
  private readonly string _ResourceName;
  public ResourceBasedSourceCode(CodeProject project, SourceParser parser, string resourceName)
    : this(project, parser, resourceName, Assembly.GetExecutingAssembly())
  {
  }
  public ResourceBasedSourceCode(CodeProject project, SourceParser parser, string resourceName, Assembly assembly)
    : base(project, parser)
  {
    Guard.AssertNotEmpty(resourceName, "resourceName");
    Guard.AssertNotNull(assembly, "assembly");
    string fullResourceName = assembly.GetManifestResourceNames()
	  .FirstOrDefault(rn => rn.EndsWith(resourceName, StringComparison.OrdinalIgnoreCase));
	  
    if (string.IsNullOrEmpty(fullResourceName))
    {
      throw new ArgumentException(string.Format("No resource has a name that ends with '{0}'", resourceName), "resourceName");
    }
    _ResourceName = fullResourceName;
  }

  public static SourceCode Create(string path, CodeProject project, SourceParser parser, object context)
  {
    return new ResourceBasedSourceCode(project, parser, path);
  }

  public override TextReader Read()
  {
    Stream stream = this.GetType().Assembly.GetManifestResourceStream(_ResourceName);
    return new StreamReader(stream);
  }

  public override bool Exists
  {
    get { return true; }
  }

  public override string Name
  {
    get { return _ResourceName; }
  }

  public override string Path
  {
    get { return _ResourceName; }
  }

  public override DateTime TimeStamp
  {
    get { return DateTime.MinValue; }
  }

  public override string Type
  {
    get { return "cs"; }
  }
}

There is very little magic involved in this class. In the constructor we try to find an embedded resource matching the name that is provided as a parameter and store the full name of the resource in a field. If that step doesn’t fail we can safely assume that we can open a Stream to read that resource later on. The file extension is hard-coded to C# files (property Type). Lower-case for the extension name is OK here. Don’t ask, I have no clue why the developers decided to make that different from the behavior of the CsParser. The Create method is a factory method with the signature of the SourceCodeFactory delegate as required by the ObjectBasedEnvironment. Everything else is implemented in the most basic way to make the analysis pass.

Now just add a folder that contains the code files to your test project (I called it “Resources”). Make sure to set the files’ Build Action to “Embedded Resource”. And you are ready to roll.

That’s all the infrastructure you need. Doesn’t look that complicated, does it? If you are interested in the complete source code you can find that here. The project names are TecX.Build and TecX.Build.Test. Have fun!

Composition over Inheritance: Custom Collections

Composition over inheritance is a known but unfortunately not very well understood OOD principle.

All too often I see code like this:

public class MyFooList : List<Foo> { /* .. */ }

or this:

public class MySomething
{
  public List<Foo> Foos { get; set; }
}

The derived class adds a method or two. Maybe a property. And it carries all the weight of the super-class List<T>. The property of type List<Foo> is there for anybody to fill with content of unverified qualities. Why?!

List is a powerful class but it does not give you any control over the objects that are added to it. What if your custom collection needs to protect invariants like “You can only add Foos with a Bar > 7?” Or you can only append to your collection but not remove objects from it. There is no easy way to model this when you are inheriting from List<T> or providing raw lists as part of your API.

If you don’t need the majority of the 30-some methods and the ~10 properties why would you show them? They just blur your interface. A simple custom collection that only offers what your consumers need to know is simple enough to write. If you implement IEnumerable<T> you can even unleash all the power of LINQ to select items from your collection.

If you have many or very complex invariants encapsulate them in validators to protect your collection. Let the collection tell its consumers about the rules a Foo instance violates when they are trying to add it to the collection.

[TestMethod]
public void Should_NotifyOnViolatedInvariants()
{
  var collection = new MyFooCollection(new IFooValidator[] { new NotNullValidator(), new MinBarValidator(7) });
  
  IFooValidator violatedInvariant;
  Assert.IsFalse(collection.Add(null, out violatedInvariant));
  Assert.IsInstanceOfType(violatedInvariant, typeof(NotNullValidator));

  Assert.IsFalse(collection.Add(new Foo() { Bar = 1 }, out violatedInvariant));
  Assert.IsInstanceOfType(violatedInvariant, typeof(MinBarValidator));
  Assert.IsTrue(collection.Add(new Foo { Bar = 8 }, out violatedInvariant));
}

public class MyFooCollection : IEnumerable<Foo>
{
  private readonly IEnumerable<IFooValidator> validators;
  private readonly List<Foo> foos;
  public MyFooCollection(IEnumerable<IFooValidator> validators)
  {
    this.validators = validators ?? new IFooValidator[0];
    this.foos = new List<Foo>();
  }
  public bool Add(Foo foo, out IFooValidator violatedInvariant)
  {
    violatedInvariant = this.validators.FirstOrDefault(v => v.ViolatesInvariant(foo));
    if (violatedInvariant == null)
    {
      this.foos.Add(foo);
      return true;
    }
    return false;
  }
  public IEnumerator<Foo> GetEnumerator()
  {
    return this.foos.GetEnumerator();
  }
  IEnumerator IEnumerable.GetEnumerator()
  {
    return this.GetEnumerator();
  }
}
public interface IFooValidator
{
  string Description { get; }
  bool ViolatesInvariant(Foo foo);
}
public class MinBarValidator : IFooValidator
{
  private readonly int minBar;
  public MinBarValidator(int minBar)
  {
    this.minBar = minBar;
  }
  public string Description
  {
    get { return string.Format("foo.Bar must be greater than {0}", this.minBar); }
  }
  public bool ViolatesInvariant(Foo foo)
  {
    return foo.Bar <= this.minBar;
  }
}
public class NotNullValidator : IFooValidator
{
  public string Description
  {
    get { return "foo must not be null."; }
  }
  public bool ViolatesInvariant(Foo foo)
  {
    return foo == null;
  }
}
public class Foo
{
  public int Bar { get; set; }
}

You are still using the list under the covers. But your custom collection (just a couple of lines long!) is now stream-lined to only provide the functionality that is really needed. If you expose a raw List<T> anybody can modify the contents of that list. There is no way to enforce the collections invariants. With the custom collection your intentions became clearer and you made using your API safer. Isn’t that worth the bit of extra effort?