C# Unity why is module loading too late? - c#

I have a module "Toolbar", "Toolbar" contains a UserControl and a ViewModel. The viewmodel is supposed to get a service called "IShapeService" injected into its constructor, however there's an issue.
I get the following error message when running my application:
The current type, Core.Services.IShapeService, is an interface and cannot be constructed.
Are you missing a type mapping?
The interface is mapped to the type in the ServicesModule which you can see below.
public class ServicesModule : IModule
{
private readonly IUnityContainer container;
public ServicesModule(IUnityContainer container)
{
this.container = container;
}
public void Initialize()
{
container.RegisterType<IShapeService, ShapeService>(new ContainerControlledLifetimeManager());
}
}
As far as I can tell by debugging, the issue is that the ServicesModule is not loaded early enough. I quickly tried using a PriorityAttribute (you can find it via google) on the module, but had no luck this time.
The weird thing is that it is working in another project with the same setup (as far I can see it is the same setup). The other project actually also uses the PriorityAttribute, but it is to determine tab order.
This is an image of the solution structure:
All projects reference the Core, but that is also it.
Can you spot what I'm doing wrong?

Related

IServiceCollection cannot resolve type when loaded from an outside assembly

I'm running into a strange issue using dependency injection, adding in a Singleton for a type that comes from an outside assembly. This is using the Azure Function framework, but I'm not sure if that has anything to do with it or if this would repro with ASP.NET Core as well. My actual "real world" implementation is far, far too complicated to outline here, but I've managed to come up with a minimal repro.
BugRepro.dll (This is a Azure Function project)
This has two files.
Test.cs:
public class Test
{
private readonly AppConfig config;
public Test(AppConfig config)
{
this.config = config;
}
[FunctionName("Test")]
public async Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req)
{
return new OkObjectResult(config.SampleSetting);
}
}
Startup.cs:
namespace BugRepro
{
public class AppConfig
{
public string SampleSetting { get; set; } = "Test";
}
public static class Startup
{
public static void Configure(IServiceCollection services)
{
services.AddSingleton(new AppConfig());
}
}
}
This assembly has a reference to TestDll.dll.
TestDll.dll (This is a normal .NET Core library)
Startup.cs:
[assembly: FunctionsStartup(typeof(TestDll.Startup))]
namespace TestDll
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var asm = Assembly.LoadFile(Path.Combine(builder.GetContext().ApplicationRootPath, #"bin\BugRepro.dll"));
var type = asm.GetType("BugRepro.Startup");
var method = type.GetMethod("Configure");
method.Invoke(null, new object[] {builder.Services});
}
}
}
When the Azure Function runs, the TestDll.Startup.Configure method is automatically called by the framework. This method loads the other assembly, BugRepro.dll using reflection and calls the BugRepro.Startup.Configure static method, passing the IServiceCollection.
The BugRepro.Startup.Configure static method adds a single instance of AppConfig to the service collection. I can verify the instance has successfully been added to the service collection, and stepping all the way into the code, the right ServiceDescriptor and everything has been created. Everything appears perfect.
However, when I call the /Test endpoint, I get the error:
[2021-02-04T06:39:10.502Z] Executed 'Test' (Failed, Id=22cfb587-3ba9-401f-b0a5-8688aed7bc9d, Duration=386ms)
[2021-02-04T06:39:10.506Z] Microsoft.Extensions.DependencyInjection.Abstractions: Unable to resolve service for type 'BugRepro.AppConfig' while attempting to activate 'BugRepro.Test'.
Basically, it acts like the Singleton has never been registered and it cannot resolve that type.
Ways to fix:
So, if I move the AppConfig class from the BugRepro.dll to TestDll.dll (basically the AppConfig type is in the same DLL as my FunctionsStartup class), the code works as expected.
Another way to fix it is to use an interface, which is defined in TestDll:
public interface IConfig
{
}
Then make AppConfig implement that interface, then register the Singleton using its interface:
services.AddSingleton<IConfig>(new AppConfig());
However, then I have to inject IConfig into the Test constructor rather than AppConfig which I do not want to do.
My Question
Is there a way to register a Singleton for a type that lives in an external assembly? To me, this seems like a bug in the .NET Core DI framework. Thanks!
This problem is caused by your use of Assembly.LoadFile. The LoadFile method can cause the same assembly to be loaded twice in such way that the framework sees this as a totally different assembly, with different types.
The solution is to use Asssembly.Load instead:
var assembly = Assembly.Load(AssemblyName.GetAssemblyName("c:\..."));
See for instance this related topic (for Simple Injector, but the problem is identical) for more information.

Binding to method<T> with ninject

We are defining implementations to our services in an external xml configuration file. We have the name of the service, the class to instantiate, the assembly containing the class. We are migrating from an Spring AOP code.
For simple services it works without an itch with kernel.Bind().To().
We load the assembly, create an instance, return it to To().
However some services inherit from another class like :
internal abstract Bar<T>: EntityBo<T> where T : IAddress
{
protected Bar(IAddress adr)
{
}
}
internal Foo:Bar<ILocalAddress>, ILocalAddressService {
}
When I try to get ILocalAddressService from the Kernel, I get a Ninject.ActivationException :
Error activating ILocalAddress No matching bindings are available, and
the type is not self-bindable.
Activation path:
2) Injection of dependency ILocalAddress into parameter adr of constructor of type Foo
1) Request for ILocalAddressService
The Kernel is in a different project and doesn't know about the interface or its implementation.
How can I make it work ?

How to access overall AutoFac container to register a dependency in Orchard?

the question is pretty straightforward.i want to access overall AutoFac container so that i can register my dependency in it.
remark:
i am not OK with inheriting from IDependency cause in my project it results in a circular referencing (of two assemblies).what i wanna do is register a component with a Key and access it with same Key in other assembly.
thanks in advance.
EDIT:
i have found a class called DefaultOrchardHostContainer in the core ,but it only exposes Resolve<> method but not Register().
You can add an Autofac module directly to your Orchard module and Orchard will pick it up. ex...
public class MyModule : Module {
protected override void Load(ContainerBuilder builder){
builder.RegisterType<MyDependency>().As<IMyDependency>().InstancePerDependency();
}
}

Ninject in ASP.NET MVC4

So after much screwing around I finally got Ninject wired in and compiling in my MVC4 application. The problem I was running into is the IDependencyScope interface no longer exists from what I can tell and the System.Web.Http.Dependencies namespace was done away with.
So, my problem now is I have everything wired in and upon running the application I get:
Sequence contains no elements
[InvalidOperationException: Sequence contains no elements]
System.Linq.Enumerable.Single(IEnumerable`1 source) +379
Ninject.Web.Mvc.NinjectMvcHttpApplicationPlugin.Start() in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectMvcHttpApplicationPlugin.cs:53
Ninject.Web.Common.Bootstrapper.<Initialize>b__0(INinjectHttpApplicationPlugin c) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:52
Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:31
Ninject.Web.Common.Bootstrapper.Initialize(Func`1 createKernelCallback) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:53
Ninject.Web.Common.NinjectHttpApplication.Application_Start() in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\NinjectHttpApplication.cs:81
Which I haven't been able to track down or even begin to fathom where it is coming from.
My standard Ninject methods inside the Global.asax.cs look as follows:
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Bind<IRenderHelper>().To<RenderHelper>();
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NinjectDependencyResolver(kernel));
return kernel;
}
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
BundleTable.Bundles.RegisterTemplateBundles();
}
And my custom resolver:
public class NinjectDependencyResolver : IDependencyResolver
{
private readonly IKernel _kernel;
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _kernel.GetAll(serviceType);
}
catch (Exception)
{
return new List<object>();
}
}
public void Dispose()
{
// When BeginScope returns 'this', the Dispose method must be a no-op.
}
}
Any insight here would be greatly appreciated. I've spent far too much time already trying to get any DI framework wired into the latest MVC4 RC running on .NET 4.5 and have now just reached my tolerance level for things just not working at all..
Edit #1
A little further research digging around in github the ExtensionsForIEnumerableOfT.cs doesn't help much:
https://github.com/ninject/ninject/blob/master/src/Ninject/Infrastructure/Language/ExtensionsForIEnumerableOfT.cs
And possibly if I had wrote it myself I would begin to understand this but Bootstrapper.cs doesn't help too much either.
https://github.com/ninject/Ninject.Web.Common/blob/master/src/Ninject.Web.Common/Bootstrapper.cs
Hoping these details will make it easier for any of you who might have more experience with Ninject.
Edit #2 The error encountered is specifically in NinjectMvcHttpApplicationPlugin.cs:
The offending line is:
ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
Which lives in the following method:
public void Start()
{
ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
DependencyResolver.SetResolver(this.CreateDependencyResolver());
RemoveDefaultAttributeFilterProvider();
}
The ModelValidatorProviders collection contains 2 elements:
{System.Web.Mvc.DataErrorInfoModelValidatorProvider}
{System.Web.Mvc.ClientDataTypeModelValidatorProvider}
And it's trying to remove a single instance of:
System.Web.Mvc.DataAnnotationsModelValidatorProvider
Which apparently isn't loaded up in the ModelValidationProviders.Providers collection. Any ideas from here?
Resolution to Above Exception And Onto The Next
To resolve the issue in the ModelValidatorProviders I had to manually add an object it was expecting. So now my CreateKernel method looks like:
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Bind<IRenderHelper>().To<RenderHelper>();
kernel.Unbind<IDocumentViewerAdapter>();
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NinjectDependencyResolver(kernel));
ModelValidatorProviders.Providers.Add(new DataAnnotationsModelValidatorProvider());
FilterProviders.Providers.Add(new FilterAttributeFilterProvider());
return kernel;
}
Now it runs and gets into the actual guts of Ninject but still has an issue, one that makes no sense yet again:
Exception Details: Ninject.ActivationException: Error activating IntPtr
No matching bindings are available, and the type is not self-bindable.
Activation path:
3) Injection of dependency IntPtr into parameter method of constructor of type Func{IKernel}
2) Injection of dependency Func{IKernel} into parameter lazyKernel of constructor of type HttpApplicationInitializationHttpModule
1) Request for IHttpModule
Suggestions:
1) Ensure that you have defined a binding for IntPtr.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
Ok after beating my head against the wall for far too long I figured out what was going on. The default project type for MVC4 running on .NET 4.5 had a reference to the original RC version of System.Web.Http instead of the updated version.
Namespaces were missing, objects didn't exist, life was not good.
Steps for resolution:
Remove your reference to System.Web.Http in your MVC4 project
Add Reference -> System.Web.Http
Delete all work arounds you put in to get the old garbage version of System.Web.Http to work
Reapply standard process to wire in Ninject.
HOWEVER, the error of:
Exception Details: Ninject.ActivationException: Error activating IntPtr
No matching bindings are available, and the type is not self-bindable.
Activation path:
3) Injection of dependency IntPtr into parameter method of constructor of type Func{IKernel}
2) Injection of dependency Func{IKernel} into parameter lazyKernel of constructor of type HttpApplicationInitializationHttpModule
1) Request for IHttpModule
Suggestions:
1) Ensure that you have defined a binding for IntPtr.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
Update This was solved by updating MVC from MVC4 Beta to MVC4 RC.
Check out the Pro ASP.NET MVC 3 book. I just ported this code over from MVC3 to MVC4 last night and works correctly. Page 322 to be exact.
What I don't see is where you are mapping your Interface to your concrete items.
Bind<ISomething>().To<Something>();
Add another constructor and add the method that calls your mapping;
public NinjectDependencyResolver() {
_kernal = new StandardKernel();
RegisterServices(_kernel);
}
public static void RegisterServices(IKernel kernel) {
kernel.Bind<ISomething>().To<Something>();
}
Here's what a resolver could/should look like;
public class NinjectDependencyResolver : IDependencyResolver {
private IKernal _kernel;
public NinjectDependencyResolver(){
_kernal = StandardKernal();
AddBindings();
}
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _kernal.GetAll(serviceType);
}
public IBindingToSyntax<T> Bind<T>() {
return _kernal.Bind<T>();
}
public static void RegisterServices(IKernel kernel){
//Add your bindings here.
//This is static as you can use it for WebApi by passing it the IKernel
}
}
Global.Asx -
Application_Start()
method
DependencyResolver.SetResolver(new NinjectDependencyResolver());
That's it.
UPDATED 11/14/2012
On a side note, if you're working with MVC WebAPI, you will want to use WebApiContrib.IoC.Ninject from nuget. Also, check out the "Contact Manager" in their samples asp.net.com. This helped to cleanup the implementation of Ninject
Just delete NinjectWebCommon.cs file from your project (it is in App_Start folder). and everything should be working.
Source: http://mlindev.blogspot.com.au/2012/09/how-to-implement-dependency-injection.html
When you will install latest Ninject.MVC3 from NuGet package we find following code on top of the NinjectWebCommon.cs file:
[assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Stop")]
in this case we dont need to register ninject explicitly in global.asax
I found a good content on using Ninject with MVC 4 here
I tend to keep my Ninject bootstrapping in a separate project. In order to use the .InRequestScope() extension method of IBindingInSyntax<T>, I had added via Nuget the Ninject.Web.Common library. Alas, this library includes the app_start bootstrapper, resulting in duplicate NinjectWebCommon classes and attachment via WebActivator (1 in said project and 1 in the MVC project itself).
I deleted the duplicate App_Start folder from my bootstrap project, and this solved it.
I have come across the same issue not quite sure what has fixed after below changes
added Ninject.MVC4 to project
deleted NinjectWebCommon.cs (the generated file, as the integration already exists in global.ascx.cs file)
I am using DD4T, and encountered same error.
After confirming that all packages are installed by nuget package manager,
I found that some of the DLLs/references were missing (newtonsoft etc):
Then, after re-installing Newtonsoft.Json (to re-install package use following command in Nuget Package Manager:Update-Package –reinstall Newtonsoft.Json), and putting netrtsn.dll from Tridion Deployer bin, I got this error - "Sequence contains no elements" with exactly same stack trace as given in this question.
Thanks to Naga, for providing this resolution
deleted NinjectWebCommon.cs (the generated file, as the integration already exists in global.ascx.cs file), and wohooooo!!!! all errors resolved, Tridion + MVC4 = DD4T is running fine now.
I have also had this problem when I used nuget to install Ninject.MVC4 in a project referenced by my actual MVC website project.
The trouble is that the NinjectWebCommon.cs file automatically installed in the App_Start directory of the referenced project conflicts with the (actual, useful) one installed in my website project. Removing the NinjectWebCommon.cs file from the referenced project resolves the error.

How View is resolved in Prism

I am newbie in using Prism. I have created a sample application to understand it. I have some queries on, how it is working.
Question 1:
public class HelloModuleCls : IModule
{
IRegionManager regionManager;
IUnityContainer container;
public void Initialize()
{
RegisterViewAndServices(); // Injecting occurs here
if (regionManager.Regions.ContainsRegionWithName("ViewHolder"))
{
regionManager.Regions["ViewHolder"].Add
(
***container.Resolve().View***
);
}
}
protected void RegisterViewAndServices()
{
//since angular brace is not appearing, I am using ( , )....
container.RegisterType(IHelloView, HelloViewUC)();
container.RegisterType(IHelloViewModel, EmployeeVM)();
}
}
public class EmployeeVM : INotifyPropertyChanged, IHelloViewModel
{
public EmployeeVM(IHelloView targetview)
{
}
}
Upon hitting the line, container.Resolve().View,
the ctor of the VM, gets executed with, view type got injected in the param "targetview".
1. So, what will happen behind the scene, when that line got a hit...?
Question 2:
Project Name:- HelloModule (Another Silvelight Class Library referred in the startup Silverlight Application)
public class HelloModuleCls : IModule
{
public HelloModuleCls(IRegionManager rm, IUnityContainer um)
{
regionManager = rm;
container = um;
}
}
(Shell.Xaml) (In Startup Silverlight Application)
<ContentControl Prism:RegionManager.RegionName="ViewHolder" Grid.Row="0">
</ContentControl>
This Module is in another project. I am having the Region in the startup project. I have seen that, in the ctor of the HelloModuleCls, the region got which is used in the Startup project, got injected perfectly...
2. So, how the prism is passing those regions..... Is it like, once the region got created, then it will be injected to all the available Modules ctor or some other concept.
May I kindly know, how this is working out, So I can able to understand more.
Thanks in advance.
Answer 1: it resolve the one view, normally you want to register views with some key to be able to differentiate them.
Answer 2: it's the other way round, the regions exist in the application and the modules use them. They need to somehow know the name of the region, of course.
Unsorted comments:
RegisterType<ISomeInterface, OneOfItsImplementations>() lives in the Microsoft.Practices.Unity namespace, so add using Microsoft.Practices.Unity; to "see the angular brace appearing"
use something like regionManager.RegisterViewWithRegion("MyRegion", typeof(AView)) to make the view automatically appear in the region
to switch views in a region, have a look at prism's navigation features, like RegisterTypeForNavigation and RequestNavigate
the view uses the viewmodel, not the other way round. The viewmodel normally doesn't know about the view.

Categories

Resources