I am calling a method GetData from a class DataProvider, where the method is implemented as a interface. Calling is done as:
Response = ObjectRegistry.Instance.Resolve<IDataProvider>().GetData(id).
Structure of the interface looks like.
namespace A.B.C.D
{
///<Summary>
/// Gets the answer
///</Summary>
public interface IDataProvider
{
GetDataInfo GetData(int id);
}
}
and my DataProvider class looks like.
namespace A.B.C.D
{
public class DataProvider : IDataProvider
{
public GetDataInfo GetData(int id)
{
GetDataInfo DataInfo = new GetDataInfo();
//return obj;
return DataInfo;
}
}
}
But when I am trying to execute this I am getting following error:
Message: Resolution of the dependency failed, type = ".DataInfo.IDataProvider", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, DataInfo.IDataProvider, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:
Resolving DataInfo.IDataProvider,(none)
Tried searching in almost all the SO posts, but couldn't find any helpful suggestion
Related
I tried to use dynamic to access methods of classes that are located in another assembly. These classes are internal and created by builders that return a public interface. For some reason dynamic is not able to invoke the method defined on the interface. I can use "classic" reflection to get the code running but I don't understand why it's not working with dynamic.
I know that dynamic is not working with methods of internal classes but here we have a public interface. So please can someone explain why dynamic throws the RuntimeBinderException in the example below?
namespace SandboxLib // located in SandboxLib.dll
{
public class InternalBuilder
{
public static IInterface Build()
{
return new InternalClass();
}
}
public interface IInterface
{
void IfMethod();
}
internal class InternalClass : IInterface
{
public void IfMethod() { }
}
}
namespace Sandbox // located in Sandbox.dll
{
public class Program
{
static void Main(string[] args)
{
var inst = InternalBuilder.Build();
dynamic dynInst = inst;
inst.IfMethod(); // ok
dynInst.IfMethod(); // Unhandled exception. Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'IfMethod'
}
}
}
This behaviour is described in the C# Standard:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#dynamic-binding
Under "Member Lookup" it states:
Member lookup considers not only the name of a member but also the
number of type parameters the member has and whether the member is
accessible.
Since the member IfMethod() that the dynamic resolution has found is internal, the call will fail, as per the specification.
As i have this child class defined below.
internal class ParserZillowForSale : Parser
{
public ParserZillowForSale(int threadsCount)
: base(threadsCount) {}
}
And have base class defined below.
public class Parser
{
private readonly int _threadsCount;
public Parser(int threadsCount = 10)
{
_threadsCount = threadsCount;
}
}
Now as i'm trying to define Dependency Injection below.
internal class ParserZillowForSale : Parser
{
private readonly List<ListingDetailsData> listings;
private readonly ListingHeader _ListingHeader;
public ParserZillowForSale(int threadsCount)
: base(threadsCount) {}
public ParserZillowForSale(List<ListingDetailsData> listingsD, ListingHeader _ListingHeaderD)
{
listings = listingsD;
_ListingHeader = _ListingHeaderD;
}
}
As i try to call this object.
ParserZillowForSale ParserZillowForSale = new ParserZillowForSale(maxThreads)
It throws an exception and i want to call both with DI and without. Here is the error which i recieve in the PostMan.
"Exception while executing function: ParserZilowForSale -> The type
initializer for 'Parser.ParserZillowForSale' threw an exception. -> No
valid combination of account information found.",
"errorDetails": "Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception
while executing function: ParserZilowForSale --->
System.TypeInitializationException : The type initializer for
'Parser.ParserZillowForSale' threw an exception. --->
System.FormatException : No valid combination of account information
found"
As i don't want to pass multiple arguments on the base keyword so that's why i created another constructor.
I have simple controller with one dependency
public TestController(ITestFacade testFacade)
{
_testFacade = testFacade;
}
and simple facade
public class TestFacade : ITestFacade
{
public TestFacade()
{
throw new Exception("Test");
}
}
I have Unity resolver and registration
public static void RegisterDependencies(IUnityContainer container)
{
container.RegisterType<ITestFacade, TestFacade>();
}
UnityResolver is common as found everywhere. Nothing custom.
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
// Here in one of Inner Exceptions is my Facade exception, but I want to get it later
return null;
}
}
Please consider this as test scenario. Facade in constructor should fail for any reason. It is not important now.
Running application results in exception:
An error occurred when trying to create a controller of type 'TestController'. Make sure that the controller has a parameterless public constructor.
Ok, this is because of error in constructor of Facade when resolver is not able to get instance and activator in controller failed.
My question is - is there any way how to catch this exception in IHttpControllerActivator or somewhere?
I can try catch code in Facade constructor and log it somehow, but why this exception is ignored after resolver.
I am new to Unity and I'm having trouble resolving the correct object.
I have a class CustomerManager that takes, as a dependency IDataAccess.
CustomerManager
public class CustomerManager
{
private IDataAccess dataAccess;
public CustomerManager(IDataAccess dataAccess)
{
this.dataAccess = dataAccess;
}
public Customer GetCustomer(int id)
{
return this.dataAccess.GetCustomer(id);
}
public void SaveCustomer(Customer customer)
{
this.dataAccess.SaveCustomer(customer);
}
}
IDataAccess
public interface IDataAccess
{
void SaveCustomer(Customer customer);
Customer GetCustomer(int id);
}
I have 2 classes that implement IDataAccess called SQLServerDataAccess and MongoDataAccess.
What I am trying to do is register both the classes that implement IDataAccess and then use Resolve to create an instance of CustomerManager.
Here is my register:
UnityIoC.Instance.RegisterType<IDataAccess,SQLServerDataAccess>("SQL");
UnityIoC.Instance.RegisterType<IDataAccess,MongoDataAccess>("Mongo");
When I try to resolve an instance of the IDataAccess classes directly it works fine.
IDataAccess dataAccess = UnityIoC.Instance.Resolve<IDataAccess>("Mongo");
However, when I try to resolve CustomerManager I get an exception.
I am doing this:
CustomerManager manager = UnityIoC.Instance.Resolve<CustomerManager>();
I am getting the following exception:
Resolution of the dependency failed, type = "UnityIoCExample.CustomerManager", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, UnityIoCExample.IDataAccess, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:
Resolving UnityIoCExample.CustomerManager,(none)
Resolving parameter "dataAccess" of constructor UnityIoCExample.CustomerManager(UnityIoCExample.IDataAccess dataAccess)
Resolving UnityIoCExample.IDataAccess,(none)
It's clear to me that the exception is caused by Unity not knowing what registered type of IDataAccess to use as the dependency to CustomerManager but I can't figure out how to specify that. I'm I doing it mostly correct and just missing one piece or am I way off?
My only thought is to use ParameterOverride when resolving CustomerManager and to resolve IDataAccess inside of CustomerManager using that parameter.
Modified CustomerManager constructor:
public CustomerManager(string dbType)
{
this.dataAccess = UnityIoC.Instance.Resolve<IDataAccess>(dbType);
}
To resolve CustomerManager
CustomerManager manager = UnityIoC.Instance.Resolve<CustomerManager>(new ParameterOverride("dbType", "Mongo"));
I'm not sure if that is really the best practice.
You need to use an InjectionContructor in the scenario that you have described.
UnityIoC.Instance.RegisterType<IDataAccess,SQLServerDataAccess>("SQL");
UnityIoC.Instance.RegisterType<IDataAccess,MongoDataAccess>("Mongo");
UnityIoC.Instance.RegisterType<CustomerManager,CustomerManager>("Mongo", new InjectionConstructor(new ResolvedParameter<IDataAccess>("Mongo")));
UnityIoC.Instance.RegisterType<CustomerManager,CustomerManager>("SQL", new InjectionConstructor(new ResolvedParameter<IDataAccess>("SQL")));
CustomerManager manager = UnityIoC.Instance.Resolve<CustomerManager>();
To keep this class tidy its some times better to extract it out into a DIConfig Class of its own. several of these InjectionConstructors will be reusable and extracting in a class will help with that.
I am having trouble using Ninject to load my generic type implementations given the following simplified interface/class structure.
public interface IEntry {}
public class TestEntry : IEntry {}
public interface IDBConnection<T> {}
public class DBConnection<T> : IDBConnection<T> where T : IEntry {}
I am using binds within my loaded NinjectModule:
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<>)).To(typeof(DBConnection<>));
I want to fetch an instance of DBConnection<TestEntry> with a call of:
Kernel.TryGet<IDBConnection<IEntry>>();
However this just returns an open instance type of DBConnection<IEntry> ; I have been able to return an instance of DBConnection<TestEntry> if I change my Kernel.Get call to:
Kernel.TryGet<IDBConnection<TestEntry>>();
I understand that generics are incovariant but it seems that we circumvent the entire purpose of DI/IOC if I need to stipulate the implementation of my generic class in order for Ninject to load it... So I must be either binding, fetching or understanding things incorrectly.
Furthermore I tried a different approach to binding/loading:
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<IEntry>)).To(typeof(DBConnection<TestEntry>));
and
Kernel.TryGet<IDBConnection<IEntry>>();
However, this yields the exception:
System.InvalidCastException : Unable to cast object of type
'DBConnection1[TestEntry]' to type 'IDBConnection1[IEntry]'.
This is because the generic type IDBConnection<IEntry> is not covariant with DBConnection<TestEntry> right?
I want to be able to Ninject DBConnection<TestEntry> into my IDBConnection<IEntry> declaration for consumption; however incovariance of generics seems to disallow this. What's the solution?
Edit: Here is a unit Test to demonstrate/explain
public interface IEntry { }
public class TestEntry : IEntry { }
public interface IDBConnection<T> where T : IEntry { }
public class DBConnection<T> : IDBConnection<T> where T : IEntry { }
class TestModule : NinjectModule
{
public override void Load()
{
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<IEntry>)).To(typeof(DBConnection<TestEntry>));
}
}
[Test]
public void NinjectGenericLoadTest()
{
/// this loads the expected type from interfaces however is useless
/// since loaded against a "var"
///(runtime casts knowing the impl would be required to use)
StandardKernel kernel = new StandardKernel(new TestModule());
var ninjected = kernel.TryGet(typeof(IDBConnection<IEntry>));
Assert.IsInstanceOf<DBConnection<TestEntry>>(ninjected);
/// The following is what I want but it won't compile
///:"Cannot implicitly convert type 'object' to
///'EasyMongo.Contract.IReader<EasyMongo.Contract.IEasyMongoEntry>'.
/// An explicit conversion exists (are you missing a cast?)"
//kernel = new StandardKernel(new TestModule());
//IDBConnection<IEntry> ninjectedInterface = kernel.TryGet(typeof(IDBConnection<IEntry>));
//Assert.IsInstanceOf<DBConnection<Entry>>(ninjectedInterface);
/// this throws System.InvalidCastException : Unable to cast object of type
/// 'DBConnection`1[EasyMongo.Test.Base.RandomTest+Entry]'
/// to type 'IDBConnection`1[EasyMongo.Test.Base.RandomTest+IEntry]'.
/// this is due to incovariance of generic types such that DBConnection<Entry>
/// is not a IDBConnection<IEntry>
IDBConnection<IEntry> ninjectedInterface = (IDBConnection<IEntry>)kernel.TryGet(typeof(IDBConnection<IEntry>));
Assert.IsInstanceOf<DBConnection<TestEntry>>(ninjectedInterface);
}
Ninject will always return the type you ask for. If you ask for IDBConnection<IEntry> then you will get that type if you ask for IDBConnection<TestEntry>. There is no super logic that will analyze your code and get you a different type then the one you are asking for.
But asking for things like IDBConnection directly is the wrong way to use Ninject anyway. You should inject it using constructor injection:
public class NeedDbConnection<T> {
public NeedDbConnection(IDBConnection<T> connection) { ... }
}
That way you get your specific db connection appropriate for that class.