locked
Code Contracts conflicts with custom SettingsProvider RRS feed

  • Question

  • I'm using Code Contracts in my project (static & runtime), and I'm trying to implement a custom class derived from System.Configuration.SettingsProvider. From what I've gleaned on MSDN and various other sites, I need to override the Initialize() method like this:

    public override void Initialize(string name, NameValueCollection config)
    {
        base.Initialize(this.ApplicationName, config);
    }

    However when I run the code, I get a Contract error saying 'Precondition failed: !string.IsNullOrEmpty(name)'. Stepping through the code reveals that the Settings architecture is calling my method and passing in a null value for the 'name' parameter every time (I can't find any way to change that); and viewing the compiled code in .NET Reflector, sure enough my method has contracts attached:

    public override void Initialize(string name, NameValueCollection config)
    {
        __ContractsRuntime.Requires(!string.IsNullOrEmpty(name), null, "!String.IsNullOrEmpty(name)");
        base.Initialize(this.ApplicationName, config);
        if (__ContractsRuntime.insideContractEvaluation <= 4)
        {
            try
            {
                __ContractsRuntime.insideContractEvaluation++;
                __ContractsRuntime.Ensures(this.Name != null, null, "this.Name != null");
            }
            finally
            {
                __ContractsRuntime.insideContractEvaluation--;
            }
        }
    }
    
    But looking at both the SettingsProvider and ProviderBase classes in Reflector, I don't see any contracts on them. So #1, where is this contract coming from?!? And #2, how do I get this class to work? Apparently I need to override the method and provide a name to the base implementation, but I can't because the Settings system itself always passes in a null value and Code Contracts throws an exception before my code can do anything about it! Any ideas?
    Sunday, December 23, 2012 8:43 AM

Answers

  • Hi,

    > #1, where is this contract coming from?!?

    The contract is coming from a .NET Framework contract assembly provided by the Code Contracts installer.  The actual .NET assemblies do not specify any code contracts; instead, they still use the legacy if...throw style contracts, as can be seen in Reflector.  So in order to specify code contracts for Framework assemblies, Code Contracts installs a set of contract-only assemblies that match the .NET reference assemblies, but only specify code contracts.

    More specifically, you'll find the code contracts for ProviderBase specified in the following assembly:

    C:\Program Files (x86)\Microsoft\Contracts\Contracts\.NETFramework\v4.0\System.Configuration.Contracts.dll

    Here's the Initialize method decompiled:

    public virtual void Initialize(string name, NameValueCollection config)
    {
    	Contract.Requires(!string.IsNullOrEmpty(name), null, "!String.IsNullOrEmpty(name)");
    	Contract.Ensures(this.Name != null, null, "this.Name != null");
    }

    Contract inheritance is one of the best features of Code Contracts.  An overridden method automatically inherits the preconditions of the base method.  The rewriter injects the contracts that it finds in the contract assembly, so that you don't have to redefine them yourself.

    > #2, how do I get this class to work?

    Unfortunately, this particular contract appears to be a bug.  If the .NET Framework can pass in null as the name argument, then the contract shouldn't be there in the first place.  Now that you've reported it, the CC team will hopefully investigate and fix it in a future release.

    Until the faulty contract is removed, you may be able to suppress contract inheritance using ContractOptionAttribute as follows, though I haven't tested this myself.

    [ContractOption("contract", "inheritance", false)]
    public override void Initialize(string name, NameValueCollection config)
    {
        ...
    }

    Note that ContractOptionAttribute isn't defined in .NET 4.0; however, it's defined in .NET 4.5.  To use it in .NET 4.0, you must add its definition yourself.  The easiest way is to simply copy the following file into your project:

    C:\Program Files (x86)\Microsoft\Contracts\Languages\CSharp\ContractExtensions.cs

    You'll find more details in the Contracts User Manual, §4.8.  The manual is installed with Code Contracts, or you can download it here.

    - Dave


    http://davesexton.com/blog

    • Marked as answer by Taffarel Sunday, December 23, 2012 5:51 PM
    Sunday, December 23, 2012 1:06 PM

All replies

  • Hi,

    > #1, where is this contract coming from?!?

    The contract is coming from a .NET Framework contract assembly provided by the Code Contracts installer.  The actual .NET assemblies do not specify any code contracts; instead, they still use the legacy if...throw style contracts, as can be seen in Reflector.  So in order to specify code contracts for Framework assemblies, Code Contracts installs a set of contract-only assemblies that match the .NET reference assemblies, but only specify code contracts.

    More specifically, you'll find the code contracts for ProviderBase specified in the following assembly:

    C:\Program Files (x86)\Microsoft\Contracts\Contracts\.NETFramework\v4.0\System.Configuration.Contracts.dll

    Here's the Initialize method decompiled:

    public virtual void Initialize(string name, NameValueCollection config)
    {
    	Contract.Requires(!string.IsNullOrEmpty(name), null, "!String.IsNullOrEmpty(name)");
    	Contract.Ensures(this.Name != null, null, "this.Name != null");
    }

    Contract inheritance is one of the best features of Code Contracts.  An overridden method automatically inherits the preconditions of the base method.  The rewriter injects the contracts that it finds in the contract assembly, so that you don't have to redefine them yourself.

    > #2, how do I get this class to work?

    Unfortunately, this particular contract appears to be a bug.  If the .NET Framework can pass in null as the name argument, then the contract shouldn't be there in the first place.  Now that you've reported it, the CC team will hopefully investigate and fix it in a future release.

    Until the faulty contract is removed, you may be able to suppress contract inheritance using ContractOptionAttribute as follows, though I haven't tested this myself.

    [ContractOption("contract", "inheritance", false)]
    public override void Initialize(string name, NameValueCollection config)
    {
        ...
    }

    Note that ContractOptionAttribute isn't defined in .NET 4.0; however, it's defined in .NET 4.5.  To use it in .NET 4.0, you must add its definition yourself.  The easiest way is to simply copy the following file into your project:

    C:\Program Files (x86)\Microsoft\Contracts\Languages\CSharp\ContractExtensions.cs

    You'll find more details in the Contracts User Manual, §4.8.  The manual is installed with Code Contracts, or you can download it here.

    - Dave


    http://davesexton.com/blog

    • Marked as answer by Taffarel Sunday, December 23, 2012 5:51 PM
    Sunday, December 23, 2012 1:06 PM
  • Dude, you rock! That totally worked! I figured there must be some kind of bug here, I've been banging my head on it for like 3 days. I didn't know there was a way to ignore the contract, that's the missing piece that I needed! Thanks so much!

    Sunday, December 23, 2012 5:51 PM
  • I also hit this problem and your solution worked.  Is there a connect page or something we can use to help incentivize the fixing of this issue?
    Tuesday, February 17, 2015 6:57 PM