dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.75k stars 1.07k forks source link

Alias in ProjectReference does not work for framework-included packages #15443

Open aortiz-msft opened 3 years ago

aortiz-msft commented 3 years ago

Issue moved from NuGet/Home#10438


From @weltkante on Friday, January 8, 2021 4:19:41 PM

Details about Problem

In #4989 alias support for PackageReference was added, but when I try to create an alias to a framework-provided package this does not appear to work.

In particular, in a .NET 5 web application I add

<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" Aliases="logging" />

but extern alias logging; does not compile:

error CS0430: Der externe Alias "logging" wurde nicht in einer /reference-Option angegeben.

If I instead do it in a console application it indeed does work.

Using VS 2019 Update 9 Preview 2

aortiz-msft commented 3 years ago

Issue moved from NuGet/Home#10438


From @JonDouglas on Friday, January 8, 2021 5:49:15 PM

Hi @weltkante,

Thanks for the report!

Can you please provide us a sample project or reproducible steps to help us debug this further?

Feel free to refer to our section on bug reports for more information on what we're looking for!

aortiz-msft commented 3 years ago

Issue moved from NuGet/Home#10438


From @weltkante on Friday, January 8, 2021 7:25:18 PM

Sure, the reproduction steps are literally just what I said above, adding a PackageReference to a framework package and a corresponding extern alias statement. I'm adding a full example below, changing the SDK to Microsoft.NET.Sdk (i.e. removing the Web) makes things compile but obviously I'm then missing a lot of implicit behavior of the Web SDK, both in implicit package references and project system behavior.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" Aliases="logging" />
  </ItemGroup>
</Project>
extern alias logging;

using System;

namespace PackageAlias
{
    public class Helper
    {
        public void MethodWithLogger(logging::Microsoft.Extensions.Logging.ILogger logger)
        {
        }
    }
}
Program.cs(1,14,1,21): error CS0430: The extern alias 'logging' was not specified in a /reference option
Program.cs(9,47,9,56): error CS0234: The type or namespace name 'Microsoft' does not exist in the namespace 'logging' (are you missing an assembly reference?)
aortiz-msft commented 3 years ago

Issue moved from NuGet/Home#10438


From @JonDouglas on Friday, January 8, 2021 8:14:16 PM

@weltkante Thank you kindly! We'll look into this shortly in our next triaging session. Thanks for the clarification on the .csproj items!

dotnet-issue-labeler[bot] commented 3 years ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

GeirGrusom commented 3 years ago

I've never in my life needed to use extern alias before but when I do of course it's completely broken. The Aliases property has no effect in net48 or net5.0 projects. Visual Studio 16.8.5.

coldacid commented 3 years ago

I'm now getting tripped up on this too. net5.0 project.

khayes commented 2 years ago

I'm also having this problem. The context is I am making a library that has multiple TFMs.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>net6.0;net472</TargetFrameworks>
  </PropertyGroup>

  <!-- Conditional PackageReferences are in here with Aliases set -->
</Project>

There is a type I need that exists in the same namespace but different assemblies, so I need an external alias. But this won't work as one of my targets is net472.

timmydo commented 2 years ago

Migrating some code from <Reference> to <ProjectReference> I stumbled across this also.

JoyXuBaidu commented 1 year ago

Any update on this issue? I face similar issue: `

MyProjectDS

The Aliases within ProjectReference doesn't work. Have this issue: Error CS0430 The extern alias 'MyProjectDS' was not specified in a /reference option `

While the Aliases for PackageReference works: `

..\Dlls\EntityCore.DataSchemas.PureBond.dll
  <Aliases>EC</Aliases>
  <Private>True</Private>
</Reference>

`

e212156822000 commented 1 year ago

Dear @wli3, Do you have any updates or suggestions to work around it?

tdhatcher commented 1 year ago

This looks like a related issue. https://github.com/dotnet/msbuild/issues/4943

Problem Only the extern alias of the first occurrence of NuGet PackageReference is recognized v12. v11 results in compilation error CS0430

Reproduce Steps

  1. csproj

    <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" Aliases="v12" />
    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" Aliases="v11" />
    </ItemGroup>
  2. Program.cs (C# 11 / NET 7)

    
    extern alias v12;
    extern alias v11;

using Json12 = v12::Newtonsoft.Json; using Json11 = v11::Newtonsoft.Json;

Json12.JsonConvert.SerializeObject(new { message = "Hello, world!" }); Json11.JsonConvert.SerializeObject(new { message = "Hello, world!" });



I even stumped ChatGPT with this one, it seemed so confident that it _should be_ working and that I was doing something wrong.
<img width="551" alt="image" src="https://user-images.githubusercontent.com/360359/215599662-8efc7987-e633-49c4-8020-ec9f9d965b9d.png">
AdriaanLarcai commented 1 year ago

I'm assuming this is a dead issue that will never be addressed?

CodeOptimist commented 1 year ago

Still busted, my project is net472.

jscarle commented 9 months ago

Confirmed that this still does not work. I tried to do this with .NET 8.0.2 using a regular NuGet package, and extern alias throws CS0430.

AndrewDRX commented 9 months ago

Any updates on this? I am trying to write a test to compare multiple versions of the same library, but this is making it impossible.

jscarle commented 9 months ago

Any updates on this? I am trying to write a test to compare multiple versions of the same library, but this is making it impossible.

That was exactly what I was trying to do. Didn't work for me because if I loaded the csproj and the NuGet package at the same time, the NuGet package simply wouldn't get loaded.

AndrewDRX commented 9 months ago

For me it is two versions of a local project. I have the same issue regardless of whether I use a ProjectReference or a Reference. In both cases, it is the later include that works, and the alias for the earlier one is not found (so, if I swap the order, then the later one is still the only one found).

<ItemGroup Label="Project References">
    <ProjectReference Include="../old/MyProject.csproj">
        <Aliases>OldCode</Aliases>
        <Project>{D82F0573-0863-47A0-8280-0C0FEE65BD0F}</Project>
    </ProjectReference>
    <ProjectReference Include="../new/MyProject.csproj">
        <Aliases>NewCode</Aliases>
        <Project>{83895685-5E0B-447E-8560-4CD0DA32E2A6}</Project>
    </ProjectReference>
</ItemGroup>
<ItemGroup Label="References">
    <Reference Include="MyProject">
        <Aliases>OldCode</Aliases>
        <HintPath>../old/bin/Debug/net7.0/MyProject.dll</HintPath>
    </Reference>
    <Reference Include="MyProject">
        <Aliases>NewCode</Aliases>
        <HintPath>../new/bin/Debug/net7.0/MyProject.dll</HintPath>
    </Reference>
</ItemGroup>
jscarle commented 9 months ago

Take a look here: https://jeanarjean.com/blog/2021-03-10-how-to-create-alias-property-in-your-csproj/

I wasn't able to get the whole thing working because of my own scenario, but the key seems to be be that you have call your classes using the :: convention.

extern alias CustomNamespace1
extern alias CustomNamespace2

using CustomNamespace1::whatevernamespace.youwant;
using CustomNamespace2::whatevernamespace.youwant;
AndrewDRX commented 9 months ago

Yes, that is exactly what I did. No luck.

For:

extern alias OldCode;
extern alias NewCode;

I get the error:

error CS0430: The extern alias 'OldCode' was not specified in a /reference option
jscarle commented 9 months ago

Yea, that's where I end up as well.

carmanj commented 8 months ago

@wli3 @aortiz-msft - any update or progress on this? This issue is 3 years old at this point. While certainly not something I've ever had to do until now, it's quite obviously completely broken without any viable alternative/workaround.

Thanks, Justin Carman

gmkado commented 5 months ago

FWIW I reproduced on the Nuget.Versioning example that is linked in the microsoft docs:

image

Their example only has one alias, but if you add a second one it has the same was not specified in a /reference option error. What is the use of only having one alias?

Also, does anyone know if the Aliases option was intended to work with central package management? I had something akin to:

<ItemGroup>
    <PackageReference Include="NuGet.Versioning" VersionOverride="5.8.0" Aliases="ExampleAlias" />
    <PackageReference Include="NuGet.Versioning" VersionOverride="6.10.0" Aliases="Latest" />
  </ItemGroup>

(Note the VersionOverride instead of Version)

I originally thought my error was due to this package being defined already in Directory.Packages.props but sounds like that is unrelated and this should still work.

AndrewDRX commented 5 months ago

Including recent top dotnet/sdk contributor @v-wuzhai to see if this can be reassigned to an active contributor to investigate this (or to include other active contributors for their thoughts) as there has been no notable feedback here from contributors and this ticket is almost 3.5 years old.

AndrewDRX commented 5 months ago

@marcpopMSFT @dsplaisted also tagging a couple other recent top dotnet/sdk contribs for the same reason.

marcpopMSFT commented 5 months ago

Triage: There are two scenarios outlined in this issue. Extern alias was originally designed to use two different assemblies that have the same name. Neither case above is that exact case and it was not designed for that.

We'd like to understand the why of the original scenarios. For the original issue, why would a customer need to reference two versions of the shared framework and require the alias so as to use both logging dlls? We now have namespace aliasing now that might satisfy some of the usages the customer was trying to achieve back in 5: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive

For the second scenario, we do not believe that nuget supports referencing two different versions of the same package. That seems to be the more common request from later commentors. CC @nkolev92 @aortiz-msft

weltkante commented 5 months ago

For the original issue, why would a customer need to reference two versions of the shared framework and require the alias so as to use both logging dlls?

As the OP, this was not my scenario, I simply needed to give an assembly an alias to resolve a naming conflict (same namespace and typename used in different assemblies). I did not need to load the same assembly twice or in different versions.

Extern alias was originally designed to use two different assemblies that have the same name.

Given that it just drops the alias (instead of merging it) when it resolves the package references in msbuild, I don't think it was "designed" at all, certainly it is not compatible with modern msbuild grouping and resolution of package references.

As for the other people who posted over the years, can't speak for their use-cases.

AndrewDRX commented 5 months ago

Extern alias was originally designed to use two different assemblies that have the same name.

This is specifically my complaint for what is broken so I am glad to see confirmation that it is indeed supposed to work for my use case. So, I think this is the behavior that we need to investigate for a bug fix.

The reason for why I need this to work is so that I can write tests to compare the output from two builds of the same library (same assembly name). But I suppose the reasoning is moot since you are confirming that it is broken based on how it was originally designed vs how it is functioning now.

My comment here explains the failing behavior in a little more detail: https://github.com/dotnet/sdk/issues/15443#issuecomment-1956748678

For me it is two versions of a local project. I have the same issue regardless of whether I use a ProjectReference or a Reference. In both cases, it is the later include that works, and the alias for the earlier one is not found (so, if I swap the order, then the later one is still the only one found).

<ItemGroup Label="Project References">
  <ProjectReference Include="../old/MyProject.csproj">
      <Aliases>OldCode</Aliases>
      <Project>{D82F0573-0863-47A0-8280-0C0FEE65BD0F}</Project>
  </ProjectReference>
  <ProjectReference Include="../new/MyProject.csproj">
      <Aliases>NewCode</Aliases>
      <Project>{83895685-5E0B-447E-8560-4CD0DA32E2A6}</Project>
  </ProjectReference>
</ItemGroup>
<ItemGroup Label="References">
  <Reference Include="MyProject">
      <Aliases>OldCode</Aliases>
      <HintPath>../old/bin/Debug/net7.0/MyProject.dll</HintPath>
  </Reference>
  <Reference Include="MyProject">
      <Aliases>NewCode</Aliases>
      <HintPath>../new/bin/Debug/net7.0/MyProject.dll</HintPath>
  </Reference>
</ItemGroup>

And my comment here provides a little more detail in relation to that: https://github.com/dotnet/sdk/issues/15443#issuecomment-1956781994

Yes, that is exactly what I did. No luck.

For:

extern alias OldCode;
extern alias NewCode;

I get the error:

error CS0430: The extern alias 'OldCode' was not specified in a /reference option

I have also run into other issues when trying to load both versions of the assembly via reflection, which throws errors due to the same assembly name being registered multiple times. So, I am also unable to use reflection as a workaround for an alternate approach to the explicit assembly references.

jscarle commented 5 months ago

Extern alias was originally designed to use two different assemblies that have the same name.

This is specifically my complaint for what is broken so I am glad to see confirmation that it is indeed supposed to work for my use case. So, I think this is the behavior that we need to investigate for a bug fix.

This is also my use case, except that it's to compare my current build with my last published NuGet package to be able to do performance regression testing.

GeirGrusom commented 5 months ago

In my case we were moving from old project format to new project format. Two assemblies, neither built by my team so I couldn't change them, contained the same namespace with the same class, and an alias was used to resolve this. I don't remember the details of why they had the same namespace, but probably because we implemented, like many do, a Smurf naming convention in namespaces.

After converting to the new project format the alias no longer worked, so we couldn't move forward with the project format change because it would no longer build. We wanted to move to the new project format, and PackageReference over packages.config. Because our build system was a Rube Goldberg machine (I guess like most build systems) and we frequently got runtime errors from binding redirects caused by packages.config being out of sync with the project file. Tracking those issues down was very time consuming.

marcpopMSFT commented 5 months ago

Triage: Thank you all for the comments here. For the scenario of same assembly but different versions, it sounds like there is a valid use case there but not what this feature was designed for. Please file a separate issue that we will put on the backlog and use to gather feedback for potentially revisiting in the future.

Let's keep this issue focused on the original report which should be supported and we'll need some time to investigate why it's not working.

CC @nkolev92