dotnet/wpf

PackageReference broken in WPF projects due to tmp_proj not importing Package-supplied build authoring

hayer opened this issue Β· 45 comments

hayer commented
  • .NET Core Version: 3.0-preview5

  • Windows version: Windows 10, 1903

  • Does the bug reproduce also in WPF for .NET Framework 4.8?: No

Problem description:
Trying to use a gRPC service as shown in the AspNetDocs-repo in a WPF app, <UseWPF>true</UseWPF>, results in a build error. Visual Studio and VSCode does not report the problem in intellisense but it appears when doing a dotnet build .sln.

Actual behavior:
Results in a

error CS0246: The type or namespace name 'Greet' could not be found (are you missing a using directive or an assembly reference?)

When building. Greet here is the gRPC service defined in a .proto file.

Expected behavior:
Build & run with no error.

Minimal repro:
I made a repro-repo here.

hayer commented

Not sure if this is the correct repository to open the issue in, but I can't reproduce the error when using a console app.

It’s a good idea to open an issue against AspNet as well.

@hayer @vatsan-madhavan

This looks like an issue with the interaction between gRPC targets and PBT:

MainWindow.xaml.cs(1,7): error CS0246: The type or namespace name 'Greet' could not be found (are you missing a using directive or an assembly reference?) [d:\repos\grpcfail\DemoWpfApp\DemoWpfApp_t1mpsdxb_wpftmp.csproj]

It looks like the temp project used for markup compilation doesn't have access to the generated gRPC class from the protobuffer file. From looking at the buildlog, the temp project is building before the gRPC targets have run.

I believe you can split the client gRPC portion into a separate project and it will build fine. I did this here and it all built fine. I didn't test anything out at runtime, so you might want to ensure it works.

WPF itself doesn't seem to have anything it can do to fix this. I think this is a bug for the gRPC team to ensure their targets are aware of the temp projects used for markup compilation. Of course the above is a simple workaround that should allow you to utilize the types.

Let me know if this works for you.

hayer commented

@rladuca yes, its seems like you can split it into a library project. But isn't it supposed to work directly with .NET Core 3 WPF projects?

@hayer You're probably correct, and maybe this is actually something WPF is doing incorrectly. This could be related to us not getting NuGet PackageReferences in our temporary markup projects.

@ryalanms Do you think this is related to NuGet/Home#5894? It seems like if we ensured that PackageReferences flowed to the temp project, it should get and use all the appropriate targets from gRPC (and other generators) without an issue.

hayer commented

What seems to be happening is that the WPF MSBuild target is generating a temporary project, like DemoWpfApp_rdowyz5w_wpftmp.csproj, this project does not include the code files generated by protobuf.

There is also a
DefaultItemExcludes = ;bin\Debug\/**;obj\Debug\/**;bin\/**;obj\/**;**/*.user;**/*.*proj;**/*.sln;**/*.vssscc
which is passed throughout the build which would include the generated code files.

Guessing the correct solution is to have generated code files passed explicitly into some WPF build target. Still looking into that.

@hayer Without PackageReferences making it to the temp project, it will never pull in the build targets for gRPC. If we had that working, then gRPC would generate the code files in the temp project's build.

WPF temp projects used for markup compilation are basically ignorant of NuGet, seems to be the cause of this and the issue I linked (which is also about missing targets from a PackageReference).

@vatsan-madhavan and @ryalanms have, I believe, done some thinking about this in the past.

hayer commented

@rladuca yes, that's how far I got in my investigation. Was hoping this was something else as the issues linked to earlier seems to have 'stopped'. Guessing this can be closed now?

@grubioe I'm working on a gRPC e-book for Microsoft Docs and I've run into this issue. Since you've moved it to the 5.0 milestone, should I document the workaround of using a separate client library in my book for 3.0?

Yes please, you can document the workaround for 3.0. Thanks!

FYI I'm experiencing this same issue on .NET Framework 4.7.2 as well. WPF projects create a temporary project that does not include the Protobuf targets in the build.

The problem seems to be that Grpc.Tools hooks into BeforeCompile, which appears to not be executed for the temporary project.

Hooking it into CoreCompile instead (eg. by defining <CoreCompileDependsOn>$(CoreCompileDependsOn);Protobuf_Compile</CoreCompileDependsOn> in an imported targets file) successfully works around the problem.

A potential nasty solution is to copy the nuget.g.*.props and targets.
That should end up important the right props and targets from packages.

See comment here: NuGet/Home#5894 (comment).

If indeed this is the issue that will track NuGet/Home#5894 going forward, please update the title of this issue to match the other one or somehow similarly reflect the general problem instead of its current title which suggests a far more limited scope.

Possible solutions:

  • Refactor WPF Xaml compilation to avoid tmp_proj generation
  • When creating tmp_proj, also copy nuget.g.props and nuget.g.targets from source project to corresponding file names for tmp_proj (in the task which creates the tmp_proj)
  • Run restore on the tmp_proj

Just a note that this is not limited to gRPC only. I have a PackageReference that has some source codes (*.cs files) that I want to include in my project. The files are not picked up (although are shown correctly in the IDE) at compile time.

jnm2 commented

Yes, same with two NuGet packages that I contribute to which conditionally include source files through .targets.

Faced the issue today as well, spent the last hours trying to figure out what I did wrong, till I gave up looking for a mistake on my side.

Still have this problem today. Unable to use the gRPC in WPF. Dot net 5. Console app works fine. Nobody fixed this after all this while?

@kennzhang This bug does not affect SDK projects, please open a new build with a build log.

@kennzhang If you set the IncludePackageReferencesDuringMarkupCompilation property to true in your project file, does that help?
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>

@davkean
Doubt this statement is correct, since as you may see the repro from the original post is a SDK project.
Here: https://github.com/hayer/WpfGrpcBuildFail

@clairernovotny Nope, just tried that in PropertyGroup and still doesn't work. Don't understand what @davkean was referring to.. it's WPF. Open new issue?

@Rand-Random I should clarify, by SDK-project I mean "SDK-projects that use the new WPF SDK". In .NET 5, the WPF SDK is by default if you have UseWpf set to true. The original problem is when you are building for WPF, but implicitly using the WPF support that shipped in .NET Framework.

@davkean UseWPF is set to true. This is a new dot net 5 project created from scratch.

''
'WinExe'
'net5.0-windows'
'true'
'true'
''

@davkean
Maybe I am to dumb to understand you, but I have downloaded the repro project changed the DemoWpfApp.csproj to this

<!-- Use Microsoft.NET.Sdk instead of Microsoft.NET.Sdk.WindowsDesktop -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <!-- .net5.0-windows instead of .netcoreapp3.1 -->
    <TargetFramework>net5.0-windows</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

   ...

</Project>

Build still gives the same error.
Here the output:

1>------ Rebuild All started: Project: DemoService, Configuration: Debug Any CPU ------
2>------ Rebuild All started: Project: DemoWpfApp, Configuration: Debug Any CPU ------
1>C:\Program Files (x86)\dotnet\sdk\5.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.EolTargetFrameworks.targets(28,5): warning NETSDK1138: The target framework 'netcoreapp3.0' is out of support and will not receive security updates in the future. Please refer to https://aka.ms/dotnet-core-support for more information about the support policy.
1>DemoService -> C:\Users\rfa\Downloads\WpfGrpcBuildFail-master\WpfGrpcBuildFail-master\DemoService\bin\Debug\netcoreapp3.0\DemoService.dll
1>Done building project "DemoService.csproj".
2>C:\Users\rfa\Downloads\WpfGrpcBuildFail-master\WpfGrpcBuildFail-master\DemoWpfApp\MainWindow.xaml.cs(1,7,1,12): error CS0246: The type or namespace name 'Greet' could not be found (are you missing a using directive or an assembly reference?)
2>Done building project "DemoWpfApp_hdabilkc_wpftmp.csproj" -- FAILED.
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========

Edit:

msbuild.zip

@kennzhang I don't work on this anymore, however, this bug is tracking an issue with using the SDK format while opt'ing into basically legacy WPF support.

The project you have above isn't doing that - if you want see traction on this issue, you would be better approach to file a new bug calling out above with a repro project and/or a build log via msbuild [foo.csproj] /bl.

@davkean
Added msbuild.binlog to my previous comment.

@kennzhang I forgot to mention, you need to be using at least the latest 5.0.200-preview SDK for that property to work. Can you try with that?

Just an update that using <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation> does indeed fix the issue (albeit on .NET 5).

@HEskandari I hope you don't have to target .NET 5 in order to get the fix. I believe the fix is in the SDK. I wonder if you change TargetFramework to net472 if you can build a WPF app for .NET Framework and the fix still works.

The fix is in the .NET 5 SDK, the targets don't matter.

I don't get it, people here mentioning that it's been fixed, however I still have the original issue (.proto compiled files aren't included into WPF build) and can't compile the demo with the latest .NET 5 SDK 2.0.202. IncludePackageReferencesDuringMarkupCompilation property has no effect on my build. The only option left for me is to fallback to creating a class library project and reference it, which looks like a bad practice.

Could someone confirm that it's actually been fixed?

I can confirm that this is still an issue for me as well. I cannot include .proto files in a WPF project. I tried both .NET 5 and 6 with and without IncludePackageReferencesDuringMarkupCompilation and I still get errors.

I can manually include the generated .cs files from the obj directory into the project and the build will succeed, but this is an ugly workaround.

@mikkqu and @ccifra: Please see @uecasm's comment above for the grpc bug and workaround. Thanks.

This is in .NET 6.0 and .NET 5.0. Thanks.

I tested the fix and saw that it works in the 6.0 SDK. But it did not appear to be in 5.0.100. Is it in a later 5.0 version, @ryalanms ?

@AArnott: .NET 5.0 is still 'opt-in' and requires the property (IncludePackageReferencesDuringMarkupCompilation). Is it not working with the property set?

Oh, right. I forgot about the opt-in property. :)

I'm facing this issue on .NET 6 RC1 (Visual Studio 2022 Preview 4).
Even if I added <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation> on .csproj, I can't compile WPF project that is added .proto file.

Build started...
1>------ Build started: Project: WpfApp1, Configuration: Debug Any CPU ------
1>You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
1>C:\Users\xxxx\source\repos\GrpcService2\WpfApp1\MainWindow.xaml.cs(2,7,2,19): error CS0246: The type or namespace name 'GrpcService2' could not be found (are you missing a using directive or an assembly reference?)
1>Done building project "WpfApp1_gtyqsxcq_wpftmp.csproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========

Repro steps:

  1. Create a new WPF Application project
  2. Add greet.proto file to the project via Service References.
syntax = "proto3";

option csharp_namespace = "GrpcService2";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}
  1. Build the project
  2. Add following code snippets to constructor of MainWindow.
var channel = Grpc.Net.Client.GrpcChannel.ForAddress("https://localhost");
var client = new GrpcService2.Greeter.GreeterClient(channel);
  1. Build the project
  2. You can see the following compile error message on Output window.
Build started...
1>------ Build started: Project: WpfApp12, Configuration: Debug Any CPU ------
1>You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
1>C:\Users\xxxx\source\repos\WpfApp12\WpfApp12\MainWindow.xaml.cs(28,30,28,42): error CS0246: The type or namespace name 'GrpcService2' could not be found (are you missing a using directive or an assembly reference?)
1>Done building project "WpfApp12_wlf3wqfd_wpftmp.csproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
  1. Add <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation> to .csproj
  2. Same compile error...

Are there any missing steps?

I wonder if the .proto file is added to the project via contentFiles in the nuget package. I recently encountered this and I wonder if the WPF fix in place accounts for that feature, since it doesn't come in via imported g.props or g.targets files.

Just came across this today when trying gRpc with WPF for the first time. Didn't know this was an issue; can't believe 2 years later it hasn't been fixed.
I am using the latest released versions of all tooling, SDK, .Net 6, etc.

The problem for gRPC is that it hooks onto BeforeCompile which is never called in CompileTemporaryAssembly. To solve this, gRPC would have to hook onto CoreCompile, which is called in CompileTemporaryAssembly. A quick workaround would be to add this to the project that uses gRPC: <CoreCompileDependsOn>Protobuf_Compile;$(CoreCompileDependsOn)</CoreCompileDependsOn>.

EDIT:
I completely missed the comment by @uecasm who provided the same diagnostic/fix:

The problem seems to be that Grpc.Tools hooks into BeforeCompile, which appears to not be executed for the temporary project.

Hooking it into CoreCompile instead (eg. by defining <CoreCompileDependsOn>$(CoreCompileDependsOn);Protobuf_Compile</CoreCompileDependsOn> in an imported targets file) successfully works around the problem.

So I tried the workaround of creating a DLL with the protos. I found it actually works great. I configure the protos with GrpcServices="Both" and reference it from the server and all clients. It would be simple enough to distribute the DLL as a NuGet package if need be.