title: Protocol buffers in C# projects using protobuf-net - best practices for code generation
body: <p>I'm trying to use protobuf in a C# project, using protobuf-net, and am wondering what is the best way to organise this into a Visual Studio project structure.</p>
  
  <p>When manually using the protogen tool to generate code into C#, life seems easy but it doesn't feel right.</p>
  
  <p>I'd like the .proto file to be considered to be the primary source-code file, generating C# files as a by-product, but before the C# compiler gets involved.</p>
  
  <p>The options seem to be:</p>
  
  <ol>
  <li>Custom tool for proto tools (although I can't see where to start there)</li>
  <li>Pre-build step (calling protogen or a batch-file which does that)</li>
  </ol>
  
  <p>I have struggled with 2) above as it keeps giving me "The system cannot find the file specified" unless I use absolute paths (and I don't like forcing projects to be explicitly located).</p>
  
  <p>Is there a convention (yet) for this?</p>
  
  <hr>
  
  <p><strong><em>Edit:</em></strong>
  Based upon @jon's comments, I retried the pre-build step method and used this (protogen's location hardcoded for now), using Google's address-book example:</p>
  
  <pre><code>c:\bin\protobuf\protogen "-i:$(ProjectDir)AddressBook.proto" 
         "-o:$(ProjectDir)AddressBook.cs" -t:c:\bin\protobuf\csharp.xslt
  </code></pre>
  
  <hr>
  
  <p><strong><em>Edit2:</em></strong>
  Taking @jon's recommendation to minimise build-time by not processing the .proto files if they haven't changed, I've knocked together a basic tool to check for me (this could probably be expanded to a full Custom-Build tool):</p>
  
  <pre><code>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 &lt; 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 &gt; 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 &gt; 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);
          }
      }
  }
  </code></pre>
  
  <p>My pre-build command is now (all on one line):</p>
  
  <pre><code>$(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
  </code></pre>