Rolling Forward to Major Versions in .NET

By admin
๐Ÿ˜›

On this page:

I’m currently playing around with .NET

8
CARDINAL

RC Preview release and upgrading several of my applications to run under .NET

8
CARDINAL

both Web server and

Desktop
ORG

based. In my early testing, moving those applications to .NET

8
CARDINAL

has been very much a painless operation with

zero
CARDINAL

required changes and only a few warnings/obsolescence related issues that had to be addressed. Nice!

But – especially for my desktop applications – I wanted to start running the existing .NET

7
CARDINAL

targeted applications under the .NET

8.0
CARDINAL

preview to see if I’d run into any issues in day to day operations without fully converting or re-targeting the applications to .NET

8.0
CARDINAL

.

Turns out .NET has the ability to define a

RollForward
ORG

policy that lets you move an application to a newer version than it was compiled under. You can specify this value in the .csproj file using a <

RollForward
ORG

>Minor</RollForward> key in the <PropertyGroup> section.

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net7.0-windows</TargetFramework> <RollForward>LatestMajor</RollForward> <PropertyGroup> </Project>

Here are the options you can specify for

RollForward
ORG

(from

Microsoft
ORG

):

Value Description Minor Default if not specified.

Roll-forward to the lowest higher minor version, if requested minor version is missing. If the requested minor version is present, then the

LatestPatch
ORG

policy is used. Major Roll-forward to the next available higher major version, and lowest minor version, if requested major version is missing. If the requested major version is present, then the

Minor
ORG

policy is used.

LatestPatch Roll
ORG

-forward to the highest patch version. This value disables minor version roll-forward.

LatestMinor Roll
ORG

-forward to highest minor version, even if requested minor version is present.

LatestMajor Roll
PERSON

-forward to highest major and highest minor version, even if requested major is present. Disable Don’t roll-forward, only bind to the specified version. This policy isn’t recommended for general use since it disables the ability to roll-forward to the latest patches. This value is only recommended for testing.

The

Minor
ORG

default is sensible – it basically tries to find the next higher minor version installed, if any.

LastestMinor
ORG

on the other hand will find the latest higher minor version installed.

In my scenario however, I want to roll forward the lastest major version, so for my scenario I’d want to use

LatestMajor
PERSON

, which effectively says – use the latest version of

the .NET Core
PRODUCT

runtime available.

So my app is compiled to .NET

7.0
CARDINAL

but I would like to run on the .NET

8.0
CARDINAL

RC, so I expected the following to work:

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <Title>Markdown Monster</Title> <Version>3.0.4.1</Version> <TargetFramework>net7.0-windows</TargetFramework> <RollForward>LatestMajor</RollForward> … <PropertyGroup> … </Project>

You can also use the –roll-forward command line option to specify the roll forward mode at runtime or set these modes in an optional global.json of your project. More info here)

It turns out that does not work. The above does not roll forward to the .NET

8.0
CARDINAL

RC Preview and the application continues to run under .NET

7.0
CARDINAL

.

The problem is that the current release is net8.0.0-rc-123419.4 which is a pre-release version, and preview releases are excluded from automatic roll forward operations.

To make

RollForward
ORG

work with a pre-release version an additional step is needed: It involves creating an Environment variable that enables the functionality:

$env:DOTNET_ROLL_FORWARD_TO_PRERELEASE=1 #Run MM MarkdownMonster # or mm

Alternately you can add the environment variable to your machine’s environment settings.

Now with that in place you can launch the pre-release version of .NET

8.0
CARDINAL

RC even though the application is compiled for .NET

7.0
CARDINAL

.


Yay
PERSON

!

Unlike the <

RollForward
ORG

> project option which is project specific and can be compiled in, the DOTNET_ROLL_FORWARD_TO_PRERELEASE is an add-on to the <

RollForward
ORG

> project flag that is externally applied. The environment variable has no effect unless <

RollForward
ORG

> behavior is enabled in the

first
ORDINAL

place, so it doesn’t all of a sudden roll forward any .NET Core application to .NET

8.0
CARDINAL

.

Running a Preview Rollforward Release? Is this a good idea?

For a production application this obviously not a great idea. But since you can only enable roll forward to a pre-release version with an environment variable, users who want to try this would have to be pretty explicit in doing this.

That said, I’ve found that the last few .NET Core releases have been very good about not breaking existing functionality, so I’ve felt pretty comfortable running applications using preview releases, at least locally for myself.

And true to form .NET

8.0
CARDINAL

RC doesn’t disappoint!

I have

3
CARDINAL

separate desktop applications that are in production and all of those are running fine on .NET

8.0
CARDINAL

with

RollForward
ORG

. I’ve also ported

2
CARDINAL

production server apps (actual port to net8.0 rather than

RollForward
ORG

) also with no changes required and no apparent issues. All apps informally show some light perceived performance improvements.

However,

one
CARDINAL

of my desktop/cli apps that is performance centric – West Wind WebSurge – is seeing a robust performance boost and resource reduction running under .NET

8.0
CARDINAL

. Because this application is using a lot of resources and running many operations in parallel for stress testing, the perf improvements in the framework are more pronounced.

Side Effects

updated a while after

I did run into

one
CARDINAL

problem with

Roll Forward
ORG

behavior at least with the current RC preview:

I noticed that running the app with the debugger attached, any call to Process.Start() was hard crashing the application with a ExecuteEngineException . Turns out I ran into a bug in .NET

8.0
CARDINAL

RC1.

And that neatly describes the possibility of problems you can run into, especially with pre-release builds. In this case it was an outright bug, but in other cases it can simply be a slight change to an

API
ORG

interface (new or changed overloads for example) or a slightly different implementation. That’s always a risk you take when running previews.

But the advantage of running this way is that you get a crack at front-running any potential issues, and if you find a bug or issue in your very specific application scenarios, being able to report it before an RTM release goes out the door.

In this case, the bug is already fixed for RC2 so somebody else was way ahead of me ๐Ÿ˜„

Doing it right: Migrate to .NET

8.0
CARDINAL

proper

The right way to do this is to actually take the applications and properly target them to net8.0 for each project.

As a matter of fact, I did that with

Markdown Monster
ORG


first
ORDINAL

, to ensure that there weren’t any obvious API difference in the framework libraries. Just be forewarned, that you may end up having to re-target multiple projects. At minimum all top level projects, and if you want to do it right probably also your child projects. In

Markdown Monster’s
ORG

case this involves:

The main EXE project


3
CARDINAL

Addin Projects


2
CARDINAL

Test Projects


2
CARDINAL

CLI Projects


2
CARDINAL

Support libraries that are compiled in

So, to do this right is not a

5 minute
TIME

affair. But if you stick to the top level project(s) you can get this done fairly quickly.

The re-targeting allows the compiler to find actual runtime call changes, but neither

Markdown Monster
PRODUCT

or

WebSurge
PRODUCT

including their compiled dependencies showed any hard API breaks, although there were a few additional warnings related to crypto APIs and deprecated old Http clients that were not flagged in previous versions.

Once compiled I can easily run the application under .NET

8.0
CARDINAL

preview and that works fine without any

RollForward
ORG

semantics at all. Prim and proper and all!

So, why use

RollForward
ORG

?

So why not compile for .NET

8.0
CARDINAL

and ship that in the

first
ORDINAL

place?

Well, I didn’t want to wait until

November
DATE

when .NET

8.0
CARDINAL

officially ships – until then the runtimes are in

Preview
ORG

, and for commercial software installation, it wouldn’t be appropriate to install a preview version of the runtime.

By using the above

RollForward
ORG

plus an Environment variable, I can set up my environment locally to run on .NET

8.0
CARDINAL

, while leaving all the old .NET

7.0
CARDINAL

runtime compilation and behavior for the release version in place. It gives me a chance to test, and also some of my more enthusiastic users to do the same and report any issues they might be running into. I can point them at directions on how to run on a preview version of .NET as described in the

MM
PERSON

documentation.

When .NET

8.0
CARDINAL

ships RTM, the

RollForward
ORG

directive automatically kicks in and so if .NET

8.0
CARDINAL

(released) is installed on the machine it’ll automatically be used.

By then however I would also have a newer version of the software that’s explicitly compiled for .NET

8.0
CARDINAL

, so this would only apply to users who haven’t upgraded, but then could still take advantage of the improved features of a new runtime.

Summary

You have to appreciate that .NET supports the ability to specify how applications roll forward with so many options. And also appreciate that understanding all the different combinations are going to take

a minute
TIME

to figure out and which one is appropriate for your specific scenario.

But I’m very happy that I’m able to keep creating releaseable builds for .NET

7.0
CARDINAL

that I can also run on the latest unreleased version of .NET, without having to manage to separate compilation targets, until I’m ready for it when .NET

8.0
CARDINAL

goes RTM.

When .NET

8.0
CARDINAL

gets closer to release I’ll switch over all projects to .NET

8.0
CARDINAL

and update libraries etc. for a complete upgrade. But for now I can use my tools as is on the new version of .NET…

Resources