I'm very new to using Unity.
I'm trying to test a segment of code in LINQPad. This code uses a DBContext which relies on Log4Net as a service. I'm trying to write the sample code to use the actual DBContext, but can't get it to construct.
The code I'm trying is below. If there is more information needed, please ask for it before down-voting, since I'm not sure how much you need to see to understand my issue, since I'm still learning Unity.
void Main()
{
RegisterObjects();
var logger = IoCHelper.Resolve<ILogger>();
//var _logger = new Clark.Logging.MultiLogger();
var _logger = logger;
var _ediContext = new EdiContext();
var transactionId = 1008;
var limit = 0;
var temp = new Type210SubscriberProvider(_ediContext)
.GetAfterNew(transactionId, limit);
temp.Dump();
var temp2 = new Type210SubscriberProvider(_ediContext)
.GetAfter(transactionId, limit);
temp2.Dump();
}
public void RegisterObjects()
{
XmlConfigurator.Configure();
var multiLogger = new MultiLogger();
multiLogger.Register(new Log4NetLogger());
IoCHelper.RegisterInstance<ILogger>(multiLogger);
}
If I try just this:
void Main()
{
var _ediContext = new EdiContext();
}
The error message I am receiving in LINQPad is:
Resolution of the dependency failed, type = "Clark.Logging.ILogger", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, Clark.Logging.ILogger, is an interface and cannot be constructed. Are you missing a type mapping?
At the time of the exception, the container was:
Resolving Clark.Logging.ILogger,(none)
UPDATE:
Here is some more detail from the Global.asax.cs file. I'm not sure how to translate this to LINQPad.
protected void Application_Start()
{
// GlobalConfiguration.Configuration is an HttpConfiguration object.
ConfigureContainer(GlobalConfiguration.Configuration);
ConfigureServices(GlobalConfiguration.Configuration);
}
private static void ConfigureServices(HttpConfiguration configuration)
{
configuration.Services.Add(typeof (IExceptionLogger), new UnhandledExceptionLogger(GetLogger()));
configuration.Services.Replace(typeof (IExceptionHandler), new UnhandledExceptionHandler());
}
private static void ConfigureContainer(HttpConfiguration config)
{
config.DependencyResolver = new IoCContainer(IoCHelper.Container);
new LoggingDependencyInitializer().RegisterObjects();
IoCHelper.RegisterType<IEdiContext>(new InjectionFactory(unityContainer => new EdiContext()));
IoCHelper.RegisterType<SubscriberController>();
IoCHelper.RegisterType<ConsumerInformationController>();
IoCHelper.RegisterType<TransactionTypeController>();
}
private static ILogger GetLogger()
{
return IoCHelper.Resolve<ILogger>();
}
Here is the IoCHelper class:
public static class IoCHelper
{
private static UnityContainer _container;
public static UnityContainer Container
{
get { return _container ?? (_container = new UnityContainer()); }
}
public static T Resolve<T>()
{
return Container.Resolve<T>();
}
public static void RegisterType<TFrom, TTo>() where TTo : TFrom
{
Container.RegisterType<TFrom, TTo>();
}
public static void RegisterInstance(Type type, object instance)
{
Container.RegisterInstance(type, instance);
}
public static void RegisterType<T>()
{
Container.RegisterType<T>();
}
public static void RegisterInstance<T>(T instance)
{
Container.RegisterInstance(instance);
}
public static void RegisterType<T>(InjectionFactory injectionFactory)
{
Container.RegisterType<T>(injectionFactory);
}
}
When using an IOC container, you need to register your types (e.g. map interfaces \ abstract classes into their real types). Since when you want the container to resolve an interface, it will want to find it's mapping before providing the instance.
BTW, if Unity doesn't find a map, it will try to construct the type. In your case it fails since you cannot construct an interface.
With Unity, you can do it either by configuration using:
var section = ConfigurationManager.GetSection(SectionName) as UnityConfigurationSection;
if (section != null)
{
section.Configure(container);
}
Or directly:
container.RegisterType<InterfaceType, ConcreteType>();
Since I see this code line in your example:
IoCHelper.RegisterInstance<ILogger>(multiLogger);
You are registering ILogger with a specific instance. There must be a problem with your IoCHelper implementation. Please add more code and I'll edit my answer with a specific solution.
Related
I'm trying to resolve an interface that I registered in Autofac but it seems to be not working. There is
nullreferenceexception.
Class where I register the inferface :
public void RegisterAutofac(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
(...)
builder.RegisterType<ApiFileTester>().As<IApiFlTester>().InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
Then I want to use it in a class :
public class ApiFileSendingController : ApiClientBase
{
private readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester) : base(dto)
{
_tester = tester;
}
public void Send(List<AftInvFileDTO> filesToSendRetry = null)
{
_apiFileTester.RegisterTestingMethods();
}
}
Then in some other class:
DTO dto = new DTO(); //some configuration here
ApiFileSendingController sender = new ApiFileSendingController(dto, null);
sender.Send();
There is a problem here because my interface is null. I've tried to pass it like this:
ApiFileSendingController sender = new ApiFileSendingController(dto,
null);
but it's null and it's completely reasonable (I am passing the null).
IS it possible to configure optional parameter or something? I'd like to have this interface resolved automatically by autofac, not manually.
I don't seem to have a problem resolving your class. Technically it's impossible to really answer your question since the code won't even compile and it appears you have a ton of missing autofac registrations.
Working Example.
// #nuget: Autofac
using System;
using Autofac;
public class Program
{
private static IContainer _container;
public static void Main()
{
RegisterAutofac();
using (var httpRequestScope = _container.BeginLifetimeScope("AutofacWebRequest"))
{
var apiController = httpRequestScope.Resolve<ApiFileSendingController>();
Console.WriteLine(apiController._apiFileTester);
}
}
public static void RegisterAutofac()
{
var builder = new ContainerBuilder();
//builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<ApiFileTester>().As<IApiFlTester>().InstancePerLifetimeScope();
builder.RegisterType<ApiFileSendingController>().AsSelf();
builder.RegisterType<DTO>().AsSelf();
_container = builder.Build();
}
public class ApiFileSendingController : ApiClientBase
{
public readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester): base (dto)
{
_apiFileTester = tester;
}
}
public interface IApiFlTester { }
public class ApiFileTester : IApiFlTester { }
public class ApiClientBase
{
public ApiClientBase(DTO dto)
{
}
}
public class DTO { }
}
You have misconception at Autofac DI, most of the DI frameworks are good at creating instances for you, via constructor injection and property injection you will get the instance with their dependencies automatically wired up.
Your constructor contains DTO instance which you will provide during runtime, Autofac will not resolve that since you had not declare it to the DI container during ConfigureServices cycle.
You might need to giving up using Autofac in this case to get the freedom of creating controller instance at your own code, you will need to get the concrete class instance from Reflection instead. The abstraction / implementation isolation is still there via this approach.
public class ApiFileSendingController : ApiClientBase
{
private readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester) : base(dto)
{
if (tester is null)
_tester = GetApiTesterViaReflection();
else
_tester = tester;
}
public ApiFileSendingController(DTO dto) : base(dto)
{
_apiFileTester = GetApiTesterViaReflection();
}
public void Send(List<AftInvFileDTO> filesToSendRetry = null)
{
_apiFileTester.RegisterTestingMethods();
}
private IApiFlTester GetApiTesterViaReflection()
{
Type type = typeof(IApiFlTester).Assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IApiFlTester))).FirstOrDefault();
return Activator.CreateInstance(type) as IApiFlTester;
}
}
Some time ago I worked on a project that I THINK used LightInject. I no longer have access, so I can't just go look for myself. It seemed like once the ServiceContainer was instantiated, something triggered reflection across all assemblies, and any properties of a certain interface type were automatically instantiated. Something like this:
A C# class library that contains a logger class; the logger is what should be injected.
namespace Common {
public interface ILogger { void Log(string msg); }
public class Logger : ILogger {
public Logger() { }
public void Log(string msg) { Console.WriteLine(msg); }
}
}
A C# console app that references the class library. Some things that didn't seem to help are commented out.
namespace TestLightInject {
class Program {
private static ServiceContainer container;
static void Main(string[] args) {
container = new ServiceContainer();
//container.EnableAnnotatedPropertyInjection();
container.Register<ILogger, Logger>();
//container.RegisterPropertyDependency<ILogger>((factory, propertyInfo) => new Logger());
var worker = new Worker();
worker.DoSomething();
}
}
public class Worker {
//[Inject]
ILogger logger { get; set; } = null; // THIS IS THE PROPERTY THAT NEEDS TO BE SET
public Worker() { }
public void DoSomething() { logger.Log("It works!"); }
}
}
I guess I could allow public access to the service container, and change the Worker ctor to something like
public Worker() { logger = Program.container.GetInstance<ILogger>(); }
but it was simpler when any ILogger property was automatically instantiated.
Is there a way to do this with LightInject, or was it some other DI framework that did it? Or am I just imagining it all?
I want to resolve some dependencies which will only be known at runtime. I am using configuration file to configure Unity (not programmatically).
Here is some code to show what I want to achieve.
Classes:
internal class WorkflowFactory : IWorkflowFactory
{
public IItemWorkflow GetWorkflow(string discriminator)
{
// return an implementation of IItemWorkflow as specified in config file
return null;
}
}
public interface IWorkflowFactory
{
IItemWorkflow GetWorkflow(string discriminator);
}
public interface IItemWorkflow
{
void Handle(int id);
// More methods
}
Usage:
internal class Program
{
private static void Main(string[] args)
{
IWorkflowFactory factory = new WorkflowFactory();
// I am using args to show I do not know the string until runtime
var wf1 = factory.GetWorkflow(args[0]);
var wf2 = factory.GetWorkflow(args[1]);
}
}
If you know a better way, I am totally open and invite suggestions.
I'm experiencing with .Net Core and I'm currently facing it's DI engine.
My Project is a class library, therefore, asp's binding is irrelevant here.
I followed the tips from this article in order to make DI work.
now, to the juicy part:
I have made a service provider that looks like this:
public static class ServiceProvider
{
public static IServiceProvider GetServiceProvider()
{
var services = new ServiceCollection();
//Singletons
services.AddSingleton<IInstance, Instance>();
//Transients
services.AddTransient<IDate, Date>();
services.AddTransient<IMath, Math>();
services.AddTransient<INumber, Number>();
return services.BuildServiceProvider();
}
}
I have then tried executing it in a static class that looks like this:
public static class MySingleton
{
public static IInstance Instance
=> ServiceProvider.GetServiceProvider().GetService<IInstance>();
}
and in order to test the singleton behavior, I have tested it like this:
[Test]
public void Instance_HundredTimes_ReturnsSameInstance()
{
//Arrange
const int callCount = 100;
var results = new IInstance[callCount];
//Act
for (var i = 0; i < callCount; i++)
{
results[i] = MySingleton.Instance;
}
//Assert
Assert.That(results.Distinct().Count(), Is.EqualTo(1));
}
the test results came back negative and instead of having a single reference after the distinct (cause it is a singleton) I'm still left with a hundred instances.
am I doing anything wrong?
did I miss anything in configuration?
Your problem is in this code block:
public static class MySingleton
{
public static IInstance Instance
=> ServiceProvider.GetServiceProvider().GetService<IInstance>();
}
What you are doing here is to call ServiceProvider.GetServiceProvider().GetService<IInstance>() each time you access the property. That means do not actually have a singleton. What you want to do is to set the singleton instance once:
public static class MySingleton
{
public static IInstance Instance
{
get;
} = ServiceProvider.GetServiceProvider().GetService<IInstance>();
}
Additionally, you have a similar problem when you create your services. You create a new ServiceCollection each time you call GetServiceProvider(). You probably don't want that. You probably want something like this:
public static class ServiceProvider
{
private static IServiceProvider serviceProvider = null;
public static IServiceProvider GetServiceProvider()
{
if (serviceProvider == null)
{
var services = new ServiceCollection();
//Singletons
services.AddSingleton<IInstance, Instance>();
//Transients
services.AddTransient<IDate, Date>();
services.AddTransient<IMath, Math>();
services.AddTransient<INumber, Number>();
serviceProvider = services.BuildServiceProvider();
}
return serviceProvider;
}
}
Problem:
My problem laid in not keeping my IserviceProvider instance in MySingleton
Solution:
TL;DR
have a static instance of IserviceProvider
Code Refactor
refactor ServiceProvider to Look as following:
public class LodashServiceProvider
{
private static readonly Lazy LazyServiceProvider;
static LodashServiceProvider()
{
LazyServiceProvider = new Lazy<IServiceProvider>(InitializeServiceProvider);
}
public static IServiceProvider GetServiceProvider() => LazyServiceProvider.Value;
private static IServiceProvider InitializeServiceProvider()
{
var services = new ServiceCollection();
//Singletons
services.AddSingleton<ILodashInstance, LodashInstance>();
//Transients
services.AddTransient<ILodashDate, LodashDate>();
services.AddTransient<ILodashMath, LodashMath>();
services.AddTransient<ILodashNumber, LodashNumber>();
return services.BuildServiceProvider();
}
}
I'd like to thank Kiziu & Sefe for their solutions to the question.
I'm rewriting this entire question because I realize the cause, but still need a solution:
I have a recurring job in Hangfire that runs every minute and check the database, possibly updates some stuff, then exits.
I inject my dbcontext into the class containing the job method. I register this dbcontext to get injected using the following
builder.RegisterType<ApplicationDbContext>().As<ApplicationDbContext>().InstancePerLifetimeScope();
However, it seems that Hangfire does not create a seperate lifetime scope every time the job runs, because the constructor only gets called once, although the job method get's called every minute.
This causes issues for me. If the user updates some values in the database (dbcontext gets injected somewhere else, and used to update values), the context still being used Hangfire starts returning out-dated values that have already been changed.
Hangfire currently uses a shared Instance of JobActivator for every Worker, which are using the following method for resolving a dependency:
public override object ActivateJob(Type jobType)
It is planned to add a JobActivationContext to this method for Milestone 2.0.0.
For now, there is no way to say for which job a dependency gets resolved. The only way I can think of to workaround this issue would be to use the fact that jobs are running serial on different threads (I don't know AutoFac so I use Unity as an example).
You could create a JobActivator that can store separate scopes per thread:
public class UnityJobActivator : JobActivator
{
[ThreadStatic]
private static IUnityContainer childContainer;
public UnityJobActivator(IUnityContainer container)
{
// Register dependencies
container.RegisterType<MyService>(new HierarchicalLifetimeManager());
Container = container;
}
public IUnityContainer Container { get; set; }
public override object ActivateJob(Type jobType)
{
return childContainer.Resolve(jobType);
}
public void CreateChildContainer()
{
childContainer = Container.CreateChildContainer();
}
public void DisposeChildContainer()
{
childContainer.Dispose();
childContainer = null;
}
}
Use a JobFilter with IServerFilter implementation to set this scope for every job (thread):
public class ChildContainerPerJobFilterAttribute : JobFilterAttribute, IServerFilter
{
public ChildContainerPerJobFilterAttribute(UnityJobActivator unityJobActivator)
{
UnityJobActivator = unityJobActivator;
}
public UnityJobActivator UnityJobActivator { get; set; }
public void OnPerformed(PerformedContext filterContext)
{
UnityJobActivator.DisposeChildContainer();
}
public void OnPerforming(PerformingContext filterContext)
{
UnityJobActivator.CreateChildContainer();
}
}
And finally setup your DI:
UnityJobActivator unityJobActivator = new UnityJobActivator(new UnityContainer());
JobActivator.Current = unityJobActivator;
GlobalJobFilters.Filters.Add(new ChildContainerPerJobFilterAttribute(unityJobActivator));
We have created a new pull request in the Hangfire.Autofac with the work around described by Dresel. Hopefully it gets merged in the main branch:
https://github.com/HangfireIO/Hangfire.Autofac/pull/4
Edit: With Autofac, .NET 4.5 and Hangfire >= 1.5.0, use the Hangfire.Autofac nuget package (github).
Working with .NET 4.0 (Autofac 3.5.2 and Hangfire 1.1.1), we set up Dresel's solution with Autofac. Only difference is in the JobActivator:
using System;
using Autofac;
using Hangfire;
namespace MyApp.DependencyInjection
{
public class ContainerJobActivator : JobActivator
{
[ThreadStatic]
private static ILifetimeScope _jobScope;
private readonly IContainer _container;
public ContainerJobActivator(IContainer container)
{
_container = container;
}
public void BeginJobScope()
{
_jobScope = _container.BeginLifetimeScope();
}
public void DisposeJobScope()
{
_jobScope.Dispose();
_jobScope = null;
}
public override object ActivateJob(Type type)
{
return _jobScope.Resolve(type);
}
}
}
To work around this problem, I've created a disposable JobContext class that has a ILifetimeScope that will be disposed when Hangfire completes the job. The real job is invoked by reflection.
public class JobContext<T> : IDisposable
{
public ILifetimeScope Scope { get; set; }
public void Execute(string methodName, params object[] args)
{
var instance = Scope.Resolve<T>();
var methodInfo = typeof(T).GetMethod(methodName);
ConvertParameters(methodInfo, args);
methodInfo.Invoke(instance, args);
}
private void ConvertParameters(MethodInfo targetMethod, object[] args)
{
var methodParams = targetMethod.GetParameters();
for (int i = 0; i < methodParams.Length && i < args.Length; i++)
{
if (args[i] == null) continue;
if (!methodParams[i].ParameterType.IsInstanceOfType(args[i]))
{
// try convert
args[i] = args[i].ConvertType(methodParams[i].ParameterType);
}
}
}
void IDisposable.Dispose()
{
if (Scope != null)
Scope.Dispose();
Scope = null;
}
}
There is a JobActivator that will inspect the action and create the LifetimeScope if necessary.
public class ContainerJobActivator : JobActivator
{
private readonly IContainer _container;
private static readonly string JobContextGenericTypeName = typeof(JobContext<>).ToString();
public ContainerJobActivator(IContainer container)
{
_container = container;
}
public override object ActivateJob(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition().ToString() == JobContextGenericTypeName)
{
var scope = _container.BeginLifetimeScope();
var context = Activator.CreateInstance(type);
var propertyInfo = type.GetProperty("Scope");
propertyInfo.SetValue(context, scope);
return context;
}
return _container.Resolve(type);
}
}
To assist with creating jobs, without using string parameters there is another class with some extensions.
public static class JobHelper
{
public static object ConvertType(this object value, Type destinationType)
{
var sourceType = value.GetType();
TypeConverter converter = TypeDescriptor.GetConverter(sourceType);
if (converter.CanConvertTo(destinationType))
{
return converter.ConvertTo(value, destinationType);
}
converter = TypeDescriptor.GetConverter(destinationType);
if (converter.CanConvertFrom(sourceType))
{
return converter.ConvertFrom(value);
}
throw new Exception(string.Format("Cant convert value '{0}' or type {1} to destination type {2}", value, sourceType.Name, destinationType.Name));
}
public static Job CreateJob<T>(Expression<Action<T>> expression, params object[] args)
{
MethodCallExpression outermostExpression = expression.Body as MethodCallExpression;
var methodName = outermostExpression.Method.Name;
return Job.FromExpression<JobContext<T>>(ctx => ctx.Execute(methodName, args));
}
}
So to queue up a job, e.g. with the following signature:
public class ResidentUploadService
{
public void Load(string fileName)
{
//...
}
The code to create the job looks like
var localFileName = "Somefile.txt";
var job = ContainerJobActivator
.CreateJob<ResidentUploadService>(service => service.Load(localFileName), localFileName);
var state = new EnqueuedState("queuename");
var client = new BackgroundJobClient();
client.Create(job,state);
A solution is supported out-of-the-box since hangfire.autofac 2.2.0.
In your situation, where your dependency is being registered per-lifetime-scope, you should be able to use non-tagged scopes when setting up hangfire.autofac. From the link:
GlobalConfiguration.Configuration.UseAutofacActivator(builder.Build(), false);