I created a simple program as a PoC for an old SharePoint On-Prem project that uses ASP.NET Webforms. In its pages, I have to use property injection, and for everything else, I can use constructor injection. I am also using:
- Ninject.Extensions.Factory
- Ninject.Extensions.Interception
- Ninject.Extensions.Interception.DynamicProxy
Everything was working relatively well until I added interceptors and used Lazy<> to tackle some cyclic dependencies. To simplify this in an example, I've written the following example as a console application:
public class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(
new NinjectSettings() { LoadExtensions = false },
new DynamicProxyModule(),
new FuncModule());
kernel.Bind<ISomeClass>().To<SomeClass>();
kernel.Bind<IOtherClass>().To<OtherClass>();
kernel.Bind<IAnotherClass>().To<AnotherClass>();
kernel.Intercept(p => true).With(new ClassInterceptor()); // Removing this works, but I need the interceptors.
ISomeClass someClass = kernel.TryGet<ISomeClass>();
someClass.Foo();
}
public interface ISomeClass
{
void Foo();
}
public class SomeClass : ISomeClass
{
[Inject]
public IOtherClass OtherClass { get; set; }
public SomeClass() { }
public void Foo()
{
Console.WriteLine("Foo");
this.OtherClass.Bar();
}
}
public interface IOtherClass
{
void Bar();
}
public class OtherClass : IOtherClass
{
private readonly Lazy<IAnotherClass> _anotherClass;
public IAnotherClass AnotherClass { get { return this._anotherClass.Value; } }
public OtherClass(Lazy<IAnotherClass> anotherClass)
{
this._anotherClass = anotherClass;
}
public void Bar()
{
Console.WriteLine("Bar");
}
}
public interface IAnotherClass
{
void FooBar();
}
public class AnotherClass : IAnotherClass
{
private readonly Lazy<IOtherClass> _otherClass;
public IOtherClass OtherClass { get { return this._otherClass.Value; } }
public AnotherClass(Lazy<IOtherClass> otherClass)
{
this._otherClass = otherClass;
}
public void FooBar()
{
Console.WriteLine("FooBar");
this.OtherClass.Bar();
}
}
public class ClassInterceptor: SimpleInterceptor
{
public ClassInterceptor() { }
protected override void BeforeInvoke(IInvocation invocation)
{
base.BeforeInvoke(invocation);
Console.WriteLine("I'm doing stuff before.");
}
protected override void AfterInvoke(IInvocation invocation)
{
base.BeforeInvoke(invocation);
Console.WriteLine("I'm doing stuff after.");
}
}
}
As a result, I am getting the following error:
Unhandled Exception: System.TypeLoadException: Could not load type 'Castle.Proxies.Func`2Proxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=a621a9e7e5c32e69' because the parent type is sealed.
If I remove the "Lazy<>", it will re-introduce cyclic dependencies. If I remove interception, it will not have any errors, but I need the interceptors. And, I have to use property injection on the pages because the constructors of the pages are managed by webforms with no helpful hooks like there are in MVC land. NOTE: webforms are being used because SharePoint 2013 is being used.
Any ideas how to keep both interception and Lazy<> declarations without encountering the error above?