views:

364

answers:

3

I'm creating an ASP.NET MVC application using F# on IIS 7.

When I attempt to run it from the browser, I'm met with a YSOD containing the following:

[ArgumentNullException: Value cannot be null. Parameter name: dictionary]
System.Collections.Generic.Dictionary2..ctor(IDictionary2 dictionary, IEqualityComparer`1 comparer) +12700827
System.Web.Compilation.CompilationUtil.CreateCodeDomProviderWithPropertyOptions(Type codeDomProviderType) +84
System.Web.Compilation.CompilationUtil.CreateCodeDomProviderNonPublic(Type codeDomProviderType) +16
System.Web.Compilation.AssemblyBuilder..ctor(CompilationSection compConfig, ICollection referencedAssemblies, CompilerType compilerType, String outputAssemblyName) +469
System.Web.Compilation.CompilerType.CreateAssemblyBuilder(CompilationSection compConfig, ICollection referencedAssemblies, String generatedFilesDir, String outputAssemblyName) +127
System.Web.Compilation.BuildProvidersCompiler.ProcessBuildProviders() +675 System.Web.Compilation.BuildProvidersCompiler.PerformBuild() +46 System.Web.Compilation.ApplicationBuildProvider.GetGlobalAsaxBuildResult(Boolean isPrecompiledApp) +11321455
System.Web.Compilation.BuildManager.CompileGlobalAsax() +50 System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled() +872

I looked up the method using Reflector to see if it could give me any more context and found that it was failing on the first line

private static CodeDomProvider CreateCodeDomProviderWithPropertyOptions(Type codeDomProviderType)
{
IDictionary<string, string> providerOptions = new Dictionary<string, string>(GetProviderOptions(codeDomProviderType));
//Snip
}

It leads me to believe that the propertyOptions I've specified in my Web.config for the F# CodeDom are incorrect. However, if I remove them I receive the same error.

<system.codedom>
 <compilers>
  <compiler language="F#;f#;fs;fsharp" extension=".fs" warningLevel="4" 
            type="Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider, 
                  FSharp.Compiler.CodeDom">
    <providerOption name="CompilerVersion" value="v4.0"/>
    <providerOption name="WarnAsError" value="false"/>
  </compiler>
 </compilers>
</system.codedom>

Any ideas on correcting this error?

+4  A: 

It’s a bug in ASP.NET in VS2010 Beta2 (it has since been fixed, so will work in next release). It affects any 3rd party CodeDOM provider, and I don’t believe there is any workaround.

Brian
Any documentation on this bug?
statenjason
All I have is internal emails/bug info at Microsoft, dunno if there is e.g. a public-facing Connect bug. I did find some conversation that says that supplying "CodeDomProvider.FileExtension" might work around it. I know next to nothing about ASP.Net, but maybe that means something to you?
Brian
Thanks for the mentioning of the FileExtension. I did some digging and found out the usable file extensions are hardcoded and don't include "fs". I've explained in more detail in my answer.
statenjason
A: 

Perhaps the bug Brian noted can be worked around by specifying some more info in web.config:

type="Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider, 
      FSharp.Compiler.CodeDom,
      Version=1.9.7.8, 
      Culture=neutral, 
      PublicKeyToken=a19089b1c74d0809"
Chris R. Timmons
Gave it a shot. Same result.
statenjason
+3  A: 

I found the cause to the problem.

The Microsoft.FSharp.Compiler.CodeDom.FSharpAspNetCodeProvider.FileExtension is hardcoded to "fs".

Inside of System.CodeDom.Compiler.CodeDomCompilationConfiguration..ctor() CompilerInfos are created for each of the allowed languages. A CompilerInfo for FSharp is not found within the creation of this.

internal CodeDomCompilationConfiguration()
{
this._compilerLanguages = new Hashtable(StringComparer.OrdinalIgnoreCase);
this._compilerExtensions = new Hashtable(StringComparer.OrdinalIgnoreCase);
this._allCompilerInfo = new ArrayList();
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.WarningLevel = 4;
string codeDomProviderTypeName = "Microsoft.CSharp.CSharpCodeProvider, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
CompilerInfo compilerInfo = new CompilerInfo(compilerParams, codeDomProviderTypeName);
compilerInfo._compilerLanguages = new string[] { "c#", "cs", "csharp" };
compilerInfo._compilerExtensions = new string[] { ".cs", "cs" };
compilerInfo._providerOptions = new Dictionary<string, string>();
compilerInfo._providerOptions["CompilerVersion"] = "v4.0";
this.AddCompilerInfo(compilerInfo);
compilerParams = new CompilerParameters();
compilerParams.WarningLevel = 4;
codeDomProviderTypeName = "Microsoft.VisualBasic.VBCodeProvider, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
compilerInfo = new CompilerInfo(compilerParams, codeDomProviderTypeName);
compilerInfo._compilerLanguages = new string[] { "vb", "vbs", "visualbasic", "vbscript" };
compilerInfo._compilerExtensions = new string[] { ".vb", "vb" };
compilerInfo._providerOptions = new Dictionary<string, string>();
compilerInfo._providerOptions["CompilerVersion"] = "v4.0";
this.AddCompilerInfo(compilerInfo);
//Snip
}

The FileExtension is compared against _compilerExtensions in System.CodeDom.Compiler.CodeDomProvider.GetCompilerInfoForExtensionNoThrow which (in the case of "fs") returns null to System.CodeDom.Compiler.CodeDomProvider.IsDefinedExtension which will then return false to System.Web.Compilation.CompilationUtil.GetProviderOptions that returns the null that was causing the ArgumentNullException.

Thanks for pointing me in the right direction, @Brian

statenjason
Thats pretty bizzare although i'm sure there is a method to the madness of hardcoding extensions.
AboutDev