Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# 7 tuples not working (roslyn compiler exception)

For some time we're using some of the new c# 7.0 features in our razor files. We've integrated the Roslyn compiler into our web projects, which are currently targetting .NET Framework 4.6.2.

Today I wanted to try out the tuples in a razor file, like so:

@functions
{
    public (string labelName, string sfName) GetNames(PurchaseType purchaseType)
    {
        switch (purchaseType)
        {
            case PurchaseType.New:
                return (labelName: Booklist.New, sfName: SpecflowIdentifiers.BooklistItem.CheckBoxNew);
            case PurchaseType.Rental:
                return (labelName: Booklist.Rent, sfName: SpecflowIdentifiers.BooklistItem.CheckBoxRental);
            case PurchaseType.SecondHand:
                return (labelName: Booklist.Secondhand, sfName: SpecflowIdentifiers.BooklistItem.CheckBoxSecondHand);
            default:
                throw new ArgumentOutOfRangeException(nameof(purchaseType), @"should not get here");
        }
    }
}

@helper RenderCheckbox(PurchaseType purchaseType, int index, decimal priceTo)
{
    var names = GetNames(purchaseType);
    var x = name.labelName;
    // render something
}

This produces the following runtime exception:

CS8137: Cannot define a class or member that utilizes tuples because the compiler required type 'System.Runtime.CompilerServices.TupleElementNamesAttribute' cannot be found. Are you missing a reference?

CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported

This led me to https://stackoverflow.com/a/40826779/2772845 which mentions that I should add the System.ValueTuple package to the project. But I've already got that added.

These are the packages used in the config:

<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.8" targetFramework="net462" />
<package id="Microsoft.Net.Compilers" version="2.4.0" targetFramework="net462" developmentDependency="true" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net462" />

So, I'm back to using the old Tuple<> right now. I'd like to know if anyone knows what I'm overlooking.

Edit 11/16/2017:

So I've altered the public (string labelName, string sfName) GetNames(PurchaseType purchaseType) into public ValueTuple<string, string> GetNames(PurchaseType purchaseType) and that gives me the following exception:

CS0433: The type 'ValueTuple' exists in both 'System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' and 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'

And that led me to 'ValueTuple<T1, T2>' exists in both 'System.ValueTuple ...' and 'mscorlib ...' giving the actual answer. I've got .NET Framework 4.7 installed, and since razor is compiled at runtime it just uses that version.

Kind regards, Rick

like image 922
rdvanbuuren Avatar asked Nov 15 '17 10:11

rdvanbuuren


2 Answers

Razor views are compiled at runtime by ASP.Net, and don't automatically inherit references or other settings from your project.

You need to add System.ValueTuple to the ASP.Net runtime compilation in Web.config:

<system.web>
    <compilation>
      <assemblies>
        <add assembly="System.ValueTuple" />
like image 88
SLaks Avatar answered Oct 24 '22 04:10

SLaks


This seems to be good hell of Razor. 1st if you are targeting .NET 4.7 or later, you should not reference System.ValueTuple because all the needed types are already part of mscorlib. But it seems to me that somehow Razor is using the latest version of mscorlib even when you specificallly target e.g. .NET 4.6.2. So it seems to me that at least on system where there is .NET 4.7 installed the solution is actually to remove

 <system.web>
    <compilation>
        <assemblies>
            <add assembly="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"/>

That way you can of course break runtime compilation of your application on servers where .NET 4.7 is missing, or pre-compilation if you use it.

If at least all your servers are in the same status, you can use config transformations.

Also when checking web.configs check both - the root web.config and the web.config in view folder.

If anybody has similar problem with pre-compilation during deployment, so far the only way I managed to solve it was to add the reference to System.ValueTuple to CSC commandline directly like this:

<system.codedom>
    <compilers>
        <compiler extension=".cs" compilerOptions='/langversion:7 /nowarn:1659;1699;1701 /R:"../packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll"' xdt:Locator="Match(extension)" xdt:Transform="SetAttributes" />
    </compilers>
</system.codedom>

In the transformation file for server deployment. This want work for runtime-compilation because it does not have access to ../packages.

like image 1
Đonny Avatar answered Oct 24 '22 04:10

Đonny