2

I have three solution configurations in my UWP solution in Visual Studio:

  • Development
  • Staging
  • Production

Each is a associated with a different web service and auth provider in the configuration files. In my code, how do I tell which one is which? In the past I've explicitly provided DEFINE constants, but there must be a better way by now.

Quark Soup
  • 4,272
  • 3
  • 42
  • 74
  • Note that `Configuration` exists at **compile time**, while the code ran at **runtime**, of course. – baruchiro Apr 03 '19 at 04:13
  • What is 'Configuration'? A compiler constant? – Quark Soup Apr 03 '19 at 12:14
  • https://stackoverflow.com/questions/1452962/list-of-msbuild-built-in-variables – baruchiro Apr 03 '19 at 12:17
  • I understand these macros are available for the build. I'm looking for something the compiler can use. We have a 'DEBUG' macro, but I don't have a configuration called 'DEBUG'. I need something where I can say #if CONFIGURATION == PRODUCTION ... #endif. – Quark Soup Apr 03 '19 at 12:20

2 Answers2

2

The active solution configuration is stored in the .suo file beneath the .vs directory at the root solution folder. The .suo file has a compound file binary format, which means you can't just parse it with text manipulation tools.

However, using OpenMcdf -- a tool that can be used to manipulate these types of files -- you can easily get the active solution configuration.

Here's a console app I wrote that works. Feel free to adapt the code to your situation:

using OpenMcdf;
using System;
using System.IO;
using System.Linq;
using System.Text;

namespace GetActiveBuildConfigFromSuo
{
    internal enum ProgramReturnCode
    {
        Success = 0,
        NoArg = -1,
        InvalidFileFormat = -2
    }

    internal class Program
    {
        private const string SolutionConfigStreamName = "SolutionConfiguration";
        private const string ActiveConfigTokenName = "ActiveCfg";

        internal static int Main(string[] args)
        {
            try
            {
                ValidateCommandLineArgs(args);

                string activeSolutionConfig = ExtractActiveSolutionConfig(
                    new FileInfo(args.First()));

                throw new ProgramResultException(
                    activeSolutionConfig, ProgramReturnCode.Success);
            }
            catch (ProgramResultException e)
            {
                Console.Write(e.Message);
                return (int)e.ReturnCode;
            }
        }

        private static void ValidateCommandLineArgs(string[] args)
        {
            if (args.Count() != 1) throw new ProgramResultException(
                "There must be exactly one command-line argument, which " +
                "is the path to an input Visual Studio Solution User " +
                "Options (SUO) file.  The path should be enclosed in " +
                "quotes if it contains spaces.", ProgramReturnCode.NoArg);
        }

        private static string ExtractActiveSolutionConfig(FileInfo fromSuoFile)
        {
            CompoundFile compoundFile;

            try { compoundFile = new CompoundFile(fromSuoFile.FullName); }
            catch (CFFileFormatException)
            { throw CreateInvalidFileFormatProgramResultException(fromSuoFile); }

            if (compoundFile.RootStorage.TryGetStream(
                SolutionConfigStreamName, out CFStream compoundFileStream))
            {
                var data = compoundFileStream.GetData();
                string dataAsString = Encoding.GetEncoding("UTF-16").GetString(data);
                int activeConfigTokenIndex = dataAsString.LastIndexOf(ActiveConfigTokenName);

                if (activeConfigTokenIndex < 0)
                    CreateInvalidFileFormatProgramResultException(fromSuoFile);

                string afterActiveConfigToken =
                    dataAsString.Substring(activeConfigTokenIndex);

                int lastNullCharIdx = afterActiveConfigToken.LastIndexOf('\0');
                string ret = afterActiveConfigToken.Substring(lastNullCharIdx + 1);
                return ret.Replace(";", "");
            }
            else throw CreateInvalidFileFormatProgramResultException(fromSuoFile);
        }

        private static ProgramResultException CreateInvalidFileFormatProgramResultException(
            FileInfo invalidFile) => new ProgramResultException(
                $@"The provided file ""{invalidFile.FullName}"" is not a valid " +
                $@"SUO file with a ""{SolutionConfigStreamName}"" stream and an " +
                $@"""{ActiveConfigTokenName}"" token.", ProgramReturnCode.InvalidFileFormat);
    }

    internal class ProgramResultException : Exception
    {
        internal ProgramResultException(string message, ProgramReturnCode returnCode) 
            : base(message) => ReturnCode = returnCode;

        internal ProgramReturnCode ReturnCode { get; }
    }
}
rory.ap
  • 34,009
  • 10
  • 83
  • 174
2
  1. Download DTE nuget packages : EnvDTE.8.0.2
  2. Add below code

    EnvDTE.DTE DTE = Marshal.GetActiveObject("VisualStudio.DTE.15.0") as EnvDTE.DTE;

    var activeConfig = (string)DTE.Solution.Properties.Item("ActiveConfig").Value;

Rohit
  • 31
  • 5