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

extern alias support for NuGet package references #4989

Closed
davkean opened this issue Apr 6, 2017 · 57 comments
Closed

extern alias support for NuGet package references #4989

davkean opened this issue Apr 6, 2017 · 57 comments

Comments

@davkean
Copy link

davkean commented Apr 6, 2017

From @fubar-coder on April 5, 2017 15:59

Currently, when a NuGet package reference is added, there is no way to set the alias from the project system for the new style csproj projects.

This feature is needed, because NuGet package references don't result in direct assembly references any more and only those can have an alias.

My proposal is to add the alias(es) to all assemblies referenced for the NuGet package, but not the indirectly referenced NuGet packages.

Copied from original issue: dotnet/project-system#1930

notes

dotnet/sdk#10947 The build tasks on (.NET Core SDK side)
dotnet/NuGet.BuildTasks#70 The build tasks for the non-SDK based PackageReference
dotnet/project-system#6011 Nomination updates on project-system side.

@davkean
Copy link
Author

davkean commented Apr 6, 2017

Great suggestion. I'll move this over to the NuGet repo, they own the syntax for PackageReference.

@andymac4182
Copy link

This would be great since we are running into this issue due to https://www.nuget.org/packages/StackExchange.Redis/ and https://www.nuget.org/packages/StackExchange.Redis.StrongName/

@brianpos
Copy link

brianpos commented May 3, 2017

We have this issue to if we want to add both of these
https://www.nuget.org/packages/Hl7.Fhir.DSTU2
https://www.nuget.org/packages/Hl7.Fhir.STU3

@wburgers
Copy link

@brianpos exactly the same problem here.
We would like to run both fhir versions next to each other.

@brianpos
Copy link

@wburgers i have a project using the extern alias trick https://github.com/brianpos/FhirPathTester but do have to set manually after inclusion. So can't wait for this to be fixed.

@JoseFMP
Copy link

JoseFMP commented Jun 21, 2017

+1, can't wait for this. I think this is important because right now different packages implementing same namespaces.

@brianpos could you share your trick please?

@fubar-coder
Copy link

IIRC you can configure NuGet to store the NuGet packages in an packages folder instead of using the cache in the users home folder using the NuGet.config. This allows you to manually specify project-relative assembly references (via Reference Update) which can include the alias. The problem with this approach is, that you have to update the reference whenever the package version changes. However, you can restore the packages into folders without the package version of you don't have conflicting package versions.

@JoseFMP
Copy link

JoseFMP commented Jun 21, 2017

Ok, so basically referencing the .dll quasi-manually and including then the alias, right? I was also thinking about that as a work around

@davkean
Copy link
Author

davkean commented Jun 21, 2017

As a side note, a workaround is to write a target that does something like this: https://github.com/dotnet/project-system/blob/master/build/Targets/VSL.Imports.targets#L340.

Here we're setting the EmbedInteropTypes metadata, but the same could be applied to alias.

@andymac4182
Copy link

It would be great if someone on the NuGet team could point in the right direction of the repo that requires the change. I am sure people are happy to look if they know where to look.

@davkean
Copy link
Author

davkean commented Jun 21, 2017

I think they'll need a design first, I don't see a flushed out proposal on syntax/behavior. Once we do that, we'll then need to work with the project systems (http://github.com/dotnet/project-system) and SDK (http://github.com/dotnet/project-system) to add/respect the property so that it can be passed to NuGet/show in Properties, etc, added to the <REference/> when we dynamically produce them, and then plumbed through pack (what does an aliased set of references do when we add the package as a reference in the nuspec?). Just to set expectations, this isn't a couple of lines change.

@davkean
Copy link
Author

davkean commented Jun 21, 2017

I'll help sponsor, point to the locations that need to change in SDK, ProjectSystem (NuGet team will need to jump in on the nuget side, as I don't have context), and driving this through, if a community member wants to pick up the design/changes.

@gertjvr
Copy link

gertjvr commented Jun 23, 2017

After some experimentation and got it to work.

Placed the below snippet into my csproj file where I had both references of StackExchange.Redis and StackExchange.Redis.StrongName nuget dependencies.

<Target Name="ChangeAliasesOfStrongNameAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
    <ItemGroup>
      <ReferencePath Condition="'%(FileName)' == 'StackExchange.Redis.StrongName'">
        <Aliases>signed</Aliases>
      </ReferencePath>
    </ItemGroup>
  </Target>

@JoseFMP
Copy link

JoseFMP commented Jun 23, 2017

@gertjvr sounds great! I will give it a try over here

@ewoutkramer
Copy link

ewoutkramer commented Jun 26, 2017

if a community member wants to pick up the design/changes.

What would that entail? Sorry, I am not very familiar with the process!

@fubar-coder
Copy link

@gertjvr Just to clarify: ChangeAliasesOfStrongNameAssemblies is just a random target name? Does it need to be called/targeted somewhere?

@gertjvr
Copy link

gertjvr commented Jun 26, 2017

@fubar-coder the target name is just a random name same goes for the alias signed, the snippet above was all I added to my csproj file.

<Project Sdk="Microsoft.NET.Sdk">
  
  <PropertyGroup>
    <TargetFramework>net461</TargetFramework>
  </PropertyGroup>
  
  <ItemGroup>
    <PackageReference Include="Autofac" Version="4.6.0" />
    <PackageReference Include="AutofacSerilogIntegration" Version="2.0.0" />
    <PackageReference Include="AWSSDK.DynamoDBv2" Version="3.1.5" />
    <PackageReference Include="AWSSDK.S3" Version="3.1.7.2" />
    <PackageReference Include="ConfigInjector" Version="2.2.1175" />
    <PackageReference Include="Linq2DynamoDb.DataContext" Version="2.0.0" />
    <PackageReference Include="Linq2DynamoDb.DataContext.Caching.Redis" Version="2.0.0" />
    <PackageReference Include="MassTransit" Version="3.5.7" />
    <PackageReference Include="Microsoft.AspNet.SignalR.Core" Version="2.2.2" />
    <PackageReference Include="Microsoft.AspNet.SignalR.Redis" Version="2.2.2" />
    <PackageReference Include="Microsoft.Owin" Version="3.1.0" />
    <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
    <PackageReference Include="Owin" Version="1.0.0" />
    <PackageReference Include="Serilog" Version="2.5.0" />
    <PackageReference Include="ThirdDrawer" Version="1.1.9" />
  </ItemGroup>

  <ItemGroup>
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>
  
  <Target Name="ChangeAliasesOfStrongNameAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
    <ItemGroup>
      <ReferencePath Condition="'%(FileName)' == 'StackExchange.Redis.StrongName'">
        <Aliases>signed</Aliases>
      </ReferencePath>
    </ItemGroup>
  </Target>
  
</Project>

jasonmalinowski added a commit to jasonmalinowski/roslyn that referenced this issue Sep 6, 2017
…udio

We don't need the split anymore now that we're only supporting Dev15.

Unfortunately this required the introduction of a NuGet package that
has a namespace "Workspace" to our VS project, which meant I had to
disambiguate Workspace wherever it's used in that layer. I considered
doing an extern alias instead to disambiguate, but applying that to a
ProjectReference isn't supported. That's tracked by NuGet/Home#4989.
jasonmalinowski added a commit to jasonmalinowski/roslyn that referenced this issue Sep 11, 2017
…udio

We don't need the split anymore now that we're only supporting Dev15.

Unfortunately this required the introduction of a NuGet package that
has a namespace "Workspace" to our VS project, which meant I had to
disambiguate Workspace wherever it's used in that layer. I considered
doing an extern alias instead to disambiguate, but applying that to a
ProjectReference isn't supported. That's tracked by NuGet/Home#4989.
@emgarten emgarten added this to the Backlog milestone Oct 17, 2017
@emgarten
Copy link
Member

This workaround should be added to the official docs.

@nkolev92 @anangaur

@brianpos
Copy link

I've tried this out with the Fhir assembly @ewoutkramer, works a treat.
Agree this should be in official docs

@nkolev92
Copy link
Member

With dotnet/sdk#11612 and dotnet/sdk#11954, finally all the legs of this feature are completed.

The feature will be available in 16.7 and all the matching tooling versions (3.1.400 of the SDK, 5.0 of the SDK) & 5.7 of NuGet.exe.

If you are using NuGet.exe, keep in mind that you need VIsual Studio/ MSBuild to be 16.7

@anangaur
Copy link
Member

Awesome!! Thanks @nkolev92 for consistently following up on this one 👏

@TFTomSun
Copy link

@nkolev92 can you please provide a link to the documentation / sample?

@nkolev92
Copy link
Member

@TFTomSun Design at https://github.com/NuGet/Home/blob/dev/designs/PackageReference-Extern-Alias.md.

I'll update the docs by the time this ships in a GA release.

@TFTomSun
Copy link

TFTomSun commented Jun 12, 2020

@nkolev92 are the aliases transistive? I mean, are they applied to indirect, transistive dependencies, too?

@nkolev92
Copy link
Member

nkolev92 commented Jun 12, 2020

They only apply to the package reference they are specified on.

The challenge with applying to transitive dependencies is the diamond dependency scenario where: Project -> A -> C and Project -> B -> C.

For the time being the answer to how do I apply metadata to a transitive package still remains elevate it to top level.

@YanerTavuz
Copy link

Hi!
We're waiting for Visual Studio 16.7 to use this feature, do you know if it's available yet in any of the VS16.7 previews? Saw that Preview 3 was just released.

@nkolev92
Copy link
Member

@YanerTavuz Preview 3 should have it

@YanerTavuz
Copy link

YanerTavuz commented Jun 28, 2020

Got it to work with VS16.7 Preview 3.1 and .NET 5 Preview 6 with a .NET project SDK style.

Trying to get it to work with .NET Framework 4.8 with old csproj style,, any tips on how to get it working there? @nkolev92
It works when the csproj is SDK-style, but our solution projects uses the old style.

Edit: After some investigating, it seems that the dll for Microsoft.NuGet.Build.Tasks that is shipped with Visual Studio 16.7 Preview 3.1 does not contain your changes from dotnet/NuGet.BuildTasks#70 so I guess that's the issue.

@brian-pickens
Copy link

Will this work to alias different versions of the same package?

@fubar-coder
Copy link

Will this work to alias different versions of the same package?

Yes

@davkean
Copy link
Author

davkean commented Oct 19, 2020

No, this cannot be used to alias different versions of the same package that has the same identifier. This is entirely used to alias assemblies within a package.

@tdhatcher
Copy link

tdhatcher commented Jan 31, 2023

@davkean Is there any plan to enable this in the case of "different version of same nuget package"?

This would be very handy for versioning classes and allowing a single service to interop with both (or many versions) concurrently using aliases.

@davkean
Copy link
Author

davkean commented Jan 31, 2023

@tdhatcher I'm aware of no plans to allow the ability to reference multiple versions of the same NuGet packages, but one of the NuGet folks would need to chime in, @nkolev92 .

@nkolev92
Copy link
Member

nkolev92 commented Jan 31, 2023

@davkean Is there any plan to enable this in the case of "different version of same nuget package"?

There are no active plans to enable multiple versions of the same package in a project at this point.

@tdhatcher
Copy link

@nkolev92 my feedback is as someone who is not familar with inner workings of nuget package resolution. I'm curious if this doesn't exist because it's more of a technical hurdle to accomplish or more of a logical decision?

It seems if two or more distinctly named packages can resolve namespace collision with aliases then two or more of the same named packages should be able to resolve namespace collision.

I haven't really come across a solid prescribed strategy as for how to actually implement your API versions especially when breaking changes are present (and without separately hosting older version of the API). Just that there is flexibility in ASP.NET Core to support mapping multiple API versions to different controllers to handle the request/response (concurrently in the same running instance of an API).

Consider a common scenario when you publish a nuget package that serves as a convenient SDK for your API. That SDK contains all the classes that act as the contracts and client for consumers to interact with the API. The version of the SDK's nuget package is kept in-sync with the version of the API (eg. you'd use version 5 of the SDK you are communicating with v5 of the API).

By allowing aliases on same Nuget package with different versions, the API implementation would be able to reference the proper version of the SDK nuget package to obtain the proper contracts for the specific version of API controllers.

Nuget Multiple Version Support

This approach would be in contrast to an approach of maintaining a versioned yet disjointed SDK library separately while in the API it is cloning/maintaining multiple versions of the contracts globbed together in a single project to support backwards compatibility. Seems like a clean option like this is missing.

Allowing aliases for the same package but different versions would be a very complementary feature to ASP.NET Core API versioning. https://github.com/dotnet/aspnet-api-versioning/wiki/Existing-Services-Quick-Start

@nkolev92
Copy link
Member

nkolev92 commented Jan 31, 2023

@tdhatcher Having multiple versions of the same assembly (by extension of package) is a pretty involved feature.

I won't be able to address all your concerns, but one difficult challenge is what happens transitively. Sure if you reference a package directly, you can choose to alias it's assemblies, but what happens for the transitive dependencies that might have some incompatibilities?

You're likely to need some sort of assembly rewriting to make this work, which would have it's own set of problems.

If you'd like you can file a different issue with that ask.

The first thing that would need to happen to make progress on your idea is for the tooling overall to support multiple versions of the same package within 1 project.

@commonsensesoftware
Copy link

@tdhatcher I appreciate the callout 😉 , but an API version is not like a Semantic Version or assembly version; this is a false equivalency. Backward compatibility should in no way be implied or inferred from any API version. This is a common misconception. The rules for versioning binaries are quite different and are well-known across many languages and tools. These rules do not generically apply to an API. Even if the changes to the message body of an API is additive, a server cannot guarantee that the client implements a tolerant reader and will not break. There's nothing about 1.1 that says it's backward compatible with 1.0. I could have just as easily removed a data attribute and that would be considered a minor change. The conflation with numbers for API versions and binary versions are one reason why dates are often a better choice for an API version. Nothing about 2023-01-01 implies that it is compatible with 2019-07-01. 😸

API authors that vend a client that they want to have affinity to the API version usually take one of the following approaches:

  1. Include all supported API versions in a single package, separated by namespace
  2. Include a single package that maps to the most recent supported API versions
  3. Include a meta package that maps to individual packages corresponding to independently versions clients

While it is possible, it's usual and uncommon to need multiple versions of the same API simultaneously. Azure SDKs are backed by versioned Azure APIs. When you use a particular version of the client SDK, you typically don't think about the backing API version and certainly not multiple API versions at the same time. As @nkolev92 mentioned, the complexity of SxS assemblies is involved and goes beyond just aliasing. Even if you got it to work, it's pretty painful for package consumers. I doubt many would actually want that.

There are like other ways to achieve your goals, including, but not limited to having a clearly defined API versioning policy such as N-2.

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

No branches or pull requests