Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microsoft.Extensions 3.0 are incompatible with aspnetcore 2.2 #14393

Closed
rockfordlhotka opened this issue Sep 24, 2019 · 39 comments
Closed

Microsoft.Extensions 3.0 are incompatible with aspnetcore 2.2 #14393

rockfordlhotka opened this issue Sep 24, 2019 · 39 comments
Labels
Milestone

Comments

@rockfordlhotka
Copy link

rockfordlhotka commented Sep 24, 2019

Describe the bug

I have a netstandard2.0 class library deployed via NuGet. It depends on Microsoft.Extensions.Configuration and other Extensions packages. I upgraded the dependency references to 3.0.

After this upgrade I can use my class library from aspnetcore 2.1 and aspnetcore 3.0 projects. But I can not use it from aspnetcore 2.2 projects because of version limitations in the Microsoft.AspNetCore.App metapackage. Specifically because all dependencies are bounded to 2.3.0 so 3.0.0 is unavailable.

image

Basically, it appears that aspnetcore 2.2 is broken, at least in terms of using the new .NET Core 3.0 dependencies.

As an open source library author I'm not sure what to do? Force my user base to move from 2.2 back to 2.1? Or forward to 3.0?

I don't see a way to create a NuGet package that supports 2.1, 2.2, and 3.0. I can support 2.1 and 3.0, or I can continue to use the pre-3.0 dependencies and support all three versions of aspnetcore (but obviously only sort of supporting 3.0).

Expected behavior

I would expect that there's some way to create a netstandard2.0 library, put it in a NuGet package, and have it support aspnetcore 2.1, 2.2, and 3.0.

At the very least I hope that the product team thought through this problem space and has a recommended workaround or solution so aspnetcore 2.2 projects aren't just totally broken with the release of 3.0.

Possible workaround

On further research and conversation via Slack, there are a couple workarounds for people using aspnetcore 2.2.

  1. Switch the Microsoft.AspNetCore.App reference to Microsoft.AspNetCore.All because the ".All" metapackage doesn't have the upper bound version limits
  2. Replace the Microsoft.AspNetCore.App reference with references to all the packages you are using in your project (far more work, but provides more control)
@poke
Copy link
Contributor

poke commented Sep 24, 2019

If you want to support all of ASP.NET Core 2.1, 2.2 and 3.0, then your best bet is to cross-target netstandard2.0 and netcoreapp3.0.

ASP.NET Core 3.0 only runs on netcoreapp3.0, so you can make that build exclusive to this version. This also allows you to conditionally reference the framework reference for ASP.NET Core (so you can depend on its stuff).

For ASP.NET Core 2.1 and 2.2, you target netstandard2.0 and reference the 2.1 packages. This unfortunately means that you cannot depend on features that were introduced with 2.2 but that is going to run out of support in a few months anways (while 2.1 stays relevant).

So you would do it like this:

<PropertyGroup>
    <TargetFrameworks>netcoreapp3.0;netstandard2.0</TargetFrameworks>
    …
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
    <!-- Just reference the full framework -->
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0">
    <!-- Reference what you need -->
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0" />
</ItemGroup>

For Microsoft.Extensions.*, you will effectively be limited to 2.x packages with ASP.NET Core 2.x. Even if the 3.0 versions still target .NET Standard 2.0, ASP.NET Core is built against 2.x, so you will need that for compatibility.

@rockfordlhotka
Copy link
Author

Thank you @poke . I'm not 100% sure that works for me, but I might try it.

My issue is that my library has nothing at all to do with ASP.NET or WinForms/WPF/UWP/etc. That's why it targets netstandard2.0, because it is entirely platform/runtime neutral.

Creating a targeted version seems like a major step backwards. Before netstandard2.0 I was building 11 different versions of the library for all the flavors of .NET. I surely hope we're not headed back to THAT nightmare!!

@Pilchie
Copy link
Member

Pilchie commented Sep 24, 2019

@DamianEdwards was looking at writing some guidance for library authors here I believe.

@davidfowl
Copy link
Member

I don't see a way to create a NuGet package that supports 2.1, 2.2, and 3.0. I can support 2.1 and 3.0, or I can continue to use the pre-3.0 dependencies and support all three versions of aspnetcore (but obviously only sort of supporting 3.0).

What @poke says is correct. You have 2 options:

  • Target the lowest version that works in all cases (2.1) OR
  • Multi target

.NET Standard doesn't solve anything here and is unrelated to this specific issue. Library authors will always need to make this choice and this isn't a new problem nor is it unique to .NET.

@mkArtakMSFT mkArtakMSFT added this to the Discussions milestone Sep 25, 2019
@rockfordlhotka
Copy link
Author

Thank you @davidfowl.

My concern is partly for me, but also for anyone consuming NuGet packages.

What I am hearing is that people who've been focused on getting their old .NET Framework code into netstandard2.0 libraries are now in for a shock, because their libraries just became problematic, and most people will need to start multitargeting.

Here's a common scenario:

  1. Web site - dotnetcore 2.1 or 2.2
  2. Business library (model, rules, etc) - netstandard2.0
  3. Data access layer - netstandard2.0

And let's assume each of those uses some common NuGet packages (in my case they might each reference Csla), and that NuGet package is netstandard2.0 and in turn references Microsoft.Extensions.* packages.

If I understand you correctly, my new Csla package must include 2 binaries - a netstandard2.0 one and a netcore3.0 one. In this case the existing code for an enterprise app keeps working, because it keeps using the netstandard2.0 binary and dependencies.

But if I start migrating my web site from 2.x to 3.0, and can't "big bang" migrate, then I'm stuck (as an enterprise dev) multitargeting all my stuff too:

  1. Web site - netcore3.0
  2. Business library (model, rules, etc) - netcore3.0
  3. Data access layer - netcore3.0

Because if all my DLLs don't target netcore3.0 then I won't get the netcore3.0 versions of the binaries out of the Csla package.

I'm not saying this is good or bad - I'm just trying to figure out how much of a mess everyone is in, and what guidance we need to provide as people consider moving to 3.0 (or not).

@davidfowl
Copy link
Member

If I understand you correctly, my new Csla package must include 2 binaries - a netstandard2.0 one and a netcore3.0 one. In this case the existing code for an enterprise app keeps working, because it keeps using the netstandard2.0 binary and dependencies.

Not really no. You don't need to target netcoreapp3.0 unless you're trying to use new features in netcoreapp3.0 (or if you end up hitting a breaking change between versions). The library author guidance is usually to target the lowest version that satisfies where you need to run. You only end up needing to multi-target when you want to take advantage of new functionality in the newer version or if you run into something truly incompatible between the 2 versions.

Because if all my DLLs don't target netcore3.0 then I won't get the netcore3.0 versions of the binaries out of the Csla package.

That's not true. You don't need to target everything to netcoreapp3.0 to get the netcoreapp3.0 assembly from a single binary. You just need to change the main application (in the above example Web Site)

@rockfordlhotka
Copy link
Author

Yeah, I'm confused.

  1. Web app - netcore3.0 - references Csla.dll (nc3)
  2. Business library - netstandard2.0 - references Csla.dll (ns2)
  3. Data access library - netstandard2.0 - references Csla.dll (ns2)

Which Csla.dll is actually used at runtime? And which set of dependencies are used at runtime? In other words, which Microsoft.Extensions.* is actually used, given that one Csla.dll references/uses the 3.0 versions and the others use the 2.2 versions?

@rockfordlhotka
Copy link
Author

Or given that Csla.dll doesn't currently use any 3.0 features, does that mean I should just skip 3.0 entirely and continue to focus exclusively on 2.x dependencies?

Which works except that when referenced in an aspnetcore 3.0 project I get warnings that Razor is being downgraded (for example) - I assume because older dependencies are used in business/DAL assemblies and drag back the aspnetcore3.0 project's dependencies?

@davidfowl
Copy link
Member

Seems like something is missing from the picture. Is Csla.dll in a package? If it is then what target frameworks does it target?

Or given that Csla.dll doesn't currently use any 3.0 features, does that mean I should just skip 3.0 entirely and continue to focus exclusively on 2.x dependencies?

Sure you can skip 3.0 if you want the package to work on 2.x and 3.x without having to multitarget.

Which works except that when referenced in an aspnetcore 3.0 project I get warnings that Razor is being downgraded (for example) - I assume because older dependencies are used in business/DAL assemblies and drag back the aspnetcore3.0 project's dependencies?

Show me the warning, it usually prints out the graph where the conflict occurs.

@rockfordlhotka
Copy link
Author

Csla.dll is in a package, and it targets .NET 4, 4,5, 4.6.1, and netstandard2.0.

I was rather hoping never to have to target a specific platform variant of .NET again, slowly dropping the .NET Framework ones and ending up supporting purely netstandardX.X over time. The primary use of CSLA is to create reusable cross-platform assemblies that contain all business logic. But I do use configuration and dependency injection, which is what got me into this mess, because that seems to have intertwined me with unforseen platform variations of .NET Core 😢

Right now I released CSLA 5 targeting Microsoft.Extensions.* 3.0, which appears to work fine for .NET Core 2.1 and 3.0 - and 2.2 if you switch from Microsoft.AspNetCore.App to Microsoft.AspNetCore.All.

I'll recreate a branch that targets extensions 2.x and get you the warning I was seeing from aspnetcore 3.0.

@davidfowl
Copy link
Member

I was rather hoping never to have to target a specific platform variant of .NET again, slowly dropping the .NET Framework ones and ending up supporting purely netstandardX.X over time. The primary use of CSLA is to create reusable cross-platform assemblies that contain all business logic. But I do use configuration and dependency injection, which is what got me into this mess, because that seems to have intertwined me with unforseen platform variations of .NET Core 😢

That a noble goal and I don't see why you can't do that. You just need to never upgrade your dependencies 😄, that's how you stay compatible.

Being netstandard doesn't say anything about the version of your dependencies. The latest version of JSON.NET supports .NET standard but it doesn't mean that it'll work with ASP.NET Core 1.x or 2.x or 3.x.

Does that make sense?

@rockfordlhotka
Copy link
Author

I guess my problem is that I see no way to ever upgrade the dependencies, and that worries me. I'll be trapped at 2.x forever right?

Well, until there's a newer version of netstandard I can target, and then maybe I'll be able to update dependencies at that point.

This just seems like a slow motion disaster happening in front of my eyes as everyone is trapped in the past or forced to abandon netstandard entirely.

Is that the goal? For us just to abandon netstandard and move everything to netcore3.0, netcore5.0, etc?

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 25, 2019

Doesn't this put you in a bad spot too?

What happens when aspnetcore3.5 (for example) uses Microsoft.Extensions.Configuration 3.5, and that version is incompatible with version 2.2?

So then every assembly targeting netstandard2.0 and using configuration 2.2 (the latest possible) can no longer be used by this updated website?

Right now I'm assuming (!!) that all the extensions 3.0 are backward compatible with the 2.2.0 or 2.2.4 versions that exist, so we can host all our pre-existing libraries in an aspnetcore3.0 web project right? At runtime I assume the only version of Microsoft.Extensions.Configuration that loads is the 3.0 one, so all our code is using that newer binary but with the older API right?

Or better yet, the DI library - where we assume one services collection, regardless of whether we added our services via the 2.2 API or the 3.0 API or the (future) 3.5 API that is no longer binary compatible?

@davidfowl
Copy link
Member

I guess my problem is that I see no way to ever upgrade the dependencies, and that worries me. I'll be trapped at 2.x forever right?

As long as the places where you want to run how lower or equal dependencies then no, you can't upgrade.

Well, until there's a newer version of netstandard I can target, and then maybe I'll be able to update dependencies at that point.

That's right.

This just seems like a slow motion disaster happening in front of my eyes as everyone is trapped in the past or forced to abandon netstandard entirely.

Is that the goal? For us just to abandon netstandard and move everything to netcore3.0, netcore5.0, etc?

I think you're still missing something. Imagine a world where there is no more netstandard and we just had .NET Core. We'd be having the EXACT same discussion but instead of netstandard versions, we'd be discussing .NET Core versions and which ones CSLA wants to support.

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 25, 2019

I think you're still missing something. Imagine a world where there is no more netstandard and we just had .NET Core. We'd be having the EXACT same discussion but instead of netstandard versions, we'd be discussing .NET Core versions and which ones CSLA wants to support.

I can totally imagine it. That was 2-3 years ago when my Csla package included 11 different versions of the assembly for all the variations of .NET that existed at the time.

I guess I'm just at Stage 4 with my grief as I work to reconcile myself to the reality that the past was prologue, and the future is lots of versions of Csla.dll in the package again.

@davidfowl
Copy link
Member

I can totally imagine it. That was 2-3 years ago when my Csla package included 11 different versions of the assembly for all the variations of .NET that existed at the time.

Perfect! Then there should be no confusion, that problem is unsolvable, we'll just have less flavors .NET in the mix but there will always be version numbers and you'll always need to decide when you can update your dependencies.

Right now I'm assuming (!!) that all the extensions 3.0 are backward compatible with the 2.2.0 or 2.2.4 versions that exist, so we can host all our pre-existing libraries in an aspnetcore3.0 web project right? At runtime I assume the only version of Microsoft.Extensions.Configuration that loads is the 3.0 one, so all our code is using that newer binary but with the older API right?

Yes Microsoft.Extensions are mostly backwards compatible but ASP.NET Core decided to constrain the versions of those assemblies because it was tested with 2.x versions. There may be behavior changes that make things work differnetly (after all it is a major version).

That creates a dilemma for library authors though, you need to target 2.x if you want to run on ASP.NET Core 2.1, 2.2 and 3.0 (if you want to avoid multi-targeting).

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 25, 2019

My dilemma, even if I assume multitargeting, is that I don't see how library consumers (i.e. enterprise developers) resolve the versioning issues. It won't be automatic via NuGet, and that's my fundamental issue here.

If I create a Csla NuGet package that includes:

  1. .NET 4
  2. .NET 4.5
  3. .NET 4.6.1
  4. netstandard2.0 (against extensions 2.x)
  5. netstandard2.0 (against extensions 3.x)

Then there's no way for NuGet to disambiguate between those last two items. So that means I actually need to do this:

  1. .NET 4
  2. .NET 4.5
  3. .NET 4.6.1
  4. netstandard2.0 (against extensions 2.x)
  5. netcore3.0 (against extensions 3.x)

But THAT forces everyone who consumes the Csla package to stop using netstandard as they upgrade to .NET Core 3.

So again, I come back to the meta-answer here is that netstandard is basically useless going forward. Right?

And in the immediate timeframe everyone is forced to multitarget if they use their business assemblies in the web (netcore3) and Xamarin (still netstandard2 afaik).

@davidfowl
Copy link
Member

.NET 4
.NET 4.5
.NET 4.6.1
netstandard2.0 (against extensions 2.x)
netstandard2.0 (against extensions 3.x)

Right this isn't a thing.

.NET 4
.NET 4.5
.NET 4.6.1
netstandard2.0 (against extensions 2.x)
netcore3.0 (against extensions 3.x)

That's correct.

But THAT forces everyone who consumes the Csla package to stop using netstandard as they upgrade to .NET Core 3.

Why would it force consumers to stop using .NET Standard? Did you mean to say that people using .NET Core 3.0 will get the .NET Core 3.0 version of Csla? If so then yes. It doesn't force people currently using NS 2.0 to have to upgrade anything.

So again, I come back to the meta-answer here is that netstandard is basically useless going forward. Right?

I don't understand why that's the conclusion.

And in the immediate timeframe everyone is forced to multitarget if they use their business assemblies in the web (netcore3) and Xamarin (still netstandard2 afaik).

Just don't upgrade your Microsoft.Extensions.* dependencies.

@rockfordlhotka
Copy link
Author

So is this comment I made earlier invalid then?

@davidfowl
Copy link
Member

Which comment exactly? Microsoft.Extensons.* is compatible.

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 25, 2019

The link should have gone directly to the comment. But the gist is this.

If I have the following:

  1. web site netcore3 referencing Csla.dll (nc3) referencing extensions 3.0
  2. business library ns2 referencing Csla.dll (ns2) referencing extensions 2.x

At runtime only the extensions 3.0 will load right? So the ns2 assemblies will use the 2.x API, but will actually be using the 3.0 bits.

You are saying that today they are backward compatible, so no issue (except asp.net core 2.2 doesn't trust the 3.0 versions, so that doesn't inspire confidence).

Eventually though, won't there be an extensions 5.0 that might not be backward compatible? At which point people won't be able to use Csla.dll (ns2) because it will be stuck back in time until all users are off .NET Core 2 (which I expect will happen in 20 years give or take).

@davidfowl
Copy link
Member

At runtime only the extensions 3.0 will load right? So the ns2 assemblies will use the 2.x API, but will actually be using the 3.0 bits.

Yes.

You are saying that today they are backward compatible, so no issue.

Yes.

Eventually though, won't there be an extensions 5.0 that might not be backward compatible? At which point people won't be able to use Csla.dll (ns2) because it will be stuck back in time until all users are off .NET Core 2 (which I expect will happen in 20 years give or take).

Maybe. But what's the point you're trying to make? This is how the library ecosystem works. If a breaking change is made, then dependent packages need to fork. Just don't conflate any of this with netstandard, it's just a general problem that platforms have (it's not even unique to .NET).

@rockfordlhotka
Copy link
Author

Thank you David, this all makes sense.

I'm not intending to conflate it with netstandard as much as NuGet targets. I wish the decision had been made (or will be made) to have a rolling set of NuGet targets that are platform independent, like netstandard, but that roll slowly forward over time.

As it is, because the only valid NuGet targets (over time) appear to be ns2, ns2.1, nc3, nc5 (?) and so forth, at least my use of ns2 as a target is rapidly drawing to a close, because ns2 generally equates to .NET Core 2, and there's no ns3 for .NET Core 3.

So right, this isn't a netstandard thing. But the lack of viable rolling NuGet targets relegates ns2 to the dustbin of history as of this week, because it isn't very useful when looking at .NET Core 3 support while still supporting .NET Core 2.

@davidfowl
Copy link
Member

I'm not intending to conflate it with netstandard as much as NuGet targets. I wish the decision had been made (or will be made) to have a rolling set of NuGet targets that are platform independent, like netstandard, but that roll slowly forward over time.

How exactly does this fix things? As I said earlier, imagine a world where .NET Core is the only thing on the planet, we'd be having this same discussion. To be even more specific, because ASP.NET Core depends on these extensions, it ends up being problematic for package authors to take dependencies on newer ones (in older versions of ASP.NET Core).

That isn't the issue the problem is that you can't pivot based on dependencies. Today TFM is the only tool you have to pivot single package for "multiple things". Luckily ASP.NET Core targets netcoreapp so you have a way out. Otherwise you only real options are:

  • Change the package id
  • Multi target
  • Use the lowest compatible version

This is one of the big reasons we tried our best to get rid of 3rd party packages in the shared framework. The less things you depend on less the chance of conflict.

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 25, 2019

From what I can gather, if you build a library/package that takes a dependency on pretty much anything, your targeting compatibility looks like this:

  Net4 Net45 Net461 Net48 UWP Ns2 Mono Nc3 Nc5?
Net4 X                
Net45   X              
Net461     X     X      
Net48       X   X      
UWP         X X      
Ns2     X X X X X ?  
Mono           X X    
Nc3           ?   X  
Nc5?                 X

The X means compatible. The '?' means "buyer beware", dependencies might or might not work, even if your code compiles - you won't know about failure until runtime. As a tip, ASP.NET Core 2.2 precludes the use of 3.0 dependencies due to possible issues.

So for a short period of time (~2 years?) we've enjoyed ns2 being a nearly universal target. All I'm saying is that I got spoiled, and as the right and bottom of this chart grow we'll have a steady stream of single-X options like we had prior to ns2.

I think I've now reconciled myself to that thanks to your help.

As long as .NET can avoid fragmenting back into .NET/mono/uwp/silverlight/phone/PCLx/PCLy/etc. again, at least the issue isn't so bad.

@rockfordlhotka
Copy link
Author

I do hope the tooling resumes helping. Specifically, I'd hope that Nc5 can't reference Nc3 or Ns2 libraries - avoiding the otherwise nearly inevitable dependency conflicts.

That was one thing that was simpler back in the .NET 2, 3, 4 days - you couldn't cross the streams because there was no pretense of cross-version compatibility.

@kevinchalet
Copy link
Contributor

Specifically, I'd hope that Nc5 can't reference Nc3 or Ns2 libraries - avoiding the otherwise nearly inevitable dependency conflicts.

You were kidding, right? Because that would be absolutely terrible 🤣

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 25, 2019

How am I kidding? How is it good to think that a Nc3 project is allowed to reference an Ns2 library, where that library brings in incompatible dependencies?

Once netstandard goes out of our vocabulary - which I now suspect will happen rapidly - we'll be back to the simple .NET versioning story where there's no pretense of an assembly from version X working in a version Y app.

Nobody expected a .NET 4 project to use a .NET 2 library. That'd be silly. Nobody should expect a Nc5 project to use a Nc3 library. Same scenario.

We had this brief dalliance with netstandard, and it has been fun, but that time is over. .NET 5 is unified right? So we no longer need something to span various flavors of .NET because there'll be just one (plus UWP of course - but that affects such a tiny percentage of devs I think it can be ignored).

@kevinchalet
Copy link
Contributor

kevinchalet commented Sep 25, 2019

How am I kidding? How is it good to think that a Nc3 project is allowed to reference an Ns2 library, where that library brings in incompatible dependencies?

Because it would be pretty much like when .NET Core 1.0 was released? Nothing was compatible, the adoption rate was insanely low and many people waited for 2.0 (that reduced the gap between .NET Framework and .NET Core) for that sole reason.

So, with your approach, every year, we'd have a new .NET version, that would be completely incompatible with all the existing projects/libs/packages? What a PITA, it would be even more terrible than the existing situation, where you have at least a chance to use a lib written for ASP.NET Core 2.x on 3.x if it doesn't use an API that was removed in 3.x.

Nobody expected a .NET 4 project to use a .NET 2 library.

Really? Luckily, most libs written and compiled for .NET 2 could be used flawlessly on .NET 4 😕

Against, it's not a TFM/platform issue, it's a dependencies problem, which is something @davidfowl explained clearly. Not sure why you're blaming .NET Standard.

The real discussion should be about breaking changes in the Microsoft.Extensions.* packages, for which I hope the bar should be quite high. If there are no breaking changes between major versions, mixing versions becomes less problematic.

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 25, 2019

Everyone hears me blaming .NET Standard. I don't mean to "blame" it, as much as point out that due to the way it integrates with NuGet targeting, it is now obsolete for people like me who have dependencies in our packages. My next step is to create netcore3 versions of my projects and add those assemblies to my NuGet packages, so as people move to netcore3 they'll stop relying on anything to do with netstandard.

That's not blame. That's just an observation of reality.

I totally agree with you on the Extensions compatibility. I can see where people will be using the 2.2 versions for years - up to the point that host apps (ASP.NET, WPF, etc.) start using a future-and-incompatible version of Extensions.

Or maybe not years? Maybe that'll happen with .NET 5. Time will tell - but when Extensions (especially config and DI) become incompatible that'll cause a whole lot of pain for people.

Actually - to riff on that a bit - aren't we using semver now? So if 3.0 is backward compatible with 2.x, then why is it 3.0?

Isn't this really the core of the problem I'm discussing here? That a totally compatible version was released as a major point version instead of a minor version? If it is compatible then it wasn't breaking, so the major number should have stayed the same.

@poke
Copy link
Contributor

poke commented Sep 26, 2019

Eventually though, won't there be an extensions 5.0 that might not be backward compatible? At which point people won't be able to use Csla.dll (ns2) because it will be stuck back in time until all users are off .NET Core 2 (which I expect will happen in 20 years give or take).

You really seem to be confusing the target framework with the version of a dependency. You can ignore .NET Standard and .NET Core in your situation, and you will still have the same problem. Imagine, there is only a single runtime, and that will never need to be update. So everything targets the same thing.

Now, if you have M.E.* 23 introduces a breaking change over M.E.* 2 to 22, then there is nothing the target framework will help you with. If you share a dependency in different versions, you will always have this problem. And there is really no way around it for now.

M.E.* 3.0 is mostly API compatible to 2.2 (not completely, but if you depend on the .Abstraction – which your library should probably do – then you will be fine). But yeah, if M.E.* 5 will introduce a breaking change, then that means that your library that references 2.2 will not work with applications that have 5.0.

That is when you will have to update your library also to enable compatibility with 5.0, likely by updating its dependency version. At that time, your new version of your library will become incompatible to old 2.2 solutions. So those will have to reference the old version of that library until they can update themselves.

Cross targeting both netstandard2.0 and netcoreapp3.0 is just a workaround to provide a single library version that runs on all (current) ASP.NET Core versions. But that strategy won’t continue to work forever.

but when Extensions (especially config and DI) become incompatible that'll cause a whole lot of pain for people.

Same with every other dependency. Breaking changes are always a pain which is why there is a huge priority on avoiding them in the first place. But they cannot be avoided forever if you want to move forward. And one way to move forward is bumping the version; another might be changing the name so it can coexist.

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 26, 2019

I understand that this is complex @poke - I'm trying to figure out the guidance to provide to people going forward.

We've (and by "we" I mean a lot of authors/speakers/etc.) been telling folks to move as much of their code into netstandard2.0 projects as possible, as it was the best option to start the multi-year migration from .NET Framework to .NET Core.

(I've been giving a migration talk for the past 18 months, and am giving it again next week - obviously I'm changing the messaging for next weeks' delivery 😄 )

I still think that's good advice.

However, as soon as a Microsoft execution environment (such as ASP.NET Core 3) takes a dependency on a non-compatible library (such as Microsoft.Extensions.*) then everyone's live becomes super complex, because there's no way to differentiate between an ns2 assembly built using extensions 2.x and one built using extensions 3.x.

Cross targeting both netstandard2.0 and netcoreapp3.0 is just a workaround to provide a single library version that runs on all (current) ASP.NET Core versions. But that strategy won’t continue to work forever.

And that is my point. netstandard2 is effectively at end of life as of this week. It was super useful to bridge from .NET Framework/mono/etc. to .NET Core 2, and that's all. Going forward people should clearly be creating netcore3 projects for greenfield.

But for the massive numbers of people who are in the middle of migrating from .NET Framework to netstandard2.0 life is a bit more complex as I see it. They still build all their code for net461 or something, plus they are building it for ns2, and now they'll probably also need to build for nc3 - or just ignore .NET Core 3 entirely and continue working toward .NET Core 2.

(remember that most of these migrations are 2-5 years in length)

I can see too, where if an org has not yet started migrating off .NET Framework, they can totally skip ns2 and just start targeting nc3 - while still building for net461 or whatever. Next year they'll have to start multitargeting nc3 and nc5 of course, so life will still be challenging at that point, but they can skip the ns2 step at least.

@poke
Copy link
Contributor

poke commented Sep 26, 2019

However, as soon as a Microsoft execution environment (such as ASP.NET Core 3) takes a dependency on a non-compatible library (such as Microsoft.Extensions.*) then everyone's live becomes super complex, because there's no way to differentiate between an ns2 assembly built using extensions 2.x and one built using extensions 3.x.

But those libraries are compatible with netstandard2.0 and the .NET Framework. That’s the thing here; this is not something netstandard is there to solve, this is a normal dependency versioning issue that has nothing to do with .NET Standard, .NET Core or a migration from .NET Framework to one of those. The same thing happens as well when you are just using .NET Framework.

or just ignore .NET Core 3 entirely and continue working toward .NET Core 2

You are not ignoring .NET Core 3 when you target .NET Standard. That is just false. If you target .NET Standard, then you are building something that is supposed to run everywhere. It is not limited to .NET Core 2, and it is also not limited to some transitioning phase between .NET Framework and .NET Core.

@rockfordlhotka
Copy link
Author

rockfordlhotka commented Sep 26, 2019

I think you are missing the practical reality here, at least given the use of NuGet.

If I target ns2 with no dependencies then sure, my code can run everywhere. But as soon as I create a NuGet package with an ns2 assembly that has dependencies then my package is only useful for .NET Core 2 (or 3) because my dependencies have locked me in.

Since there's no NuGet target to solve this problem other than platform/version specific targets I have to quit using ns2.

I'm not saying this is a problem to solve - or that can be solved!

I'm saying that people like me need to provide guidance to enterprise devs on the best strategy for them to use as they navigate multi-year migrations from .NET Framework to the future.

@poke
Copy link
Contributor

poke commented Sep 26, 2019

A .NET Standard library can only reference other .NET Standard libraries, so no, every .NET Standard library will stay useful for all the implementations (.NET Core, .NET Framework) regardless of how many dependencies it has.

Again: Your problem is not related to .NET Standard at all. This is just basic versioning hell, which always existed.

I'm saying that people like me need to provide guidance to enterprise devs on the best strategy for them to use as they navigate multi-year migrations from .NET Framework to the future.

Then that guidance is: Stick to the versions you chose, and don’t update too early again. Do one migration at a time, don’t introduce even more migration issues by migrating several overlapping things.

@rockfordlhotka
Copy link
Author

I'm not saying this is a problem to solve - or that can be solved!

I'm saying that people like me need to provide guidance to enterprise devs on the best strategy for them to use as they navigate multi-year migrations from .NET Framework to the future.

@rockfordlhotka
Copy link
Author

It is worse now because of the faster cadence of releases, and the decoupling of dependencies from major version releases. We've left the "safe" world of .NET in the past, and are getting dangerously close to the utter chaos of JavaScript.

@poke
Copy link
Contributor

poke commented Sep 26, 2019

We've left the "safe" world of .NET in the past

If that’s really what you think how it was, then I suppose you were living a lie unfortunately. Nothing really changed in that regard.

@rockfordlhotka
Copy link
Author

Maybe. Things were reasonably manageable from 2005-2015 as long as you stayed away from mono/Silverlight/WP/Xamarin/WinRT - things most enterprise devs did avoid.

I chose to dive into all of them, so nothing you are saying is remotely new to me. I've lived the versioning life over the entirety of .NET's existence.

I also work very hard to provide guidance and support so most people don't have to suffer the pain some of us choose as our path.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants