Prism + DryIoc crashes when trying to perform constructor injection? - c#

I'm having trouble using DryIoc for constructor injection into a ViewModel using Prism with Xamarin. I am using the Nuget package Prism.DryIoc.Forms.
In my project I get the following error in AuthenticatePage.xaml.g.cs
Unable to resolve Object {RequiredServiceType=Project.ViewModels.AuthenticatePageViewModel} with 1 arg(s)
in wrapper Func<Xamarin.Forms.Page, Object> {RequiredServiceType=Project.ViewModels.AuthenticatePageViewModel} with 1 arg(s)
from container
with normal and dynamic registrations:
MainPage, {ID=44, ImplType=Project.Views.MainPage}}
NavigationPage, {ID=43, ImplType=Xamarin.Forms.NavigationPage}}
AuthenticatePage, {ID=45, ImplType=Project.Views.AuthenticatePage}}
Specifically, it points to the line
private void InitializeComponent() {
global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(AuthenticatePage));
}
Of note is that if I call the following in App.OnInitialized, the object resolves fine:
c.Register<INegotiator, Negotiator>(Reuse.Singleton);
var n = c.Resolve<INegotiator>();
n.ResumeSessionAsync(); // This works fine, no problems.
await NavigationService.NavigateAsync("NavigationPage/AuthenticatePage"); // Error thrown here
If I remove the constructor injection from my ViewModel it works fine (Aside from keeping the default navigationService injection, which works fine). Even trying to inject a basic class like ILogger (no dependencies) fails.
public AuthenticatePageViewModel(INavigationService navigationService, ILogger logger) : base (navigationService)
{
Title = "Authentication Page...";
}
I'm going to keep investigating, but is it obvious to someone here if I'm fundamentally doing something wrong? If I had to guess I would say it's to do with a conflict with Prisms built in Ioc container and DryIoc?
Edit:
I'm using the latest version of Prism.DryIoc.Forms available on NuGet (7.0.0.396) which says it includes DryIoc 2.12.26. I have so far simply followed the template available for Visual Studio which lists setting up navigation as follows:
protected override async void OnInitialized()
{
InitializeComponent();
var c = new Container();
c.Register<ILogger, LoggerConsole>(Reuse.Singleton);
c.RegisterMany(new[] { Assembly.Load("Project.UWP") },
serviceTypeCondition: type => type == typeof (ILocalFileHandler));
c.Register<INegotiator, Negotiator>(Reuse.Singleton);
// var n = c.Resolve<INegotiator>();
// n.ResumeSessionAsync(); // <- This will run fine. Negotiator class has ILogger and ILocalFileHandler injected into it.
await NavigationService.NavigateAsync("NavigationPage/AuthenticatePage");
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<MainPage>();
containerRegistry.RegisterForNavigation<AuthenticatePage>();
}
I can't find any info online on if/how I should be using Prism.DryIoc.DryIocContainerExtensions to set up navigation? Even modifying the sample app to include basic construction injection results in the error "Value Cannot Be Null" in the same xaml.g.cs file?

Prism 7.0 and below allows the exception to bubble up, in order to diagnose the root cause of your issue you want to better diagnose this issue I suggest you do a little try/catch to see what and where the error really is.
protected override void OnInitialized()
{
try
{
// Check if there is an initialization exception
var page = new AuthenticationPage();
// Validate that the page resolves ok
var page2 = Container.Resolve<object>("AuthenticationPage");
// Validate that your ILogger interface is registered and resolves ok
var logger = Container.Resolve<ILogger>();
// Check for Registration/initialization exceptions
var vm = Container.Resolve<AuthenticationPageViewModel>();
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
System.Diagnostics.Debugger.Break();
}
}
You haven't specified at what point you're getting this error, though typically with XAML Compilation enabled you would see exceptions in the {pageName}.xaml.g.cs during compilation and not runtime. Either way, given that your exception is coming from the generated XAML code behind class, this tells me it is most likely a problem with your XAML. A very simple way to validate this is to remove all of the XAML content in your AuthenticationPage so that you have an empty page.
Given the code you've provided as part of your question, I would say you have no registration for your ILogger interface which would likely throw an exception causing the problem you're seeing. Regardless of what/where the error is, the try/catch shown above would be the easiest way to determine the root cause.

Following #Dan S.'s diagnoses suggestion as well as reading this article (http://brianlagunas.com/whats-new-in-prism-for-xamarin-forms-7-0/) I realized that I should have been using the Prism.Ioc.ContainerRegistry abstraction layer to interface with DryIoc. Prior to this I had been working directly with DryIoc's classes.
Once I modified my registration code to use Prism.Ioc.IContainerRegistry it worked perfectly.
protected override void RegisterTypes(IContainerRegistry cr)
{
cr.Register<ILogger, LoggerConsole>();
cr.GetContainer().RegisterMany(new[] { Assembly.Load("Project.UWP") },
serviceTypeCondition: type => type == typeof(ILocalFileHandler));
cr.Register<INegotiator, Negotiator>();
cr.RegisterForNavigation<NavigationPage>();
cr.RegisterForNavigation<MainPage>();
cr.RegisterForNavigation<AuthenticatePage>();
}

Related

Unity framework doesn't resolve OptionalDependency

I'm building a program on Unity 5 and Prism 7. I want my program to be highly modular so I want it to behave correctly if some modules are unavailable.
For this I want to mark optional dependencies with [OptionalDependency] attribute and let a classes with them to decide themselves what to do if there's null passed in constructor.
But if I mark a dependency with this attribute, Unity doesn't resolve it and just pass null instead of dependency instance, despite the module is available as usual.
How do I make dependency as really nice to have?
Or another option, how do I make Unity to not throw when dependency cannot be resolved, and just pass null instead and let the constructing classes decide what to do?
There's App.xaml.cs of my program:
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
InitializeModules();
this.ShutdownMode = ShutdownMode.OnMainWindowClose;
var shell = Container.Resolve<Shell>();
this.MainWindow = shell;
return shell;
}
protected override void RegisterTypes(IContainerRegistry containerRegistry) { }
/// <summary>
/// Creating catalog of Modules from .dlls in "Modules" folder
/// </summary>
protected override IModuleCatalog CreateModuleCatalog()
{
var catalog = new DirectoryModuleCatalog() { ModulePath = #"./Modules" };
catalog.Initialize();
// by the way, modules aren't getting recognized without
// catalog.Initialize() or InitializeModules in CreateShell.
// Should it be such as that? Seems to me like no..
return catalog;
}
}
Beside main question, I appreciate any suggestions on how to make my code better in the comments under the question, because I'm a noob in Prism+Unity. Thank you!
This approach is not a good idea. Constructor injection means that the dependencies are required. Also, I don't think the OptionalDependencyAttribute works in the ctor, but rather must be applied to a property. Try making a property and applying the attribute to it.
All the code in the CreateShell method is not needed. Just return Container.Resolve<Shell>() and that's it.
Also, the modules not loading is a bug which was fixed and is available in the latest Prism CI biuld on MyGet.

Unity: What is actually needed to make RegisterInstance work?

So, I'm using Prism and Prism.Unity to build my app. However, I'm running into an issue I haven't been able to find documentation on. It's probably quite basic but the error message is not so helpful and the stack trace doesn't help either.
So, basically, when registering an instance of an existing object, I'm supposed to simply do this, according to the docs I found:
EmailService myEmailService = new EmailService();
myContainer.RegisterInstance<IMyService>(myEmailService);
I'm following that to the letter, the class and interface in question are currently empty, though, so kind of like this:
interface IMyService { }
class EmailService : IMyService { }
Now, when the app is executing the commands above, it throws an exception at RegisterInstance() with the following message:
Value cannot be null.
Parameter name: container
So, where does this go wrong?
Okay, I actually found the answer. Basically, I had stuffed the registration of the instance into the App.App() routine (which is treated as the equivalent of main() in UWP), after the this.InitializeComponent();
After thinking about the error message some more (and seeing that the error message came from an IEnumerable.Any(), so something like <null>.Any() was the actual source, I thought to myself:
What if InitializeComponent() has yet stuff to finish and the UnityContainer hasn't been fully constructed?
So, I shoved the registration into the OnLaunchApplicationAsync() routine like this:
protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
{
EmailService myEmailService = new EmailService();
Container.RegisterInstance<IMyService>(myEmailService);
NavigationService.Navigate("Main", null);
return Task.FromResult(true);
}
And now it works. As I said, basic stuff. Damn.

Using Custom IHttpActionInvoker in WebAPI for Exception Handling

I'm trying to add a custom IHttpActionInvoker to my WebAPI application in order to prevent the need for lots of repeated exception handling code in my action methods.
There really doesn't seem to be much out there about how to do this other than this article. After writing my IHttpActionInvoker as per the article I added this code:
GlobalConfiguration.Configuration.Services.Remove(typeof(IHttpActionInvoker),
GlobalConfiguration.Configuration.Services.GetActionInvoker());
GlobalConfiguration.Configuration.Services.Add(typeof(IHttpActionInvoker),
new MyApiControllerActionInvoker());
Into a method within my Global.asax file. Now when executing a call to my API I get the following exception raised at the Remove() method:
The service type IHttpActionInvoker is not supported
I guess I have two questions.
Considering there doesn't seen to be an awful lot out there about writing custom IHttpActionInvoker classes is this considered a good approach to solve exception handling in WebAPI applications?
Does anyone know why I would get such an exception when executing the Remove() method and how best to fix this particular issue?
I suffered the same error you describe when attempting to remove the service.
I discovered I didn't need to remove anything from the global config, as it appears if you've registered the interface in your container then it will resolve this first.
For example, I'm using SimpleInjector and in my global.asax I have this:
container.Register<IHttpActionInvoker , MyApiControllerActionInvoker >();
// Register the dependency resolver.
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
At runtime, it is resolving MyApiControllerActionInvoker dependency when required.
You can then perform exception handling in your customer ActionInvoker and any dependencies set in your constructor will be wired up correctly. The reason I was looking at the ActionInvoker was to get the constructor injection, since injecting into Attributes appears to require property injection.
Also rather than the remove/insert, replace seems to work. (in Global.asax)
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionInvoker), new MyApiControllerActionInvoker(fooService));
Have you considered registering an exception filter instead? Here's some documentation about that:
http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling
You shouldn't have to fall down to the action invoker layer if all you want to do is handle some exceptions in a particular way.
As for me it works with IActionInvoker instead of IHttpActionInvoker. As I understand, IHttpActionInvoker is used for the async api calls, isn't it?
public class RepControllerActionInvoker : ControllerActionInvoker
{
ILogger _log;
public RepControllerActionInvoker()
: base()
{
_log = DependencyResolver.Current.GetService<ILogger>();
}
public override bool InvokeAction(ControllerContext controllerContext, string actionName)
{
try
{
return base.InvokeAction(controllerContext, actionName);
}
catch (Exception e)
{
_log.Error(e);
throw new HttpException(500, "Internal error");
}
}
}

Unable to step into interface implementation configured by unity application block

I have configured a set of interface implementations with EntLib. unity block. The constructor of implementation classes work fine as soon as I run the application:
1. The interface to implement
when I run the application the cctor runs fine, which shows that unity resolution was successful:
But when I try to call a method of this class, the code just passes through without actually invoking the function of the implemented class:
Edit: Added on June 11, 2012
Following is the Unity Configuration I have. (This is all the unity configuration I am doing)
public class UnityControllerFactory : DefaultControllerFactory
{
private static readonly IUnityContainer container;
private static UnityControllerFactory factory = null;
static UnityControllerFactory()
{
container = new UnityContainer();
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Configure(container);
factory = new UnityControllerFactory();
}
public static UnityControllerFactory GetControllerFactory()
{
return factory;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return container.Resolve(controllerType) as IController;
}
}
I am unable to step into this code and the implementation simply skips out without executing anything. What is wrong here?
The actual problem was with a yield statement, which does not step into the code until the result is parsed.
When the debugger is stopped at the break point, right click on the line and select "step into specific", then choose the method you wish to step into.
Is this class/method in another assembly (not another project)? Its possible that the source for this class isn't loaded (or the debug symbols aren't refreshed correctly, restarting VS might fix it if that is the case.), so the debugger skips it. Also the method might be decorated with the DebuggerStepThroughAttribute, which causes the debugger to skip it.

Prism 2.1 Injecting Modules into ViewModel

I've been trying to inject the modules from my ModuleCatalog into my Shell's ViewModel but I'm not having much luck...
I'm creating the ModuleCatalog in my Bootstrapper and my module is getting onto the screen from its Initializer without problem. However, I'd love to be able to bind my list of modules to a container with a DataTemplate which allowed them to be launched from a menu!
Here's my Boostrapper file, I'll be adding more modules as times goes on, but for now, it just contains my rather contrived "ProductAModule":
public class Bootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
Container.RegisterType<IProductModule>();
base.ConfigureContainer();
}
protected override IModuleCatalog GetModuleCatalog()
{
return new ModuleCatalog()
.AddModule(typeof(ProductAModule));
}
protected override DependencyObject CreateShell()
{
var view = Container.Resolve<ShellView>();
var viewModel = Container.Resolve<ShellViewModel>();
view.DataContext = viewModel;
view.Show();
return view;
}
}
Following on from that, here's my Shell's ViewModel:
public class ShellViewModel : ViewModelBase
{
public List<IProductModule> Modules { get; set; }
public ShellViewModel(List<IProductModule> modules)
{
modules.Sort((a, b) => a.Name.CompareTo(b));
Modules = modules;
}
}
As you can see, I'm attempting to inject a List of IProductModule (to which ProductAModule inherits some of its properties and methods) so that it can then be bound to my Shell's View. Is there something REALLY simple I'm missing or can it not be done using the Unity IoC? (I've seen it done with StructureMap's extension for Prism)
One more thing... When running the application, at the point the ShellViewModel is being resolved by the Container in the Bootstrapper, I receive the following exception:
Resolution of the dependency failed, type = "PrismBasic.Shell.ViewModels.ShellViewModel", name = "". Exception message is: The current build operation (build key Build Key[PrismBasic.Shell.ViewModels.ShellViewModel, null]) failed: The parameter modules could not be resolved when attempting to call constructor PrismBasic.Shell.ViewModels.ShellViewModel(System.Collections.Generic.List`1[[PrismBasic.ModuleBase.IProductModule, PrismBasic.ModuleBase, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] modules). (Strategy type BuildPlanStrategy, index 3)
Anyway, simple huh... Looks bemused...
Any help would be greatly appreciated!
Rob
I think you could probably just do this:
public class Bootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
Container.RegisterType<IProductModule>();
base.ConfigureContainer();
}
private static ObservableCollection<IProductModule> _productModules = new Obser...();
public static ObservableCollection<IProductModule> ProductModules
{
get { return _productModules; }
}
protected override IModuleCatalog GetModuleCatalog()
{
var modCatalog = new ModuleCatalog()
.AddModule(typeof(ProductAModule));
//TODO: add all modules to ProductModules collection
return modCatalog;
}
...
}
Then you would have a static property that anything could bind to directly, or could be used from your ViewModel.
Here is how to get a list of module names that have been registered with the module catalog.
public class MyViewModel : ViewModel
{
public ObservableCollection<string> ModuleNames { ... }
public MyViewModel(IModuleCatalog catalog)
{
ModuleNames = new ObservableCollection<string>(catalog.Modules.Select(mod => mod.ModuleName));
}
}
That's pretty much it. IModuleCatalog and IModuleManager are the only things that are setup in the container for you to access in terms of the modules. As I said, though, you won't get any instance data because these modules (hopefully) are yet to be created. You can only access Type data.
Hope this helps.
I think you misunderstood the purpose of the modules. The modules are just containers for the views and services that you wish too use. The shell on the other hand should just contain the main layout of your application.
What I think you should do is to define a region in your shell, and then register the views (which in your case are buttons) with that region.
How you wish do deploy your views and services in terms of modules is more related to what level of modularity you're looking for, i.e. if you want to be able to deploy the views and services of ModuleA independently of the views and services of ModuleB and so on. In your case it might be enough to register everything in one single module.
Take some time to play around with the examples provided with the documentation, they are quite good.
The reason why your examples throws an example is because your ShellViewModel is depending on List and that type is not registered in Unity. Furthermore you're registering IProductModule with Unity, which makes no sense because an Interface cannot be constructed.
I think I encountered a similar problem today, it turns out that PRISM creates the shell before initializing the modules, so you can't inject any services from the modules into the shell itself.
Try creating another module that depends on all of the others and implements the functionality you want, then you can add it to a region in the shell to display your list of services. Unfortunately I haven't had a chance to try it yet, but this is the solution I plan on implementing.
As a side note, I think you need to mark the property with an attribute to use property injection, but I could be mistake (it's been a while since I played with Unity directly).
Edit: You need to apply the DependencyAttribute to properties to use setter injection in Unity; you can read about it here.
var modules = new IProductModule[]
{
Container.Resolve<ProductAModule>()
//Add more modules here...
};
Container.RegisterInstance<IProductModule[]>(modules);
That's it! Using this code, I can inject my modules into the ShellViewModel and display each module as a button in my application!
SUCH a simple resolution! From a great guy on the CompositeWPF Discussion group. I recommend them without reserve ^_^

Categories