15

In most (if not all) C# (and F# and VB) library and executable projects created in Visual Studio there is an automatically added app.config file that specifies runtime version and target framework moniker (TFM):

<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
. . .

Even absent the app.config file entirely, the compiler seems to always generate an assembly-level attribute, as ILDASM shows:

.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01    // ....NETFramework
                                                                                                      ..    // ,Version=v4.6.1.
                                                                                      bytes snipped-> ..    // .T..FrameworkDis
                                                                                                      ..    // playName..NET Fr
                                                                                                      61  ) // amework 4.6.1

The .csproj file does specify the target frameworks, and my guess this is where the target is passed from on to the compiler during build.

The executable seems to run just fine without the <startup> section in the config file. The documentation explains what do the attributes mean, but, seeing them for many years, I never understood why they are needed in the configuration file. I mostly dealt with desktop applications for Windows, however.

This answer explicitly states that “making a program compiled to target .NET 4.0 behave like it runs on a higher version is not possible,” and I would be really surprised if, conversely, running a program on a lower version of the framework were also possible.

So, under what scenarios does the application developer need to specify the version and TFM of the runtime in the .config file of the application, and does it have to always duplicate information that is hardcoded into the binary by the compiler? The requirement seems counterintuitive at first sight.


UPDATE 2018-06-29: X-ref: I asked for a clarification of the documentation in the GitHub issue dotnet/docs#6234.

  • To me the design seems to be "reserving something for the future". The information hardcoded into the binaries is impossible to change, but sometimes Microsoft might need to present a way to developers to change the runtime behaviors (I could not name a concrete case, but runtime version dependent behaviors are common in .NET Framework), where they can simply modify the SKU in `app.config` (and in that case the two are not duplicate any more). – Lex Li Mar 03 '19 at 17:26

2 Answers2

3

It's needed to declare which framework versions your application is actually compatible with. Suppose, we have an application that targets .NET Framework 4.7.2 and try to run it on the machine that have only .NET Framework 4.5 installed. If we add this app.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>

Windows will show a nice error message that asks to install needed framework version:

error message

If we omit the app.config, Windows will try to run it and then application will crash first time it hits a feature specific to .NET Framework 4.7.2 and absent in installed framework version.

Note that documentation is misleading in saying that "This element should be used by all applications built with version 1.1 or later of the .NET Framework". It might be interpreted as "This element is required for application to run on .NET 1.1+", while in reality it only means that .NET 1.1 changed a syntax from previosly used in .NET 1.0 requiredRuntime syntax. More often then not supportedRuntime is NOT required for application to run, it's just for prettiness.

One common scenario when supportedRuntime is really needed for application to run is when we have application targeting .NET 2.x-3.x and try to run it on machine that have only 4.x (for example, Windows 10 have 4.6+ but does not have .NET 2.x-3.x installed by default). In this case, without supportedRuntime in app.config the application won't run at all, even though 4.x is mostly compatible with previous versions. Adding <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" /> will fix the issue.


So, to sum up, it does not duplicate the information in assembly metadata, but rather give Windows additional information on how to connect application with framework version it is compatible with, and what version to ask user to install if it's not present on target machine.

MSDN.WhiteKnight
  • 664
  • 7
  • 30
  • “supportedRuntime is […] needed for application to run is when we have application targeting .NET 2.x-3.x and try to run it on machine that have only 4.x”--this is remarkable. Looks like the attribute in the app.config *overrides* the assembly-level attribute (assuming the old tooling also embedded the TargetFrameworkAttribute). The behavior with the download prompt is baffling; looks like the initial exe loading process (which is mysterious to me, really) picks the target version from app.config, but ignores the TargetFrameworkAttribute in the same assembly. *Interesting* design decision… – kkm inactive - support strike Mar 31 '20 at 10:34
  • When 4.8 is installed, but not 4.7.2, this would show the above dialog and fail anyway. So the attribute feels somewhat useless. – JB. Sep 23 '22 at 09:26
  • @JB. In my tests it does not seem to be the case. I have 4.8 installed too, but if i try to run app that targets 4.7.2 in app.config, it runs just fine. If you see error, it's probably caused by some local issue with .NET Framework installation. – MSDN.WhiteKnight Sep 24 '22 at 18:18
0

The targetFramework attribute primarily determines the .NET Framework to be used for compilation purposes. It is also used to determine compatibility for referencing .NET libraries (DLLs). However, a question arises when you distribute your .NET project as an app and deploy it on some other computer. The question is "what happens if the target computer does not have the .NET Framework version installed used during compilation?". That's where the supportedRuntime element has some significance. The first version matching in a list of supportedRuntime elements will be used to run the app. If none of the versions in the supportedRuntime elements match with the installed version(s) on the target computer then the latest version of the framework will be used to run the app.

I hope this explanation answers your question.

Tanveer Yousuf
  • 386
  • 1
  • 3
  • 16