In our real world application we defined an attribute that is used to enable logging in methods or classes (the usual AOP use case). When we apply this attribute to a WPF window class, objects of this class can't be created by Ninject. Here is a minimal example to reproduce the issue:
dummy interceptor for logging:
public class MyInterceptor: IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("Calling {0} at {1}", invocation.Request.Method.Name, DateTime.Now);
invocation.Proceed();
}
}
the corresponding attribute:
public class MyAttribute: InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return new MyInterceptor();
}
}
the window class (completely empty, only the automatically generated empty grid is inside):
[My]
public partial class MainWindow: Window
{
public MainWindow()
{
InitializeComponent();
}
}
and finally the app startup code where the object is requested:
public partial class App: Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
var kernel = new StandardKernel(new NinjectSettings() { LoadExtensions = false }, new DynamicProxyModule());
var window = kernel.Get<MainWindow>();
window.ShowDialog();
}
}
When requesting the window via kernel.Get<MainWindow>();
an TargetInvocationException
is thrown with an inner exception telling me that Castle.Proxies.MainWindowProxy
doesn't have a resource specified by URI "/NinjectInterceptionWPF;component/mainwindow.xaml"
where NinjectInterceptionWPF
is our assembly's short name.
When we look at the automatically created InitializeComponent
of MainWindow
we can see that an URI is created to address the XAML code, which seems to be missing for the proxy:
System.Uri resourceLocater = new System.Uri("/NinjectInterceptionWPF;component/mainwindow.xaml", System.UriKind.Relative);
#line 1 "..\..\..\MainWindow.xaml"
System.Windows.Application.LoadComponent(this, resourceLocater);
I already played around a bit and tried to use an absolute URI but LoadComponent
only accepts relative ones.
Some internet searching shows that a lot of people use Ninject Interception and DynmaicProxy for WPF binding (INotifyPropertyChanged), so I think in general it should be possible to build a proxy of a WPF window.
But how?