C# Project calling another Project failing with App.config - c#

I have a solution with 2 projects. One project is a console app that you plug information into and it will provide data back. The second project creates multiple processes that call the first project by passing an argument. Up to this point everything is working.
I wanted to play around with being able to change the format the first project generates so I changed it's static format string to load from App.Config instead. When I run the first project by itself there is no issue and everything still works. After this change whenever the second project creates a process of the first project it fails with an ArgumentNullException and seems to not load the format string.
Here is my code for the second project that is calling the console application.
public static void Main(string[] args)
{
for (int i = 1; i < 10; i++)
{
Process EulerProblemN = CreateNewProcess(ExecutionPath, i.ToString());
EulerProblemN.Start();
string output = EulerProblemN.StandardOutput.ReadToEnd().Replace(Environment.NewLine, "");
Console.WriteLine(output);
EulerProblemN.WaitForExit();
}
Console.Read();
}
public static Process CreateNewProcess (string path, string argument)
{
Process eulersOutput = new Process();
eulersOutput.StartInfo.FileName = path;
eulersOutput.StartInfo.Arguments = argument;
eulersOutput.StartInfo.RedirectStandardOutput = true;
eulersOutput.StartInfo.UseShellExecute = false;
return eulersOutput;
}
In case it's relevant this is how I'm accessing the configuration in the first project:
private string AnswerFormat = ConfigurationManager.AppSettings["AnswerFormat"];
Contents of App.Config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="AnswerFormat" value="The answer to Problem {0} is {1}, the program took: {2} milliseconds to complete."/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
What is cause of this error? Does it have to do with how the second project calls the first?
EDIT:
First I tried to override the default env. config path as described here: Using ConfigurationManager to load config from an arbitrary location. I added that code to both projects. Unfortunately this didn't resolve the error so I moved a copy of app.config into both projects. The First project continues to run with no issues. I tested it and the second project successfully loads from its own app configuration, but when it calls .Start() on the process of the first project it is still failing with the same ArgumentNullException error.
It seems like Project 1 is not loading from the configuration file if called as a Process from project 2. Project 2 can see it's own config file and it's identical to the one in Project 1. Is this still a configuration file issue or could it be something else?

The App.config which is loaded is that of the project you run. the other project is effectively referenced as a class library and its App.config file will not be loaded. You'll need to place the setting in your first project's config file as well.

Related

How do I get a c# Unit Test to use App.Config?

I have reduced this to the simplest possible.
VS2019 MSTest Test Project (.NET Core) template
Default unit test project .
Use nuget to install System.Configuration.ConfigurationManager(5.0.0)
Add app.config file to project (add -> new Item -> select Application Configuration File>
Add entry to config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="TestKey" value="testvalue"/>
</appSettings>
</configuration>
Debug the code below and k is null.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Configuration;
namespace UnitTestProject1
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var k = System.Configuration.ConfigurationManager.AppSettings["TestKey"];
}
}
How do you get the unit test to read the config file?
If you add this line to your TestMethod, it will tell you what is the name of the config file it is expecting to use:
public void TestMethod1()
{
string path = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
var k = ConfigurationManager.AppSettings["TestKey"];
}
When I ran it, it called the file "(path-to)\testhost.dll.config", not "App.config". So all I did was rename the file to "testhost.dll.config", change its Build Action to "Content" and "Copy always", ran the unit test, and it gave me the right value in var k.
I can't explain why it would look specifically for that filename, but for some reason it is.
You have to tell the configuration manager what file to load. Don't rely on the file matching the exe name, etc. Just keep the name as app.config.
System.Configuration.ConfigurationFileMap configMap = new ConfigurationFileMap("./app.config");
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedMachineConfiguration(configMap);
string value = configuration.AppSettings["TestKeyā€¯];

MStest throwing errors for Class library using multiple config files [duplicate]

This question already has answers here:
Can a unit test project load the target application's app.config file?
(12 answers)
Closed 4 years ago.
I have created a class library MultipleConfigFiles, which has a method getConfigData. This method reads data from config files.
public class Class1
{
public string getConfigData()
{
string configData = ConfigurationManager.AppSettings["key"].ToString();
return configData;
}
}
Now I have a console application ConsoleAppConfig, in which I have given the reference of the class library.In the main method, I have created a object for the library class and called the method.
static void Main(string[] args)
{
Class1 c = new Class1();
string data = c.getConfigData();
Console.Write(data);
}
This console application has 2 different config files dev.config and prod.config. In the main App.config file , I have used configSource to map the appropriate config file.
<appSettings configSource="dev.config" />
Dev.config file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
<add key="key" value="dev" />
</appSettings>
Till here it is working fine.That is, when I run the console app, the method returns dev.
Now,I have created a MSTest project for this class library.
public class Class1Tests
{
[TestMethod()]
public void getConfigDataTest()
{
Class1 obj = new Class1();
var result = obj.getConfigData();
}
}
Now the problem is, when I run this test, it throws an error saying
"An exception of type 'System.NullReferenceException' occurred in MultipleConfigFiles.dll but was not handled in user code.
Additional information: Object reference not set to an instance of an object."
Since the config files are in ConsoleApplication , the method is not able to read the appsetting variables from there. Is there any way I can maintain the configuration files globally so that both of them use individually , or is there any better way to handle this.
Any inputs are appreciated.Thanks.
Without duplicating the files you can the Link the files in existing Unit Test project.
You can try the same as mentioned in the image Link (https://grantwinney.com/content/images/2014/04/AddExistingFileAsLink-002.png)
Google this term "Visual Studio - Add File As Link" for more Info
Image Credits : https://grantwinney.com

NUnit appSettings file attribute (linked config file) is not seen by ConfigurationManager in test

I have NUnit test (version 2.6.4) test. It uses ConfigurationManager.AppSettings["foo"] to retrive a configuration setting from the app.config file (which is in the test project). This is my App.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings file="bar.config">
<add key="thisSettingIsVisible" value="yes, indeed"/>
</appSettings>
</configuration>
and this is bar.config file:
<appSettings>
<add key="foo" value="this setting isn't visible"/>
</appSettings>
I'm using ReSharper 10 test runner to execute the test. bar.config file is copied to the bin/Debug directory. In fact, that configuration was working some time ago, but stopped. Any clues what can be wrong?
Now, I've figured out a workaround, but I'm not happy with this solution:
private static void InitializeAppSettings()
{
var exeAssembly = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyName = exeAssembly.GetName().Name + ".dll";
var testDllFolder = new Uri(System.IO.Path.GetDirectoryName(exeAssembly.CodeBase)).LocalPath;
var openExeConfiguration = ConfigurationManager.OpenExeConfiguration(Path.Combine(testDllFolder, assemblyName));
foreach (var setting in openExeConfiguration.AppSettings.Settings.AllKeys)
{
ConfigurationManager.AppSettings[setting] = openExeConfiguration.AppSettings.Settings[setting].Value;
}
}
BTW. I can't abstract away ConfigurationManager usage form existing, legacy code.
I replicated your use case and found that my additional config worked in the context of an ASP.NET site but the additional appSetting was null in a test project until I changed the Copy to Output Directory property to Copy Always
If you use R# 10.0.0 or R# 10.0.1 - it is a known issue for such builds and it has been fixed in R# 10.0.2 build.

System.TypeLoadException: Could not load type 'x' from assembly 'x'?

I would just like to apologise by the overload of information, I just want to provide anything that could be related, I'm not sure what's happening
Test method DCIM_Test_1.MySQLDefTest.ConnectionStringTest threw exception:
System.TypeLoadException: Could not load type 'DCIM_With_Test.Database.Database_MySQLDef' from assembly 'DCIM, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
I am getting this error when I run one of my tests, and I believe it's coming from how I re-named my Solution and Projects recently.
I renamed them all from 'DCIM_With_Test' to 'DCIM', (Changed the directories, file names etc.) but it is still causing inconsistencies here and there.
Another cause could possibly be the way the method that is causing the issue is running. I have changed the method from reading from a text file to reading from an app.config file and I am new to this process and XML so I could be missing a step somewhere.
Here is my app.config:
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<connectionStrings>
<add name="mySqlConnectionString" connectionString="server=localhost;database=dcim;uid=root;pwd=LlmD62jL;"/>
</connectionStrings>
</configuration>
I am also getting three messages about app.config:
Could not find the schema information for the element 'supportedRuntime'.
Could not find the schema information for the attribute 'version'.
Could not find the schema information for the attribute 'sku'.
Here is the method being tested NOTE: The OLD METHOD runs fine, but the test still throws the exception, but the NEW METHOD doesn't work at all.
public static string GetConnectionString()
{
/* OLD METHOD
StreamReader rdr = new StreamReader(#"C:\Users\Benjamin\Documents\setupfile.txt");
mySqlConnectionString = rdr.ReadToEnd();
rdr.Close();
*/
// NEW METHOD
mySqlConnectionString = ConfigurationManager.ConnectionStrings["mySqlConnectionString"].ConnectionString;
return mySqlConnectionString;
}
And here is the test:
[TestMethod()]
public void ConnectionStringTest()
{
int actual = 0;
int expected = 1;
Database_MySQLDef.GetConnectionString();
if (Database_MySQLDef.mySqlConnectionString != "")
{
actual = 1;
}
else { actual = 0; }
Assert.AreEqual(expected, actual);
}
Does your test assembly have an app.config?
my test project doesn't but my main project does. Not sure if that's the same thing?
No, they aren't. I suspect what is happening is that ConfigurationManager.ConnectionStrings is going to the test assembly's app config (this is MSTest's behavior, I believe), not the your main project's app config. Then, because that doesn't exist, you are getting an Exception thrown in a static initializer or static constructor and this is wrapped by the TypeLoadException.
A simple way to solve this is to just add an app.config to your test assembly. Then you can put in whatever connection string you need for the tests.

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