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

Razor compiler doesn't understand "@using Alias = Namespace.ComponentClass" #7670

Open
egil opened this issue Aug 13, 2019 · 28 comments
Open
Labels
area-blazor area-compiler Umbrella for all compiler issues enhancement Small improvement request
Milestone

Comments

@egil
Copy link

egil commented Aug 13, 2019

Using a Razor component via an alias isn't recognized by the compiler

If I want to rename/alias a Razor component when using it in a Razor page/Razor component, I should be able to reference it using the alias syntax, @using Alias = Namespace.ComponentClass. However, the Razor compiler does not recognized <Alias /> as a component, and will instead generate code that treats <Alias /> as a MarkupString.

Visual Studio Razor editor doesn't recognize Alias as a ComponentClass component either.

To Reproduce

Steps to reproduce the behavior:

  1. Setup test project:
dotnet new blazor -o using-rename
cd .\using-rename\
mkdir Components
cd .\Components\
dotnet new razorcomponent -n Test
  1. Modify .\using-rename\Pages\Index.razor to look like this:
@page "/"
@using Renamed = using_rename.Components.Test
<Renamed />
  1. Build using dotnet build. See no errors in output.

  2. See .\using-rename\obj\Debug\netstandard2.0\Razor\Pages\Index.razor.g.cs contains builder.AddMarkupContent(3, "\r\n\r\n<Renamed></Renamed>");. Here is the relevant snippet:

using Renamed = using_rename.Components.Test;

[Microsoft.AspNetCore.Components.Layouts.LayoutAttribute(typeof(MainLayout))]
[Microsoft.AspNetCore.Components.RouteAttribute("/")]
public class Index : Microsoft.AspNetCore.Components.ComponentBase
{
	protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder)
	{
		builder.AddMarkupContent(0, "<h1>Hello, world!</h1>\r\n\r\nWelcome to your new app.\r\n\r\n");
		builder.OpenComponent<using_rename.Shared.SurveyPrompt>(1);
		builder.AddAttribute(2, "Title", "How is Blazor working for you?");
		builder.CloseComponent();
		builder.AddMarkupContent(3, "\r\n\r\n<Renamed></Renamed>"); 
	}
}

Expected behavior

Visual Studio should recognize Renamed as a using_rename.Components.Test component, and the compiler should output the correct C# render tree builder code.

Additional context

.NET Core SDK (reflecting any global.json):
 Version:   3.0.100-preview7-012821
 Commit:    6348f1068a

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.16299
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.0.100-preview7-012821\

Host (useful for support):
  Version: 3.0.0-preview7-27912-14
  Commit:  4da6ee6450

.NET Core SDKs installed:
  2.1.201 [C:\Program Files\dotnet\sdk]
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.400 [C:\Program Files\dotnet\sdk]
  2.1.402 [C:\Program Files\dotnet\sdk]
  2.1.403 [C:\Program Files\dotnet\sdk]
  2.1.500 [C:\Program Files\dotnet\sdk]
  2.1.504 [C:\Program Files\dotnet\sdk]
  2.1.600-preview-009497 [C:\Program Files\dotnet\sdk]
  2.1.600 [C:\Program Files\dotnet\sdk]
  2.1.601 [C:\Program Files\dotnet\sdk]
  2.1.602 [C:\Program Files\dotnet\sdk]
  2.1.700-preview-009618 [C:\Program Files\dotnet\sdk]
  2.1.700 [C:\Program Files\dotnet\sdk]
  2.1.800-preview-009677 [C:\Program Files\dotnet\sdk]
  2.1.800-preview-009696 [C:\Program Files\dotnet\sdk]
  3.0.100-preview7-012821 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview3-19153-02 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview7.19365.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview7-27912-14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.0.0-preview7-27912-14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
@egil egil changed the title Razor compiler doesn't understand "@using Alias = Namespace.ComponentClass" #blazor #razor-components Razor compiler doesn't understand "@using Alias = Namespace.ComponentClass" Aug 13, 2019
@mkArtakMSFT
Copy link
Member

Thanks for contacting us, @egil .
@ajaybhargavb do we have a separate tracking issue for this?

@mkArtakMSFT mkArtakMSFT added the enhancement Small improvement request label Aug 13, 2019
@ajaybhargavb
Copy link
Contributor

@ajaybhargavb do we have a separate tracking issue for this?

Nope. We didn't add support for this as part of dotnet/aspnetcore#5577. We wanted to add it later based on usage and demand because adding support for this isn't trivial.

@mkArtakMSFT
Copy link
Member

Sounds like you have some background regarding this, @ajaybhargavb.
Please apply a cost to this issue then.

@egil
Copy link
Author

egil commented Aug 14, 2019

Thanks for taking the time to (re)consider this. I think it will be a very useful thing to have when dealing with naming conflicts between different component libraries, and that could have a pretty big impact on the stability of our apps when we upgrade libraries or add now ones.

@vertonghenb
Copy link

+1 for this one, as the project grows I can really see the benefit of this one.

@edgolub
Copy link

edgolub commented Jan 11, 2020

This is definitely something we would need.

I am building a multi-tenant system where I want to include a component and be able to overwrite it with a different one with the same name but in a different namespace. If I could alias all my components that would be the perfect solution to resolve the issue of having the same component name in different namespace and not being able to use both namespaces because of it.

Instead of doing @using Components, we could just do a @using Header=Components.Header

@mkArtakMSFT
Copy link
Member

We've moved this issue to the Backlog milestone. This means that it is not going to happen for the coming release. We will reassess the backlog following the current release and consider this item at that time. However, keep in mind that there are many other high priority features with which it will be competing for resources.

@brianlagunas
Copy link

This is a big deal for component vendors to help developers avoid naming conflicts with native components as well as other 3rd party components.

@ghost
Copy link

ghost commented Sep 15, 2020

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@ghost
Copy link

ghost commented Oct 9, 2020

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@TLabWest
Copy link

TLabWest commented Mar 25, 2021

This is a huge issue. We can't use any external component libraries that use the namespace Blazor.SomeLib because our components reside in the namespace MyProduct.Blazor. The generated code will try to resolve <Blazor.SomeLib.SomeComponent> as <MyProduct.Blazor.SomeLib.SomeComponent> and understandably fail hard.

I can't use an alias to get around the issue and razor syntax doesn't understand global:: so I can't even use <global::Blazor.SomeLib.SomeComponent> or anything like that. If I declare the same type as a variable in a code block in the .razor file I can get it to resolve but that's obviously of little use unless I BuildRenderTree() manually.

I'm not sure what to do besides changing the entire namespace of our product, disregarding company policies.

@javiercn javiercn added the area-compiler Umbrella for all compiler issues label Apr 19, 2021
@zxsanny
Copy link

zxsanny commented Jun 1, 2021

Guys, any thoughts to make this resolved? More than 2 years have passed since the original post. It would be more convenient for me and a lot of people to have aliases in razor pages - I think people expecting mostly the same behavior for razor pages as for usual cs files. Please consider to take this issue from the backlog to some sprint, thanks

@TLabWest
Copy link

We're still looking forward to have this issue (and our classes) resolved. As a quick tip to the other suffering souls out there, a partial workaround is to subclass the 3:rd party components as local classes in your own namespace. It's not great and doesn't work for sealed classes, but it's a useful hack for now.

@Xeevis
Copy link

Xeevis commented Aug 29, 2021

This would be great for a bit of abstraction when using various libraries. For example you might be using Blazorise.Button.

@using Blazorise
<Button Color="Color.Primary">My Button</Button>

But then you realize it would be great if your buttons got disabled when they are loading. So you inherit Blazorise.Button and change the behavior.

namespace Blazorise.Providers.MyCustomProvider
{
    using Microsoft.AspNetCore.Components.Rendering;

    public class Button : Blazorise.Button
    {
        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            this.Disabled = this.Loading;
            base.BuildRenderTree(builder);
        }
    }
}

But to use your custom Button, because of ambiguity you now have 2 not-so-ideal options

  1. Use weird custom name
<CustomButton Color="Color.Primary">My Button</CustomButton>
  1. Specify lengthy namespaces
<MyCustomProvider.Button Color="Color.Primary">My Button</MyCustomProvider.Button>

Both approaches require replacement of all current occurrences of the Button 😢

Would be great if we could just write inside _Imports.razor

using Button = Blazorise.Providers.MyCustomProvider.Button

@CaiusJard
Copy link

Another vote for this, for slightly different reasons outlined in the linked issue

@brianlagunas
Copy link

It's been a year since my last comment, but this limitation is really having a negative impact on my company's ability to provide a great experience with custom Blazor components. The only option we are really left with is to provide some silly prefix to the name of our components just to avoid any collisions.

@mkArtakMSFT can we get some type of response on the current status for planning implementation of alias support?

@TanayParikh
Copy link
Contributor

can we get some type of response on the current status for planning implementation of alias support?

We'll be considering this during .NET 7 planning.

@ghost
Copy link

ghost commented Nov 11, 2021

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@Wynadorn
Copy link

Wynadorn commented Jul 11, 2022

The lack of global:: operator in combination with the inability to use namespace aliases is a real headache

Besides the already mentioned issues, I believe the following issues are also related

As @TLabWest mentioned back in March 2021 this scope of this issue is quite large.
The only work-around I see is renaming either namespace, however this isn't always an option.

I think it's a mistake to label this issue as severity: minor and affected-few
Hope someone can find the time to resolve long standing (3y old) issue.

A small use-case example:

MyPage.razor

@namespace Contoso.UI.Blazor
@using global::Blazor.FancyButton

<div class="my-component">
    This Blazor component is defined in the <strong>Contoso.UI.Blazor</strong> package.
</div>

<Blazor.FancyButton.MyButton />

MyButton.razor (for example from an external NuGet package)

@namespace Blazor.FancyButton

<div class="my-component">
    This Blazor component is defined in the <strong>Blazor.FancyButton</strong> package.
</div>

MyPage_razor.g.cs will output the following error
The type or namespace name 'FancyButton' does not exist in the namespace 'Contoso.UI.Blazor' (are you missing an assembly reference?)

@Dreamescaper
Copy link

Dreamescaper commented Sep 12, 2022

@TanayParikh @333fred
I could submit a partial fix, which would allow to use using aliases specifically to resolve ambiguous references (i.e. adding @using Button = SomeLibrary.Components.Button when there is more than one Button available).

It seems to be relatively easy comparing to the full aliases support, but still would allow to resolve a lot of requests related to the aliases support.

Would you accept it?

@chsienki chsienki transferred this issue from dotnet/razor-compiler Oct 28, 2022
@ghost ghost added the untriaged label Oct 29, 2022
@chsienki chsienki removed the untriaged label Jan 5, 2023
@ghost ghost added the untriaged label Jan 5, 2023
@chsienki chsienki added this to the Backlog milestone Jan 5, 2023
@ghost ghost removed the untriaged label Jan 5, 2023
@daver77
Copy link

daver77 commented Mar 16, 2023

I'm surprised this hasn't been implemented from day 1. I've been trying to get this working but just came across this thread. My page looks like this

image

So I want to make it look neater with aliasing like this but it doesn't work

image

@ScarletKuro
Copy link

The lack of alias support can be a problem for MudBlazor. We have PropertyColumn and TemplateColumn, same as in QuickGrid. Most users will have @using MudBlazor in the _Imports.razor, meaning that if you want to use QuickGrid, you need to use full qualifier <Microsoft.AspNetCore.Components.QuickGrid.PropertyColumn />.

@SNiedinger
Copy link

SNiedinger commented Feb 11, 2024

Suggestion:

The compiler should store the last namespace of a Blazor component in a variable as it "steps" through the Razor page. When there is a RZ9985 error and one of the conflicting types namespace matches (or partially matches?) the current namespace component variable namespace, then that namespace should be used otherwise throw RZ9985 error.

E.g.

<MudGrid>  --> namespace = MudBlazor.MudGrid
    <PropertyColumn../> --> RZ9985 apply the MudBlazor.MudGrid namespace
 ....
 <QuickGrid> --> namespace = Microsoft.AspNetCore.Components.QuickGrid
    <PropertyColumn../> --> RZ9985 apply the Microsoft.AspNetCore.Components.QuickGrid namespace
  ....

@mdhampton
Copy link

mdhampton commented Sep 25, 2024

Still nothing on this? I mean, having my code look like this:

            <QuickGrid Items="Items">
                <Microsoft.AspNetCore.Components.QuickGrid.PropertyColumn Property="@(d => d.LowerBound)" Title="Lower" />
                <Microsoft.AspNetCore.Components.QuickGrid.TemplateColumn Title="Action">
                      <stuff removed />
                </Microsoft.AspNetCore.Components.QuickGrid.TemplateColumn>
            </QuickGrid>

Very concise.

@ViRuSTriNiTy
Copy link

I come here after years of using Blazor to see that it is still not implemented. What the heck!

@ShawnTheBeachy
Copy link

ShawnTheBeachy commented Oct 9, 2024

This is an issue for us using multiple variants of an icon, all with the same name. For example, I want to show either a solid bell icon or an outline bell icon based on whether the user has unread notifications. Right now I have to do:

@if (unread)
{
    <My.Big.Long.Namespace.Components.Icons.Solid.BellIcon />
}
else
{
    <My.Big.Long.Namespace.Components.Icons.Outline.BellIcon />
}

It would be far more usable to be able to do:

@using OutlineBellIcon = My.Big.Long.Namespace.Components.Icons.Outline.BellIcon
@using SolidBellIcon = My.Big.Long.Namespace.Components.Icons.Solid.BellIcon

@if (unread)
{
    <SolidBellIcon />
}
else
{
    <OutlineBellIcon />
}

@CaiusJard
Copy link

CaiusJard commented Oct 9, 2024

Push comes to shove, Shawn, you could look to inherit from each into your own namespace with class names of the Old/New you propose..?

namespace My{
  class SolidBellIcon: My.Long.Solid.BellIcon {}
}

@ShawnTheBeachy
Copy link

@CaiusJard Yeah for sure, there are ways around it. Aliasing would just be a better way around it 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor area-compiler Umbrella for all compiler issues enhancement Small improvement request
Projects
None yet
Development

No branches or pull requests