C# read custom configuration build - c#

In my .net application, I have added new build modes for the configurations.
I currently have: Debug, Release, BetaDebug & BetaRelease.
Each having a specific purpose for software engineering purposes.
I wish to know if I can get a C# string containing this text. So I can then do:
string configurationBuild = GetConfigurationBuild();
if(configurationBuild.Contains("Beta") {
//do something
}
else {
//do something else
}

You can configure that each configuration will define Conditional Compilation symbols use preprocessor instructions like #if to find out which build configurationis being used.
Here is a link on msdn forum http://social.msdn.microsoft.com/Forums/vstudio/en-US/7d574468-c890-49d2-984e-16ad068a006e/build-configuration-in-preprocessor

You can use conditional compilation symbols ( http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(CS.PROJECTPROPERTIESBUILD);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22)&rd=true ) for your build modes.
In your code you can then use the #if directive http://msdn.microsoft.com/de-de/library/4y6tbswk(v=vs.100).aspx

Related

Out of curiosity is there a way to use compilation symbols on a single statement in C#? [duplicate]

In Solution properties, I have Configuration set to "release" for my one and only project.
At the beginning of the main routine, I have this code, and it is showing "Mode=Debug".
I also have these two lines at the very top:
#define DEBUG
#define RELEASE
Am I testing the right variable?
#if (DEBUG)
Console.WriteLine("Mode=Debug");
#elif (RELEASE)
Console.WriteLine("Mode=Release");
#endif
My goal is to set different defaults for variables based on debug vs release mode.
DEBUG/_DEBUG should be defined in VS already.
Remove the #define DEBUG in your code. Set preprocessors in the build configuration for that specific build.
The reason it prints "Mode=Debug" is because of your #define and then skips the elif.
The right way to check is:
#if DEBUG
Console.WriteLine("Mode=Debug");
#else
Console.WriteLine("Mode=Release");
#endif
Don't check for RELEASE.
By default, Visual Studio defines DEBUG if project is compiled in Debug mode and doesn't define it if it's in Release mode. RELEASE is not defined in Release mode by default. Use something like this:
#if DEBUG
// debug stuff goes here
#else
// release stuff goes here
#endif
If you want to do something only in release mode:
#if !DEBUG
// release...
#endif
Also, it's worth pointing out that you can use [Conditional("DEBUG")] attribute on methods that return void to have them only executed if a certain symbol is defined. The compiler would remove all calls to those methods if the symbol is not defined:
[Conditional("DEBUG")]
void PrintLog() {
Console.WriteLine("Debug info");
}
void Test() {
PrintLog();
}
I prefer checking it like this over looking for #define directives:
if (System.Diagnostics.Debugger.IsAttached)
{
//...
}
else
{
//...
}
With the caveat that of course you could compile and deploy something in debug mode but still not have the debugger attached.
I'm not a huge fan of the #if stuff, especially if you spread it all around your code base as it will give you problems where Debug builds pass but Release builds fail if you're not careful.
So here's what I have come up with (inspired by #ifdef in C#):
public interface IDebuggingService
{
bool RunningInDebugMode();
}
public class DebuggingService : IDebuggingService
{
private bool debugging;
public bool RunningInDebugMode()
{
//#if DEBUG
//return true;
//#else
//return false;
//#endif
WellAreWe();
return debugging;
}
[Conditional("DEBUG")]
private void WellAreWe()
{
debugging = true;
}
}
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='
The method Debug.Assert has conditional attribute DEBUG. If it is not defined, the call and the assignment isDebug = true are eliminated:
If the symbol is defined, the call is included; otherwise, the call (including evaluation of the parameters of the call) is omitted.
If DEBUG is defined, isDebug is set to true (and passed to Debug.Assert , which does nothing in that case).
If you are trying to use the variable defined for the build type you should remove the two lines ...
#define DEBUG
#define RELEASE
... these will cause the #if (DEBUG) to always be true.
Also there isn't a default Conditional compilation symbol for RELEASE. If you want to define one go to the project properties, click on the Build tab and then add RELEASE to the Conditional compilation symbols text box under the General heading.
The other option would be to do this...
#if DEBUG
Console.WriteLine("Debug");
#else
Console.WriteLine("Release");
#endif
Be sure to define the DEBUG constant in the Project Build Properties. This will enable the #if DEBUG. I don't see a pre-defined RELEASE constant, so that could imply that anything Not in a DEBUG block is RELEASE mode.
Remove your defines at the top
#if DEBUG
Console.WriteLine("Mode=Debug");
#else
Console.WriteLine("Mode=Release");
#endif
NameSpace
using System.Resources;
using System.Diagnostics;
Method
private static bool IsDebug()
{
object[] customAttributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);
if ((customAttributes != null) && (customAttributes.Length == 1))
{
DebuggableAttribute attribute = customAttributes[0] as DebuggableAttribute;
return (attribute.IsJITOptimizerDisabled && attribute.IsJITTrackingEnabled);
}
return false;
}
Slightly modified (bastardized?) version of the answer by Tod Thomson as a static function rather than a separate class (I wanted to be able to call it in a WebForm viewbinding from a viewutils class I already had included).
public static bool isDebugging() {
bool debugging = false;
WellAreWe(ref debugging);
return debugging;
}
[Conditional("DEBUG")]
private static void WellAreWe(ref bool debugging)
{
debugging = true;
}
A tip that may save you a lot of time - don't forget that even if you choose debug under the build configuration (on vs2012/13 menu it's under BUILD => CONFIGURATION MANAGER) - that's not enough.
You need to pay attention to the PUBLISH Configuration, as such:
It is worth noting here that one of the most significant differences between conditionally executing code based on #if DEBUG versus if(System.Diagnostics.Debugger.IsAttached) is that the compiler directive changes the code that is compiled. That is, if you have two different statements in an #if DEBUG/#else/#endif conditional block, only one of them will appear in the compiled code. This is an important distinction because it allows you do do things such as conditionally compile method definitions to be public void mymethod() versus internal void mymethod() depending on build type so that you can, for example, run unit tests on debug builds that will not break access control on production builds, or conditionally compile helper functions in debug builds that will not appear in the final code if they would violate security in some way should they escape into the wild. The IsAttached property, on the other hand, does not affect the compiled code. Both sets of code are in all of the builds - the IsAttached condition will only affect what is executed. This by itself can present a security issue.
I got to thinking about a better way. It dawned on me that #if blocks are effectively comments in other configurations (assuming DEBUG or RELEASE; but true with any symbol)
public class Mytest
{
public DateTime DateAndTimeOfTransaction;
}
public void ProcessCommand(Mytest Command)
{
CheckMyCommandPreconditions(Command);
// do more stuff with Command...
}
[Conditional("DEBUG")]
private static void CheckMyCommandPreconditions(Mytest Command)
{
if (Command.DateAndTimeOfTransaction > DateTime.Now)
throw new InvalidOperationException("DateTime expected to be in the past");
}
Remove the definitions and check if the conditional is on debug mode. You do not need to check if the directive is on release mode.
Something like this:
#if DEBUG
Console.WriteLine("Mode=Debug");
#else
Console.WriteLine("Mode=Release");
#endif
Since the purpose of these COMPILER directives are to tell the compiler NOT to include code, debug code,beta code, or perhaps code that is needed by all of your end users, except say those the advertising department, i.e. #Define AdDept you want to be able include or remove them based on your needs. Without having to change your source code if for example a non AdDept merges into the AdDept. Then all that needs to be done is to include the #AdDept directive in the compiler options properties page of an existing version of the program and do a compile and wa la! the merged program's code springs alive!.
You might also want to use a declarative for a new process that is not ready for prime time or that can not be active in the code until it's time to release it.
Anyhow, that's the way I do it.

Embedding build information in local and CI builds like in Gradle

my question does not target a problem. It is more some kind of "Do you know something that...?". All my applications are built and deployed using CI/CD with Azure DevOps. I like to have all build information handy in the create binary and to read them during runtime. Those applications are mainly .NET Core 2 applications written in C#. I am using the default build system MSBuild supplied with the .NET Core SDK. The project should be buildable on Windows AND Linux.
Information I need:
GitCommitHash: string
GitCommitMessage: string
GitBranch: string
CiBuildNumber: string (only when built via CI not locally)
IsCiBuild: bool (Detecting should work by checking for env variables
which are only available in CI builds)
Current approach:
In each project in the solution there is a class BuildConfig à la
public static class BuildConfig
{
public const string BuildNumber = "#{Build.BuildNumber}#"; // Das sind die Namen der Variablen innerhalb der CI
// and the remaining information...
}
Here tokens are used, which get replaced with the corresponding values during the CI build. To achieve this an addon task is used. Sadly this only fills the values for CI builds and not for the local ones. When running locally and requesting the build information it only contains the tokens as they are not replaced during the local build.
It would be cool to either have the BuildConfig.cs generated during the build or have the values of the variables set during the local build (IntelliSense would be very cool and would prevent some "BuildConfig class could not be found" errors). The values could be set by an MSBuild task (?). That would be one (or two) possibilities to solve this. Do you have ideas/experience regarding this? I did not found that much during my internet research. I only stumbled over this question which did not really help me as I have zero experience with MSBuild tasks/customization.
Then I decided to have a look at build systems in general. Namly Fake and Cake. Cake has a Git-Addin, but I did not find anything regarding code generation/manipulation. Do you know some resources on that?
So here's the thing...
Short time ago I had to work with Android apps namly Java and the build system gradle. So I wanted to inject the build information there too during the CI build. After a short time I found a (imo) better and more elegant solution to do this. And this was modifying the build script in the following way (Scripting language used is Groovy which is based on Java):
def getGitHash = { ->
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim().replace("\"", "\\\"")
}
def getGitBranch = { ->
def fromEnv = System.getenv("BUILD_SOURCEBRANCH")
if (fromEnv) {
return fromEnv.substring("refs/heads/".length()).replace("\"", "\\\"");
} else {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim().replace("\"", "\\\"")
}
}
def getIsCI = { ->
return System.getenv("BUILD_BUILDNUMBER") != null;
}
# And the other functions working very similar
android {
# ...
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
buildConfigField "String", "GitBranch", "\"${getGitBranch()}\""
buildConfigField "String", "BuildNumber", "\"${getBuildNumber()}\""
buildConfigField "String", "GitMessage", "\"${getGitCommitMessage()}\""
buildConfigField "boolean", "IsCIBuild", "${getIsCI()}"
# ...
}
The result after the first build is the following java code:
public final class BuildConfig {
// Some other fields generated by default
// Fields from default config.
public static final String BuildNumber = "Local Build";
public static final String GitBranch = "develop";
public static final String GitHash = "6c87e82";
public static final String GitMessage = "Merge branch 'hotfix/login-failed' into 'develop'";
public static final boolean IsCIBuild = false;
}
Getting the required information is done by the build script itself without depending on the CI engine to fulfill this task. This class can be used after the first build its generated and stored in a "hidden" directory which is included in code analysis but exluded from your code in the IDE and also not pushed to the Git. But there is IntelliSense support. In C# project this would be the obj/ folder I guess. It is very easy to access the information as they are a constant and static values (so no reflection or similar required).
So here the summarized question: "Do you know something to achieve this behaviour/mechanism in a .NET environment?"
Happy to discuss some ideas/approaches... :)
It becomes much easier if at runtime you are willing to use reflection to read assembly attribute values. For example:
using System.Reflection;
var assembly = Assembly.GetExecutingAssembly();
var descriptionAttribute = (AssemblyDescriptionAttribute)assembly
.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false).FirstOrDefault();
var description = descriptionAttribute?.Description;
For most purposes the performance impact of this approach can be satisfactorily addressed by caching the values so they only need to read once.
One way to embed the desired values into assembly attributes is to use the MSBuild WriteCodeFragment task to create a class file that sets assembly attributes to the values of project and/or environment variables. You would need to ensure that you do this in a Target that executes before before compilation occurs (e.g. <Target BeforeTargets="CoreCompile" ...). You would also need to set the property <GenerateAssemblyInfo>false</GenerateAssemblyInfo> to avoid conflicting with the functionality referenced in the next option.
Alternatively, you may be able to leverage the plumbing in the dotnet SDK for including metadata in assemblies. It embeds the values of many of the same project variables documented for the NuGet Pack target. As implied above, this would require the GenerateAssemblyInfo property to be set to true.
Finally, consider whether GitVersion would meet your needs.
Good luck!

c# preprocessor directives to evaluate a value from configuration manager

I need to get a value from configuration manager in C# Preprocessor directive
And want to do as like below,
#if System.Configuration.ConfigurationManager.AppSettings["Language"].Equals("en-US");
{
bool languageCheck=TRUE
}
#endif
Is it possible ?
No, pre-processors mean "pre-compilation", and at that point it does not know what values are stored in objects or configurations. However, you can add a different build configuration (by clicking on project properties going to build tab), and add the language flag to it to do a similar thing.
public void SayLanguage()
{
#if en_US
Console.WriteLine("en_US");
#else
Console.WriteLine("Language not defined.");
#endif
}

How to load referenced script libraries from a Roslyn script file?

I figured out I cannot load one script library from another easily:
module.csx
string SomeFunction() {
return "something";
}
script.csx
ExecuteFile("module.csx");
SomeFunction() <-- causes compile error "SomeFunction" does not exist
This is because the compiler does not know of module.csx at the time it compiles script.csx afaiu. I can add another script to load the two files from that one, and that will work. However thats not that pretty.
Instead I like to make my scripthost check for a special syntax "load module" within my scripts, and execute those modules before actual script execution.
script.csx
// load "module.csx"
SomeFunction()
Now, with some basic string handling, I can figure out which modules to load (lines that contains // load ...) and load that files (gist here https://gist.github.com/4147064):
foreach(var module in scriptModules) {
session.ExecuteFile(module);
}
return session.Execute(script)
But - since we're talking Roslyn, there should be some nice way to parse the script for the syntax I'm looking for, right?
And it might even exist a way to handle module libraries of code?
Currently in Roslyn there is no way to reference another script file. We are considering moving #load from being a host command of the Interactive Window to being a part of the language (like #r), but it isn't currently implemented.
As to how to deal with the strings, you could parse it normally, and then look for pre-processor directives that are of an unknown type and delve into the structure that way.
Support for #load in script files has been added as of https://github.com/dotnet/roslyn/commit/f1702c.
This functionality will be available in Visual Studio 2015 Update 1.
Include the script:
#load "common.csx"
...
And configure the source resolver when you run the scripts:
Script<object> script = CSharpScript.Create(code, ...);
var options = ScriptOptions.Default.WithSourceResolver(new SourceFileResolver(new string[] { }, baseDirectory));
var func = script.WithOptions(options).CreateDelegate()
...

Monotouch Compiler Directive if debug

In my MonoTouch app, how can I put in a # compiler directive to include code only if in debug mode?
MonoDevelop by default sets the DEBUG define when you create a solution, so you can use two things: you can use [Conditional ("DEBUG")] attributes on methods that you use to instrument your code and you can use standard if #DEBUGs in your source.
Like this:
[Conditional ("DEBUG")]
void Log (string msg)
{
Console.WriteLine (msg);
}
void Foo ()
{
Log ("Start");
..
Log ("End");
}
What is nice about the Conditional attribute is that the compiler will remove the calls at compile time if the switch is not set, and it is prettier than littering your source code with:
#if DEBUG
Console.WriteLine ("start");
#endif

Categories