How to pass a function to another class using IoC - c#

I am trying to implement inversion of control (IoC) in order to develop a plug-in based application, which needs to be able to pass data (e.g. strings) back to my main EXE when something happens. To achieve this, I am passing an Action to the DLL which it can use to send data back to the EXE. The following code shows a little test application to explain my beginner-problem:
namespace MainExe
{
class Program
{
[Import(typeof(IDataProvider))]
public IDataProvider stringProvider { get; set; }
public void myCallback(string str)
{
Console.WriteLine(str);
}
public Program()
{
try
{
AggregateCatalog aggregatecatalogue = new AggregateCatalog();
aggregatecatalogue.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory));
CompositionContainer container = new CompositionContainer(aggregatecatalogue);
container.ComposeParts(this);
}
catch (FileNotFoundException fnfex)
{
Console.WriteLine(fnfex.Message);
}
catch (CompositionException cex)
{
Console.WriteLine(cex.Message);
}
}
void Run()
{
if (stringProvider != null)
{
stringProvider.SaySomething("myrequest", myCallback);
Console.ReadKey();
}
}
static void Main(string[] args)
{
Program program = new Program();
program.Run();
}
}
}
My Interface looks like this:
namespace DataInterfaceDll
{
public interface IDataProvider
{
void SaySomething(string request, Action<string> callback);
}
}
And this is the Plug-In (DLL), which should be able to send something back to the EXE (or call a function from the EXE that does this):
namespace StringDataDll
{
[Export(typeof(IDataProvider))]
public class StringData : IDataProvider
{
public void SaySomething(string request, Action<string> callback)
{
callback("This is just a test program...");
}
}
}
When I run this code, I get a System.Reflection.ReflectionTypeLoadException in the following line
container.ComposeParts(this);
Can anyone tell me what I am doing wrong here?

It works for me by loading dynamically the DLL.
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(Assembly.LoadFile("yourpath\StringDataDll.dll")));
aggregatecatalogue.Catalogs.Add(new AssemblyCatalog(Assembly.GetAssembly(typeof(IDataProvider))));
And it works too with new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory) when you copy the stringDataDll.dll in the output folder of your main program.
Be sure to have all of your dll files in your output folder of your main program.

Related

C# UnitTest void static method

I'm trying to make an unit test for a logger in an application.
For example I need to test the method Logger.info("some message"), but this method is static and return void.
Searching on Google I understand that I have to use Moq but am unable to implement that on the UnitTest class.
The Logger constructor does not have an argument and in x.Debug I have an error that says that I can't access
from instance reference.
Is there a way to implement UnitTest without editing the production code?
[TestClass()]
public class LoggerTests
{
[TestMethod()]
public void DebugTest()
{
var mock = new Mock<Logger>();
mock.Setup(x => x.Debug(It.IsAny<string>());
new Logger(mock.Object).AddLog("testing");
mock.VerifyAll;
}
}
Program.cs
private static void ConfigureLogger()
{
Logger.AddLog(new NLogAppender());
Logger.Level = TraceLevel.Verbose;
Logger.Info("Configured Logger");
}
Logger.cs
public class Logger
{
public static readonly List<IAppender> loggings = new List<IAppender>();
public static void AddLog(IAppender appender)
{
loggings.Add(appender);
}
public static TraceLevel Level { get; set; }
static Logger()
{
Level = TraceLevel.Verbose;
}
public static void Info(string message)
{
LogMessage(message);
}
}
NlogAppender.cs
public class NLogAppender : IAppender
{
public NLog.Logger logger;
public NLogAppender()
{
logger = LogManager.GetLogger(nameof(NLogAppender));
}
public void AddLog(string str)
{
}
}
IAppender.cs
public interface IAppender
{
void AddLog(string str);
}
You can't mock a static class, and you shouldn't mock the class/system under test.
Add a mock appender to the logger:
// Arrange
var logString = "test-info"
var appenderMock = new Mock<IAppender>();
appenderMock.Setup(a => a.AddLog(logString));
Logger.AddLog(appenderMock.Object);
// Act
Logger.Info(logString);
// Assert
// TODO: exactly once
appenderMock.VerifyAll();
Note this static class may persist data between tests causing unexpected results, consult your test framework for configuring this.
Apart from that, you usually don't want to roll your own logging infrastructure, there's lots of things you can do wrong and why reinvent the wheel? Plenty of ILogger(<T>) implementations around.

C# Specflow - BeforeScenario hook is not being called

packages:
.net core 3.1,
Specflow 3.8.7
Solution Structure:
I have Step definitions in project UMW.Selenium.UI (A)
namespace UMW.Selenium.UI.Steps
{
[Binding]
public class CalculatorStepDefinitions : UIFramework
{
UIBrowser uiBrowser;
public CalculatorStepDefinitions()
{
uiBrowser = new UIBrowser();
}
[Given(#"the first number is (.*)")]
public void GivenTheFirstNumberIs(int p0)
{
uiBrowser.NavigateToURL("https://demoqa.com/browser-windows");
}
}
}
I have Hooks (BeforeTestRun, BeforeScenario etc.) in another project Selenium.UI.Framework (B).
namespace Selenium.UI.Framework.Framework.Utilities.ScenarioFactory
{
using LogBuffer = List<string>;
[Binding]
[TestClass]
public class SetupAndTearDown
{
internal readonly ScenarioContext _scenarioContext;
internal readonly FeatureContext _featureContext;
private readonly IObjectContainer _objectContainer;
public SetupAndTearDown()
{
}
public SetupAndTearDown(IObjectContainer objectContainer, FeatureContext featureContext, ScenarioContext scenarioContext)
{
this._objectContainer = objectContainer;
_featureContext = featureContext;
_scenarioContext = scenarioContext;
}
[BeforeTestRun]
public static void InitializeTestSuite()
{
ReportsFactory.Report.StartTestSuite();
}
[BeforeScenario]
public void InitializeTestScenario()
{
ReportsFactory.Report.StartTestCase();
//_objectContainer.RegisterInstanceAs(Webdriver.Driver);
}
}
}
When I execute scenario from A, it does not call BeforeTestRun/BeforeScenario from B. Here project A uses functions from project B. The test runs successfully bypassing hooks.
You need to declare bindings from an external assembly in specflow.json.
{
"stepAssemblies": [
{
"assembly": "Selenium.UI.Framework"
}
]
}
Note: the name of the assembly, not the namespace, is required with no file extension. You will need to double check the name of the DLL file created by the Selenium.UI.Framework project.

Injection into Console Application with the Simple Injector

I am using Simple Injector for test purpose but pretty new on OOP. I am trying to create loosely couple classes. Here is the my scenario.
I have User repo and interface like this.
public class UserRepository : IUserRepository
{
public void Add(Model.User user)
{
Console.WriteLine("Name:"+user.Name+"\n"+"SurName:"+user.SurName);
}
public void Delete(int id)
{
throw new NotImplementedException();
}
}
public interface IUserRepository
{
void Add(User user);
void Delete(int id);
}
My TestInjectedClass Class and interface are something like this which I am planning to use in Program Main.
public class TestInjectedClass : ITestInjectedClass
{
private readonly IUserRepository _userRepository;
public TestInjectedClass(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void UserRepoRun()
{
var user = new User() {Id = 1,Name = "ada",SurName = "stack"};
_userRepository.Add(user);
}
}
public interface ITestInjectedClass
{
void UserRepoRun();
}
And My console program looks like this:
class Program
{
static ITestInjectedClass _testInjectedClass;
private static IUserRepository _userRepository;
static void Main(string[] args)
{
_testInjectedClass= new TestInjectedClass(_userRepository);
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
public Program()
{
Bootstrap.Start();
}
}
BootStrap class here:
class Bootstrap
{
public static void Start()
{
var container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
My problem when I run program, I am getting a value exception on the _userRepository inside TestInjectionClass.
How can I properly inject TestInjectionClass and UserRepository to Main Program. Thanks
You need to make Bootstrap.container available in Program.Main and then use it to create instances of classes instead of directly calling their constructors directly:
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
Of course you will need to expose it in Bootstrap for that to work:
class Bootstrap
{
public static Container container;
public static void Start()
{
container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
And call Bootstrap.Start from Program.Main:
static void Main(string[] args)
{
Bootstrap.Start();
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
The problem is because you are calling your Bootstrap code in Program class instance constructor.
So, actually when you start your program the execution environment, is calling entry point method Main. And your instance constructor is never executed.
Try changing your entry point method Main and 'Bootstrap' class code:
static void Main(string[] args)
{
var container = new Container();
Bootstrap.Start(container);
_testInjectedClass = container.GetInstance<TestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
class Bootstrap
{
public static void Start(Container container)
{
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
Please use SimpleInjector
Sample please refer
http://www.c-sharpcorner.com/UploadFile/4d9083/dependency-injection-using-simple-injector/

How to pre-load data in an OWIN self-hosted app

I have a OWIN/Katana self-hosted service app.
One of its functions is to service some data over WebAPI.
In this app I have a class called dataManager, which is responsible for retrieving the data, and passing it onto the API controller, which asked for it.
The data is ultimately served to a mobile platform, so it is very important to cache as much as possible for performance.
Is there a way to pre-load my DataManager at the application startup, and have it pre-execute it's linq queries?
The Application class looks like this:
namespace TaskManager
{
using System;
using Microsoft.Owin.Hosting;
public class TaskManagerApplication
{
protected IDisposable WebApplication;
public void Start()
{
WebApplication = WebApp.Start<WebPipeline>("http://*:8080");
}
public void Stop()
{
WebApplication.Dispose();
}
}
}
The Program class looks like this:
namespace TaskManager
{
using Topshelf;
internal class Program
{
private static int Main()
{
var exitCode = HostFactory.Run(host =>
{
host.Service<TaskManagerApplication>(service =>
{
service.ConstructUsing(() => new TaskManagerApplication());
service.WhenStarted(a => a.Start());
service.WhenStopped(a => a.Stop());
});
host.SetDescription("Task Manager");
host.SetDisplayName("Task Manager");
host.SetServiceName("TaskManager");
host.RunAsNetworkService();
});
return (int) exitCode;
}
}
}
And the data retrieval statement contained within DataManager class look like this:
var rawData = from data in new XPQuery<AccountView3.PipelineData>(uow)
where data.Stage.ToLower().Contains("won")
&& data.RevenueStartDate.Value.Year == DateTime.Today.Year
&& data.WeekOfTheYear >= priorWeekCutoff
select data;
What I do is create a public static class in the API library. That's where I modify the HttpConfiguration object. That is also where I define OnStartup() and OnShutdown() methods. I then call these methods in the pipeline class's methods (your WebPipeline class).
For example (in the MyWebApi library, where my controllers and stuff live):
public class Service
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.EnsureInitialized();
}
public static void OnStartup()
{
// add any startup logic here, like caching your data
}
public static void OnShutdown()
{
// add any cleanup logic here
}
}
Then in the pipeline class:
public class WebPipeline
{
public static void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
MyWebApi.Service.Register(config);
MyWebApi.Service.OnStartup();
app.UseWebApi(config);
}
public static void Shutdown()
{
MyWebApi.Service.OnShutdown();
}
}
Now your TaskManagerApplication.Start() will result in the API OnStartup() being called. Then you just have to add a call to WebPipeline.Shutdown() in your TaskManagerApplication.Stop() method.

Programmatic configuration of Enterprise Library logging block

I've previously used log4net, but my current employer uses Enterprise Library application blocks. I had previously developed unit tests for my core logging classes as follows and was wondering if someone knew the equivalent for the OneTimeSetup code below for the logging app block (sorry for the long code post):
public abstract class DataGathererBase
{
public readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void CollectData()
{
this.LogDebug("Initialize started");
}
public static class Logger
{
private static LoggingSettings settings = LoggingSettings.GetLoggingSettings(new SystemConfigurationSource());
static Logger()
{
log4net.Config.XmlConfigurator.Configure();
}
public static void LogDebug(this DataGathererBase current, string message)
{
if (current.logger.IsDebugEnabled)
{
current.logger.Debug(string.Format("{0} logged: {1}", current.GetType().Name, message));
}
}
}
[TestFixture]
public class LoggerTests:DataGathererBase
{
private ListAppender appender;
private static ILog log;
[TestFixtureSetUp]
public void OneTimeSetup()
{
appender = new ListAppender();
appender.Layout = new log4net.Layout.SimpleLayout();
appender.Threshold = log4net.Core.Level.Fatal;
log4net.Config.BasicConfigurator.Configure(appender);
log = LogManager.GetLogger(typeof(ListAppender));
}
[Test]
public void TestLogging()
{
this.LogDebug("Debug");
Assert.AreEqual(0, ListAppender.logTable.Count());
}
}
Enterprise Library 5.0 introduced a fluent interface which can be used to programmatically configure the application blocks. You will probably find this to be a more comfortable option.
To give credit, this answer is based on a David Hayden article which is based on an Alois Kraus article, Programatic Configuraton - Enterprise Library (v2.0) Logging Block . Read those two articles for a good look at programmatic access to Enterprise Library logging.
I wasn't familiar with ListAppender so I created a CustomTraceListener that sticks the log messages in a List<string>:
public class ListAppender : Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.CustomTraceListener
{
private List<string> list = new List<string>();
public override void Write(string message)
{
}
public override void WriteLine(string message)
{
list.Add(message);
}
public List<string> LogTable
{
get
{
return list;
}
}
}
Here is a modified LoggerTests class that programmatically accesses the EL logging classes to setup the tests (this does not use NUnit):
public class LoggerTests
{
private ListAppender appender;
private static LogWriter log;
public void OneTimeSetup()
{
appender = new ListAppender();
// Log all source levels
LogSource mainLogSource = new LogSource("MainLogSource", SourceLevels.All);
mainLogSource.Listeners.Add(appender);
// All messages with a category of "Error" should be distributed
// to all TraceListeners in mainLogSource.
IDictionary<string, LogSource> traceSources = new Dictionary<string, LogSource>();
traceSources.Add("Error", mainLogSource);
LogSource nonExistentLogSource = null;
log = new LogWriter(new ILogFilter[0], traceSources, nonExistentLogSource,
nonExistentLogSource, mainLogSource, "Error", false, false);
}
public void TestLogging()
{
LogEntry le = new LogEntry() { Message = "Test", Severity = TraceEventType.Information };
le.Categories.Add("Debug");
log.Write(le);
// we are not setup to log debug messages
System.Diagnostics.Debug.Assert(appender.LogTable.Count == 0);
le.Categories.Add("Error");
log.Write(le);
// we should have logged an error
System.Diagnostics.Debug.Assert(appender.LogTable.Count == 1);
}
}

Categories