I try to inject log4net in a ILogger property of my service class but the property is always NULL!
I've seen this topic but it doesn't help me!
How can I get Castle Windsor to automatically inject a property?
this is Program.cs
CastleContainer.Instance
.Install(
new RepositoriesInstaller(),
new PersistenceInstaller(),
new LoggerInstaller(),
new FormInstaller(),
new ServiceInstaller()
);
FrmStart form1 = CastleContainer.Resolve<FrmStart>(new {Id="666" });
I use log4net.config external file and this is my installer:
public class LoggerInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility("logging", new LoggingFacility(LoggerImplementation.Log4net, "log4net.config"));
}
#endregion
}
This is the class contains the property I want Windsor to inject:
public partial class FrmStart : Form
{
private EventService EventService;
private ILogger logger = NullLogger.Instance;
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
public FrmStart(EventService eventService, string Id)
: this()
{
Logger.Debug("xxx");
this.EventService = eventService;
this.id = Id;
}
Note that "eventService" and "Id" in the constructor are correctly injected!
If I try to inject the Logger in the constructor it works and I've the Logger object:
{log4net.Repository.Hierarchy.DefaultLoggerFactory+LoggerImpl}! :-(
I've tried to create a public property for EventService and Windsor can inject it properly! So I think the problem is related only to the ILogger interface.
I prepared a simple full-code example here:
using Castle.Core.Logging;
using Castle.Facilities.Logging;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
namespace IocTest
{
public class LoggerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility("logger", new LoggingFacility(LoggerImplementation.Log4net, "log4net.config"));
}
}
public class LogicInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(AllTypes.FromThisAssembly()
.Pick()
.If(t => t.Name.StartsWith("Logic"))
.Configure((c => c.LifeStyle.Transient)));
}
}
class Program
{
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
container.Install(
new LoggerInstaller(),
new LogicInstaller()
);
LogicClass1 logic1 = container.Resolve<LogicClass1>();
LogicClass2 logic2 = container.Resolve<LogicClass2>();
}
}
public class LogicClass1
{
private ILogger logger = NullLogger.Instance;
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
public LogicClass1()
{
logger.Debug("Here logger is NullLogger!");
}
}
public class LogicClass2
{
public LogicClass2(ILogger logger)
{
logger.Debug("Here logger is properly injected!");
}
}
}
What's wrong?
A problem is where you are checking it:
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
public LogicClass1()
{
logger.Debug("Here logger is NullLogger!");
}
The property injection will not happen until after the constructor is run, so checking the property value in the constructor will never show the value you are expecting
I was having the same problem. It was always null.
I managed to solve the problem by injecting the logger in the constructor this way:
public ILogger logger;
public MyController(ILogger logger)
{
this.logger = logger;
logger.Info("Something");
}
You could also initialize your Logger by using:
public ILogger Logger { get; set; }
public MyController()
{
Logger = NullLogger.Instance;
}
Related
How should I register GrainService in Orleans 7.0?
I have GrainService:
public interface IAlfaGrainService : IGrainService
{
Task<IReadOnlyList<AlfaData>> TestMethod();
}
[Reentrant]
public class AlfaGrainService : GrainService, IAlfaGrainService
{
readonly IGrainFactory _grainFactory;
private readonly ILogger<AlfaGrainService> logger;
public AlfaGrainService(
IServiceProvider services,
Silo silo,
ILoggerFactory loggerFactory,
IGrainFactory grainFactory,
ILogger<AlfaGrainService> logger)
: base(GrainId.Create(nameof(AlfaGrainService), Guid.Empty.ToString()), silo, loggerFactory)
{
_grainFactory = grainFactory;
this.logger = logger;
}
public async Task<IReadOnlyList<AlfaData>> TestMethod()
{
logger.LogInformation("TestMethod() hit");
// TODO: custom logic here.
var data = new List<AlfaData> {
new AlfaData
{
Id = 1,
Name = "Test 1"
},
new AlfaData
{
Id = 2,
Name = "Test 2"
}
};
return await Task.FromResult(data);
}
}
GrainServiceClient (because I want to call GrainService from Grain):
public interface IAlfaGrainServiceClient : IGrainServiceClient<IAlfaGrainService>, IAlfaGrainService
{
}
public class AlfaGrainServiceClient : GrainServiceClient<IAlfaGrainService>, IAlfaGrainServiceClient
{
public AlfaGrainServiceClient(
IServiceProvider serviceProvider)
: base(serviceProvider)
{ }
public Task<IReadOnlyList<AlfaData>> TestMethod()
{
// Not sure how to get grainService reference:
var grainId = GrainId.Create(nameof(AlfaGrainService), Guid.Empty.ToString());
var service = GetGrainService(grainId);
// -------------------------------------
return service.TestMethod();
}
}
Grain from which I want to call GrainService (by proxy GrainServiceClient):
public interface IAlfaGrain: IGrainWithStringKey
{
Task<IReadOnlyList<AlfaData>> LoadData();
}
public class AlfaGrain: Grain, IAlfaGrain
{
private readonly IAlfaGrainServiceClient alfaGrainServiceClient;
public AlfaGrain(
IAlfaGrainServiceClient alfaGrainServiceClient)
{
this.alfaGrainServiceClient = alfaGrainServiceClient;
}
public async Task<IReadOnlyList<AlfaData>> LoadData()
{
return await alfaGrainServiceClient.TestMethod();
}
}
But If I register GrainService like this:
siloBuilder
.AddGrainService<AlfaGrainService>() // Register grainService like this ??
.ConfigureServices(services =>
{
services.AddSingleton<IAlfaGrainServiceClient, AlfaGrainServiceClient>();
});
I got error during starting app:
A suitable constructor for type 'GrainServiceApp.GrainServices.AlfaGrainService' could not be located. Ensure the type is concrete and all parameters of a public constructor are either registered as services or passed as arguments. Also ensure no extraneous arguments are provided.
Maybe because the GrainServiceFactory() (Orleans.Hosting.GrainServicesSiloBuilderExtensions) doesn't create instance with all ctor parameters.
Microsoft documentation is only about prev version of Orleans and thus doesn't work in my case.
Does anybody know how register GrainService in Orleans 7.0?
All code is on github
I have already found the solution and it was quite simple.
I needed to inject GrainId into GrainService and pass it into the base class:
public AlfaGrainService(
GrainId grainId,
Silo silo,
IServiceProvider services,
ILoggerFactory loggerFactory,
ILogger<AlfaGrainService> logger)
: base(grainId, silo, loggerFactory)
{
this.logger = logger;
}
Then in GrainServiceClient I got GrainService instance by CurrentGrainReference.GrainId like this:
public Task<IReadOnlyList<AlfaData>> TestMethod()
{
var service = GetGrainService(CurrentGrainReference.GrainId);
return service.TestMethod();
}
I have updated the example on GitHub
Abstract Class:
public abstract class Rater
{
public Rater()
{
}
public abstract decimal Rate(Policy policy);
}
Child classes:
public class AutoPolicyRater : Rater
{
public readonly ILogger<AutoPolicyRater> _logger;
public AutoPolicyRater(ILogger<AutoPolicyRater> logger)
{
_logger = logger;
}
public override decimal Rate(Policy policy)
{
_logger.Log("Rating AUTO policy...");
_logger.Log("Validating policy.");
if (String.IsNullOrEmpty(policy.Make))
{
_logger.Log("Auto policy must specify Make");
return 0m;
}
if (policy.Make == "BMW")
{
if (policy.Deductible < 500)
{
return 1000m;
}
return 900m;
}
return 0m;
}
}
public class LandPolicyRater : Rater
{
public readonly ILogger<LandPolicyRater> _logger;
public AutoPolicyRater(ILogger<LandPolicyRater> logger)
{
_logger = logger;
}
public override decimal Rate(Policy policy)
{
_logger.Log("Rating LAND policy...");
_logger.Log("Validating policy.");
if (policy.BondAmount == 0 || policy.Valuation == 0)
{
_logger.Log("Land policy must specify Bond Amount and Valuation.");
return 0m;
}
if (policy.BondAmount < 0.8m * policy.Valuation)
{
_logger.Log("Insufficient bond amount.");
return 0m;
}
return (policy.BondAmount * 0.05m);
}
}
Factory class, where I want to dynamically pass the logger object:
public class RaterFactory
{
private readonly IRatingUpdater _ratingUpdater;
public RaterFactory(ILogger logger)
{
}
public Rater Create(Policy policy)
{
try
{
return (Rater)Activator.CreateInstance(
Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
new object[] { ?? });//here I want to pass logger object
}
catch
{
return new UnknownPolicyRater();
}
}
}
As these classes are not controllers, and I want to create object in my factory method, how can I pass logger object and log information to application insight? I would like to pass generic logger object, however, if there is another approach to achieve, I'm ok.
EDIT:
After #fildor's suggestion, I tried below and it is logging information in Application Insight traces.
public class RaterFactory
{
private readonly ILoggerFactory _loggerFactory;
public RaterFactory(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
public Rater Create(Policy policy)
{
try
{
string typeString = $"MyCompany.{policy.Type}PolicyRater";
ILogger modelLogger = _loggerFactory.CreateLogger(typeString);
return (Rater)Activator.CreateInstance(
Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
new object[] { modelLogger });
}
catch
{
return new UnknownPolicyRater();
}
}
}
public class AutoPolicyRater : Rater
{
public readonly ILogger _logger;
public AutoPolicyRater(ILogger logger)
{
_logger = logger;
}
//other code
}
As requested: a possible implementation:
public class RaterFactory
{
private readonly ILoggerFactory _loggerFactory;
public RaterFactory(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
public Rater Create(Policy policy)
{
try
{
return (Rater)Activator.CreateInstance(
Type.GetType($"MyCompany.{policy.Type}PolicyRater"),
new object[] { _loggerFactory });
}
catch
{
return new UnknownPolicyRater();
}
}
}
And then ...
public class AutoPolicyRater : Rater
{
private readonly ILogger<AutoPolicyRater> _logger;
public AutoPolicyRater(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<AutoPolicyRater>();
}
public override decimal Rate(Policy policy)
{
// ... ommited for brevity
}
}
The RaterFactory class has no need to know in advance all dependencies injected into the instances it creates.
Instead, you can inject IServiceProvider and let ActivatorUtilities resolve the dependencies of the Rater instances that you are creating each time.
This is how it can be done:
public class RaterFactory
{
private readonly IServiceProvider _serviceProvider;
public RaterFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public Rater Create(Policy policy)
{
try
{
// OPTION 1
return (Rater)ActivatorUtilities.CreateInstance(
_serviceProvider,
Type.GetType($"MyCompany.{policy.Type}PolicyRater"));
// OPTION 2
return (Rater)ActivatorUtilities.GetServiceOrCreateInstance(
_serviceProvider,
Type.GetType($"MyCompany.{policy.Type}PolicyRater"));
}
catch
{
return new UnknownPolicyRater();
}
}
}
As shown above, there are two possible options that you should choose according to your needs and constraints.
ActivatorUtilities.CreateInstance: This method creates each time a new instance and does not query the service collection for the target type. This is convenient if you don't know all the possible target types in advance (or you don't want to register them for some reason).
ActivatorUtilities.GetServiceOrCreateInstance: This method looks for the target type into the service collection; if a registration is found, it returns the corresponding instance, otherwise it behaves like ActivatorUtilities.CreateInstance. This means that you can register the target type in the service collection as usual with the most appropriate lifetime (singleton, scoped or transient) for each type. The only downside of this approach is that, if you have some singleton or scoped target types, you have to provide a way to register them in the service collection, which may be tricky in a plugin-like application.
Again, please note that there are no constraints on which dependencies can be injected in the Rater subtypes, because after all the "dirty" work of dependency resolution is done by the ActivatorUtilities class.
I have StrategyName set in appsettings.json which represents the name of the strategy class. I need to get an instance of it.
ITradingStrategy _tradingStrategy = StrategyUtils.GetStrategyInstance(logger, _tradeOptions.StrategyName)
which is equal to
ITradingStrategy _tradingStrategy = new RsiStrategy(logger);
Is it possible to be made in a better way? It works but looks ugly. Since we know the strategy name in the beginning (from appsettings.json), there should probably be a way to obtain it in a better ASP.NET Core way. Maybe some cool extension method, I don't know.
appsettings.json
{
"TradeConfiguration": {
"StrategyName": "RsiStrategy",
...
}
}
Code
public class LiveTradeManager : ITradeManager
{
private readonly ILogger _logger;
private readonly IExchangeClient _exchangeClient;
private readonly ITradingStrategy _tradingStrategy;
private readonly ExchangeOptions _exchangeOptions;
private readonly TradeOptions _tradeOptions;
public LiveTradeManager(ILogger logger, IConfiguration configuration, IExchangeClient exchangeClient)
{
_logger = logger;
_exchangeClient = exchangeClient;
_exchangeOptions = configuration.GetSection("ExchangeConfiguration").Get<ExchangeOptions>();
_tradeOptions = configuration.GetSection("TradeConfiguration").Get<TradeOptions>();
_tradingStrategy = StrategyUtils.GetStrategyInstance(logger, _tradeOptions.StrategyName); // This is the questioned line
}
}
public static ITradingStrategy GetStrategyInstance(ILogger logger, string strategyName)
{
var strategyType = Assembly.GetAssembly(typeof(StrategyBase))
.GetTypes().FirstOrDefault(type => type.IsSubclassOf(typeof(StrategyBase)) && type.Name.Equals(strategyName));
if (strategyType == null)
{
throw new ArgumentException($"The strategy \"{strategyName}\" could not be found.", nameof(strategyName));
}
var strategy = Activator.CreateInstance(strategyType, logger) as ITradingStrategy;
return strategy;
}
// Strategies
public interface ITradingStrategy
{
IReadOnlyList<TradeAdvice> Prepare(IReadOnlyList<OHLCV> candles);
}
public abstract class StrategyBase : ITradingStrategy
{
private readonly ILogger _logger;
protected StrategyBase(ILogger logger)
{
_logger = logger;
}
public abstract IReadOnlyList<TradeAdvice> Prepare(IReadOnlyList<OHLCV> candles);
}
public class RsiStrategy : StrategyBase
{
private readonly ILogger _logger;
public RsiStrategy(ILogger logger) : base(logger)
{
_logger = logger;
}
public override IReadOnlyList<TradeAdvice> Prepare(IReadOnlyList<OHLCV> candles)
{
... _logger.Information("Test");
}
}
// Main
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
})
.ConfigureServices((hostingContext, services) =>
{
services.AddSingleton(
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(hostingContext.Configuration)
.CreateLogger());
services.AddSingleton<ITradeManager, LiveTradeManager>();
services.AddSingleton<IExchangeClient, BinanceSpotClient>();
services.AddHostedService<LifetimeEventsHostedService>();
})
.UseSerilog();
}
Your problem can be solved multiple ways and using reflection would be the last one.
From your problem statement, I figure that you have multiple strategy classed implementing ITradingStrategy interface, and you configuration value from appsettings.json file decides which strategy to use.
One of the approach you can use here is to use factory to initialize appropriate strategy class based on the configuration value.
Following is the factory class and interface which will create Strategy class object based on the strategy name passed to it.
public interface IStrategyFactory
{
ITradingStrategy GetStrategy(string strategyName);
}
public class StrategyFactory : IStrategyFactory
{
private IServiceProvider _serviceProvider;
public StrategyFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public ITradingStrategy GetStrategy(string strategyName)
{
switch (strategyName)
{
case "Rsi":
// Resolve RsiStrategy object from the serviceProvider.
return _serviceProvider.GetService<RsiStrategy>();
case "Dmi":
// Resolve DmiStrategy object from the serviceProvider.
return _serviceProvider.GetService<DmiStrategy>();
default:
return null;
}
}
}
This strategy can now be used in controller and call its GetStrategy method by passing the strategy name which in-turn is retrieved from the configuration.
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
// Strategy factory.
private IStrategyFactory _strategyFactory;
// Configuration
private IConfiguration _configuration;
public HomeController(ILogger<HomeController> logger, IConfiguration configuration, IStrategyFactory strategyFactory)
{
_logger = logger;
_strategyFactory = strategyFactory;
_configuration = configuration;
}
public IActionResult Index()
{
// Get Configuration value "StrategyName" from configuration.
// In your case this will be your own custom configuration.
var strategyName = _configuration.GetValue<string>("StrategyName");
// Pass strategyName to GetStrategy Method.
var strategy = _strategyFactory.GetStrategy(strategyName);
// Call Prepare method on the retrieved strategy object.
ViewBag.PreparedList = strategy.Prepare(new List<OHLCV>());
return View();
}
}
For the above code to work you need to register strategy classed in to serviceCollection.
services.AddSingleton<RsiStrategy>();
services.AddSingleton<DmiStrategy>();
And also the StrategyFactory.
services.AddSingleton<IStrategyFactory, StrategyFactory>();
EDIT
Based on your comment below, you need to be able to resolve the strategy types without additional overhead of registering them in DI as when new types are created and also without making changes in the factory.
You need to use reflection for this. Using reflection you can determine the types which you want to register in the DI. As following.
//Get all the types which are inheriting from StrategyBase class from the assembly.
var strategyTypes = Assembly.GetAssembly(typeof(StrategyBase))
?.GetTypes()
.Where(type => type.IsSubclassOf(typeof(StrategyBase)));
if (strategyTypes != null)
{
//Loop thru the types collection and register them in serviceCollection.
foreach (var type in strategyTypes)
{
services.Add(new ServiceDescriptor(typeof(StrategyBase), type, ServiceLifetime.Singleton));
}
}
With the above code, all the types which are inheriting from StrategyBase are registered in serviceCollection. Now using serivceProvider we can get all the registered instances and look for the instance which has correct strategyName.
So the factory's GetStrategy method will look like as following.
public ITradingStrategy GetStrategy(string strategyName)
{
var strategies = _serviceProvider.GetServices<StrategyBase>();
var strategy = strategies.FirstOrDefault(s => s.GetType().Name == strategyName);
if (strategy == null)
{
throw new ArgumentException($"The strategy \"{strategyName}\" could not be found.", nameof(strategyName));
}
return strategy;
}
I hope this will help you resolve your issue.
I've created an injectable dbcontext
Startup.cs:
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddDbContext<DBContext>(options => options.UseSqlServer("Server=localhost;Database=mydb;Trusted_Connection=True;"));
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork {
private readonly DBContext _context;
public UnitOfWork(DBContext context) {
_context = context;
}
The injection working fine in the controller:
public class UserController : ControllerBase {
private readonly IUnitOfWork unitOfWork;
public UserController(IUnitOfWork unitOfWork) {
this.unitOfWork = unitOfWork;
}
}
How can I create custom class that takes IUnitOfWork in the constructor and call it from main program?
CustomClass :
public class CustomClass {
private readonly IUnitOfWork unitOfWork;
public CustomClass(IUnitOfWork unitOfWork) {
this.unitOfWork = unitOfWork;
}
}
Main program:
public class Program {
public static void Main(string[] args) {
var unitOfWork=new UnitOfWork() // Here I don't want to pass new DBContext I want to reach the same injected DBContext
var customClass =new CustomClass (unitOfWork);
}
}
Firstly, move out your code from ConfigureServices to some shared library that can be used both by Web and Console project. Create extension method to configure all your services.
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleApp13
{
public static class ConfigureServicesExtensions
{
public static void ConfigureMyServices(this IServiceCollection serviceCollection)
{
serviceCollection.AddDbContext<ApplicationDbContext>();
serviceCollection.AddScoped<IUnitOfWork, UnitOfWork>();
serviceCollection.AddScoped<CustomClass>();
}
}
}
This is how your Console app will look like
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleApp13
{
class Program
{
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.ConfigureMyServices();
using var serviceProvider = serviceCollection.BuildServiceProvider();
using var scope = serviceProvider.CreateScope();
var myService = scope.ServiceProvider.GetService<CustomClass>();
}
}
}
And your web project
public void ConfigureServices(IServiceCollection services)
{
services.ConfigureMyServices();
}
What you can do is just add your class to the dependecy injection container and inject it into your constructor, you wouldn't need to inject the IUnitOfWork in you controller.
services.AddScoped<CustomClass>();
and then in your constroller constructor
public class UserController : ControllerBase {
private readonly CustomClass _CustomClass;
public UserController(CustomClass customClass) {
_CustomClass = customClass;
}
}
after that you are able to use this class in your class methods
I would try something like this:
public class Program {
public static void Main(string[] args) {
var optionsBuilder = new DbContextOptionsBuilder<DbContext>();
optionsBuilder.UseSqlServer(connectionstring);
using(DbContext dbContext = new DbContext(optionsBuilder.Options))
{
var unitOfWork=new UnitOfWork(dbContext)
var customClass =new CustomClass (unitOfWork);
.....
}
}
}
I'm developing a framework where I've put lots of logging throughout. I used Castle Windsor's ILogger through this property pattern:
namespace Framework
{
public class SomeClass
{
private ILogger _logger = NullLogger.Instance;
public ILogger Logger
{
get { return _logger; }
set { _logger = value; }
}
public void DoSomething()
{
Logger.Info("Doing something.");
}
//...
}
}
I also provide an installer from within the framework:
namespace MyFramework
{
public class LoggerInstaller : IWindsorInstaller
{
private readonly string _configPath;
public LoggerInstaller(string configPath)
{
_configPath = configPath;
}
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility("logging", new LoggingFacility(LoggerImplementation.Log4net, _configPath));
//I've also tried this one:
//container.AddFacility<LoggingFacility>(f => f.LogUsing(LoggerImplementation.Log4net).WithConfig(_configPath));
}
}
}
This project is then referenced from other projects. For example, in the test project, I'll construct a test by first installing the logger. I do this with an abstract class that all of my long running tests extend:
namespace Framework.Test
{
public abstract class Log4NetLoggedTest
{
private const string ConfigFilePath = "log4net.config";
protected ILogger Logger { get; set; }
protected IWindsorContainer Container { get; set; }
protected Log4NetLoggedTest()
{
Container = new WindsorContainer();
Container.Install(new LoggerInstaller(ConfigFilePath));
Logger = Container.Resolve<ILogger>();
}
~Log4NetLoggedTest()
{
Container.Dispose();
}
}
}
So that my test looks like this:
namespace Framework.Test
{
[TestFixture]
public class MyLongRunningTest : Log4NetLoggedTest
{
[Test]
[Category("LongRunning")]
public void ModelConvergesForS50()
{
Logger.Info("Starting test...");
var obj = new SomeClass();
obj.DoSomething();
// ...
}
}
}
The test's ILogger Logger gets resolved and set properly, so in this example I get the "Starting test..." but not the "Doing something." The SomeClass's ILogger stays as a NullLogger.
Please help!
You are instantiating SomeObj with 'new' rather than going through the container. If you don't go through the container, it can't inject the dependency
I may be saying something stupid, but, shouldnt be something like:
namespace Framework.Test
{
[TestFixture]
public class MyLongRunningTest : Log4NetLoggedTest
{
[Test]
[Category("LongRunning")]
public void ModelConvergesForS50()
{
Logger.Info("Starting test...");
var obj = new SomeClass();
obj.Logger = Logger;
obj.DoSomething();
// ...
}
}
}
I couldn't see you applying that instance of the logger that you use inside the class anywhere.