I'm having problems resolving a repository when calling it from a console app. Everything works fine when running the application (.NET 4, C#, Entity Framework, Unity) as normal, but I've created a standalone console app that will be run from the task scheduler to import feeds. I'm very close to giving up and do a dirty hack and write a script to call a webpage instead of using a console app, but I thought I'd at least try to understand why it isn't working first.
I'm new to both Entity Framework and Unity, so please bear with me and let me know if I've left out any important information.
This is the error I'm getting:
Resolution of the dependency failed, type = "MyNamespace.Domain.Template.IRepository`2[MyNamespace.Domain.Employees.OrganisationalUnit,System.Guid]", name = "(none)".
Exception occurred while: while resolving.
Exception is: NullReferenceException - Object reference not set to an instance of an object.
at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)
at Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides)
at Microsoft.Practices.Unity.UnityContainerExtensions.Resolve[T](IUnityContainer container, ResolverOverride[] overrides)
at MyNamespace.Infrastructure.FeedDefinition.GetOrganisationalUnit(String name, OrganisationalUnit parent) in C:\FeedDefinition.cs:line 552
This is the console app code:
static void Main(string[] args)
{
if (args.Length > 0)
{
MyNamespace.Appliance.Configuration.Initialise.InitialiseContainer();
ImportFeedProcessor importFeedProcessor = new ImportFeedProcessor();
importFeedProcessor.Run(args[0]);
}
}
And this is where it fails:
IRepository<OrganisationalUnit, Guid> organisationalUnitRepository =
Context.Instance.Container.Resolve<IRepository<OrganisationalUnit, Guid>>();
If anyone can help me understand what's going wrong I'd be very grateful!
UPDATE:
Here's the (important) bits from the initialise class:
public static void InitialiseContainer()
{
UnityContainer container = new UnityContainer();
// Use HttpContext for registering instances against for live
IContext context = HttpContextWrapper.Instance;
// Register the HttpContext as the default context to use
container.RegisterInstance<IContext>(HttpContextWrapper.Instance);
// repositories
container.RegisterType<IRepository<Employee, Guid>, EmployeeRepository>(
new UnityContextLifetimeManager(context),
new InjectionConstructor(true, "OrganisationalUnit.Parent.Parent"));
container.RegisterType<IRepository<OrganisationalUnit, Guid>, EntityFrameworkRepository<OrganisationalUnit, Guid>>(
new UnityContextLifetimeManager(context),
new InjectionConstructor("Parent.Parent"));
// Create and populate a new Unity container from configuration
Context.Instance.Container = container;
}
Is it perhaps the HttpContext that does it?
Thanks,
Annelie
One option you could consider is creating two different Initialise classes (I'm guessing that is your Unity bootstrapper class).
The one you have can be used for your web application.
The other one should be non-web specific. Remove any reference to HttpContext (it won't be available in a Console app) and UnityContextLifetimeManager (assuming this is HttpContext specific as well).
Related
We're using ASP.NET core and are running into the problem, that some registered services (from third-party libraries) request a specific 'service' (based on an interface) that has been deprecated.
The problem is that we don't know which libraries are using this deprecated service interface.
What we've done so far is:
create a custom implementation for the service interface
and registered this custom implementation (class) with DI
// Registration
services.AddTransient<IServiceInterface>((services) => new CustomCustomService(Log.Logger));
// Custom implementation
internal class CustomService : IServiceInterface
{
public CustomService (ILogger logger)
{
logger.Warning("!!! CustomService is still being used !!!");
}
}
So now we can see that the unwanted service is being used 'somewhere'.
But is it in some way possible to detect for which service the deprecated service has been created?
I've tried listing the stack trace using
var st = new System.Diagnostics.StackTrace();
logger.Warning("!!! CustomService is still being used !!!" + Environment.NewLine + "{stacktrace}", st.ToString());
But that doesn't seem to give information about the service using the deprecated service...
You can try the following:
var registrationsDependingOnMyService =
from descriptor in services
where descriptor.ImplementationType != null
let dependencies =
from ctor in descriptor.ImplementationType!.GetConstructors()
from param in ctor.GetParameters()
select param.ParameterType
where dependencies.Contains(typeof(IServiceInterface))
select descriptor;
This will query the IServiceCollection for registrations whose implementation type have a constructor argument of type IServiceInterface.
This might not be a bulletproof solution, as types or registrations can more sneakily depend on the service collection (e.g. by calling back into the IServiceProvider from within a registration delegate), but this is likely the best you can do with MS.DI.
So basically - as expected - it's not possible to exactly know which libraries (for which you don't have the code) use a certain dependency.
It's just trial and error ;)
Thanks for the ideas everyone.
I am trying to add some items to the piranha sitemap using the delegate method OnGenerateSitemaps.
In this method I am calling to a service that gets data from entity framework context and then caches it. Whenever I try to use this service in the delegate-method I get a error that the dbContext has already been disposed.
System.AggregateException: 'One or more errors occurred. (Cannot
access a disposed context instance. A common cause of this error is
disposing a context instance that was resolved from dependency
injection and then later trying to use the same context instance
elsewhere in your application. This may occur if you are calling
'Dispose' on the context instance, or wrapping it in a using
statement. If you are using dependency injection, you should let the
dependency injection container take care of disposing context
instances.
I've tried making the service sync instead of async, I've tried awaiting the result and running the task sync, none of which works.
Any ideas on how to use my service in this delegate in Configure on startup?
services.AddScoped<ICachedSitemapService, CachedSitemapService>();
In startup I inject the service, which is scoped.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApi api, ICachedSitemapService cachedSitemapService)
{
App.Hooks.OnGenerateSitemap += (sitemap) =>
{
var items = await cachedSitemapService.GetCachedClinics().Result;
sitemap.AddRange(items);
return sitemap;
};
}
The service that is called is DbContext to get items:
private async Task<IEnumerable<SitemapItem>> GetSitemapClinics()
{
var spec = new ClinicSitemapSpecification();
//This throws error
var allClinics = await _clinicRepo.ListAsync(spec);
//code shortened for brevity, but returns a list.
}
I've tried below without any luck.
var items = await cachedSitemapService.GetCachedClinics().GetAwaiter().GetResult();
sitemap.AddRange(items);
We're (the Piranha team) planning on redesigning the hook system in version 10 (has to be a major version as it will break backward compatibility) to provide DI functionality in all hooks. However, in the meantime, the following should fix your issues.
using (var scope = app.ApplicationServices.CreateScope())
{
var service = scope.ServiceProvider.GetService< ICachedSitemapService>();
}
Since your service is registered to be scoped it can't be resolved directly from the root provider (like the error states). When resolving the service from a controller you are in the request scope, so the solution here is to just create a scope that will allow you to resolve it.
I'm pretty new to ASP.Net Core, C#, OOP, Javascript … basically to everything I'm using at the moment. Last couple of months I've been reading and studying in order to start a new development project.
All in all I'm progressing steadily but I've bumped into an issue with IMemoryCache that I can't really get my head around (or is it with DI?).
I'm using ASP.Net Core 2.0 and VS2017. I have a solution with 2 projects, my main ASP.Net Core MVC Web app and a .Net Core 2.0 Class Library.
In the Class Library I added a class in which I want to use caching so I added IMemoryCache to the constructor.
To instantiate the class I have another constructor that calls the function GetModelGuidAsync.
public class MdsEntityCRUD
{
#region ClassConstruct
private readonly IMemoryCache _cache;
public MdsEntityCRUD(IMemoryCache cache)
{
_cache = cache;
}
public MdsEntityCRUD(ServiceClient client, string modelName, string entityName, string versionFlag)
{
this.client = client;
this.ModelId = Task.Run(async () => await GetModelGuidAsync(modelName)).Result;
this.EntityName = entityName;
mdsWS.Version ver = Task.Run(async () => await GetVersionByPolicyAsync(client, VersionPolicy.Flag, versionFlag, this.ModelId)).Result;
this.VersionId = ver.Identifier.Id;
}
public async Task<Guid> GetModelGuidAsync(string modelName)
{
Dictionary<string, Guid> modelNames;
if (!_cache.TryGetValue("ModelNames", out modelNames) || !modelNames.ContainsKey(modelName))
{
modelNames = await GetModelNamesAsync();
_cache.Set("ModelNames", modelNames, new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60) }); // CFG
}
return modelNames[modelName];
}
I've added services.AddMemoryCache(); to ConfigureServices in Startup of my MVC project.
I'm calling the class from a Controller in my MVC project using the second constructor.
At runtime I get an error at the if (!_cache.TryGetValue-statement. These are the details shown in Exception Helper and from the exception window:
System.AggregateException HResult=0x80131500 Message=One or more
errors occurred. (Object reference not set to an instance of an
object.) Source=System.Private.CoreLib StackTrace: at
System.Threading.Tasks.Task.ThrowIfExceptional(Boolean
includeTaskCanceledExceptions) at
System.Threading.Tasks.Task`1.GetResultCore(Boolean
waitCompletionNotification) at
mdXmdsWS.MdsEntityCRUD..ctor(ServiceClient client, String modelName,
String entityName) in C:\Users..\MdsEntityCRUD.cs:line 59 at
MDS_MVC_Proto2.Controllers.DataExplorerController.EntityDataSource(DataManagerRequest
dmr) in C:\Users..\Controllers\DataExplorerController.cs:line 165
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object
target, Object[] parameters) at
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext()
Inner Exception 1: NullReferenceException: Object reference not set to
an instance of an object.
and from ($exception).InnerException
InnerException {System.NullReferenceException: Object reference not set to an instance of an object. at
Microsoft.Extensions.Caching.Memory.CacheExtensions.TryGetValue[TItem](IMemoryCache
cache, Object key, TItem& value) at
mdXmdsWS.MdsEntityCRUD.d__18.MoveNext() in
C:\Users..\MdsEntityCRUD.cs:line 84
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at
mdXmdsWS.MdsEntityCRUD.<>c__DisplayClass16_0.<<-ctor>b__0>d.MoveNext()
in C:\Users..\MdsEntityCRUD.cs:line 59} System.Exception
{System.NullReferenceException}
I don't know why I'm getting the error:
Is it because the cache is in the Class library and not in the MVC project?
Is it because I'm trying to use the cache in a function executed from the constructor?
Am I missing some configuration?
Eager to learn where I'm going wrong ...
As pointed in the comments, Dependency Injection (DI)/Inversion of Control (IoC) is no magic. At its very base, Dependency Injection just means: "Pass instance of object A to the constructor/method instead of new-ing it inside the constructor/method".
var service = new MyService(new MyDependency());
This above is already dependency injection, you inject a dependency to MyService and if its accepts a base class/interface, its implementation can be changed without changing MyService. This approach is commonly called "poor mans DI", without any external tools or libraries.
Then there are DI/IoC frameworks, which make that easier, so you don't have to new the instances yourself and inject it into the services as well as manage the objects live times for you (should every class get the same instance? (Singleton Lifetime) Or every time a new instance? (Transient Lifetime) Should specific group of classes get one instance and other group another ones? (Scoped Lifetime)).
When you use DI/IoC with or without a framework, you have to use it all the way down. There is no magic involved. The IoC frameworks do the same as above, new-ing a class and its dependencies and pass to the their constructors.
In case of ASP.NET Core the controller is resolved via the built-in DI/IoC Framework, so you can inject any registered class (inside Startup's ConfigureServices method).
In your case you obviously are new-ing the class with the second constructor, so the first one is never called and never setting the _cache member variable. When you try to access it, you get the dreaded NullReferenceException exception. You have to add the dependency to the main constructor.
If like in your case you like have to new a class, you have to pass the dependencies in yourself. In your case, you need to inject IMemoryCache into your controller and then pass it to your new-ed class.
IMemoryCache cache
public class MyController : Controller
{
private readonly MdsEntityCRUD mdsCrud;
public MyController(IMemoryCache memoryCache)
{
ServiceClient client = ...;
mdsCrud = new MdsEntityCRUD(memoryCache, client, "modelname", "entityName", "v1");
}
}
This way you get the correct IMemoryCache instance from the Controller which you can pass to the services.
There are other, more elegant ways to abstract it (using factory classes or factory methods within ConfigureServices) to perform that, but its out of scope of the question.
I'm trying to use autofac DI in my application. I created a wrapper class to abstract away all the autofac dlls:
FrameworkDependencyResolver : Logger, IFrameworkDependencyResolver
In this class I hold the container builder, and register all my dependencies in the application root. After registering my types I build it and hold the container:
Icontainer _container;
ContainerBuilder _builder
public FrameworkDependencyResolver()
{
_builder = new ContainerBuilder();
}
Deep in my application i want to use the FrameworkDependencyResolver object to resolve protocols and open connections to external applications, therefore I registered this object as IFrameworkDependencyResolver with the following code:
_builder.RegisterInstance(obj).As<T>();
Obj is thr FrameworkDependencyResolver, T is the interface
In my starter thread, I resolve object that takes the FrameworkDependencyResolver in his ctor, and it works perfectly, resolvings are fine, however when I resolve an inner layer(on new thread) that takes the FrameworkDependencyResolver in it's ctor and try to resolve a registered protocol object I face deadlock.
Exmaple:
main:
var rootResolver = new FrameworkDependencyResolver();
rootResolver.RegisterType<IClass3, Class3>(Lifecycles.Singleton);
rootResolver.RegisterType<IClass2, Class2>(Lifecycles.Singleton);
rootResolver.RegisterType<Container, TestContainer>(Lifecycles.Singleton);
rootResolver.RegisterObject<IFrameworkDependencyResolver, FrameworkDependencyResolver>(rootResolver);
rootResolver.BuildContainer();
rootResolver.Resolve<TestContainer>();
Console.ReadKey();
TestContainer code:
public TestContainer(IFrameworkDependencyResolver resolver) : base(resolver){}
protected override void InitializeContainer()
{
_class2 = DependencyResolver.Resolve<IClass2>();
Thread.Sleep(20000);
Console.WriteLine("Container initialize finished");
}
Class2 code:
public class2(IFrameworkDependencyResolver resolver)
{
_resolver = resolver;
var thread = new Thread(startMethod);
thread.Start();
Console.WriteLine("Class2 ctor ended");
}
void StartMethod()
{
_class3 = _resolver.Resolve<IClass3>();
Console.WriteLine("Start method finished");
}
The output of this simple example program is:
Class2 ctor ended
Container initialize ended
Start method finished
Meaning that the thread I created is waiting for the main thread to finish and only than it can resolve. I want to prevent this and make it possible to resolve anytime from every thread. Please help me understand what is causing this.
Thank you
Edit:
The problem is not solved because autofac resolves singletons from the root scope..I believe my problem is similar to the one described here : Autofac resolving a singleton creates a bottleneck
but I don't really understand the solution
Edit 2:
for the bottleneck issue I learned that ctors should not contain logic at all.
I also learned I probably shouldn't pass around my IFrameworkDependencyResolver object and should probably use Func<>.
My application structure:
I have a layer in my application that handles connection requests and for every kind of request creates a different kind of protocol (a different protocol object)
// For example lets say a protocol takes in ctor these 3 services + runtime configuration object:
public Protocol1(IFramingAgent, IFramingAlgorithm, IFramingParser, configObject configuration)
Each service is registered with key because each protocol uses a different one
And here is my terrible class:
public class ProtocolsLayer : Layer
{
private IFrameworkDependencyResolver _resolver;
private IConfigurationService _configService;
public ProtocolsLayer(IFrameworkDependencyResolver resolver, IConfigurationService configurationService)
{
_resolver = resolver;
_configService = configurationService;
}
void HandleConnection1()
{
// What I have at the moment (terrible):
// Resolve the fitting services (All keyed - key is received by the type, Resolve and ResolveWithParameters used here are my wrappers)
var agent = _resolver.Resolve<IFramingAgent>(typeof(Protocol1FramingAgent));
var algo = _resolver.Resolve<IFramingAlgorithm>(typeof(Protocol1FramingAlgorith));
var parser = _resolver.Resolve<IFramingParser>(typeof(Protocol1FramingParser));
// A parameter I get and pass to each protocol at runtime
var protocolConfig = _configService.GetConfig<Protocol1Configuration>();
// Finally resolve the protocol with it's parameters:
protocol = _resolver.ResolveWithParameters<IProtocol>(typeof(Protocol1), new List<object>{
agent, resolver, parser, protocolConfig
});
//...
// Theres gotta be a better way!!
}
void HandleConntection2()
{
// Same as in protocol1
}
void HandleConnection3()
{
// Same as in protocol1
}
}
Take in mind that I don't want references to autofac, meaning I can't use IIndex<> which I heard off.
Thanks!
I made a sample to reproduce your issue : https://dotnetfiddle.net/WOGwoD
If I summarize, your issue is that Autofac Resolve for only thread at a time.
Let take another code sample to reproduce the issue :
class Foo1
{
public Foo1()
{
Console.WriteLine("begin Foo1");
Thread.Sleep(1000);
Console.WriteLine("end Foo1");
}
}
class Foo2
{
public Foo2()
{
Console.WriteLine("begin Foo2");
Thread.Sleep(1000);
Console.WriteLine("end Foo2");
}
}
public class Program
{
public static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Foo1>().AsSelf().SingleInstance();
builder.RegisterType<Foo2>().AsSelf().SingleInstance();
IContainer container = builder.Build();
var t1 = Task.Run(() => container.Resolve<Foo1>());
var t2 = Task.Run(() => container.Resolve<Foo2>());
Task.WaitAll(t1, t2);
}
}
The output of this program is the following :
begin Foo1
end Foo1
begin Foo2
end Foo2
If you change the lifetime scope from SingleInstance to InstancePerDependency (the default one) for a single registration, the output will be :
begin Foo1
begin Foo2
end Foo1
end Foo2
We can see that Autofac lock the IContainer for Shared registration while it is activating a Shared registration.
The lock statement is Line 258 of LifetimeScope.cs.
I think this behavior is here to prevent issue with complex dependency graph. ie : What happens if Foo1 has a nested dependency on Foo2 ?
You won't be able to bypass this behavior of Autofac.
To change this behavior, you will need to change the way your code works. A constructor is not intended to take time. I recommend you to change your constructor to do only required things, if some of initialization process takes time I would defer it or refactor the code to ensure that constructor takes only few milliseconds to complete.
I created a wrapper class to abstract away all the autofac dlls
Your core code should not rely on dependency injection component. In your case, it looks like you use the IFrameworkDependencyResolver interface to lazy load component or to have a factory component. You should rely on Lazy<T> of Func<T> instead. See implicit relation type for more information.
I follow the same strategy in my application to wrap DI library with my classes to have ability to change it later on if I need to.
I followed the same approach, with only one difference
in your code you create ContainerBuilder in your class constructor and keep reference to it, this is the problem
instead, you may need remove away the ContainerBuilder instance, and just depend on Autofac.ILifetimeScope as constructor dependency for your FrameworkDependencyResolver, this dependency will be just injected by autofac runtime with correct lifetime scope.
then at any level on your code, you can just depend on FrameworkDependencyResolver as you need
EDIT
after i saw your update, i would recommend that you separate registration of your service from resolving instances, i.e make new class like FrameworkDependencyRegister and keep the other one for resolving and follow the steps answer above
in my opinion abstracting registration might be too much unneeded abstraction, you can just write one method to do this stuff using normal autofac APIs
Using Unity / Bootstrapper, I'm registering my base class - ServiceBase to multiple concrete services.
container.RegisterType<ServiceBase, ClearedPaymentService>("ClearedPaymentService");
container.RegisterType<ServiceBase, MissedPaymentService>("MissedPaymentService");
I'm also registering an external service below this:
container.RegisterType<IPaymentService, PaymentServiceClient>("PaymentService");
The external service is used in both the ClearedPaymentService and MissedPaymentService as shown below:
public partial class ClearedPaymentService : ServiceBase
{
private readonly IPaymentService _paymentService;
private readonly IScheduler _scheduler;
private Timer _timer;
public ClearedPaymentService(IPaymentService paymentService, IScheduler scheduler)
{
_paymentService = paymentService;
_scheduler = scheduler;
}
...etc
}
When I come to use my 2 services, I run into trouble:
var container = (IUnityContainer)Bootstrapper.Container;
var services = container.ResolveAll<ServiceBase>();
if (Environment.UserInteractive)
{
RunInteractive(services.ToArray());
}
The code throws an exception on "services.ToArray()":
Resolution of the dependency failed, type = "System.ServiceProcess.ServiceBase", name = "ClearedPaymentService".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, Think.IncomeProtection.ThirdParty.Service.Contract.Outbound.IPaymentService, is an interface and cannot be constructed. Are you missing a type mapping?
At the time of the exception, the container was:
Resolving ThirdPartyPaymentInvoker.ClearedPaymentService,ClearedPaymentService (mapped from System.ServiceProcess.ServiceBase, ClearedPaymentService)
Resolving parameter "paymentService" of constructor ThirdPartyPaymentInvoker.ClearedPaymentService(Think.IncomeProtection.ThirdParty.Service.Contract.Outbound.IPaymentService paymentService, ThirdPartyPaymentInvoker.IScheduler scheduler)
Resolving Think.IncomeProtection.ThirdParty.Service.Contract.Outbound.IPaymentService,(none)
I understand what the error is saying - the constructor of ClearedPaymentService is expecting a concrete instance of IPaymentService, but it hasn't been resolved for some reason...
I'm fairly new to Unity, so presume it's something basic that I haven't understood yet!
Any help appreciated.
Thanks,
Alex
Your registrations to container provide a name for each service that is registered. So basically there is no default (not named) service that Unity can use in your scenario.
To fix this just remove the names while registering thins. If on other hand you wish to use specific named service then there is an attribute that you can add on parameter of your constructor [NamedDependancy("Your name")]. But by default you should not use this feature the code is simpler without it.