dotnet / project-system

The .NET Project System for Visual Studio
MIT License
968 stars 386 forks source link

Implicit includes of resource files should include appropriate metadata #3764

Open dsplaisted opened 6 years ago

dsplaisted commented 6 years ago

From @dsplaisted on May 10, 2017 18:48

Adding a .resx file to an SDK project using Visual Studio results in the following added to the project file:

  <ItemGroup>
    <Compile Update="Resource1.Designer.cs">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
      <DependentUpon>Resource1.resx</DependentUpon>
    </Compile>
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Update="Resource1.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resource1.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>

Ideally, nothing would be added to the project file when you add a .resx to the project. We may be able to do this in the SDK just by setting the appropriate metadata on the implicit EmbeddedResource items and the Compile items for .Designer.cs files.

Copied from original issue: dotnet/sdk#1199

dsplaisted commented 6 years ago

From @wli3 on September 14, 2017 0:48

It need a way to link each other, by convention? I am thinking start from blah.resx, and look for in @(Compile), if there is a file matches blah.Designer.cs then "link" them.

dsplaisted commented 6 years ago

Related #1441

dsplaisted commented 6 years ago

From @wli3 on September 20, 2017 17:12

(Some what related https://github.com/Microsoft/VSProjectSystem/issues/169 https://github.com/dotnet/project-system/issues/1467#issuecomment-327064967)

dsplaisted commented 6 years ago

From @davkean on September 26, 2017 0:39

I've done some research on what some of this metadata is used for:

Conclusion, we can remove all metadata from the designer file.

dsplaisted commented 6 years ago

From @wli3 on July 19, 2018 18:46

@dsplaisted @davkean sorry for the long delay. Conclude from David's research, can we close this issue?

dsplaisted commented 6 years ago

From @davkean on July 19, 2018 23:31

We never removed the metadata, so the bug is still relevant. We should move to project system.

Pilchie commented 6 years ago

@davkean is this distinct from #1158?

cartermp commented 4 years ago

Is the result of this isseu a failure to nest files in the solution explorer?

Using this explicitly:

    <EmbeddedResource Update="Properties\Resources.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
      <SubType>Designer</SubType>
    </EmbeddedResource>
    <Compile Update="Properties\Resources.Designer.cs">
      <AutoGen>True</AutoGen>
      <Dependent

image

But commenting that out yield this:

image

zastrowm commented 4 years ago

Is there a workaround for this? I attempted to follow this stackoverflow answer to implicitly add the metadata, but then VS still doesn't seem to nest or autogenerate the file as needed.

dsplaisted commented 4 years ago

I think that in recent VS releases, the items in solution explorer should now be automatically nested appropriately without any explicit metadata in the project file. Is this correct @davkean?

zastrowm commented 4 years ago

It doesn't seem to be the behavior that I have observed, using VS2019 16.5 and donetsdk 3.1.201 - at least for a Microsoft.NET.Sdk project.

I did determine that you can use the stackoverflow answer, but if you're intending to share the settings, it must be done via Directory.Build.targets instead of Directory.Build.props - which is where I first attempted to use it and it didn't work.

jnm2 commented 4 years ago

I don't think it nests yet, and besides that it also adds or fills this back in to the csproj every time you save the .resx file:

  <ItemGroup>
    <Compile Update="Properties\Resources.Designer.cs">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>

    <EmbeddedResource Update="Properties\Resources.resx">
      <Generator>PublicResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>
jnm2 commented 4 years ago

(By constrast, non-standalone .resx files nest automatically and don't insert pollution into the csproj when edited.)

davidwengier commented 4 years ago

it also adds or fills this back in to the csproj every time you save the .resx file

What version of Visual Studio are you using? https://github.com/dotnet/project-system/issues/2873 should have solved that in 16.5, where any item metadata will not be written to the project file if it already has that value at that point of the evaluation (ie, if your globbing is in Directory.Build.props or something imported at the start of the project)

jnm2 commented 4 years ago

It's reproing in 16.5.2, both the lack of nesting and generating the block I posted above. I'll put a repro project here I guess.

jnm2 commented 4 years ago

Use any SDK csproj, such as this:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

</Project>

And add this empty .resx file at Properties\Resources.resx, or add one using the Add New Item dialog:

Click to expand ```xml text/microsoft-resx 1.3 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ```

If you didn't use the Add New Item dialog, open the .resx and select either the Internal or Public access modifier to get it to generate the corresponding designer file. Now, save and look at the csproj:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="Properties\Resources.Designer.cs">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Update="Properties\Resources.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>

</Project>

Why is this there? Surely Internal is the default and there should be nothing at all in the csproj representing that, and Public would be a single piece of metadata added as an attribute to save space.

Here's the result:

image

Now, let's remove these values from the csproj:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

</Project>

The nesting is gone:

image

jnm2 commented 4 years ago

Now, let's say I remove what seems to be inessential or should be SDK defaults, but I leave the metadata that appears to be required in order to nest, and I leave the metadata that appears to be required to keep the RESX designer from switching from Internal to (custom):

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="Properties\Resources.Designer.cs" DependentUpon="Resources.resx" />
    <EmbeddedResource Update="Properties\Resources.resx" Generator="ResXFileCodeGenerator" />
  </ItemGroup>

</Project>

For one thing, VS constantly tries to auto expand these to fill out the metadata I removed, while I'm typing. It's a little weird. I fight it using Ctrl+Z several times and manage to save.

Now I open the RESX designer, add a single string entry, and click Save. The csproj bloats back up:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="Properties\Resources.Designer.cs" DependentUpon="Resources.resx">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
    </Compile>
    <EmbeddedResource Update="Properties\Resources.resx" Generator="ResXFileCodeGenerator">
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>

</Project>
jnm2 commented 4 years ago

.settings files act just the same as the description above of .resx files:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="Properties\Settings.Designer.cs">
      <DependentUpon>Settings.settings</DependentUpon>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
      <AutoGen>True</AutoGen>
    </Compile>
  </ItemGroup>

  <ItemGroup>
    <None Update="Properties\Settings.settings">
      <Generator>SettingsSingleFileGenerator</Generator>
      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
    </None>
  </ItemGroup>

</Project>
jnm2 commented 4 years ago

All the above appears to repro in VS 16.6-p2.1 as well.

davidwengier commented 4 years ago

Sorry, I misunderstood what you were saying originally. I thought you meant you had globs in place that would mean all of that extra info in the project file wasn't needed. Without anything custom involved, indeed the SDK doesn't default any of that info. We do have https://github.com/dotnet/project-system/issues/5707 logged to improve that situation, but what you're seeing in these comments is what would be expected with the current SDK.

jnm2 commented 4 years ago

I'm sorry! Thanks for that issue reference. I'll follow that then.

cremor commented 4 years ago

So if #5707 handles the request that the metadata should already be added by the SDK, which issue handles the bug that Visual Studio adds the metadata for specifc files again even if all metadata is already correctly set by glob updates? This one?

I did determine that you can use the stackoverflow answer, but if you're intending to share the settings, it must be done via Directory.Build.targets instead of Directory.Build.props - which is where I first attempted to use it and it didn't work.

I also noticed that setting the metadata in glob updates in the Directory.Build.props file doesn't work. Very weird, since this is the correct location for such things, right? Will this also be handled in this issue? Or is there a seperate issue for it?

davidwengier commented 4 years ago

which issue handles the bug that Visual Studio adds the metadata for specifc files again even if all metadata is already correctly set by glob updates?

https://github.com/dotnet/project-system/issues/2873 fixed things so that metadata would not be written for items if it already matched the value at that point in evaluation, so it would rely on globs being in props and not targets. It sounds like its worth logging a new issue for the problems you had with using a props file to see if there is another bug there.

onyxmaster commented 3 years ago

It looks like something is off in the project system for the general (non-.resx) case. Please consider the example -- CodegenProjects. Load it into VS (using 16.7.7 right now), then try to copy the Test.tt file. Also, try adding a new Test2.tt file, then save all files and observe the diff for the project file. It looks like it adds unnecessary files and sometimes even breaks evaluation (adding things like <LastGenOutput>%(Filename).cs</LastGenOutput> instead of <LastGenOutput>Test1 - Copy.cs</LastGenOutput>).

P.S. I'm not sure if this is a perfect issue to add this comment to; I would gladly move it to a new issue if considered a separate one.