Using import in proto file with Visual Studio/Rider - visual-studio

I am getting a "File not found" error when using import in a .proto file.
I am using Rider but have the same problem when using Visual Studio.
First proto File:
syntax = "proto3";
import "/fileToImport.proto";
service GreeterAPI {
rpc SayHello (SayHelloRequest) returns (SayHelloResponse);
}
message SayHelloRequest {
string name = 1;
}
message SayHelloResponse {
string answer = 1;
}
Second proto file that i want to import:
syntax = "proto3";
message Foo {
string bar = 1;
}
Both files are located next to each other in the project directory.
.csprjo File:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.10.1" />
<PackageReference Include="Grpc.Core" Version="2.25.0" />
<PackageReference Include="Grpc.Tools" Version="2.25.0" />
<Protobuf Include="**/*.proto" />
</ItemGroup>
</Project>
If i build the project without the import line everything is fine. But with the import line i get "File not found"
I know i can use the --proto_path to tell protoc all the files.
But i don't want to build an extra pre-build script or something like that.
I want to use the build in support of the IDE.

I had the same problem as you, the fix that worked for me was adding the containing folder of the .proto files to the import. Assuming both .proto file are in a folder "Protos", try changing
import "/fileToImport.proto";
to
import "Protos/fileToImport.proto".
Also try changing in the .csproj file from
<Protobuf Include="**/*.proto" />
to
<ItemGroup>
<Protobuf Include="Protos/includingFile.proto" Link="includingFile.proto"/>
<Protobuf Include="Protos/fileToInclude.proto" Link="fileToInclude.proto"/>
</ItemGroup>
Hope that helps

Related

Linking different Protobuf files C#

I'm trying to link protobuf together from different projects in my solution.
I seem to get File Not Found errors every time I build and can't find a way for the protobuf compiler to find the files.
The following protobuf files i'm using also a note that I trimmed some small things.
Project A
Service/Identity/Protos/User.Proto
import "Identity/Protos/Common.proto";
option csharp_namespace = "Service.Identity";
package user;
service ProfileController {
rpc CreateProfile(CreateProfileRequest) returns (common.GenericResult);
}
Project B
Shared/Protos/Common.Proto
option csharp_namespace = "Shared";
package common;
message GenericResult {
bool success = 1;
string exceptions = 2;
}
In the csproj files the following settings have been made.
Project A
<ItemGroup>
<Protobuf Include="Identity\Protos\User.proto" GrpcServices="Server" />
<Protobuf Include="..\Shared\Protos\Common.proto" Link="Identity\Protos\Common.proto" ProtoRoot=".." GrpcServices="None" >
</Protobuf>
Project B
<ItemGroup>
<Protobuf Include="Protos\Common.proto" GrpcServices="None" />
</ItemGroup>
The link seems to work but I can't import it in my user.proto
When I try and import it which I have tried in the following import statements in my user.proto seems to be able to find it.
import "Identity/Protos/Common.proto";
import "Protos/Common.proto";
import "Common.proto";
import "/Identity/Protos/Common.proto";
It gives me the following error.
All i want to do is be able to use the Common.Proto in my User.Proto. But it just does not work.

how use properties from Directory.Build.props in Import from project file of Visual Studio

I have this situation:
I have a .proj file in project directory:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Include="PQExtensionTest.pq">
<SubType>Code</SubType>
</Compile>
<Content Include="PQExtensionTest.query.pq">
<SubType>Code</SubType>
</Content>
</ItemGroup>
<!-- <Import Project="..\Directory.Build.props" /> -->
<Import Project="$(aProperty)add.targets" />
</Project>
In the solution directory (..\ from project directory) I have file Directory.Build.props:
<Project DefaultTargets="BuildExtension" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<aProperty>$(MSBuildProjectDirectory)/Subdir/</aProperty>
</PropertyGroup>
</Project>
In the project directory I have subdirectory "Subdir", where there is file add.targets, which contains all the targets I need (do not show it's contains here because it is not relevant to the problem).
So all above has this folder structure:
Solution directory
Directory.Build.props
Project Directory
Project.mproj
Subdir
add.targets
Preparing all the above, I expected that aProperty will be initiated before the import and the import of add.targets will happen without problem. But I get error that imported project is not found, and I see in error message that MSBuild tries to import from project directory, and not from subdirectory Subdir.
If I uncomment this row:
<Import Project="..\Directory.Build.props" />
all works fine.
The only reasonable explanation for me of such behavior is that aProperty is empty at the moment of importing, because explicit import happens before implicit one.
Is there any way to force MSBuild to inexplicitly import Directory.Build.props before any other imports, while work in Visual Studio?
"While in Visual Studio"
For C# and VB language project, we don't need to import
Directory.Build.props manually or force it before other imports.
When creating a new project(C# or VB) in VS, open its proj file we can find the format is like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
...
</PropertyGroup>
<ItemGroup>
...
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Every time when creating new C# or VB project, the top line within the <Project>node is Import project="Microsoft.Common.props", and we can find the sentence from this document:
When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). If it finds one, it imports the property.
So in visual studio, we don't need to force it before other imports.Its always called after import Microsoft.Common.props, and since the import Microsoft.Common.props is always first line of project node by default, the Directory.Build.Targets is always implicitly imported right after the Microsoft.Common.props and before others.
Note: This feature only supports C# and VB, cause only these two kinds of projects will import the Microsoft.Common.Props in proj file.
And for other kinds of projects, just like your .mproj or
.vcxproj(C++), this feature(Directory.Build.props) is not supported
yet.
So the Directory.Build.Targets or .props is the same as any custom .props. It doesn't make difference between Directory.Build.Targets and anyName.props.
In this way,to read the value in it we have to use import project to call it manually. And that's why the build can't succeed until you uncomment the row:<Import Project="..\Directory.Build.props" />
The way to import properties from 'Directory.Build.props' file from nested folder structure is given below:
Refer: https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019
Note that:
1. These property file definition works from MSBuild tools version 15.0
2. You need to be aware of where to place this import: At the beginning of the file or at the end of the file. Generally it is good to place at the end as nested properties will be visible to parent properties.

What is the value of MSBuildThisFileDirectory?

If I have a project structure like this:
\MySolution
\MyProject
ReadMe.md
\build
MyProject.targets
What would the value of $(MSBuildThisFileDirectory) be when used in the MyProject.targets file?
Assuming my solution folder is in the root of C: drive, would it be?..
c:\MySolution\MyProject\build\
In the MyProject.targets file, how would I reference the ReadMe.md file using the $(MSBuildThisFileDirectory)?
Additional information:
MyProject.targets looks like:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)\xxx\ReadMe.md">
<Link>FrameworkTests.feature</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CustomToolNamespace></CustomToolNamespace>
</None>
</ItemGroup>
</Project>
What is the value of MSBuildThisFileDirectory?
It depends on your MyProject.targets. According to the literal meaning of this variable, you could to know ThisFileDirectory means "This File Directory".
Since you have use this argument in the file MyProject.targets, the path should be related to the location of the "this file" MyProject.targets. So the value of this argument should be the directory of this file MyProject.targets.
After install the nuget, the file MyProject.targets should be added to the path:
c:\MySolution\packages\MyProject.1.0.0<YouPackagefolder>\build
You can use a target to output that value in your project file, to accomplish this, unload your project. Then at the very end of the project, just before the end-tag </project>, place below scripts:
<Target Name="TestValue" AfterTargets="build">
<Message Text="#(none)">
</Message>
</Target>

Include XML file from package when using "Publish Web"

I have a Web API project that depends on a NuGet package. This package contains an XML file that is referenced by my application at runtime.
When I build the solution and run it in debug mode from Visual studio the file gets copied to \bin, and the application runs without problem.
When I publish the application the file doesn't get copied to the final output, and I can see that it's never been copied to the \obj folder.
I've though of adding the file reference directly to the package in the \packages folder, but this will break whenever the package version is updated.
How can I specify that the file should be copied when deploying?
I figured it out based on this blogpost.
I added the following to the end of the .csproj file:
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
<Message Text="=== CustomCollectFiles ===" Importance="high" />
<ItemGroup>
<_CustomFiles Include="..\Packages\**\*PackageName.*.xml*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>bin\%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
Petter Brodins answer almost work for me. And since I am new to Stackoverflow commenting i can not add a comment. In order for it to work I changed the Include to "..\Packages*\lib*.xml". But this was a life saver since i wrote a lot of documentation and couldn't get it to my swagger implementation.

Update Post-Build with custom nuget package

I need help to be able to update the post-build event of a project thanks to a custom nuget package.
I've created a package thanks to a nuspec file that include a .targets file :
<file src="*.targets" target="build"/>
Here is the .targets file :
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild" AfterTargets="Build" >
<Message Text="Hello World" Importance="high" />
</Target>
</Project>
Actually, the file is read when i install the package (if i delete some '>', i've an error).
But the .csproj isn't updated (so, nothing in the post-build event textbox).
Did i miss something ?
I agree with Matt Ward. From NuGet 2.5, NuGet recognizes a new top-level folder: \build.
Within the \build folder, you can provide a “.props” file and/or a
“.targets” file that will be automatically imported into the project.
For this convention, the file name must match your package id with
either a “.props” or “.targets” extension.
Please refer to the MSBuild Integration part in following document:
http://blog.nuget.org/20130426/native-support.html
And after install the package, you will see a import node in .csproj which import the package.targets file. Then when build your project, you will see "Hello World" text in output window.

Resources