Replace #ifdefs in C# DLL - c#

I have a C++ DLL which has #defines used like (these defines are automatically defined based on the build configuration, e.g. Debug, Release, etc)
#if defined(CONSTANT)
..
// Some code
#else
// Some other code
I need same functionality in C# dll.
Is it ok if I define some global constants in C# dll and use them
instead of defines?
e.g.
if(Globals.SomeConstant == SOMEVALUE)
// Do this
else
// Do smth else
Then when I want to ship the DLL I will in advance (probably as a default value during declaration) assign SOMEVALUE to Globals.SomeConstant - will this work this way? (Depending on which configuration I need).
I saw some similar questions but they weren't about DLLs.

You can use it similarly as in c++
You can define / undefine them in your source code or as a conditional compilation symbol. In visual studio this can be done using Solution Explorer - Properties - Build - conditional compilation symbols
However, nowadays people tend to use a configuration file for these constants. This way, you don't have to recompile your source code nor redistribute it to change the behaviour.
The most easy method is via visual studio solution explorer - properties - settings
You can add settings for most types. Booleans come closest to #define. Using an int can give you more than two possibilities. See the difficulties if you wanted to be able to use several values for a TimeSpan or an URI using #define.
The nice thing about using the settings is that a class is generated for you to easily access the settings.
Another method is to read the config file directly using the System.Configuration.ConfigurationManager class. This gives you more freedom about the format of the configuration. The disadvantage is that you have to convert the read values into proper types yourself, inclusive handling errors if the value can't be read.
Summarized: advantages of the config file method:
No need to change source files
No need to recompile
No need to re-install
only change the config file on those machines that need the change
improved type safety

My previous answer lead to a more questions than it answered. Hence I thought an example would help.
Suppose I have a DLL, called MyDll. It has a configuration setting that in really old times would have been defined using #define.
My C-synctax is a bit rusty, but it would look like:
#define UseAlternateGreeting
public class MyClass
{
public string GetGreeting()
{
#if defined UseAlternateGreeting
return "Hello World!";
#else
return "Here I am!";
#endif
}
}
Now suppose we have several programs that use this DLL. Program! wants to use the default setting. However Program2 wants to use the alternate setting. There is no way to solve this.
Besides if we want to change the value of the setting we have to recompile and redistribute everything to everyone.
Wouldn't it be easier if we could just edit a file with notepad to change the string?
Luckily Microsoft also saw the advantage of this. Over more than 10 years we have the idea of configuration files. Assemblies have a config file with the name of the application and the extension config. This file can easily be edited using any text editor by those who know what the configuration items mean.
If we replace the #define with an item in the config file the greeting could be changed to the alternate greeting without having to recompile and redistribute the whole program.
Luckily Visual Studio helps us a lot when creating the config file.
Preparations
Let Visual Studio Create a console application in a new Solution: name the program ConfigExample
Add a new Library to this application, name it MyDll
View the properties of MyDll
Add a Setting.
Name: MySetting,
Type: string,
Scope: application,
Value: Hello World! (without string quotes)
In project MyDll create a class MyClass
public class MyClass
{
public string GetText()
{
return Properties.Settings.Default.MySetting;
}
}
Go to project ConfigExample
Project Add reference to MyDll (via tab page solution)
Use the code in your main:
using MyDll;
static void Main(string[] args)
{
var obj = new MyClass();
var txt = obj.GetText();
Console.WriteLine(txt);
}
Compile and run, and you'll see the proper text displayed. If you go to the debug / bin directory of the program you'll find a text file ConfigExample.config. Open it in a text editor and you'll see... nothing abut hello world!
This means that your program is not really interested in a special setting, the setting that was default the time that MyDll was built may be used.
However, if you want to use a special setting,
In visual Studio, Go to project MyDll
open file app.config
a.o. you'll find the following
(to prevent the editor interfering with the formatting, I added an apostrophe to each line)
'</configSections>
'<applicationSettings>
'<MyDll.Properties.Settings>
'<setting name="MySetting" serializeAs="String">
'<value>Hello World!</value>
'</setting>
'</MyDll.Properties.Settings>
'</applicationSettings>
Copy paste this part to ConfigExample.Config
for all already distributed programs do this in the folder where the executable is (in your case: debug/bin)
for all ConfigExample programs that will be built in the future do this in visual studio in App.Config of the ConfigExample project.
The result will be as follows:
'<?xml version="1.0" encoding="utf-8" ?>
'<configuration>
' <configSections>
' <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="MyDll.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
' </sectionGroup>
' </configSections>
' <applicationSettings>
' <MyDll.Properties.Settings>
' <setting name="MySetting" serializeAs="String">
' <value>Hello World!</value>
' </setting>
' </MyDll.Properties.Settings>
' </applicationSettings>
'
' <startup>
' <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
' </startup>
'</configuration>
Now all we have to do is change the Hello World into an alternat greeting
' <MyDll.Properties.Settings>
' <setting name="MySetting" serializeAs="String">
' <value>Here I am!</value>
' </setting>
' </MyDll.Properties.Settings>
Run the program without building it and you'll see that the new value is used.
Advantages:
- It works with a lot of types that can be assigned from string - Type.IsAssignableFrom(typeof(string)). Visual Studio already supports a lot of types including TimeSpan and DateTime.
- You don't have to recompile your source code to change the value
- Several executables can use their own configuration setting: one program could use the original greeting, the other can use the alternate one
- If your program doesn't provide a value in the config file the default value is used.
- You don't have to read the configuration yourself.
- It is type safe: if you say it is a TimeSpan, then you have to do some serious typing to confuse it with for example an integer.
Well there is a lot more to be said about configuration, you can even have a configuration per user. But that's far outside your question about alternatives for plain C #define

Related

Registering generic types and services with Castle Windsor IoC

Hello again stackoverflowians,
I thought it was about time that I learnt how to use a DI framework. I've heard a lot of good things about Castle Windsor so I decided to go with that. Now there are PLENTY of tutorials out there on how to use it, however, I cannot find much useful information about what to do when Generics get involved. Here is my issue.
I have a BaseDAO
namespace Utilities.DataAccess
{
public class BaseDAO<T> : IBaseDAO<T>
{
public BaseDAO(IConnectionProvider _connectionProvider)
{
// Stuff
}
}
}
Im a little bit new to generics in this context and I have seen some tutorials which have a 'BaseDAO' with no generic declaration and simply the interface it implements with the generics on it. I have used the above way of doing things on many previous projects (without IoC) and its worked fine for me...anyways, onwards to the App.config !
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"></section>
</configSections>
<castle>
<components>
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1, Utilities.DataAccess"
type="Utilities.DataAccess.BaseDAO`1, Utilities.DataAccess" />
<component
id="NHibernateConnection"
service="Utilities.DataAccess.ConnectionProviders.IConnectionProvider, Finchtils"
type="Utilities.DataAccess.ConnectionProviders.NHibernateConnection" />
<component
id="XMLConnection"
service="Utilities.DataAccess.ConnectionProviders.IConnectionProvider, Finchtils"
type="Utilities.DataAccess.ConnectionProviders.XMLConnection, Utilities" />
</components>
</castle>
</configuration>
Now as some of you may of figured by now, this is a utility library. I intend to use this assembly for each project I create so that I don't have to write the same data access code which remains the same across all solutions. The implications of such of course is that I cannot tell castle exactly what type parameter I will pass to the BaseDAO, in one project it might be a Customer object, another entirely different. I have read on other forums that this is entirely possible as when you request the object from the container you can specify the type then like;
BaseDAO<Customer> baseDao = container.Resolve<BaseDAO<Customer>>();
Although it is against my design efforts, I have tried to use the following notation in the App.config
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1[[Utilities.DataInterface.IEntity]], Finchtills.DataAccess"
type="Utilities.DataAccess.BaseDAO`1[[Utilities.DataInterface.IEntity]], Finchtils.DataAccess" />
However, this has not worked either, in any case I get the following error:
Utilities.Testing.DataAccess.Unit.Testing_BaseDAO (TestFixtureSetUp):
System.Exception : The type name Utilities.DataAccess.BaseDAO`1, Utilities.DataAccess could not be located.
----> System.IO.FileNotFoundException : Could not load file or assembly 'Utilities.DataAccess' or one of its dependencies. The system cannot find the file specified.
Reading this error, I think it could be one of two things:
I am missing something from the config file to do with the generics of the types and services.
I have named something incorrectly I.E an assembly name.
I have treated the assembly name as the project that item is contained within, in other words, at no point have i used <solution name>.<project name>.<item folder>.<item name> but merely started at the project level...I assume that any config option would know what solution it is being called from.
Thank you for any help you may be able to give on this subject.
The assembly name can be found in Visual Studio thus:
In the solution explorer, double-click the properties node
Open the Application tab
Assembly name is near the top right corner
Or, if you're compiling at the command line, you use the /out argument.
Also, you need to specify the assembly for the type arguments (inside the square brackets). So, assuming all your types are in the DataAccess assembly, and that the assembly is called (for brevity's sake) "DataAccess":
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1[[Utilities.DataInterface.IEntity, DataAccess]], DataAccess"
type="Utilities.DataAccess.BaseDAO`1[[Utilities.DataInterface.IEntity, DataAccess]], DataAccess" />
But I agree with other commenters that it's better to do the registrations in code. You don't have to use the verbose type syntax, for one, and you get compiler checking of your types. There are some disadvantages, however: it's harder to tell if you have unused types because the registration call counts as using the type.

Is there a standard method to create a configuration file for C# program?

In the past I would just create a text file with key value pairs for example WIDTH=40 and manually parse the file. This is getting a little cumbersome is there a standard way to do this preferably with inbuilt support from Visual Studio or the .NET framework.
Configuration files are one of the built-in templates. Right-click on your project, choose Add->New Item. In the template box, select configuration file.
You could to create an Application Configuration File in Visual Studio. It's basically and XML file which you can to use to save your application configuration data, but it's not meant to be read as an XML file: .net framework provides some classes to interact with it.
This link can provide some background and sample code: Using Application Configuration Files in .NET
You could to place this code inside your .config file:
<configuration>
<appSettings>
<add key="SomeData" value="Hello World!" />
</appSettings>
</configuration>
And you can read it this way in C# (requires a reference to System.Configuration assembly):
Console.WriteLine(
"Your config data: {0}",
ConfigurationManager.AppSettings["SomeData"]);
Note you'll need to escape your data ti fit into a XML file; for instance, a & character would became &
In your C# project look in the folder: Properties and open the file Settings.setting.
Here you can specify settings at the user or application level.
The following code sample shows how to use the settings:
public partial class MyControl : UserControl
{
MyProject.Properties.Settings config_;
public MyControl
{
InitializeComponent();
config_ = new MyProject.Properties.Settings();
}
public void SaveToConfig()
{
// save to configuration file
config_.ReportFileName = dataFileName.Text;
config_.Save();
}
public void LoadFromConfig()
{
string dataFileName = config_.ReportFileName;
}
}
You can also use settings when starting your application, and to modify your settings as you upgrade you application.
static void Main()
{
// if user setting program version user setting is less than
MyProject.Properties.Settings config = new MyProject.Properties.Settings();
string version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
if (config.Version != version)
{
// migrate from version 1.0.2 to future versions here...
if (config.Version == null)
{
}
config.Upgrade();
config.Reload();
config.Version = version;
config.Save();
}

.Net Configuration Editor problem

I have added some settings to my c# application using the configuration editor. There are three configuration items; two of type string and one of type int. All three have Application scope.
When I compile my application the exe.config file contains two subsections under <applicationSettings>. These are <appName.Settings> containing all three configuration items and <appName.Settings1> containing only the string values.
So, instead of having the following structure
<applicationSettings>
<appName.Settings>
...
...
...
</appName.Settings>
</applicationSettings>
I have the following structure
<applicationSettings>
<appName.Settings>
...
...
...
</appName.Settings>
<appName.Settings1>
...
...
</appName.Settings1>
</applicationSettings>
I have looked at the properties and cannot see anything that looks like it could prompt this behaviour. Can anyone shed any light on why this is happening and tell me how to stop it?
Thanks.
Look near the top of the config file for:
<sectionGroup name="applicationSettings" ...
<section name="Settings" ...
<section name="Settings1" ...
</sectionGroup>
Delete the Settings1 entry, then delete the applicationSettings section for Settings1 that you mention above.
<appName.Settings1>
...
...
</appName.Settings1>
By chance did you change the name of this application or assembly after creating the 2 string settings? When the assembly name changes it creates a new applicationSettings entry, AND leaves the old assembly name settings in the config file.

How do I find the current time and date at compilation time in .net/C# application?

I want to include the current time and date in a .net application so I can include it in the start up log to show the user what version they have. Is it possible to retrieve the current time during compilation, or would I have to get the creation/modification time of the executable?
E.g.
Welcome to ApplicationX. This was built day-month-year at time.
If you're using reflection for your build number you can use that to figure out when a build was compiled.
Version information for an assembly consists of the following four values:
Major Version
Minor Version
Build Number
Revision
You can specify all the values or you can accept the default build number, revision number, or both by using an asterisk (*). Build number and revision are based off Jan 1, 2000 by default.
The following attribute will set Major and minor, but then increment build number and revision.
[assembly: AssemblyVersion("5.129.*")]
Then you can use something like this:
public static DateTime CompileTime
{
get
{
System.Version MyVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
// MyVersion.Build = days after 2000-01-01
// MyVersion.Revision*2 = seconds after 0-hour (NEVER daylight saving time)
DateTime compileTime = new DateTime(2000, 1, 1).AddDays(MyVersion.Build).AddSeconds(MyVersion.Revision * 2);
return compileTime;
}
}
The only way I know of doing this is somewhat convoluted -
You can have a pre-build event that runs a small application which generates the source code on the fly. An easy way to do this is to just overwrite a very small file that includes a class (or partial class) with the day/month/year hardcoded as a string constant.
If you set this to run as a pre-build event, it will rewrite that file before every build.
You could use PostSharp to weave in the date immediately post-build. PostSharp comes with a lightweight aspect-oriented programming library, but it can be extended to weave in anything you need in a wide variety of ways. It works at the IL level, but the API abstracts you a bit from that.
http://www.postsharp.org/
There's nothing built into the language to do this.
You could write a pre-build step to write out the current date and time to a source file though (in a string literal, for example, or as source code to generate a DateTime), and then compile that as part of your build.
I would suggest you make this source file as simple as possible, containing nothing but this information. Alternatively it could edit an existing file.
For an example of this, see the build file for MiscUtil which embeds the current SVN revision into the AssemblyFileVersion attribute. Some assorted bits of the build file:
<!-- See http://msbuildtasks.tigris.org -->
<Import
Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<!-- Find out what the latest version is -->
<SvnInfo RepositoryPath="$(SvnUrl)">
<Output TaskParameter="LastChangedRevision" PropertyName="Revision" />
</SvnInfo>
<!-- Update the AssemblyInfo with the revision number -->
<FileUpdate Files="$(OutputDirectory)\MiscUtil\MiscUtil\Properties\AssemblyInfo.cs"
Regex='(\[\s*assembly:\s*AssemblyFileVersion\(\s*"[^\.]+\.[^\.]+)\.([^\.]+)(\.)([^\.]+)("\)\s*\])'
ReplacementText='$1.$2.$(Revision)$5' />
In makefiles for C programs, it is common to see something like this:
echo char * gBuildSig ="%DATE% %TIME%"; > BuildTimestamp.c
And then the resulting C source file is compiled into the image. The above works on Windows because the %date% and %time% variables are known in cmd.exe, but a similar thing would work on Unix using cat.
You can do the same thing using C#. Once again, this is how it would look if you are using a makefile. You need a class, and a public static property.
BuildTimestamp.cs:
echo public static class Build { public static string Timestamp = "%DATE% %TIME%";} > BuildTimestamp.cs
And then for the thing you are building, a dependency and a delete:
MyApp.exe: BuildTimestamp.cs MyApp.cs
$(_CSC) /target:exe /debug+ /optimize- /r:System.dll /out:MyApp.exe MyApp.cs BuildTimestamp.cs
-del BuildTimestamp.cs
Be sure to delete the BuildTimestamp.cs file after you compile it; you don't want to re-use it. Then, in your app, just reference Build.Timestamp.
Using MSBuild or Visual Studio, it is more complicated. I couldn't get %date% or %time% to resolve. Those things are pseudo environment variables, I guess that is why. So I resorted to an indirect way to get a timestamp, using the Touch task with AlwaysCreate = true. That creates an empty file. The next step writes source code into the same file, referencing the timestamp of the file. One twist - I had to escape the semicolon.
Your pre-build step should build the target "BuildTimestamp". And be sure to include that file into the compile. And delete it afterwards, in the post-build step.
<ItemGroup>
<StampFile Include="BuildTimestamp.cs"/>
</ItemGroup>
<Target Name="BuildTimestamp"
Outputs="#(StampFile)">
<Message Text="Building timestamp..." />
<Touch
AlwaysCreate="true"
Files="#(StampFile)" />
<WriteLinesToFile
File="#(StampFile)"
Lines='public static class Build { public static string Timestamp = "%(StampFile.CreatedTime)" %3B }'
Overwrite="true" />
</Target>
You could update the Assembly version in AssemblyInfo.cs as part of your build. Then you could do something like this
FileVersionInfo lvar = FileVersionInfo.GetVersionInfo(FileName);
FileVersionInfo has the information (build/version,etc) that you looking for. See if this works out for you.
Hi I used following method for the same...
private DateTime ExecutableInfo()
{
System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath.Trim());
try
{
return fi.CreationTime;
}
catch (Exception ex)
{
throw ex;
}
finally
{
fi = null;
}
}

How to obtain build configuration at runtime?

Does anyone know how to get the current build configuration $(Configuration) in C# code?
If you unload your project (in the right click menu) and add this just before the </Project> tag it will save out a file that has your configuration in it. You could then read that back in for use in your code.
<Target Name="BeforeBuild">
<WriteLinesToFile File="$(OutputPath)\env.config"
Lines="$(Configuration)" Overwrite="true">
</WriteLinesToFile>
</Target>
There is AssemblyConfigurationAttribute in .NET. You can use it in order to get name of build configuration
var assemblyConfigurationAttribute = typeof(CLASS_NAME).Assembly.GetCustomAttribute<AssemblyConfigurationAttribute>();
var buildConfigurationName = assemblyConfigurationAttribute?.Configuration;
Update
Egors answer to this question ( here in this answer list) is the correct answer.
You can't, not really.
What you can do is define some "Conditional Compilation Symbols", if you look at the "Build" page of you project settings, you can set these there, so you can write #if statements to test them.
A DEBUG symbol is automatically injected (by default, this can be switched off) for debug builds.
So you can write code like this
#if DEBUG
RunMyDEBUGRoutine();
#else
RunMyRELEASERoutine();
#endif
However, don't do this unless you've good reason. An application that works with different behavior between debug and release builds is no good to anyone.
Conditional Compilation Symbols can by used to achieve this. You can define custom symbols the Properties > Build settings pane for each project, and the use the #if directives to test them in the code.
Example showing how the define the symbol UNOEURO and how to use it in code.
bool isUnoeuro = false;
#if UNOEURO
isUnoeuro = true;
#endif
Install the SlowCheetah Visual Studio extension.
Right-click on your config file and select 'Add Transform'.
Notice a transform for each build configuration.
Place a "Build" appSetting into the root config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<appSettings>
<add key="Build" value="" />
</appSettings>
</configuration>
And place a "Build" directive in each transform:
<?xml version="1.0" encoding="utf-8"?>
<!--For more information on using transformations see the web.config examples at http://go.microsoft.com/fwlink/?LinkId=214134. -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="Build" value="Debug" xdt:Transform="Replace" xdt:Locator="Match(key)"/>
</appSettings>
</configuration>
Then obtain the "Build" appSetting value in your C# code:
ConfigurationManager.AppSettings["Build"]
Please be mindful that you will not see the transforms when you are debugging: https://stackoverflow.com/a/17336009/109941
You can use a common static method with Conditional Attribute to set the flag to detect DEBUG or RELEASE mode. The SetDebugMode method will be called only when running in the DEBUG mode otherwise it is ignored by Runtime.
public static class AppCompilationConfiguration
{
private static bool debugMode;
private static bool IsDebugMode()
{
SetDebugMode();
return debugMode;
}
//This method will be loaded only in the case of DEBUG mode.
//In RELEASE mode, all the calls to this method will be ignored by runtime.
[Conditional("DEBUG")]
private static void SetDebugMode()
{
debugMode = true;
}
public static string CompilationMode => IsDebugMode() ? "DEBUG" : "RELEASE";
}
You can call it in the code like below
Console.WriteLine(AppCompilationConfiguration.CompilationMode);
I don't believe you can inject that at compile time into the assembly but one way you could achieve it would be to use MSBuild and add it to the config file of the application.
See this blog post about how to do multi-environment config files using MSBuild - http://adeneys.wordpress.com/2009/04/17/multi-environment-config/
Alternatively you could write an MSBuild task which would edit a certain compiled file (your C# or VB file) and have that run in the BeforeBuild task. It'd be rather tricky as you'd need to work out where to inject it into the file, but provided you had some kind of tokenization set up you should be able to do it. I also doubt it would be pretty!

Categories