How to pass a config file as parameter to a console application .Net - c#

I need a sample/example demonstrating how to pass a config file as a parameter to a console application in .Net

Pass it in command line parameters, in args[].
Something like this.
class Program
{
static void Main(string[] args)
{
if (args == null)
{
Console.WriteLine("args is null."); // Check for null array
}
else
{
// use args to get passed config file path
}
}
}
~~~ How to call the program ~~~
C:\ConsoleApplication1.exe "your config
file path" (like C:\config\app.config)

Do you have access to target console application source code? Is it .NET application?
If yes do next: add target app as a reference to the source application project (exe can be added like dll, there is no difference). And call some public method.
// target.exe code
namespace Target {
public class MyConfig { }
public class Program {
static void Main(string[] args) { }
public static void EntryPoint(MyConfig conf) { }
}
}
// source.exe code
namespace Source {
class Program {
static void Main(string[] args) {
Target.MyConfig conf = new Target.Config();
Target.Program.EntryPoint(conf);
}
}
}

If u want to store data like FileOutputDirectory you can also use Settings page instead of config file. Settings page is easy to configure and use. Read more at msdn website: link text

Related

How to declare global variable in Program cs and use it in controllers in .NET 6.0 Web Api

I have default Program.cs file from Web Api template in .NET 6.0.
I am adding variable "test" so I can use its value in controllers.
var builder = WebApplication.CreateBuilder(args);
const string test = "test123";
builder.Configuration.Bind(test);
//rest of the file...
And now I want to use variable "test" outside Program.cs but I have no idea how to do it. I cannot just simply use it because when trying to read it in controller like this:
string localVar = test;
I am getting an error "'test' is not null here. Cannot use local variable or local function declared in a top-level statement in this context".
This is probably some stupid mistake but I can't figure it out...
Starting C# 9, we don't need to explicitly mention the Main method in Program.cs file as we can use the top-level statements feature. However, it doesn't mean that we shouldn't use the default Program class in the created file at all. In your case, you have a need to define the static/const property so you can change the newly created structure into the old one.
namespace WebApplication;
public class Program
{
public static string Test { get; private set; }
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
Program.Test = "approach1";
builder.Services.Configure<MyOptions>(x => x.Test = "approach2");
///
}
public class MyOptions
{
public string Test { get; set; }
}
I assumed that you have a need to set the value to the Program.Test field during runtime, so in the first approach, I used the static field with a private set; accessor instead of the constant.
In the second approach, I used the C# options feature to configure the MyOptions.Test field value, this will be very flexible and useful to write unit tests later. But, you need to inject the MyOptions class wherever is required.
In the below controller template, I specified how to access the configured values at Program.cs file, inside the Get method
public class TestController : ControllerBase
{
private readonly MyOptions _myOptions;
public TestController (IOptions<MyOptions> myOptions)
{
_myOptions = myOptions.Value;
}
public IActionResult Get()
{
string test1 = Program.Test;
string test2 = _myOptions.Test;
///
}
}
Add public partial class Program { } at the very end of your Program.cs file and add constant, property or whatever you like in there.

Action<ISomeInterface> use for configuration

Yesterday, I watched a RabbitMQ course on Pluralsight. I noticed that they used Action delegate as a method parameter to set come configurations. So, there were already some settings in the method, and if there is a requirement to add more configuration, we can pass it by the Action delegate parameter. The way, they used Action Delegate as a parameter with an interface, was new for me. So, I try to replicate it in a test console application. Not sure, I implemented it perfectly or not.
class Program
{
static void Main(string[] args)
{
// If I want to set/add configuration, I can send it by Action delegate.
Program.DoSomeConfiguration((cdd) =>
{
cdd.SetConfig("New Config");
});
// If I do not want to set new configuration and just want to execute it.
// Call 'DoSomeConfiguration' with null.
//Program.DoSomeConfiguration();
}
public static void DoSomeConfiguration(Action<ITest> actionMy = null)
{
ConfigClass obj = new ConfigClass();
obj.MyConfigurations.Add("Old Config");
obj.SetConfig();
Console.WriteLine("**************************************");
actionMy?.Invoke(obj);
}
}
public interface ITest
{
void SetConfig(string config);
}
public class ConfigClass : ITest
{
public List<string> MyConfigurations { get; set; }
public ConfigClass()
{
MyConfigurations = new List<string>();
}
public void SetConfig(string config = null)
{
if (config != null)
{
MyConfigurations.Add(config);
}
foreach (var configuration in MyConfigurations)
{
Console.WriteLine($"config {configuration}");
}
}
}
MyCode explanation: I have some default configuration in the "DoSomeConfiguration" method. If anyone wants to add more configuration to it, they can pass it by Action Delegate.
Did I use it correctly?
It is not seen how you use those configurations. Because ConfigClass obj is not accessible out side DoSomeConfiguration. Regarding ConfigClass - MyConfigurations shouldn't be exposed and SetConfig has more than one resposibility - sent config and print out config values (I assume when null is passed purpose it just to print out config values)

How can I update a parameter within a C# Class when running the application via a BAT file?

I currently have a suite of Selenium automation tests using SpecFlow and C# (IDE is Visual Studio 2017).
I created a batch file to run the applicable feature files.
Currently I set my test environment (i.e. QA, UAT, Prod) within Environments.cs by using the following property
public static string CurrentEnvironment { get; set; } = uat;'
What I want to achieve is to some how pass the test environment via the batch file so there is no need to open the solution and modify before running the BAT file.
There will likely be other parameters I will want to update via this method in the future such as Specflow parameters whereby I might want to override a parameter value.
I've tried Googling a solution but I've found structuring my question doesn't yield the results I want.
Batch file:
ECHO ON
set Date=%date:~0,2%%date:~3,2%%date:~6,4%
set Time=%time:~0,2%%time:~3,2%
cd C:\Users\%username%\source\repos\AutomationTests\TestProject\packages\SpecRun.Runner.1.8.0\tools
SpecRun.exe run default.srprofile /basefolder:C:\Users\%username%\source\repos\AutomationTests\TestProject\TestProject\bin\Debug /filter:testpath:"Feature:TestFeature"
In essence if the CurrentEnvironment property in my solution is set to 'UAT' I want to be able to override that to say 'QA' via the BAT file.
What modifications do I need to make to the BAT file and what to my solution (if any)?
You can set the test environment with environment variables. Environment.GetEnvironmentVariable() is the method to call to read environment variables.
Here is an example:
Program.cs (in a console app):
using System;
namespace TestEnvironmentVariable
{
class Program
{
static void Main(string[] args)
{
string testEnvironment = Environment.GetEnvironmentVariable("test_env");
Console.WriteLine($"Test environment: {testEnvironment}");
}
}
}
run.bat:
set test_env=uat
TestEnvironmentVariable.exe
When running run.bat:
>run.bat
>set test_env=uat
>TestEnvironmentVariable.exe
Test environment: uat
You can also put all your settings in a json file that you use as a configuration file. It also makes it possible to change the settings without having to compile. Here is a small example:
Create a json file, e.g. settings.json:
{
"TestEnvironment": "UAT"
}
It can be created in the root folder of the solution. In the file's properties, set Copy to Output Directory to Copy always or Copy if newer. This makes sure it's moved to the binary output directory.
Then create a Settings.cs file that is representing the class we deserialize the json file to:
namespace TestEnvironmentVariable
{
public sealed class Settings
{
public Settings() { }
public string TestEnvironment { get; set; }
}
}
You can add more variables here when they are needed. The json file should have the same variables. And then the code that does the deserialization:
using System.IO;
using Newtonsoft.Json;
namespace TestEnvironmentVariable
{
public static class SettingsUtil
{
public static T GetObjectFromJsonFile<T>(string filename)
{
string json = File.ReadAllText(filename);
var deserializedObject = JsonConvert.DeserializeObject<T>(json);
return deserializedObject;
}
}
}
You have to add Newtonsoft.Json with NuGet. We can then read the json file in our code:
using System;
namespace TestEnvironmentVariable
{
class Program
{
static void Main(string[] args)
{
Settings settings = SettingsUtil.GetObjectFromJsonFile<Settings>("settings.json");
Console.WriteLine($"Test environment: {settings.TestEnvironment}");
}
}
}
Output:
>TestEnvironmentVariable.exe
Test environment: UAT

How to find C# entry point for Non exe program?

All information I read regarding C# entry point class relate to:
static int Main(string[] args)
As this is specific to an EXE program.
But my program is a C# Automation Test framework (.cs within the solution), designed with Specflow feature files and step definitions.
I have now added an (entry point) class called Program.cs - Int Main class but I’ve noticed that this entry point class is not called any time when running my automation tests. Most likely because my program is not an EXE program but a Test framework.
How can I find the C# entry point for Non exe program?
As I want to use utilise my 'Reporting' code from one class that will be called every time I run a test:
namespace Project.Core
{
public class Program
{
public static int Main(string[] args)
{
Adapter.DefaultSearchTimeout = 5000;
int error;
try
{
error = TestSuiteRunner.Run(typeof (Program), Environment.CommandLine);
}
catch (Exception e)
{
TestReport.Setup(ReportLevel.Debug, "myReport.rxlog", true);
Report.Screenshot();
throw new ApplicationException("Error Found", e);
}
return error;
}
}
}
Non-exe projects (i.e. DLLs) have no entry-point. They are APIs that are called by other processes, which have their own entry-points.
You should research the appropriate "before test" methodology for the test framework you are using with SpecFlow. For example in MSTest, such code would go in a method with a signature of:
[TestInitialize]
public void TestInitialize()
{
// Your code
}
MSDN Documentation.
As my project is using both MsTest and the Ranorex API I cannot be sure what aspect of the project is being initialised before/during a test run. So I have decided to add the Try/Catch code structure directly into every Step Defintion method in my project.
Try()
{
// code
}
Catch (Exception e)
{
TestReport.Setup(ReportLevel.Debug, "myReport.rxlog", true);
Report.Screenshot();
throw new ApplicationException("Error Found", e);
}
And I can easily move the Catch code into a helper class so that I only have one instance of the code being used through my project:
catch (Exception)
{
WpfHelpers.ExtensionMethods.CatchException(null);
}
Helper class:
public static class ExtensionMethods
{
public static void CatchException(SystemException e)
{
TestReport.Setup(ReportLevel.Debug, "myReport.rxlog", true);
Report.Screenshot();
throw new ApplicationException("Error Found", e);
}
}
Note that I am using this structure so that I can utilise the Report.Screenshot functionality of Ranorex when a failure occurs.

How can I get the ServiceName in a Windows Service written in C#?

How can I get the service name programatically using this.ServiceName in a Windows Service written in C#? When I try this, it's asking for assembly reference but its not accepting anything:
string path = this.ServiceName + ".config";
but its getting error.
Your service needs to inherit ServiceBase from System.ServiceProcess.dll.
When you will have that you will be able to access this.ServiceName property.
Sample:
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
string test = this.ServiceName;
}
protected override void OnStop()
{
}
}
If you want to access it from Main() (Program class), then you can do something like this:
namespace WindowsService1
{
static class Program
{
static ServiceBase[] _servicesToRun;
static void Main()
{
_servicesToRun = new ServiceBase[]
{
new Service1()
};
string serviceName = _servicesToRun[0].ServiceName;
ServiceBase.Run(_servicesToRun);
}
}
}
To find the .config file for your service, do not use the service name. That's not how the CLR works, it selects the .config file based on the EXE name. Fix:
var path = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
To access the configuration file you need the application name not the service name (if you are using standard .Net application configuration files).
To get the application executable use System.AppDomain.CurrentDomain.FriendlyName

Categories