Emulate VB.Net Module in C# - c#

I just started working in C# after working in VB.Net for a while. I have a dll that contains frequently used database connection strings (and some other db info) and another dll that contains frequently used directory paths. When creating an application in VB, I would use these dlls in a Module to set the environment to testing so the databases would point to the QA versions of the databases and the directories would point to my local directories. When I was ready to publish the application, I would set the environment to production. It looked something like this.
Module MyModule
Friend MyBizDBs As BizDBs
Friend MyBizPaths As BizPaths
Friend TodaysDate As Date
Friend Sub InitializeModule()
MyBizDBs = New BizDBs(DBReference.BizDatabases.DBConfig.DB_Environment.QA)
MyBizPaths = New BizPaths(BizPaths.PathEnvironment.Test)
TodaysDate = DBReference.BizDatabases.DBMethods.GetTodaysDate
End Sub
End Module
I could then call InitializeModule at the start of the application and whenever a class needed a connection string or a directory or anything else offered by those dlls, it would be pointing to the correct environment. Moreover, I didn't need to create a new instance of MyModule each time. Instead I could simply write:
Using sw as new StreamWriter(MyBizPaths.ReconciliationReport)
I know C# doesn't have Modules. I know static classes are similar, but I can't initialize the objects (MyBizDBs and MyBizPaths) to set them to the appropriate environment in static classes. I'm looking at a C# Singleton, but that reinitializes each time the class is called. Is there a better way to achieve what I'm trying to do in C#?
Thanks!
EDIT: Here is what the singleton looks like in C#.
public sealed class MySingleton
{
private static readonly MySingleton instance = new MySingleton();
private MySingleton() { }
public static MySingleton Instance
{
get
{
return instance;
}
}
public BizPaths MyBizPaths = new BizPaths(BizPaths.PathEnvironment.Test);
public BizDBs MyBizDBs = new BizDBs(DBConfig.DB_Environment.QA);
public DateTime todaysDate = DBMethods.GetTodaysDate();
}

There's only one way to emulate a VB module in C# and that's with a static class. Once compiled, a VB module IS a static class, so obviously that's what you should use in C# if you want the same behaviour as a VB module. The difference is that module members don't have to be qualified with their type name in VB, while C# static class members do require qualification.

Related

String from getter is empty when called in another Project C#

I am a total beginner in C# programming language. I am trying to use Getter and Setter in order to set the string in ProjectA and the retrieve it in Project B.
Project B uses Windows Forms, and I wasnt to set the value of TextBox
with the retrieved string.
Project A is a Console Project and it just reads out some stuff from
file and stores it in string, which I want to retrieve.
However, this is my call in Project B:
string cardOwner = Transmit.Program.CardOwner;
Debug.WriteLine("Card owner = " + cardOwner);
tb_cardholder.Text = cardOwner;
And this is my Getter / Setter in Project A:
private static string _cardOwner;
public static string CardOwner
{
get
{
return _cardOwner;
}
set
{
_cardOwner = value;
}
}
_cardOwner = System.Text.Encoding.ASCII.GetString(bCardOwner);
But in Project B I get "" empty string.
I have included Project A in Project B (added Reference and wrote "using ProjectA").
Any ideas what's going wrong?
Thanks.
Just because you include a project and use its classes in your project B, it doesn't mean that you also use the instances of these classes.
Take the following class:
public class Test
{
public string Message { get; set; }
}
You can put this class into a DLL project (Tools) and reference it from other projects, like a WinForms project ProjectA and a console project ProjectB.
In both projects, you can write something like:
Test t = new Test() { Message = "Hello" };
That creates a new instance of the Test class, but the two running applications ProjectA and ProjectB do not exchange the data! They are completely separated.
The same is true for class properties.
You can't share information between two different applications so easily. Static properties only share data within the same Application Domain, that is in most simple constellations within the same Windows process.
If you want to transfer data between two different processes, you need to use an explicit mechanism for interprocess communication.
When is this line executed?
_cardOwner = System.Text.Encoding.ASCII.GetString(bCardOwner);
You'll need to put that in a method and call that method (and knowing when the call happens will help you understand why _cardOwner is not set:
public static void Init()
{
_cardOwner = System.Text.Encoding.ASCII.GetString(bCardOwner);
}
Then call this method somewhere that you know will be executed before you need _cardOwner:
Transmit.Program.Init();
string cardOwner = Transmit.Program.CardOwner;
tb_cardholder.Text = cardOwner;

PowerShell: how does the PowerShell instantiate C# classes

Initially, I think PowerShell instantiate one class only when the cmdlet tagged on this class is called. On execution, each cmdlet falls into the BeginProcess -> ProcessRecord -> EndProcess(StopProcess) path, and after the EndProcess is done, it seems the process will end and then the memory will collect all these class objects as garbage.Therefore each class should live in their own life cycle and not share any resources. When we are calling these cmdlets,
However I find that classes do share the same static values in the same module. For example, assume in my project I have two classes:
namespace PSDSL
{
[Cmdlet(VerbsCommon.Get, "MyTest")]
public class GetMyTest : Cmdlet
{
public static GlobalUserName = "";
[Parameter(Mandatory = false)]
public string Filepath { get; set; }
protected override void InnerProcessRecord()
{
if (_filepath != null)
{
GlobalUserName = _filepath;
}
Console.WriteLine(GlobalUserName);
}
}
}
namespace PSDSL
{
[Cmdlet(VerbsCommon.Get, "MyTest2")]
public class GetMyTest2 : Cmdlet
{
[Parameter(Mandatory = false)]
public string Filepath { get; set; }
protected override void InnerProcessRecord()
{
if (_filepath != null)
{
GlobalUserName = _filepath;
}
Console.WriteLine(GlobalUserName);
}
}
}
The two commands are pretty similar except one defines a static GlobalUserName. Calling these 2 cmdlets shows that the GlobalUserName can be read\write from both cmdlets.
My confusion is that, when are the classes be instaniated?
Whole assembly loaded at once and stays loaded till restart of the PowerShell prompt.
Details:
Smallest unit of code isolation in .Net is Assembly (in most cases single managed DLL).
Process that uses managed runtime can't load less than single assembly at a time - so all classes from that assembly (and related once on demand) will be loaded together. As result all static fields will be present at the same time in memory (note that static fields are initialized "before first use of the class" which mean they are not necessary initialized on load of the assembly).
There also no way to "unload" class or even assembly without using separate AppDomains. PowerShell does not use multiple AppDomains to load assemblies for different modules (generally cross-AddDomain calls require special attention during implementation and you'd know about it by now). As result once loaded module stays in memory till you quit PowerShell (covered in Powershell Unload Module... completely).
Since assembly is loaded once for all commandlets in it all static fields will be present at once and keep they values till exiting of PowerShell.
Side note: I'd strongly recommend avoiding static fields for anything but really static immutable data in general. It is way to easy to leave some random values there and impact future code. In PowerShell pipeline is the way to pass information between commandlets, other types of processes (WinForms, ASP.Net,...) have they own preferred mechanism to pass data instead of using static.

Ninject + Auto Discovery

Here's the deal: I want to create a C# console app. When run, this app will look in a particular folder for dll's with classes that implement a particular interface, and then run a method on those dll's.
I haven't done this before but from my reading that should be "easy enough" from an IoC/Ninject perspective. I think you can do something with kernel.Bind() to load assemblies of a certain interface in a certain directory. I think/hope I can figure that part out (if you know otherwise, please do tell!).
But here is my quandary.
Here is a visual to help first:
MainProgramFolder
-- MainProgram.exe
-- MainProgram.exe.config
-- LibraryFolder
----- Library1Folder
--------Library1.dll
--------Library1.dll.config
----- Library2Folder
--------Library2.dll
--------Library2.dll.config
The dll's that implement this interface are technically stand alone apps -- they are just libraries instead of exe's (or, rather, I'd like them to be for IoC purposes). I'd like for them to be run in their own context, with their own app.configs. So for example, MainProgram.exe would bind the ILibrary interface to classes inside Library1.dll and Library2.dll because they implement ILibrary. But inside Library1, it calls ConfigurationManager to get its settings. When I call Class.Method() for each of the bindings from MainProgram, how can I ensure they are referencing their own .config's and not MainProgram.exe.config? (Also, fwiw, these additional libraries will likely not be a part of the assembly or even namespace of the main programs -- we're basically providing a drop folder for an application to kind of "subscribe" to the main program's execution.)
IOW, I know you can attach an app.config to a class library but I wouldn't know how, after the bindings have been resolved from the IOC, to make those dll's "see" its own config rather than the main program's config.
All thoughts appreciated!
Thanks
Tom
First, to load and bind all of your classes you'll need ninject.extensions.conventions, and something like this:
var kernel = new StandardKernel();
/*add relevant loop/function here to make it recurse folders if need be*/
kernel.Bind(s => s.FromAssembliesMatching("Library*.dll")
.Select(type => type.IsClass && type.GetInterfaces().Contains(typeof(ILibrary)))
.BindSingleInterface()
.Configure(x=>x.InSingletonScope()));
To make each instance load its configuration as if it was the entry point you will need to run it in a new app domain. Your ILibrary implementation needs to inherit MarshalByRefObject and be Serializable so that it will run correctly in the alternate appdomain
[Serializable]
public class LibraryA :MarshalByRefObject, ILibrary
You can then add this activation strategy to your kernel that will cause it to swap out instances of ILibrary with an instance loaded in an alternate appdomain with your config file convention before they are returned.
public class AlternateAppDomainStrategy<T> : ActivationStrategy
{
public override void Activate(IContext context, InstanceReference reference)
{
if (reference.Instance.GetType().GetInterfaces().Contains(typeof(T)))
{
var type = reference.Instance.GetType();
var configFilePath = type.Assembly.GetName().Name + ".dll.config";
var file = new FileInfo(configFilePath);
if (file.Exists)
{
var setup = new AppDomainSetup() { ConfigurationFile = file.FullName, ApplicationBase = AppDomain.CurrentDomain.BaseDirectory };
var domain = AppDomain.CreateDomain(type.FullName, null, setup);
var instance = domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
reference.Instance = instance;
}
else
{
throw new FileNotFoundException("Missing config file", file.FullName);
}
}
}
}
And Add it to your kernel
kernel.Components.Add<IActivationStrategy, AlternateAppDomainStrategy<ILibrary>>();
From there you can simply instantiate your ILibrary instances and call methods on them. They will load in their own app domains with their own configs. It gets a lot more complicated if you need to pass things in/out of the instance either via methods or constructor, but from the sound if it you don't so this should be OK.
var libs = kernel.GetAll<ILibrary>();
foreach (var lib in libs)
{
lib.Method();
}

Common "Debug" function within class library

I am using several class libraries within a project, and one of them is a typical "project.common.dll" library containing some common helper functions. One of these functions is a debug function that creates debug output.
Now I would like to enable/disable debug output by using a user-level property (application settings). How can I reference variables defined in main application's program.cs within this class library ?
Update : Thanks all. I will probably create a static method in my base application that performs the check (to debug or not) and then calls the Debug function in the common library.
You can't.
What you will need to do is have the properties in the class library itself and when you create the instance of it in your main application pass the user setting in:
var debug = new DebugInstance { Output = this.Output };
or set the parameters if it's a static class:
StaticDebug.Output = this.Output;
You can use the ConditionalAtrribute:
[Conditional("DEBUG")]
public static void WriteDebugInfo()
{
Trace.WriteLine("what ever...")
}
This way when you build in Debug mode, the method is invoked; in Release mode not.
Use parameters on the constructor of the Debug class (or a static constructor if the class is static).

Basic: Where to initialize/set the function

I am working on a .Net project(solution) which is having 25 projects. I want to set the value in some function/method so that It can be set once for the entire application. Where to set this method so that I dnt need to set it again in the individual winforms. That function/method is in some dll so i required to set that like this:
Logger obj = Logger.GetInstance();
obj.SetLogLevel(1);
I need to use the above code only once.
Kindly help?
Thank You...
Since you talk about pages, I assume you have a web site or a web application.
What you can do, in this case is to create a static class in App_Code and do this in it's static constructor. This way the first time any page accesses the static class the code will run and it won't run again.
public static class AStaticClass {
public static Logger Obj;
static AStaticClass() {
Obj = Logger.GetInstance();
Obj.SetLogLevel(1);
}
}
EDIT:
In case this is a window application, just put this static class in one of the libraries. It doesn't really matter where the class is.

Categories