Ninject Constructor argument check parameter existence - c#

I was wondering if there is anyway, how to do a parameter existence check with Ninject?
What I am referring to: let's have a theoretical class and an interface:
public interface IFileExistenceCheck
{
bool FileExist();
}
public class FileExistenceChecker : IFileExistenceCheck
{
private readonly string filePath;
private readonly IFileSystem fileSystem;
public FileExistenceChecker(IFileSystem fileSystem, string filePath)
{
this.fileSystem = fileSystem;
this.filePath = filePath;
}
public bool FileExist()
{
return this.fileSystem.File.Exists(this.filePath);
}
}
Then somewhere in the code, I will be getting an instance of IFIleExistenceCheck interface via kernel like so:
public class Foo()
{
public void Bar()
{
// do something
var filePath = SomeMagicString;
var filePathArgument = new ConstructorArgument("filePath", filePath); // <- This part I do not really like
var checker = Kernel.Get<IFileExistenceCheck>(filePathArgument);
var fileExist = checker.FileExist();
// do the rest of code
}
}
This will work just fine, problem is, that it will only work as long as the name of file path argument stays the same. Let's say one day somebody will decide, that filePath is unnecessary and renames it just to path. The code itself will still compile, but it will not cause any error until somebody will actually do the call to the Bar() method.
Is there any way how to prevent this from happening?
I do not really want to expose the filePath. I still want it to be passed as an argument of a constructor. I do not want to change signature of FileCheck() to accept filePath as an argument and I do not even want to change filePath to publicly accessible field.

This is abusing the DI container as a service locator, and yet another reason why it service locator is considered to be anti-pattern.
Your contrived example would not happen if you were using the dependency injection pattern. Refactoring your example to use dependency injection, it would look like this:
public interface IFileExistanceCheck
{
bool FileExist(string filePath);
}
public class FileExistanceChecker : IFileExistanceCheck
{
private readonly IFileSystem fileSystem;
public FileExistanceChecker(IFileSystem fileSystem)
{
if (fileSystem == null)
throw new ArgumentNullException(nameof(fileSystem));
this.fileSystem = fileSystem;
}
// Pass runtime data through the method parameters!
public bool FileExist(string filePath)
{
// Prevent an empty file path from being used
if (string.IsNullOrEmpty(filePath))
throw new ArgumentNullException(nameof(filePath));
return this.fileSystem.File.Exists(filePath);
}
}
Foo Class
public class Foo
{
private readonly IFileExistanceCheck fileExistanceCheck;
public Foo(IFileExistanceCheck fileExistanceCheck)
{
if (fileExistanceCheck == null)
throw new ArgumentNullException(nameof(fileExistanceCheck));
this.fileExistanceCheck = fileExistanceCheck;
}
public void Bar()
{
// do something
var filePath = SomeMagicString;
var fileExist = fileExistanceCheck.FileExist(filePath);
// do the rest of code
}
}
At the composition root, Ninject would tie it all together and get Foo running.
class Program
{
static void Main(string[] args)
{
// Begin composition root
var kernel = new StandardKernel();
kernel.Bind<IFileSystem>().To<FileSystem>();
kernel.Bind<IFileExistanceCheck>().To<FileExistanceChecker>();
var app = kernel.Get<Foo>();
// End composition root
app.Bar();
}
}
If there is a need to check for the existence of the filePath parameter, this check can be done using a guard clause. You only need to use the dependency injection pattern, and pass the runtime data (the file path) through a method parameter.
If you want the filePath to be a configuration value that is passed through the constructor at application startup, then having a service to check for file existence seems rather pointless. In that case, you should check whether the file exists before allowing your application to run.
class Program
{
static void Main(string[] args)
{
var filePath = "SomeFileThatShouldExist.txt";
// Check configuration
if (!File.Exists(filePath))
throw new InvalidOperationException("Invalid configuration");
// Begin composition root
var kernel = new StandardKernel();
kernel.Bind<Foo>().To(new Bar(filePath));
// Register other services...
var app = kernel.Get<Foo>();
// End composition root
app.Bar();
}
}

If your parameter is known only in runtime you can inject factory and create your FileExistenceChecker with it:
public interface IFileExistenceCheckerFactory
{
IFileExistenceCheck Create(string path);
}
...
var kernel = new StandardKernel();
kernel.Bind<IFileExistenceCheck>().To<FileExistenceChecker>();
kernel.Bind<IFileSystem>().To<FileSystem>();
kernel.Bind<IFileExistenceCheckerFactory>().ToFactory(() => new TypeMatchingArgumentInheritanceInstanceProvider());
var factory = kernel.Get<IFileExistenceCheckerFactory>();
var checker = factory.Create("SomeMagicString");
var fileExist = checker.FileExist();
Then even if your parameter names don't match, TypeMatchingArgumentInheritanceInstanceProvider ensure that parameters will be matched by its type.

Related

Mock log file for unit test in .NET Core application

In my C# application I have a getLogFile which is set by calling the GetLogFile() method:
private static string getLogFile = GetLogFile();
private static string GetLogFile()
{
var fileTarget = (FileTarget)LogManager.Configuration.FindTargetByName("file-target");
var logEventInfo = new LogEventInfo();
string fileName = fileTarget.FileName.Render(logEventInfo);
if (!File.Exists(fileName))
throw new Exception("Log file does not exist.");
return fileName;
}
I'm now trying to unit test some code which will require the getLogFile variable to be set. I'd like to mock this in some way as I'd like to use specific log data for my test but am not sure how to go about it. How can I do this?
"Mocking" a private static field or method is not really possible.
To have this kind of method as a private member of another class smells like a violation of Single Responsibility Principle.
You should probably refactor this behavior to a separate class and hide it behind an interface. I'm not entirely sure what the NLog Code does, but what your method really seem to do is not providing the log file, but the name of the log file (you return fileName) So this is how it could look like:
public interface ILogFileNameProvider
{
string GetLogFileName();
}
public class DefaultLogFileNameProvider : ILogFileNameProvider
{
public string GetLogFileName()
{
// your code ommitted
}
}
It's just an example on how you can handle it. The naming/structure and how you use it is up to you.
This interface can then be injected in the using class that currently has the private methods. This dependency/call can be mocked.
Usage with constructor injection:
public class LogFileNameUsingService
{
private readonly ILogFileNameProvider _logFileNameProvider;
public LogFileNameUsingService(ILogFileNameProvider logFileNameProvider)
{
_logFileNameProvider = logFileNameProvider;
}
}
Test with xUnit and AutoMocker as example:
[Theory]
public void TestWithMockedLogFileName()
{
//Arrange
var mocker = new AutoMocker();
var logFileNameProviderMock = mocker.GetMock<ILogFileNameProvider>();
logFileNameProviderMock.Setup(x => x.GetLogFileName()).Returns("your mocked file name.log");
var sut = mocker.CreateInstance<LogFileNameUsingService>();
//Act
var result = sut.TestedMethodWhichUsesLogFileName();
//Assert whatever you want to test
}
This also allows you swap out the current logic to get a log file later without changing the logic of the existing class.

Unit test a void method with Mock?

I want to test a void method with Mock.
public class ConsoleTargetBuilder : ITargetBuilder
{
private const string CONSOLE_WITH_STACK_TRACE = "consoleWithStackTrace";
private const string CONSOLE_WITHOUT_STACK_TRACE = "consoleWithoutStackTrace";
private LoggerModel _loggerModel;
private LoggingConfiguration _nLogLoggingConfiguration;
public ConsoleTargetBuilder(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration)
{
_loggerModel = loggerModel;
_nLogLoggingConfiguration = nLogLoggingConfiguration;
}
public void AddNLogConfigurationTypeTagret()
{
var consoleTargetWithStackTrace = new ConsoleTarget();
consoleTargetWithStackTrace.Name = CONSOLE_WITH_STACK_TRACE;
consoleTargetWithStackTrace.Layout = _loggerModel.layout + "|${stacktrace}";
_nLogLoggingConfiguration.AddTarget(CONSOLE_WITH_STACK_TRACE, consoleTargetWithStackTrace);
var consoleTargetWithoutStackTrace = new ConsoleTarget();
consoleTargetWithoutStackTrace.Name = CONSOLE_WITHOUT_STACK_TRACE;
consoleTargetWithoutStackTrace.Layout = _loggerModel.layout;
_nLogLoggingConfiguration.AddTarget(CONSOLE_WITHOUT_STACK_TRACE, consoleTargetWithoutStackTrace);
}
The thing is I am not sure how to test it. I have my primary code.
public class ConsoleTargetBuilderUnitTests
{
public static IEnumerable<object[]> ConsoleTargetBuilderTestData
{
get
{
return new[]
{
new object[]
{
new LoggerModel(),
new LoggingConfiguration(),
2
}
};
}
}
[Theory]
[MemberData("ConsoleTargetBuilderTestData")]
public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
{
// ARRANGE
var targetBuilderMock = new Mock<ITargetBuilder>();
targetBuilderMock.Setup(x => x.AddNLogConfigurationTypeTagret()).Verifiable();
// ACT
var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
// ASSERT
Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}
Please guide me to the right direction.
It looks to me like you don't need a mock at all. You are testing AddNLogConfigurationTypeTagret. Not the constructor.
[Theory]
[MemberData("ConsoleTargetBuilderTestData")]
public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
{
// ARRANGE
var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
// ACT
consoleTargetBuilder.AddNLogConfigurationTypeTagret();
// ASSERT
Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}
If you don't want to call AddNLogConfigurationTypeTagret yourself, it should be called in the constructor. This changes the test to this :
[Theory]
[MemberData("ConsoleTargetBuilderTestData")]
public void ConsoleTargetBuilder_Should_Add_A_Console_Target(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration, int expectedConsoleTargetCount)
{
// ARRANGE
// ACT
var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
// ASSERT
Assert.Equal(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}
and the class constructor should then be :
public ConsoleTargetBuilder(LoggerModel loggerModel, LoggingConfiguration nLogLoggingConfiguration)
{
_loggerModel = loggerModel;
_nLogLoggingConfiguration = nLogLoggingConfiguration;
AddNLogConfigurationTypeTagret();
}
Please guide me to the right direction, I want two things. A) the method was called. B) two targets were added. So the expected count is 2.
A) If you wish to verify that method AddNLogConfigurationTypeTagret was called, then you need to test it on the code which is calling this method. E.g. something like the class ConsoleTargetBuilderClient which is an hypothetical example of a class which is using the ITargetBuilder (in your own code you should have some place where the class ConsoleTargetBuilder is used).
public class ConsoleTargetBuilderClient
{
private ITargetBuilder _builder;
public ConsoleTargetBuilderClient(ITargetBuilder builder)
{
_builder = builder;
}
public void DoSomething()
{
_builder.AddNLogConfigurationTypeTagret();
}
}
Then you can have a test which verifies that the method DoSomething called the method AddNLogConfigurationTypeTagret. For that purpose you can use a mock of ConsoleTargetBuilder because you test interaction with it. Test might look like this:
public void DoSomething_WhenCalled_AddNLogConfigurationTypeTagretGetsCalled()
{
// Arrange
bool addNLogConfigurationTypeTagretWasCalled = false;
Mock<ITargetBuilder> targetBuilderMock = new Mock<ITargetBuilder>();
targetBuilderMock.Setup(b => b.AddNLogConfigurationTypeTagret())
.Callback(() => addNLogConfigurationTypeTagretWasCalled = true);
ConsoleTargetBuilderClient client = new ConsoleTargetBuilderClient(targetBuilderMock.Object);
// Act
client.DoSomething();
// Assert
Assert.IsTrue(addNLogConfigurationTypeTagretWasCalled);
}
B) If you wish to verify that the targets were added you need to test the code itself (not mock of it). Test might look like this:
public void AddNLogConfigurationTypeTagret_WhenCalled_ConsoleTargetsAdded()
{
// Arrange
const int expectedConsoleTargetCount = 2;
var loggerModel = new LoggerModel();
var nLogLoggingConfiguration = new LoggingConfiguration();
var consoleTargetBuilder = new ConsoleTargetBuilder(loggerModel, nLogLoggingConfiguration);
// Act
consoleTargetBuilder.AddNLogConfigurationTypeTagret();
// Assert
Assert.AreEqual<int>(expectedConsoleTargetCount, nLogLoggingConfiguration.AllTargets.Count);
}
Note: google value-based vs. state-based vs. interaction testing.
Generally speaking, you shouldn't be mocking the class you want to test, you should be mocking it's dependencies. When you start mocking the class you're trying to test things often get entwined leading to brittle tests and it's difficult to determine if you're testing your code, or you mocking setup, or both.
The method AddNLogConfigurationTypeTagret is a public method on the class you're testing, so as #Philip has said, you should probably just be calling it from your test, or it should be called from your constructor. If you goal is for it to be called from your constructor, then I'd suggest that it should probably be a private method unless there's a reason for it to be called from outside the class.
As far as testing the effects of a void method call, you're interested in the state change caused by the method. In this instance, whether or not the _nLoggingConfiguration has two targets added with the correct attributes. You don't show us the nLoggingConfiguration.AllTargets property, but I would assume from the fact that you're using the Count property in your test, that you could simply inspect the items in the list to confirm that the correct name and layout have been added to the correct target type.
// Assert
targetBuilderMock.Verify(x => x.AddNLogConfigurationTypeTagret(), Times.Once());

Static Variable Null In Method Call, But Initialized In Program

I have a bit of a head-scratcher here that I wonder if someone may know the answer to.
The setup is basically this:
//in Visual Studio plug-in application
SpinUpProgramWithDebuggerAttached();
//in spun up program
void Start()
{
StaticClass.StaticVariable = "I want to use this.";
XmlSerializer.Deserialize(typeof(MyThingie), "xml");
}
class MyThingie : IXmlSerializable
{
ReadXml()
{
//why the heck is this null?!?
var thingIWantToUse = StaticClass.StaticVariable;
}
}
The problem that has me pulling my hair out is that StaticClass.StaticVariable is null in the IXmlSerializable.ReadXml() method, even though it's called RIGHT AFTER the variable is set.
Of note is that breakpoints aren't hit and Debugger.Launch() is ignored in the precise spot the problem occurs.
Mysteriously, I determined through raising exceptions that the AppDomain.CurrentDomain.FriendlyName property is the same for the place the static variable is populated vs. null!
Why the heck is the static variable out of scope?!? What's going on?!? How can I share my variable?
EDIT:
I added a static constructor, per a suggestion in the responses, and had it do a Debug.WriteLine. I noticed it was called twice, even though all the code appears to be running in the same AppDomain. Here is what I see in the output window, which I'm hoping will be a useful clue:
Static constructor called at: 2015-01-26T13:18:03.2852782-07:00
...Loaded 'C:...\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll'...
...Loaded 'Microsoft.GeneratedCode'...
...Loaded 'C:...\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll'....
...Loaded 'C:\USERS...\APPDATA\LOCAL\MICROSOFT\VISUALSTUDIO\12.0EXP\EXTENSIONS...SharePointAdapter.dll'. Symbols loaded.
...Loaded 'Microsoft.GeneratedCode'.
Static constructor called at: 2015-01-26T13:18:03.5196524-07:00
ADDITIONAL DETAIL:
Here is the actual code, since a couple of commenters thought it might help:
//this starts a process called "Emulator.exe"
var testDebugInfo = new VsDebugTargetInfo4
{
fSendToOutputWindow = 1,
dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess,
bstrArg = "\"" + paramPath + "\"",
bstrExe = EmulatorPath,
LaunchFlags = grfLaunch | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd | (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_WaitForAttachComplete,
dwDebugEngineCount = 0,
guidLaunchDebugEngine = VSConstants.CLSID_ComPlusOnlyDebugEngine,
};
var debugger = Project.GetService(typeof(SVsShellDebugger)) as IVsDebugger4;
var targets = new[] { testDebugInfo };
var processInfos = new[] { new VsDebugTargetProcessInfo() };
debugger.LaunchDebugTargets4(1, targets, processInfos);
//this is in the emulator program that spins up
public partial class App : Application
{
//***NOTE***: static constructors added to static classes.
//Problem still occurs and output is as follows (with some load messages in between):
//
//MefInitializer static constructor called at: 2015-01-26T15:34:19.8696427-07:00
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.0609845-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
//ContainerSingleton static constructor called at: 2015-01-26T15:34:21.3399330-07:00. Type: SystemTypes.ContainerSingleton, SystemTypes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=...
protected override void OnStartup(StartupEventArgs e)
{
//...
//initializes a MEF container singleton (stored as static variable)
MefInitilizer.Run();
//here's where it blows up. the important details are that
//FullSelection implements IXmlSerializable, and its implemention
//ends up referencing the MEF container singleton, which ends up
//null, even though it was initialized in the previous line.
//NOTE: the approach works perfectly under a different context
//so the problem is not the code itself, per se, but a problem
//with the code in the environment it's running in.
var systems = XmlSerialization.FromXml<List<FullSelection>>(systemsXml);
}
}
public static class MefInitilizer
{
static MefInitilizer() { Debug.WriteLine("MefInitializer static constructor called at: " + DateTime.Now.ToString("o")); }
public static void Run()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
var container = new CompositionContainer(catalog);
ContainerSingleton.Initialize(container);
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
Debug.WriteLine("ContainerSingleton static constructor called at: " + DateTime.Now.ToString("o") + ". Type: " + typeof(ContainerSingleton).AssemblyQualifiedName);
}
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
}
Bear in mind I've just copied your code to try to replicate your problem.
When running this code, I get a NullReferenceException on Debug.Write, AnotherClass hasn't properly initialized before the call is resolved.
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MefInitilizer.Run();
Debug.Write(AnotherClass.Test);
}
}
public class AnotherClass
{
public static String Test = ContainerSingleton.ContainerInstance;
}
public static class MefInitilizer
{
public static void Run()
{
ContainerSingleton.Initialize("A string");
}
}
public class ContainerSingleton
{
private static String compositionContainer;
public static String ContainerInstance
{
get
{
if (compositionContainer != null) return compositionContainer;
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
}
public static void Initialize(String container)
{
compositionContainer = container;
}
}
}
However, when I add static constructors to all classes with static fields it works as expected:
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
MefInitilizer.Run();
Debug.Write(AnotherClass.Test);
}
}
public class AnotherClass
{
static AnotherClass()
{
}
public static String Test = ContainerSingleton.ContainerInstance;
}
public static class MefInitilizer
{
static MefInitilizer()
{
}
public static void Run()
{
ContainerSingleton.Initialize("A string");
}
}
public class ContainerSingleton
{
static ContainerSingleton()
{
}
private static String compositionContainer;
public static String ContainerInstance
{
get
{
if (compositionContainer != null) return compositionContainer;
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
}
public static void Initialize(String container)
{
compositionContainer = container;
}
}
}
I'd say this could definitely be a BeforeFieldInit problem.
As I understood, your code is an plug-in for a Visual Studio, and the main problem of your application is that your class is being instantiated twice, once for a normal AppDomain, and once for some other reason you can't really find out.
First of all, I see here a potential sandboxing from a Visual studio - it wants to test your code in various sets of rights to ensure your code won't harm any other parts of the Visual Studio or end user work. In this case your code could be loaded into another AppDomain, without some rights (You can find a good article at the MSDN), so you can understand why is your code called twice per application.
Second, I want to point out that you are misunderstanding the idea of static constructor and static method:
public static void Initialize(CompositionContainer container)
{
compositionContainer = container;
}
is not the same as
public static ContainerSingleton()
{
compositionContainer = container;
}
So, I suggest you to move the all initialization logic into a static container, something like this:
public class ContainerSingleton
{
private static CompositionContainer compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
if (compositionContainer == null)
{
var appDomainName = AppDomain.CurrentDomain.FriendlyName;
throw new Exception("Composition container is null and must be initialized through the ContainerSingleton.Initialize()" + appDomainName);
}
return compositionContainer;
}
}
public static ContainerSingleton()
{
var catalog = new AggregateCatalog();
//this directory should have all the defaults
var dirCatalog = new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//add system type plug-ins, too
catalog.Catalogs.Add(dirCatalog);
compositionContainer = new CompositionContainer(catalog);
}
}
Second approach: I want to point out that the pattern you use for getting the singleton is outdated, try to use the Lazy<T> class, something like this:
public class ContainerSingleton
{
private static Lazy<CompositionContainer> compositionContainer;
public static CompositionContainer ContainerInstance
{
get
{
return compositionContainer.Value;
}
}
public static ContainerSingleton()
{
compositionContainer = new Lazy<CompositionContainer>(() => Initialize());
}
public static void Initialize()
{
// Full initialization logic here
}
}
Also, you should remember that simply adding the empty static constructors isn't enough - you should move all assignments to it, so you should replace such code:
public class AnotherClass
{
static AnotherClass()
{
}
public static String Test = ContainerSingleton.ContainerInstance;
}
with this one:
public class AnotherClass
{
static AnotherClass()
{
Test = ContainerSingleton.ContainerInstance;
}
public static String Test;
}
Update:
#Colin You can even use [LazyTask type][https://msdn.microsoft.com/en-us/magazine/dn683795.aspx] - simply pass a Func to your constructor, and it will be a thread-safe approach, see more in the article. The same Id of the AppDomain means nothing - the sandbox could run your code via AppDomain.ExecuteAssembly method (it's obsolete in 4.5, but still could be a possible variant) to see how it behaves in various set of permissions.
May be there is another technique for this in .NET 4.5, but can't find an article related right now.
Update 2:
As I can see in your code, you are reading some information from disk. Try to add a Code Access Security rule for this to see, if your code is being ran under restricted permissions, like this:
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
//f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, "C:\\example\\out.txt");
try
{
f2.Demand();
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
}
More about FileIOPermission Class on MSDN.
Try adding a static constructor to ContainerSingleton. I believe this is BeforeFieldInit raising its ugly head again.
Thanks to all who offered suggestions! I never did figure out exactly what was going on (and will continue to investigate/post updates if I ever do), but I did end up coming up with a workaround.
A few suggested that initialization of the static class be internalized, but due to the nature of the actual problem, initialization logic had to be externalized (I was basically loading a DI/service location container whose composition varied from environment to environment).
Also, I suspect it wouldn't have helped, since I could observe that the static constructor was called twice (thus, whatever initialization logic there was would just be called twice, which didn't directly address the problem).
However, the suggestion got me on the right track.
In my case, none of the services I loaded needed to be stateful, so it didn't really matter that the initialization happened twice aside from the performance hit.
Therefore, I simply had the static class check if the MEF container was loaded, and if it wasn't I'd read a configuration file which specified a class that handled initialization.
By doing so, I could still vary the composition of the MEF container from environment to environment, which is currently working pretty well, even if it's not an ideal solution.
I'd like to split the bounty between all who helped, but since that doesn't appear to be possible, I will probably reward OakNinja since he was a hero in spitting out as many good ideas as could realistically be expected given the information I provided. Thanks again!

log4net: different logs on different file appenders at runtime

Good morning guys.
I wrote a single istance C# 2.0 app (call it myapp).
Myapp is called many times, and at every call generates a sort of "task" that will be executed in a separated thread.
If you call myapp several times in a short time, task are executed in parallel.
Generally I use log4net for logging purposes; I configure it loading an xml file by XmlConfigurator.Configure(<config>.xml) at startup, then I use static LogManager.GetLogger(name) in every class I need a logger, quite simple.
This scenario is challenging, instead.
I need to do is this: based on one of the args received on every call (call it arg), I need to get a different RollingFileAppender that logs in a different file, e. g. .log.
Just to make an example:
1st call: myapp.exe -arg:01
- myapp creates thread1
- set a new RollingFileAppender to 01.log file, if not exists
- objects used in this thread must log in 01.log file
2nd call: myapp.exe -arg:02
- create thread2
- set a new RollingFileAppender to 02.log file, if not exists
- objects used in this thread must log in 02.log file, but not in log.01
3rd call: myapp.exe -arg:01
- create thread03
- get the RollingFileAppender to 01.log file (it already exists!)
- objects used in this thread must log in 01.log file, but not in log.02
And so on.
I don't need to leave the configuration of RollingAppender in xml file, I can create it programmatically; my idea is to use a static wrapper class, call it LogHelper, that creates appenders if they do not exist based on arg, and that dispatch right ILog istances when needed by objects (in classes I would use something like ILog log = LogHelper.GetLogger(name, arg) to get a logger to use instead o default log4net method LogManager.GetLogger(name)).
So if I have 2 istances of the same class in 2 different threads, when I log messages goes one per file, depending or arg (I will inject arg in every object, if needed).
I browse many threads here in StackOverflow, but I can't find a solution.
Can someone point me to the right direction?
Thanks in advance.
I ended up with a slightly different solution.
I created a LogMaster static class (sorry for poor name) that work similar to the default log4net LogManager class.
The difference is that you can get different ILog istances based on arg: LogMaster will create a new ILoggerRepository for each different arg you will use.
Here the code:
#region Usings
using System;
using System.IO;
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Filter;
using log4net.Layout;
using log4net.Repository;
using log4net.Repository.Hierarchy;
#endregion
namespace Common.Voyager
{
/// <summary>
/// A static class that emulates defualt log4net LogManager static class.
/// The difference is that you can get various loggers istances based from an args.
/// LogMaster will create a different logger repository for each new arg it will receive.
/// </summary>
public static class LogMaster
{
#region Const
private const string RollingFileAppenderNameDefault = "Rolling";
private const string MemoryAppenderNameDefault = "Memory";
#endregion
#region Constructors
static LogMaster()
{
}
#endregion
#region Public Methods
public static ILog GetLogger(string arg, string name)
{
//It will create a repository for each different arg it will receive
var repositoryName = arg;
ILoggerRepository repository = null;
var repositories = LogManager.GetAllRepositories();
foreach (var loggerRepository in repositories)
{
if (loggerRepository.Name.Equals(repositoryName))
{
repository = loggerRepository;
break;
}
}
Hierarchy hierarchy = null;
if (repository == null)
{
//Create a new repository
repository = LogManager.CreateRepository(repositoryName);
hierarchy = (Hierarchy)repository;
hierarchy.Root.Additivity = false;
//Add appenders you need: here I need a rolling file and a memoryappender
var rollingAppender = GetRollingAppender(repositoryName);
hierarchy.Root.AddAppender(rollingAppender);
var memoryAppender = GetMemoryAppender(repositoryName);
hierarchy.Root.AddAppender(memoryAppender);
BasicConfigurator.Configure(repository);
}
//Returns a logger from a particular repository;
//Logger with same name but different repository will log using different appenders
return LogManager.GetLogger(repositoryName, name);
}
#endregion
#region Private Methods
private static IAppender GetRollingAppender(string arg)
{
var level = Level.All;
var rollingFileAppenderLayout = new PatternLayout("%date{HH:mm:ss,fff}|T%2thread|%25.25logger|%5.5level| %message%newline");
rollingFileAppenderLayout.ActivateOptions();
var rollingFileAppenderName = string.Format("{0}{1}", RollingFileAppenderNameDefault, arg);
var rollingFileAppender = new RollingFileAppender();
rollingFileAppender.Name = rollingFileAppenderName;
rollingFileAppender.Threshold = level;
rollingFileAppender.CountDirection = 0;
rollingFileAppender.AppendToFile = true;
rollingFileAppender.LockingModel = new FileAppender.MinimalLock();
rollingFileAppender.StaticLogFileName = true;
rollingFileAppender.RollingStyle = RollingFileAppender.RollingMode.Date;
rollingFileAppender.DatePattern = ".yyyy-MM-dd'.log'";
rollingFileAppender.Layout = rollingFileAppenderLayout;
rollingFileAppender.File = string.Format("{0}.{1}", "log", arg);
rollingFileAppender.ActivateOptions();
return rollingFileAppender;
}
private static IAppender GetMemoryAppender(string station)
{
//MemoryAppender
var memoryAppenderLayout = new PatternLayout("%date{HH:MM:ss} | %message%newline");
memoryAppenderLayout.ActivateOptions();
var memoryAppenderWithEventsName = string.Format("{0}{1}", MemoryAppenderNameDefault, station);
var levelRangeFilter = new LevelRangeFilter();
levelRangeFilter.LevelMax = Level.Fatal;
levelRangeFilter.LevelMin = Level.Info;
var memoryAppenderWithEvents = new MemoryAppenderWithEvents();
memoryAppenderWithEvents.Name = memoryAppenderWithEventsName;
memoryAppenderWithEvents.AddFilter(levelRangeFilter);
memoryAppenderWithEvents.Layout = memoryAppenderLayout;
memoryAppenderWithEvents.ActivateOptions();
return memoryAppenderWithEvents;
}
#endregion
}
}
Usage:
var arg = "myArg";
var loggerName = "MyLogger";
var log = LogMaster.GetLogger(arg, loggerName);
Using this solution you can benefit from default LogManager behavior retrieving ILog loggers: if a logger with the same name already exists in a repository, you will get back that istance (recycling behavior).
Thank you #making3 for your suggestions!
I've done something similar, where I needed a different log for every instance of a class. You can create logs dynamically with a few steps.
It looks like a default Logger (Line 97) is already defined, but it's internal to their assembly, so it will need to be inherited (as far as I know).
public sealed class DynamicLogger : Logger
{
internal DynamicLogger(string name) : base(name)
{
base.Hierarchy = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
}
}
Sample method to retrieve an ILog:
public static ILog GetSample(string arg)
{
var logger = new DynamicLogger(arg);
logger.Level = Level.All;
var consoleAppender = new ConsoleAppender();
consoleAppender.Name = arg;
consoleAppender.Layout = new PatternLayout(arg + ": %m%newline");
logger.AddAppender(consoleAppender);
var newLog = new LogImpl(logger);
if (_logs.Any(log => log.Logger.Name == newLog.Logger.Name) == false)
_logs.Add(newLog);
return newLog;
}
Basic usage:
var foo = DynamicLog.GetSample("foo");
var bar = DynamicLog.GetSample("bar");
foo.Error("Test");
bar.Error("Test");
For your scenario, look at creating a RollingFileAppender, and look at the available properties on the object, since this was just an example.
EDIT: Added the below for storing ILog's, and modified the original GetSample method above.
Add an array of ILog's and a GetLogger method:
private static List<ILog> _logs = new List<ILog>();
public static ILog GetLogger(string name)
{
return _logs.SingleOrDefault(a => a.Logger.Name == name);
}
Sample usage:
DynamicLog.GetSample("foo");
var foo = DynamicLog.GetLogger("foo");

Unity Decorator Extension fails with multiple implementations

I've been struggling with this problem for a couple days, and I still am not sure how to solve it.
I've created a container extension for the Unity Container to enable me to easily register decorator classes in the container. This is the implementation I currently have, which is almost identical to the one in this article:
public class DecoratorExtension : UnityContainerExtension
{
private int m_order;
private Dictionary<Type, IList<DecoratorRegistration>> m_typeStacks;
protected override void Initialize()
{
m_typeStacks = new Dictionary<Type, IList<DecoratorRegistration>>();
Context.Registering += AddRegistration;
Context.Strategies.Add(new DecoratorBuildStrategy(m_typeStacks), UnityBuildStage.PreCreation);
}
private void AddRegistration(object _sender, RegisterEventArgs _e)
{
if (_e.TypeFrom == null || !_e.TypeFrom.IsInterface)
return;
GetStack(_e.TypeFrom)
.Add(new DecoratorRegistration {Order = m_order++, Type = _e.TypeTo});
}
private IList<DecoratorRegistration> GetStack(Type _type)
{
if (!m_typeStacks.ContainsKey(_type))
m_typeStacks.Add(_type, new List<DecoratorRegistration>());
return m_typeStacks[_type];
}
}
What this does is use a list for each type, to store all type registrations for the same target type, so that I can reassemble it when Resolve is called, using this build strategy:
internal class DecoratorBuildStrategy : BuilderStrategy
{
private readonly Dictionary<Type, IList<DecoratorRegistration>> m_typeStacks;
internal DecoratorBuildStrategy(Dictionary<Type, IList<DecoratorRegistration>> _typeStacks)
{
m_typeStacks = _typeStacks;
}
public override void PreBuildUp(IBuilderContext _context)
{
var key = _context.OriginalBuildKey;
if (_context.GetOverriddenResolver(key.Type) != null)
return;
// Only interfaces can use decorators.
if (!key.Type.IsInterface)
return;
// Gets the list of types required to build the 'decorated' instance.
// The list is reversed so that the least dependent types are built first.
var decoratorTypes = GetDecoratorTypes(key.Type).Reverse().ToList();
if (!decoratorTypes.Any())
return;
object value = null;
foreach (var type in decoratorTypes)
{
Type typeToBuild = type;
if (typeToBuild.IsGenericTypeDefinition)
{
Type[] genericArgumentTypes = key.Type.GetGenericArguments();
typeToBuild = typeToBuild.MakeGenericType(genericArgumentTypes);
}
value = _context.NewBuildUp(new NamedTypeBuildKey(typeToBuild, key.Name));
// An Override is created so that in the next BuildUp the already
// built object gets used instead of doing the BuildUp again and
// entering an infinite loop
_context.AddResolverOverrides(new DependencyOverride(key.Type, value));
}
_context.Existing = value;
_context.BuildComplete = true;
}
private IEnumerable<Type> GetDecoratorTypes(Type _type)
{
var typeList = m_typeStacks.GetValueOrDefault(_type) ?? new List<DecoratorRegistration>(0);
if (!_type.IsGenericType)
return typeList.Select(_reg => _reg.Type);
// If the type is a generic type, we need to get all open generic registrations
// alongside the closed ones
var openGenericList = m_typeStacks
.GetValueOrDefault(_type.GetGenericTypeDefinition()) ??
new List<DecoratorRegistration>(0);
// The final result is an ordered concatenation of the closed and open registrations
// that should be used for the type
return typeList
.Concat(openGenericList)
.OrderBy(_registration => _registration.Order)
.Select(_reg => _reg.Type);
}
}
This is where the DecoratorRegistration model is used. It is just a pair of type/int that represents the order of the registration. I created this to be able to mix open and closed generic registrations correctly:
internal struct DecoratorRegistration
{
public int Order { get; set; }
public Type Type { get; set; }
}
This works wonders for the most part. The problem started when I had a class that implemented two interfaces, one which was decorated, and one that wasn't.
This is the current test case I'm trying to make work:
private interface IAny<T> {}
private interface IAnotherInterface {}
private class Base<T> : IAnotherInterface, IAny<T> {}
private class Decorator1<T> : IAny<T>
{
internal readonly IAny<T> Decorated;
public Decorator1(IAny<T> _decorated)
{
Decorated = _decorated;
}
}
[TestMethod]
public void DecoratorExtensionDoesNotInterfereWithNormalRegistrations()
{
// Arrange
var container = new UnityContainer()
.AddNewExtension<DecoratorExtension>()
.RegisterType<Base<string>>(new ContainerControlledLifetimeManager())
.RegisterType<IAny<string>, Decorator1<string>>()
.RegisterType<IAny<string>, Base<string>>()
.RegisterType<IAnotherInterface, Base<string>>();
// Act
var decorated = container.Resolve<IAny<string>>();
var normal = container.Resolve<IAnotherInterface>();
var anotherDecorated = container.Resolve<IAny<string>>();
var anotherNormal = container.Resolve<IAnotherInterface>();
// Assert
Assert.IsInstanceOfType(normal, typeof (IAnotherInterface));
Assert.IsInstanceOfType(decorated, typeof (Decorator1<string>));
Assert.AreSame(normal, anotherNormal);
Assert.AreSame(decorated, anotherDecorated);
}
This test should make my intent clear. I wanted singleton classes, but the first call to Resolve, for either IAnotherInterface or IAny<string> results in every subsequent call to return the same thing. Thus, I get an exception:
System.InvalidCastException: Unable to cast object of type 'Decorator1`1[System.String]' to type 'IAnotherInterface'.
on this line:
var normal = container.Resolve<IAnotherInterface>();
I'm not sure what to do here. I had to temporarily disable singletons in our project so that this could work as intended. What I wanted is that the Base<string> instance was a sintleton, but when I requested a IAny<string> it would create a NEW instance with the SAME base being decorated.
This is still using .Net 4.0, so I'm stuck with Unity 2.1 here (shouldn't matter in this case though).
It's been a while since I've solved this, so I figured that it would be good to replicate the answer I got from Randy Levy from the EntLib team here.
It basically boils down to the build key I was using to register the decorator instance. With my code, the instance was actually registered with the base class type, while I needed to register it with the actual decorator type.
This post has the suggested workaround for the issue, which worked very nicely on our end.
I'm not exactly sure if this is what you're looking for, but I think this does the trick in the specific case in your test:
container.RegisterType<IAny<string>, Base<string>>(
new ContainerControlledLifetimeManager(), "Inner");
container.RegisterType<IAny<string>, Decorator1<string>>(
new InjectionConstructor(
new ResolvedParameter(typeof(IAny<string>), "Inner")));
container.Register<IAnotherInterface>(new InjectionFactory(
c => c.Resolve<IAny<string>>("Inner")));
You don't need that extension for that.

Categories

Resources