Print and/or modify the c# version that the razor compiler service uses to compile cshtml
Asked Answered
L

1

15

I'd like to be able to find out which C# version razor uses to compile my cshtml templates. The reason why I want this, is this breaking change.

We had a lambda in a foreach statement that worked fine on our local dev machines but produced a bug on our test environment (which doesn't have C# 5 installed). This bug was VERY hard to debug (we even copied all the test environment DLLs and databases and were still not able to reproduce the bug).

So to prevent this dev/test difference in the future I would like to know if there's a way to specify the C# version that razor should be using to compile cshtml files. It would also be nice if I could check the C# version that razor uses (by printing it).

Update: As requested, more details on how this behavior occurred.
We use a devexpress mvc grid to display data in our razor views. To add columns in a dynamic way we loop (foreach) a list which inserts columns in the datagrid (using a lambda). A simplified example:

@Html.DevExpress().GridView(
    settings =>
    {
        settings.Name = "gvDashboard";
        //Some more settings

        settings.Columns.Add(column =>
        {
            column.FieldName = Model.DashboardItems.PropertyName(p => p.Id);
            column.Caption = "Id";
            //Some more column settings
        });

        foreach (var extraColumnLoopVar in Model.ExtraColumns)
        {
            //We added this to solve the problem
            var extraColumn = extraColumnLoopVar; 

            settings.Columns.Add(column =>
            {
                column.Caption = extraColumn.Name;
                //Some more column settings

                column.SetDataItemTemplateContent(content =>
                {
                    Html.ViewContext.Writer.Write(extraColumn.MyValue);
                });
            });
        }
    });
Limit answered 24/2, 2014 at 15:26 Comment(3)
I am curious what use of the loop closing you are depending on. As the article mentions, it's something rarely actually used. So I am genuinely curious to view such a use case.Bleach
Thanks for taking the time to update your question. I thought you actually used the closure variable behaviour, but rather you ran into the issue where you don't want to use it. Looks like this is gonna bite a lot of ppl who are not aware of the different behaviour in soon-to-be-legacy setups. I did learn about this breaking change thanks to your question ;)Bleach
You're right, I over simplified the example. I do use the value and in C# 4 it ended up with the same (last) value for each column. PS. I'm glad you learned from it :).Limit
P
5

The version of razor is specified on the Web.config file within the Views directory. It has to match one of the versions on the dependent assemblies list for the System.Web.WebPages assembly. This entry is on the main Web.config file (usually located at the root of your application tree)

Retrieving data from config files is fairly simple. See the ConfigurationManager class for this. If you'd like to do it at runtime.

It's also possible to determine the Razor version based on the referenced assemblies of your application. You could use reflection for that, here's a snippet that spits out all the referenced assemblies:

var sb = new StringBuilder();
Assembly asm = Assembly.GetExecutingAssembly();
sb.AppendLine("File Version:");
sb.AppendLine(asm.FullName);

sb.AppendLine("References :");
AssemblyName[] asmNames = asm.GetReferencedAssemblies();
foreach (AssemblyName nm in asmNames)
{
    sb.AppendLine(nm.FullName);
}

// use sb.ToString() to print out wherever you need to

Obviously there might be performance implications based of the method you choose to evaluate this info at runtime.

Update 1

From the comments below I take that when you mention compilation you refer to the Razor view parsing process at compile time. There are other concepts of "Razor View Compilation" see Razor Generator, regardless of which one you do mean both rely on the reference to the System.Web.WebPages assembly which contains the library dependencies for the Razor View Engine itself. So if you know which assembly you are pointing at, you know which version of Razor you are using.

Update 2

Taking into account that you are worried about conflicts with the version of C# that you use in your views, you should use the following rule of thumb: You should always reference the DLL (System.Web.WebPages) that targets the framework you are using. It's important to remember that the MVC framework has a different update timeline than the language itself. A good example is the async keyword, it was added to the language first and later adopted by the MVC framework. Usually new versions of the .NET Framework are backwards compatible 'til version 2.0 and when you use deprecated stuff you get compilation warnings. If you'd like to use older versions of the framework while compiling you can always resort to changing the target framework on your IDE.

In addition to getting your references and target framework right, remember that when you setup Web applications in IIS you specify an application pool tied to the framework version. You might be using new features of the .NET framework, and you might expect for them to work because you have the new version installed, but your application is running in an application pool of a different version.

Before having this nasty mixup between DLL & Frameworks versions I'd follow upgrade guidelines taking into account that some of the code I implemented with the previous version might not work properly with the new one.

Update 3

Here's some code to retrieve your CLR version at Runtime as described in MSDN.

// Get the common language runtime version.
Version ver = Environment.Version;
Console.WriteLine("CLR Version {0}", ver.ToString());
Plumbaginaceous answered 27/2, 2014 at 16:50 Comment(14)
Yes this way I could get/set the version of Razor, but does this relate to the C# version razor uses to compile my views?Limit
How are you compiling your views exactly?Salvidor
Regardless of the way you compile them, your views must use the same dll everywhere. So I don't understand your question.Salvidor
It's not about dlls, it's the way razor compiles c# to binary which causes the problem (see the breaking change link in the OP). Razor uses it's own compiler service component to compile the views on the fly.Limit
After reading your update, what do you mean by 'Compile time'. Since my csharp code files are compiled at compile time and my razor views are compiled at runtime. To clearify this even more: I don't care which Razor version is used, I only care about the C# version that is used (I want my views to be compiled in C# 4 and not C# 5).Limit
Application pools are the solution on the server and the targeted framework on your IDE must help to solve this type of issues.Salvidor
The OP is talking about the version of the C# compiler, not the version of the .NET Framework or the version of ASP.NET MVC.Bodine
The C# compiler is tied to the version of the framework.Salvidor
AFAIK this is not true, you can mix newer C# versions with older .Net version. See also csharpindepth.com/Articles/Chapter1/Versions.aspx. You give a lot of pointers in your answer, I will try these in the upcoming week and report back my findings.Limit
You can use older features in newer versions. If there's a conflict or a deprecated feature you'll get a compiler warning. On the project properties in VS you can change the compiler you're using by changing the target framework, taking into account that if you choose an older framework the newer features won't work properly.Salvidor
A good example would be changing your target framework to 2.0 and trying to compile a source file containing Linq code or implicit type (var) declarations.Salvidor
I'm working with this on my local machine atm. I created a console app, set the .Net framework to 3.5 and C# version to 3. The compiler will complain about newer .Net libs and C# features (such as optional params) but when I check the behavior of closing vars in lambda's I still get C# 5 behavior... See pastebin.com/ykBPvAGQ for the code I usedLimit
This code doesn't compile when I try to replicate your scenario. What type of behavior are you getting?Salvidor
Remove the optional params method (it's there to ). I get behavior that indicates that the code is compiled in C#5, (see the comments)Limit

© 2022 - 2024 — McMap. All rights reserved.