Буферы протокола в проектах С#, использующих protobuf-net - лучшие практики для генерации кода

157
20

Я пытаюсь использовать protobuf в проекте С#, используя protobuf-net, и мне интересно, как лучше всего организовать это в структуре проекта Visual Studio.


При ручном использовании инструмента протонов для генерации кода на С# жизнь кажется легкой, но она не чувствует себя хорошо.


Я хочу, чтобы файл .proto считался основным файлом исходного кода, генерируя файлы С# в качестве побочного продукта, но до того, как компилятор С# включится.


Возможные варианты:


    Пользовательский инструмент для проточных инструментов (хотя я не вижу, с чего начать)
    Шаг предварительной сборки (вызов протогена или пакетного файла, который делает это)

Я боролся с 2) выше, поскольку он продолжает давать мне "Система не может найти указанный файл", если я не использую абсолютные пути (и мне не нравится, чтобы проекты были явно расположены).


Есть ли соглашение (пока) для этого?


Edit:
Основываясь на комментариях @jon, я повторил метод шага предварительной сборки и использовал это (расположение жестких дисков в настоящее время), используя пример адресной книги Google:


c:\bin\protobuf\protogen "-i:$(ProjectDir)AddressBook.proto" 
"-o:$(ProjectDir)AddressBook.cs" -t:c:\bin\protobuf\csharp.xslt

Edit2:
Принимая рекомендацию @jon по минимизации времени сборки, не обрабатывая файлы .proto, если они не изменились, я сбил базовый инструмент для проверки (это, вероятно, можно было бы расширить до полного инструмента Custom-Build):


using System;
using System.Diagnostics;
using System.IO;

namespace PreBuildChecker
{
public class Checker
{
static int Main(string[] args)
{
try
{
Check(args);
return 0;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return 1;
}
}

public static void Check(string[] args)
{
if (args.Length < 3)
{
throw new ArgumentException(
"Command line must be supplied with source, target and command-line [plus options]");
}

string source = args[0];
string target = args[1];
string executable = args[2];
string arguments = args.Length > 3 ? GetCommandLine(args) : null;

FileInfo targetFileInfo = new FileInfo(target);
FileInfo sourceFileInfo = new FileInfo(source);
if (!sourceFileInfo.Exists)
{
throw new ArgumentException(string.Format(
"Source file {0} not found", source));
}

if (!targetFileInfo.Exists ||
sourceFileInfo.LastWriteTimeUtc > targetFileInfo.LastAccessTimeUtc)
{
Process process = new Process();
process.StartInfo.FileName = executable;
process.StartInfo.Arguments = arguments;
process.StartInfo.ErrorDialog = true;

Console.WriteLine(string.Format(
"Source newer than target, launching tool: {0} {1}",
executable,
arguments));
process.Start();
}
}

private static string GetCommandLine(string[] args)
{
string[] arguments = new string[args.Length - 3];
Array.Copy(args, 3, arguments, 0, arguments.Length);
return String.Join(" ", arguments);
}
}
}


Моя команда pre-build теперь (все в одной строке):


$(SolutionDir)PreBuildChecker\$(OutDir)PreBuildChecker 
$(ProjectDir)AddressBook.proto
$(ProjectDir)AddressBook.cs
c:\bin\protobuf\protogen
"-i:$(ProjectDir)AddressBook.proto"
"-o:$(ProjectDir)AddressBook.cs"
-t:c:\bin\protobuf\csharp.xslt

спросил(а) 2009-01-17T21:57:00+03:00 11 лет, 8 месяцев назад
1
Решение
120

Как расширение кода Shaun, я рад сообщить, что protobuf-net теперь имеет интеграцию Visual Studio с помощью пользовательского инструмента. Установщик MSI доступен на странице проекта . Более полная информация здесь: protobuf-net; теперь с добавлением Orcas.

Visual Studio with protobuf-net as a Custom Tool

ответил(а) 2009-07-16T21:06:00+04:00 11 лет, 2 месяца назад
116

Вызов этапа предварительной сборки, но с использованием переменных проекта (например, $(ProjectPath)), чтобы создать абсолютные имена файлов, не имея их на самом деле в вашем решении, может показаться разумной для меня.


Одна вещь, которую вы, возможно, захотите рассмотреть, основываясь на моем прошлом опыте генераторов кода: вы можете написать оболочку для протогена, которая генерирует код в другом месте, а затем проверяет, является ли вновь сгенерированный код таким же, как старый код и не перезаписывает его, если это так. Таким образом, Visual Studio ничего не изменит и не заставит проект перестроить - это сократило время сборки для меня в прошлом.

В качестве альтернативы вы можете сохранить хеш md5 файла .proto в последний раз, когда был запущен протоген, и только выполнить protogen, если файл .proto изменился - даже меньше сделать для каждой сборки!


Спасибо, что подняли это как вопрос, хотя это явно говорит о том, что я должен разработать способ сделать этот простой шаг предварительной сборки для моего собственного порта.

ответил(а) 2009-01-17T22:06:00+03:00 11 лет, 8 месяцев назад
106

Добавьте в настройки проекта следующее событие предварительной сборки, чтобы сгенерировать файл С# только при изменении файла .proto. Просто замените YourFile на имя базового имени вашего .proto файла.


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 }

Это работает в любой новой версии Visual Studio, в отличие от средства создания пользовательской сборки protobuf-net, которое не поддерживает Visual Studio 2012 или Visual Studio 2013, в соответствии с проблемами 338 и 413.

ответил(а) 2012-12-13T11:52:00+04:00 7 лет, 9 месяцев назад
99

Ну, это дало мне представление (что-то о том, как изобретать колесо)...


    создать простой Makefile.mak, что-то вроде

.SUFFIXES : .cs .proto

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


(очевидно, не забудьте заменить пути на protogen и csharp.xlst). ВАЖНО - команда protogen\protogen.exe, начинающаяся с символа TAB, а не 8 пробелов


    Если вы не хотите указывать файлы, которые нужно постоянно создавать, вы можете использовать что-то вроде

.SUFFIXES : .cs .proto

all: mycs1.cs myotherfile.cs

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


    на этапе предварительной сборки, чтобы добавить
cd $(ProjectDir) && "$(DevEnvDir)..\..\vc\bin\nmake" /NOLOGO -c -f Makefile.mak mycs1.cs myotherfile.cs

или, если у вас есть nmake на вашем пути, можно использовать
 

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

ответил(а) 2009-05-22T03:44:00+04:00 11 лет, 4 месяца назад
89

Добавьте это в соответствующий файл проекта.


Преимущество, инкрементная сборка.


Недостаток, вам нужно отредактировать вручную при добавлении файлов.


<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=""@(_protoc)" "--csharp_out=$(ProjectDir.TrimEnd('\'))" @(Proto->'%(Identity)',' ')" WorkingDirectory="$(ProjectDir)" />
</Target>

ответил(а) 2015-09-17T22:50:00+03:00 5 лет назад
70

Я приложил к этой странице быстрый и грязный экземпляр Visual Studio Custom Tool вокруг ProtoGen.exe на странице Кода Google (http://code.google.com/p/protobuf-net/issues/detail?id=39). Это очень упрощает добавление файлов .proto к проектам С#.


Дополнительную информацию см. в файле readme в приложении.

ответил(а) 2009-06-24T21:02:00+04:00 11 лет, 3 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема