Protocol buffers in C# projects using protobuf-net - best practices for code generation

旧时模样 提交于 2019-12-02 16:48:42
Marc Gravell

As an extension of Shaun's code, I am pleased to announce that protobuf-net now has Visual Studio integration by way of a Custom Tool. The msi installer is available from the project page. More complete information here: protobuf-net; now with added Orcas.

Calling a pre-build step but using project variables (e.g. $(ProjectPath)) to create absolute filenames without having them actually in your solution would seem a reasonable bet to me.

One thing you might want to consider, based on my past experience of code generators: you might want to write a wrapper for protogen which generates code to a different location, then checks whether the newly generated code is the same as the old code, and doesn't overwrite it if so. That way Visual Studio will realise nothing's changed and not force that project to be rebuilt - this has cut build times dramatically for me in the past.

Alternatively, you could keep an md5 hash of the .proto file the last time protogen was executed, and only execute protogen if the .proto file has changed - even less to do on each build!

Thanks for raising this as a question though - it clearly suggests I should work out a way to make this an easy pre-build step for my own port.

Add the following pre-build event to your project settings to generate the C# file only when the .proto file has changed. Just replace YourFile with the name of base name of your .proto file.

cd $(ProjectDir) && powershell -Command if (!(Test-Path YourFile.proto.cs) -or (Get-Item YourFile.proto).LastWriteTimeUtc -gt (Get-Item YourFile.proto.cs).LastWriteTimeUtc) { PathToProtoGen\protogen -i:YourFile.proto -o:YourFile.proto.cs }

This works in any recent version of Visual Studio, unlike the protobuf-net Custom-Build tool, which does not support Visual Studio 2012 or Visual Studio 2013, according to issues 338 and 413.

Add this to the relevant project file.

Advantage, incremental build.

Disadvantage, you need to edit manually when adding files.

<ItemGroup>
    <Proto Include="Person.proto" />
    <Compile Include="Person.cs">
        <DependentUpon>Person.proto</DependentUpon>
    </Compile>
</ItemGroup>
<PropertyGroup>
    <CompileDependsOn>ProtobufGenerate;$(CompileDependsOn)</CompileDependsOn>
</PropertyGroup>
<Target Name="ProtobufGenerate" Inputs="@(Proto)" Outputs="@(Proto->'$(ProjectDir)%(Filename).cs')">
    <ItemGroup>
        <_protoc Include="..\packages\Google.Protobuf.*\tools\protoc.exe" />
    </ItemGroup>
    <Error Condition="!Exists(@(_protoc))" Text="Could not find protoc.exe" />
    <Exec Command="&quot;@(_protoc)&quot; &quot;--csharp_out=$(ProjectDir.TrimEnd('\'))&quot; @(Proto->'%(Identity)',' ')" WorkingDirectory="$(ProjectDir)" />
</Target>
Andrey Tch.

well, that gave me an idea (something about reinventing the wheel)...

  • create simple Makefile.mak, something like
.SUFFIXES : .cs .proto

.proto.cs:
    protogen\protogen.exe -i:$? -o:$@ -t:protogen\csharp.xlst

(obviously, don't forget to replace paths to protogen and csharp.xlst). IMPORTANT - protogen\protogen.exe command starting from TAB character, not 8 spaces

  • If you don't want to specify files needed to be build all the time, you might use something like
.SUFFIXES : .cs .proto

all: mycs1.cs myotherfile.cs

.proto.cs:
    protogen\protogen.exe -i:$? -o:$@ -t:protogen\csharp.xlst
  • in pre-build step to add
cd $(ProjectDir) && "$(DevEnvDir)..\..\vc\bin\nmake" /NOLOGO -c -f Makefile.mak mycs1.cs myotherfile.cs

or, if you have nmake in your path, one can use

cd $(ProjectDir) && nmake /NOLOGO -c -f Makefile.mak mycs1.cs myotherfile.cs

I have attached a quick and dirty Visual Studio Custom Tool wrapper around ProtoGen.exe to the Google Code page for this issue (http://code.google.com/p/protobuf-net/issues/detail?id=39). This makes adding .proto files to C# projects extremely easy.

See the readme in the attachment for more info.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!