ipjohnson / Grace

Grace is a feature rich dependency injection container library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error thrown on method Import with key

XanNava opened this issue · comments

The fallowing is the coding I am using (note the different commented out elements to test behaviors are working properly in other ways).

// See https://aka.ms/new-console-template for more information

using Grace.DependencyInjection;
using Grace.DependencyInjection.Attributes;

DependencyInjectionContainer container = new DependencyInjectionContainer((c) => {
	c.AutoRegisterUnknown = true;
	c.Trace = (s => {
		Console.WriteLine(s);
	});
});

container.Configure((c) => {
	c.Export<Service>().AsKeyed<IService>("ServiceM");

	c.Export<ServiceAlt>().AsKeyed<IService>("ServiceA");

	// Will default to this if a key import fails.
	// Allows for the default [import()].
	//c.Export<Service>().As<IService>();
});

var scope = container.BeginLifetimeScope("RootScope");

var alt = container.Locate<IService>(withKey: "ServiceA");
var service = container.Locate<ServiceMain>();

Console.WriteLine(service.Service.GetString());

interface IService {
	string GetString();
}

class Service : IService {
	public virtual string GetString() {
		return "Service";
	}
}

class ServiceAlt : IService {
	public string GetString() {
		return "Service AlternativeService";
	}
}

class ServiceMain {
	// Works.
	//[Import(Key = "ServiceA")]
	public IService Service { get; set; }

	// Works with export "c.Export<Service>().As<IService>();"
	//[Import()]
	
	// Throws error that type reference in Grace is null.
	[Import(Key = "ServiceA")]
	public void Recieve(IService service) {
		Console.WriteLine("Import through method");
		Service = service;
	}
}

The above throws the fallowing error.

Unhandled exception. Grace.DependencyInjection.Exceptions.LocateException: Could not locate Type IService
1 Importing ServiceMain
2 Importing IService  for method Recieve parameter service

   at Grace.DependencyInjection.Impl.InjectionContextValueProvider.GetValueFromInjectionContext[T](IExportLocatorScope locator, StaticInjectionContext staticContext, Object key, IInjectionContext dataProvider, Object defaultValue, Boolean useDefault, Boolean isRequired)
   at lambda_method2(Closure , IExportLocatorScope , IDisposalScope , IInjectionContext )
   at Grace.DependencyInjection.Impl.ActivationStrategyDelegateCache.FallbackExecution(ImmutableHashTree`2 currentNode, Type type, IExportLocatorScope scope, Boolean allowNull, IInjectionContext context)
   at Grace.DependencyInjection.Impl.ActivationStrategyDelegateCache.ExecuteActivationStrategyDelegate(Type type, IExportLocatorScope scope)
   at Grace.DependencyInjection.Impl.BaseExportLocatorScope.Locate[T]()
   [My code url]/Program.cs:line 25

Grace version 8.0.0-Beta822

So I made a fork of the repo and it looks like the key isn't getting passed into the fallowing method it is just null. InjectionContextValueProvider.GetValueFromInjectionContext<T>(....)

If I set the key manually key = (object)"ServiceA"; the path to call GetValueFromExtraDataProvider<T>(...) is taken, but there is still an issue that the fallowing two calls in the method return null.
InjectionContext.GetExtraData(object key) <-- Method
_extraDataProperties.GetValueOrDefault(stringKey) <-- Call in method
_extraDataValues.GetValueOrDefault(key)<-- Call in method

https://github.com/XanNava/GraceTests
You can see my tests by cloning the above fork. Note I removed .net FrameWork 4.5 from the build target just to get it running on my pc. Run GraceTests.ConsoleApp for Method logging.

The IExportLocatorScope locator argument for InjectionContextValueProvider.GetValueFromInjectionContext<T>(....) Is correct, and can be used to locate the service by the key.

Still not sure why the key isn't being passed in, but the call GetValueFromExtraDataProvider<T>(key, currentLocator, out value) seems to not be working properly and where the method call ends and value is still null if there is a key value. I have narrowed the issue down to seemingly the two fallowing things.

  1. Key not being passed into InjectionContextValueProvider.GetValueFromInjectionContext<T>(...)
  2. IExtraDataContainer.GetExtraData(key); not returning object, but IExportLocatorScope.locate<T>(withKey: key); will. Looks like IExtraDataContainer is getting cast incorrectly from IExportLocatorScope.

It looks like there was an issue in the auto configuration code that wasn't checking attributes on the method parameters.

I've released an updated version 8.0.0-RC824.

Note you need to specify the import on the parameter as well as the method

  class ServiceMain
  {
      public IService Service { get; set; }
      
      [Import]
      public void Recieve([Import(Key = "ServiceA")]IService service)
      {
          Console.WriteLine("Import through method");
          Service = service;
      }
  }