I want to add a logger to the Windows Form Application by using Castle IOC.
I registered the logger like below:
static class Program
{
[STAThread]
static void Main()
{
IWindsorContainer container = new WindsorContainer().Install(FromAssembly.This());
container.Register(Component.For<ICommonLogger>().ImplementedBy(typeof(CommonLogger)).LifeStyle.Singleton);
container.Kernel.Resolver.AddSubResolver(new EAE_Automation.COM.LoggerResolver(container.Kernel));
}
}
Then another form of the application, I tried to use the logger as property but It comes null to the program.
namespace Test.KNXManagement
{
public partial class Test: Form
{
public ICommonLogger Logger { get; set;}
public Tunneling()
{
Logger.Info("Testing.......................");
}
}
}
I think I am missing an important point here
I also register the Form class to resolve sub dependencies.
container.Register(Classes.FromThisAssembly().BasedOn<Form>());
Then also run the application as below
Application.Run(container.Resolve<Test>());
Thats solved my problem.
Thanks everyone.
The following code, based on yours, works perfectly fine for me:
private static IWindsorContainer _container;
static Program()
{
Debug.Listeners.Add(new ConsoleTraceListener());
_container = new WindsorContainer().Install(FromAssembly.This());
_container.Register(Component.For<ICommonLogger>().ImplementedBy(typeof(CommonLogger)).LifeStyle.Singleton);
}
private static ICommonLogger Logger { get; set; }
private static void Main(string[] args)
{
Logger = _container.Resolve<ICommonLogger>();
Logger.Write("Text");
Console.ReadLine();
}
public interface ICommonLogger
{
void Write(string str);
}
public class CommonLogger : ICommonLogger
{
public void Write(string str)
{
Console.WriteLine(str);
}
}
The output of the program in the console is Text.
Related
I Know
IoC is a design principle which recommends the inversion of different kinds of controls in object-oriented design to achieve loose coupling between application classes.
But I have confilct with the following code:
static void Main(string[] args)
{
ProductService ProductService = new ProductService(new LogInDB());
ProductService.Log();
Console.ReadKey();
}
public class ProductService
{
private readonly Ilog log;
public ProductService(Ilog _log)
{
log = _log;
}
public void Log()
{
log.Log();
}
}
public interface Ilog
{
void Log();
}
public class LogInFile : Ilog
{
public void Log()
{
Console.WriteLine("Log Into File");
}
}
public class LogInDB : Ilog
{
public void Log()
{
Console.WriteLine("Log Into Data Base");
}
}
What is difference between previous and next code
In the first code I used IOC (and added product service) but next I'm using just late binding
but i see IOC not added any value
static void Main(string[] args)
{
Ilog logObj = new new LogInDB();
logObj.Log();
//I still able to using LogInDB
//Ilog logObj = new new LogInDB();
//logObj.Log();
Console.ReadKey();
}
public interface Ilog
{
void Log();
}
public class LogInFile : Ilog
{
public void Log()
{
Console.WriteLine("Log Into File");
}
}
public class LogInDB : Ilog
{
public void Log()
{
Console.WriteLine("Log Into Data Base");
}
}
This depends on your defintion of value. One advantage of IoC would be a better testability of your code, which many would argue adds a lot of value. You can easily inject mocked classes into your test code and only test the class you want to test.
By the way your example is not compileable because of the line Ilog logObj = new new LogInDB();
I want to use context injection to remove the obsolete warnings for FeatureContext.Current and ScenarioContext.Current my code.
I have a reporter in a non binding class that requires setup before the test is run.
I have tried making a constructor and instantiating it but the values always return as Null.
In the Setup Step
namespace EclipseWebAutomationV2.Steps
{
[Binding]
class StepSetup
{
public static FeatureContext _featurecontext;
public static ScenarioContext _scenariocontext;
[BeforeTestRun]
public static void InitializeReport()
{
Reporter.ReportInit();
}
[BeforeFeature]
public static void BeforeFeature()
{
Reporter bfeature = new Reporter(_featurecontext, _scenariocontext);
bfeature.ReportFeature();
}
}
}
In the report class:
namespace EclipseWebAutomationV2.Configurations
{
class Reporter
{
private readonly FeatureContext _featurecontext;
private readonly ScenarioContext _scenariocontext;
public Reporter(FeatureContext _featurecontext, ScenarioContext _scenariocontext)
{
this._featurecontext = _featurecontext;
this._scenariocontext = _scenariocontext;
}
public static void ReportInit()
{
//does stuff
}
public void ReportFeature()
{
featureName = extent.CreateTest<Feature>(_featurecontext.FeatureInfo.Title);
}
}
}
_featurecontext always returns null. I was hoping for it to get the current feature context so i can use it to get the title and use it in other parts of the reporting class.
I am having the same issue with _scenariocontext.
The main problem is the Reporter object requires a FeatureContext and ScenarioContext object. When the [BeforeFeature] hook is executing, the ScenarioContext does not exist yet.
The [BeforeFeature] hook supports a couple of overloads, one of which accepts the newly created FeatureContext as an argument.
This coupled with removing the FeatureContext and ScenarioContext objects as dependencies for the Reporter class will solve your problem.
First, change the StepSetup class to remove the dependencies on FeatureContext and ScenarioContext, and alter the [BeforeFeature] to accept a FeatureContext object as an argument:
[Binding]
class StepSetup
{
[BeforeTestRun]
public static void InitializeReport()
{
Reporter.ReportInit();
}
[BeforeFeature]
public static void BeforeFeature(FeatureContext featureContext)
{
var reporter = new Reporter();
reporter.ReportFeature(featureContext);
}
}
Then change the Reporter class to accept a FeatureContext argument in ReportFeature:
class Reporter
{
public static ReportInit()
{
// does stuff
}
public void ReportFeature(FeatureContext featureContext)
{
featureName = extent.CreateTest<Feature>(featureContext.FeatureInfo.Title);
}
}
If the Reporter.ReportFeature method does not use any instance fields, consider making this method a static method as well, and using a static constructor instead of the Reporter.ReportInit() method:
static class Reporter
{
static Reporter()
{
// does stuff
}
public static void ReportFeature(FeatureContext featureContext)
{
featureName = extent.CreateTest<Feature>(featureContext.FeatureInfo.Title);
}
}
Then your StepSetup class becomes even simpler with no need to call a static "init" method on the Reporter class:
[Binding]
class StepSetup
{
[BeforeFeature]
public static void BeforeFeature(FeatureContext featureContext)
{
Reporter.ReportFeature(featureContext);
}
}
See Static Constructors (C# Programming Guide)
I'm trying to use Autofac to register a service into Xamarin.Forms (netstandard2.0)
here's my code:
SqliteManager.cs
public interface ISqliteManager
{
void test();
}
public class SqliteManager : ISqliteManager
{
private readonly string _path;
public SqliteManager()
{
_path = "test";
}
public void test()
{
Console.Write(_path);
}
}
App.xaml.cs
public partial class App : Application
{
public App()
{
InitializeComponent();
ViewModelLocator.RegisterDependencies();
ViewModelLocator.Resolve<ISqliteManager>().test();
}
}
ViewModelLocator.cs
public static class ViewModelLocator
{
private static IContainer _container;
public static void RegisterDependencies()
{
var builder = new ContainerBuilder();
builder.RegisterType<SqliteManager>().As<ISqliteManager>().SingleInstance();
_container?.Dispose();
_container = builder.Build();
}
public static T Resolve<T>()
{
return _container.Resolve<T>();
}
}
it's seems ok, but i get this error when i try to resolve the service in app.xaml.cs:
Registration: Activator = SqliteManager (ReflectionActivator),
Services = [Tracker.Managers.Interfaces.ISqliteManager], Lifetime =
Autofac.Core.Lifetime.RootScopeLifetime, Sharing = Shared, Ownership =
OwnedByLifetimeScope ---> No constructors on type
'Tracker.Managers.SqliteManager' can be found with the constructor
finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'.
but sqlitemanager has a constructor!
i wrote a little example to learn IoC and DI on my own.
I have one simple question:
How would you instantiate the unskilled worker in my example /
How can I swich between the following 2 inject candidates?:
kernal.Bind<IRepair>().To<Employee>();
kernal.Bind<IRepair>().To<UnskilledWorker>()
I'm a little bit confused at the moment...
class Program
{
static void Main(string[] args)
{
IWorkShop instance = GetWorkShop();
instance.StartToRepair();
Console.ReadLine();
}
private static IWorkShop GetWorkShop()
{
Ninject.IKernel kernal = new StandardKernel();
kernal.Bind<IWorkShop>().To<WorkShop>();
kernal.Bind<IRepair>().To<Employee>();
var instance = kernal.Get<IWorkShop>();
return instance;
}
}
public class WorkShop : IWorkShop
{
private IRepair _repair;
public WorkShop(IRepair repair)
{
_repair = repair;
}
public void StartToRepair()
{
_repair.RepairItNow();
}
}
interface IWorkShop
{
void StartToRepair();
}
public class Employee : IRepair
{
public void RepairItNow()
{
Console.WriteLine("Employee starts working.");
}
}
public class UnskilledWorker : IRepair
{
public void RepairItNow()
{
Console.WriteLine("Unskilled worker starts working.");
}
}
public interface IRepair
{
void RepairItNow();
}
}
If you know at compile time then you can use Ninject's contextual bindings: https://github.com/ninject/ninject/wiki/Contextual-Binding.
IKernel kernal = new StandardKernel();
kernal.Bind<IWorkShop>().To<WorkShop>();
kernal.Bind<IRepair>().To<Employee>();
kernal.Bind<IRepair>().To<UnskilledWorker>().WhenInjectedInto(typeof(IWorkShop));
var instance = kernal.Get<IWorkShop>();
return instance;
If you need to decide at runtime which dependency to instantiate you are going to have to use a factory pattern.
I am running a .NET 4.0 Web Application (not web site) and PostSharp 1.5. I cannot get the OnEntry override method to execute using the OnMethodBoundaryAspect base class. Here is some relevant code:
public sealed class MonitorAttribute : OnMethodBoundaryAspect {
public string[] SomeValue { get; protected set; }
public MonitorAttribute (params string[] someValue){
SomeValue = someValue;
}
public override void OnEntry(MethodExecutionEventArgs eventArgs){
// do Something here
base.OnEntry(eventArgs);
}
}
public sealed class MyUsageClass : IMyUsageClass {
[Monitor(new string[]{ 'Test' })
public void SomeMethod {
// Do something else in here
}
}
Am I missing something? It never hits the OnEntry method. I also tried replacing my PostSharp.dll and PostSharp.Laos.dll dependencies with the new 2.0 version. If it makes any difference MyUsageClass is instantiated by StructureMap.
Yes, every dev will need to have PostSharp installed. If you're just using the starter edition then it's all free.
Posting this as an answer to show you the code. My test code
class Program
{
[Monitor]
static void Main(string[] args)
{
}
}
[Serializable]
public class MonitorAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Console.WriteLine("OnEntry");
}
}
The code after compilation
internal class Program
{
[CompilerGenerated, DebuggerNonUserCode]
internal sealed class <>z__Aspects
{
internal static MethodBase m1 = MethodBase.GetMethodFromHandle(ldtoken(Main()));
internal static readonly MonitorAttribute a0 = (MonitorAttribute)<>z__AspectsImplementationDetails.aspects1[0];
}
private static void Main(string[] args)
{
Program.<>z__Aspects.a0.OnEntry(null);
}
}