Castle and NLog change connection string at runtime - c#

i am using the NLog built in support for castle and trying to find a way to alter the connection string at run time.
this is my latest swing and miss, im sure it has to do the life cycle at this point as all of the configuration is null so i am guessing that castle has not yet wired up the guts on NLog.
private const string NLogConnectionString = "NLogConnection";
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<LoggingFacility>(l => l.UseNLog());
var config = new NLog.Config.LoggingConfiguration();
var dbtarget = config.FindTargetByName("database") as DatabaseTarget;
if (dbtarget != null)
{
dbtarget.ConnectionString = MethodThatGiveMeConnectionString(NLogConnectionString);
}
}
looking at this post it could be an option but based on the way things have been done here i dont want to change that and much prefer just providing the connection string directly to NLog.
looking here I know i can configure this at run time but i much prefer let most of the settings come from the config file and then just override the connection string.

So I found a solution that works but not sure it's the best approach.
Using this post as a reference. This comment was the most helpful:
Initially I tried to implement a custom ILoggerFactory and inject it into LoggingFacility via the customLoggerFactory. But that soon proved to be a dead end. Then I looked into the NLog integration and noticed that there's already a NLogFactory that has it's methods marked as virtual. So I was able to derive from this class
The problem the author is solving is different than my own but it got me to come up with this solution:
public class LoggerInstall : IWindsorInstaller
{
private const string NLogConnectionString = "NLogConnection";
public void Install(IWindsorContainer container, IConfigurationStore store)
{
var config = new NLog.Config.LoggingConfiguration();
container.AddFacility<LoggingFacility>(l => l.LogUsing(new OwnNLogFactory(GetYourConnectionStringMethod(NLogConnectionString))));
}
}
public class OwnNLogFactory : NLogFactory
{
public OwnNLogFactory(string connectionString)
{
foreach (var dbTarget in LogManager.Configuration.AllTargets.OfType<DatabaseTarget>().Select(aTarget => aTarget))
{
dbTarget.ConnectionString = connectionString;
}
}
}
Still not sure this is the best solution but it works for now, would love to see other solutions if anyone has one

Related

How to pass parameter to an Autofac Module from a resolve dependency

Currently I have a autofac module which receives a string as parameter, and that string is coming from another dependency.
Im trying to pass it using below code, my question is: Is this the right approach or there is a better/improved way to do it?
builder.RegisterBuildCallback(c =>
{
var configService = c.Resolve<IConfigurationService>();
var module = new LoggingModule(configService.GetConfigurationValue("LoggerName"));
module.Configure(c.ComponentRegistry);
});
Generally try to avoid build callbacks and trying to configure the container based on configuring the container. To be honest, I'm surprised this even works since the container and registry are effectively immutable.
It would be better to use a lambda registration to resolve things. Since we don't know what your logging module is doing, let's say right now it's this:
public class LoggingModule
{
private readonly string _name;
public LoggingModule(string name)
{
this._name = name;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterInstance(new MyLogger(this._name));
}
}
Even if it's not exactly this, it's pretty easy to adapt something similar - the parameter is coming into the module and being used by a registration.
You could move that into the registration itself and remove the module entirely.
builder.Register(ctx =>
{
var configService = ctx.Resolve<IConfigurationService>();
var name = configService.GetConfigurationValue("LoggerName");
return new MyLogger(name);
}).SingleInstance();
This avoids having to "know the parameter up front" and also avoids trying to reconfigure the container. You still get to register the config in DI and resolve it like you want.

How do you inject in dotnet core project in static method an IConfiguration object?

I have a Redis store similar to this one. My problem is, since I am using .Net Core, on line 15, I should use configuration object that I normally inject in the constructor.
However, one cannot inject the configuration object in the static constructor, as static constructor should be parameterless in C#.
I tried adding a static method to initialise the config object, but then the constructor throws NullReferenceException because obviously the ctor is still called first, before the Init method, and it needs the config object... so what to do?
Doesn't seem like a good workaround.
Instead of doing all that work with statics and trying to get it to work (hint: it'd never work with a static constructor), I'd suggest you to move to newer patterns and use DI correctly.
If you don't really need the lazyness, this is as simple as injecting IConnectionMultiplexer:
services.AddScoped<IConnectionMultiplexer>(s => ConnectionMultiplexer.Connect(configuration["someSettings"]));
If you do need the lazyness:
// public interface IRedisStore { IConnectionMultiplexer RedisConnection { get; } }
public class RedisStore : IRedisStore
{
private readonly Lazy<ConnectionMultiplexer> LazyConnection;
public RedisStore(IConfiguration configuration)
{
var configurationOptions = new ConfigurationOptions
{
EndPoints = { configuration["someSettings"] }
};
LazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(configurationOptions));
}
public IConnectionMultiplexer RedisConnection => LazyConnection.Value;
}
and you'd inject it with:
services.AddScoped<IRedisStore, RedisStore>());

DependencyInjection issue during using FluentScheduler in .NET Core API application

I want to update data in my database each hour. So, I find good FluentScheduler library for this and create my IJob:
public class InfoLoader : IJob
{
private readonly DataContext _db;
public InfoLoader(DataContext db)
{
_db = db;
}
public void Execute()
{
foreach (User user in _db.Users.ToList())
{
foreach (Info i in user.Info.ToList())
{
UpdateInfo(i);
}
}
}
private void UpdateInfo(Info info)
{
// do some operations to update information in db
}
}
And of course I create my Registry implementation to schedule all tasks which I need:
public class LoadersRegistry : Registry
{
public LoadersRegistry()
{
Schedule<InfoLoader>().ToRunNow().AndEvery(1).Hours();
}
}
Also I add following code in my Program.cs file to initalize scheduler and start it:
JobManager.JobException += (obj) => { logger.LogError(obj.Exception.Message); };
JobManager.Initialize(new LoadersRegistry());
But when I run my application I see following error:
I understand that LoadersRegistry can't create instance of InfoLoader (during JobManger initializes it in Program.cs), because InfoLoader receives DataContext. But I can't do not receive DataContext, because I need it to add data in my database.
Unfortunately I can't find a way to fix this issue.
Thanks for any help.
P.S. I read about using FluentScheduler in asp.net core, but developers of this library said that this feature will not be available in the future because of this, so I still don't know how I can solve the issue.
As per the API document you'll have to change the way you register.
Following is just one way of doing it.
public LoadersRegistry()
{
var dataContext = new DataContext();
Schedule(()=> new InfoLoader(dataContext)).ToRunNow().AndEvery(1).Hours();
}
Here I'm doing new DataContext() but you could make dataContext available however you like as long as you are newing up InfoLoader with it.
If someone will meet with similar issue, this is solution which helps me:
You just need to do initialization inside Startup.cs file:
public void ConfigureServices(IServiceCollection services)
var provider = services.BuildServiceProvider();
JobManager.Initialize(new LoadersRegistry(
provider.GetRequiredService<DataContext>()
));
services.AddMvc();
}
And of course, LoadersRegistry should receive DataContext instance, and InfoLoader should receive this instance in constructor:
public LoadersRegistry(DataContext db)
{
Schedule(new InfoLoader(db)).ToRunNow().AndEvery(30).Seconds();
}
Good luck! :)

How to register multiple IDbConnectionFactory instances using Funq in ServiceStack.net

How would you go about registering diferent IDbConnectionFactory instances in Funq and then access them directly within your services? Do named instances somehow come into play here?
Is this the best approach to take when using different databases across services?
Thanks!
EDIT:
An example ;). I could be way off here because I'm pretty new to IoC, but say for example I have 2 separate database connections that I'd like to inject. In ServiceStack, this is done in the Global.asax.
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(#"Connection String 1", SqlServerOrmLiteDialectProvider.Instance));
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(#"Connection String 2", SqlServerOrmLiteDialectProvider.Instance));
Both of these seem to be injected honky dory.
These are then accessed automatically on the service end via something like this:
public IDbConnectionFactory DbFactory { get; set; }
In this case, it seems to be giving me the first one registered. How can I get access to a specific one on the service end? Hopefully that makes it a little more clear.
Here's a full fledged example from ServiceStack.Examples that only uses 1 IDbConnectionFactory:
Movies Rest
My question above is still valid, but the following might help you anyway.
Funq does not support automatic constructor injection (a.k.a. auto wiring), and you will have to do this by hand by constructing Func<T> lambda expressions. Because you are already doing constructor injection by hand, it is easy to choose what IDbConnectionFactory you wish to inject into your services. Example:
IDbConnectionFactory yellowDbConFactory =
new YellowDbConnectionFactory();
IDbConnectionFactory blueDbConFactory =
new BlueDbConnectionFactory();
IDbConnectionFactory purpleDbConFactory =
new PurpleDbConnectionFactory();
container.Register<IService1>(c =>
new Service1Impl(yellowDbConFactory,
c.Resolve<IDep1>());
container.Register<IService2>(c =>
new Service2Impl(blueDbConFactory);
container.Register<IService3>(c =>
new Service3Impl(purpleDbConFactory,
c.Resolve<IDep2>());
Of course you can also used named registrations, like this:
container.Register<IDbConnectionFactory>("yellow",
new YellowDbConnectionFactory());
container.Register<IDbConnectionFactory>("blue",
new BlueDbConnectionFactory());
container.Register<IDbConnectionFactory>("purple",
new PurpleDbConnectionFactory());
container.Register<IService1>(c =>
new Service1Impl(
c.Resolve<IDbConnectionFactory>("yellow"),
c.Resolve<IDep1>());
container.Register<IService2>(c =>
new Service2Impl(
c.Resolve<IDbConnectionFactory>("blue"));
container.Register<IService3>(c =>
new Service3Impl(
c.Resolve<IDbConnectionFactory>("purple"),
c.Resolve<IDep2>());
Because of the lack of support for auto-wiring, you'll end up with these rather awkward registrations, and this will pretty soon result in a maintenance nightmare of your composition root, but that's unrelated to your question ;-)
You should usually try to prevent ambiguity in your registration. In your case you've got a single interface, that does two things (connects to two databases). Unless both database share the exact same model, each database deserves its own interface (if the two implementations are not interchangable, you'll be violating the Liskov substitution principle):
interface IYellowDbConnectionFactory : IDbConnectionFactory
{
}
interface IPurpleDbConnectionFactory : IDbConnectionFactory
{
}
Because of the way ServiceStack works, you probably need to implement an implementation for each:
class YellowDbConnectionFactory : OrmLiteConnectionFactory,
IYellowDbConnectionFactory
{
public YellowDbConnectionFactory(string s) : base(s){}
}
class PurpleDbConnectionFactory : OrmLiteConnectionFactory,
IPurpleDbConnectionFactory
{
public YellowDbConnectionFactory(string s) : base(s){}
}
Now you should change the definition of your services to use the specific interface instead of using the IDbConnectionFactory:
public class MovieService : RestServiceBase<Movie>
{
private readonly IYellowDbConnectionFactory dbFactory;
public MovieService(IYellowDbConnectionFactory factory)
{
this.dbFactory = factory;
}
}
Note that this class now uses constructor injection instead of property injection. You can get this to work with property injection, but it is usually better to go with constructor injection. Here is a SO question about it.
With Funq, your configuration will then look like this:
container.Register<MovieService>(c =>
new MovieService(
c.Resolve<IYellowDbConnectionFactory>());
Those two new interfaces and two classes and change to the MovieService didn't win you a lot, because Funq doesn't support auto-wiring. You will be the one who is wiring everything together manually. However, when you switch to a framework that does support auto-wiring, this design allows the container to inject the right dependencies without a problem, because there is no discussion about what to inject.
Although Funq doesn't support Auto wiring, ServiceStack implementation of it does. The latest version of ServiceStack includes the Funq.Container overloads:
container.RegisterAutoWired<T>();
container.RegisterAutoWiredAs<T,TAs>();
container.RegisterAs<T,TAs>();
So in Steven's example you can also do:
container.RegisterAs<YellowDbConnectionFactory,IYellowDbConnectionFactory>();
And it will automatically register the dependencies for you.
Thought I'd chip in my 2 cents here, though I realise the question is pretty old. I wanted to access a transactional DB and a logging DB from ServiceStack and this is how I ended up doing it from the AppHostBase Configure() method:
container.Register<IDbConnectionFactory>(
c => {
OrmLiteConnectionFactory dbFactory = new OrmLiteConnectionFactory(ConfigurationManager.ConnectionStrings["MyTransactionalDB"].ConnectionString, MySqlDialect.Provider);
dbFactory.ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current);
dbFactory.RegisterConnection("LoggingDB", ConfigurationManager.ConnectionStrings["MyLoggingDB"].ConnectionString, MySqlDialect.Provider);
return dbFactory;
});
By default, the "MyTransactionalDB" is used when opening a connection from the factory, but I can explicitly access the logging DB from a service via:
using (var db = DbFactory.Open("LoggingDB"))
{
db.Save(...);
}
Try using the Repository pattern instead of this IoC (which just complicates things unnecessarily). The code above seems not to work. Suspect something has changed. I'm still unclear as to how registering an IDbConnectionFactory magically populates the IDbConnection property. Would love some explanation around this.
If someone ever does get this working using the ServiceStack IoC container.. then I'd love to see how. And it would be hugely benefitial to update the SS docs (I'm quite happy to do it)
You can also use a dictionnary
Create a enum with your database Key Name
public enum Database
{
Red,
Blue
}
In Startup.cs, create a dictionary of function that open a new SqlConnection, then inject the dependency dictionary as Singleton
Dictionary<Database, Func<IDbConnection>> connectionFactory = new()
{
{ Database.Red, () => new SqlConnection(Configuration.GetConnectionString("RedDatabase")) },
{ Database.Blue, () => new SqlConnection(Configuration.GetConnectionString("BlueDatabase")) }
};
services.AddSingleton(connectionFactory);
After you can get the instance od the dependency on object constructor like so:
public class ObjectQueries
{
private readonly IDbConnection _redConnection;
private readonly IDbConnection _blueConnection;
public ObjectQueries(Dictionary<Database, Func<IDbConnection>> connectionFactory)
{
_redConnection = connectionFactory[Database.Red]();
_blueConnection = connectionFactory[Database.Blue]();
}
}
It's clean and readable ;)

Mock implementation for use in automatic UI testing

I am working on adding basic automatic UI tests to the block of unit tests we run with each nightly build. We used MSTest coded UI and created a script.
The code-behind is dependent upon IClientManager which both the real manager and mock implement.
My problem is that I don't know how to switch automatically between the real and mock implementations inside the button click handler, when running a test.
My two other constraints are that I can't have a dependency on the mock assembly in the code-behind and that I can't use a DI framework, since the client is "security conscious" and getting a framework approved might take months.
Is there any way of doing this manually, and hopefully, not a bigger problem than the problem I am looking to solve?
Thank you!
You could build your own simple object container if you can't use a third party one (which is silly but I understand, I've been there before)
here is something that I whipped up that could get you started... haven't tested it and it is really rough, but hopefully you get the idea
public static class ObjectFactory
{
static IDictionary<Type, object> _factory = new Dictionary<Type, object>();
public static void Register<T>(Func<T> builder)
{
if (_factory.ContainsKey(typeof(T)))
_factory[typeof(T)] = builder;
else
_factory.Add(typeof(T), builder);
}
public static T GetInstance<T>()
{
if (_factory.ContainsKey(typeof(T)))
throw new ArgumentException(string.Format("Type <{0}> not registered in ObjectFactory", typeof(T).Name));
return ((Func<T>)_factory[typeof(T)])();
}
}
public interface IClientManager { }
public class RealClientManager : IClientManager { }
public class MockClientManager : IClientManager { }
public class MyView
{
public MyView()
{
// probably better to do this registry in some sort of application initialization
ObjectFactory.Register<IClientManager>(() => new RealClientManager());
}
public void SomeMethodThatNeedsClientManager()
{
var clientManager = ObjectFactory.GetInstance<IClientManager>();
}
}
public class MyTester
{
[TestMethod()]
public void SomeTest()
{
var view = new MyView();
// swap the client manager in the test
ObjectFactory.Register<IClientManager>(() => new MockClientManager());
// Asserts
}
}
you can see that if you've used StructureMap or some other DI container before they do a lot of the same thing with a lot of added niceties such as traversing your object graph and registering objects automatically based on conventions, managing object lifecycles, scoping of containers, etc... a lot of this stuff you could implement yourself too... but you should just really used a tried and true solution such as StructureMap

Categories