I'm trying to use the code from this page, http://docs.castleproject.org/Windsor.Introduction-to-AOP-With-Castle.ashx and register an interceptor in a fluent manner.
But I get this error thrown. I've tried Castle Windsor versions from 2.5 to 3.3. So it must be something very basic in how interceptors are set up
Classes
public interface ISomething
{
Int32 Augment(Int32 input);
void DoSomething(String input);
Int32 Property { get; set; }
}
class Something : ISomething
{
public int Augment(int input) {
return input + 1;
}
public void DoSomething(string input) {
Console.WriteLine("I'm doing something: " + input);
}
public int Property { get; set; }
}
public class DumpInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation) {
Console.WriteLine("DumpInterceptorCalled on method " +
invocation.Method.Name);
invocation.Proceed();
if (invocation.Method.ReturnType == typeof(Int32)) {
invocation.ReturnValue = (Int32)invocation.ReturnValue + 1;
}
Console.WriteLine("DumpInterceptor returnvalue is " +
(invocation.ReturnValue ?? "NULL"));
}
}
Setup
Console.WriteLine("Run 2 - configuration fluent");
using (WindsorContainer container = new WindsorContainer())
{
container.Register(
Component.For<IInterceptor>()
.ImplementedBy<DumpInterceptor>()
.Named("myinterceptor"));
container.Register(
Component.For<ISomething>()
.ImplementedBy<Something>()
.Interceptors(InterceptorReference.ForKey("myinterceptor")).Anywhere);
ISomething something = container.Resolve<ISomething>(); //Offending row
something.DoSomething("");
Console.WriteLine("Augment 10 returns " + something.Augment(10));
}
Error
Type 'Castle.Proxies.ISomethingProxy' from
assembly'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null' is attempting to implement an inaccessible
interface.
The answer
So I found why this was happening. Appearantly if you create inner classes and interfaces you can register and resolve them but attaching interceptors to them won't work
Example - where the error will be triggered
class Program
{
public static void Main(String [] args)
{
var container = new WindsorContainer();
container.Register(Component.For<TestInterceptor>().Named("test"));
container.Register(Component.For<InnerInterface>().ImplementedBy<InnerClass>().Interceptors(InterceptorReference.ForKey("test")).Anywhere);
// this row below will throw the exception
var innerClassInstance = container.Resolve<InnerInterface>();
}
class InnerClass : InnerInterface { }
interface InnerInterface { }
class TestInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
throw new NotImplementedException();
}
}
}
Conclusion
So to conclude my intention was not to create inner classes in the first place but rather put together a demo to showcase Castle Windsor. But maybe this can help someone if they run into the same error as me..
Related
I want to register open generic interception, so I modified explample from https://github.com/dadhi/DryIoc/blob/master/docs/DryIoc.Docs/Interception.md
[TestFixture]
public class UnitTest3
{
public interface IFoo<T>
{
void Greet();
}
public class Foo<T> : IFoo<T>
{
public void Greet() { }
}
[Test]
public void Example()
{
var container = new Container();
container.Register(typeof(IFoo<>), typeof(Foo<>));
container.Register<FooLoggingInterceptor>(Reuse.Singleton);
container.Intercept<FooLoggingInterceptor>(typeof(IFoo<>));
var foo = container.Resolve<IFoo<int>>();
foo.Greet();
// examine that logging indeed was hooked up
var logger = container.Resolve<FooLoggingInterceptor>();
Assert.AreEqual("Invoking method: Greet", logger.LogLines[0]);
}
}
public class FooLoggingInterceptor : IInterceptor
{
public List<string> LogLines = new List<string>();
private void Log(string line) => LogLines.Add(line);
public void Intercept(IInvocation invocation)
{
Log($"Invoking method: {invocation.GetConcreteMethod().Name}");
invocation.Proceed();
}
}
public static class DryIocInterception
{
private static readonly DefaultProxyBuilder _proxyBuilder = new DefaultProxyBuilder();
public static void Intercept<TInterceptor>(this IRegistrator registrator, Type serviceType, object serviceKey = null)
where TInterceptor : class, IInterceptor
{
Type proxyType;
if (serviceType.IsInterface())
proxyType = _proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(
serviceType, ArrayTools.Empty<Type>(), ProxyGenerationOptions.Default); //Exception!!!
else if (serviceType.IsClass())
proxyType = _proxyBuilder.CreateClassProxyTypeWithTarget(
serviceType, ArrayTools.Empty<Type>(), ProxyGenerationOptions.Default);
else
throw new ArgumentException(
$"Intercepted service type {serviceType} is not a supported, cause it is nor a class nor an interface");
registrator.Register(serviceType, proxyType,
made: Made.Of(pt => pt.PublicConstructors().FindFirst(ctor => ctor.GetParameters().Length != 0),
Parameters.Of.Type<IInterceptor[]>(typeof(TInterceptor[]))),
setup: Setup.DecoratorOf(useDecorateeReuse: true, decorateeServiceKey: serviceKey));
}
}
But this throws exception:
Can not create proxy for type TestDryIoc.UnitTest3+IFoo`1 because type
TestDryIoc.UnitTest3+IFoo`1 is an open generic type.
Aparently Castle.Core doesn't support open generics. My other idea was to supply delegate, which will create the proxy class on resolve, when concrete generic param is known, but looks like DryIoc doesn't support open generic delegates...
Yeah, it is possible. So you need to find the closed type to pass it to the proxy? Wrap the code into the method and use the Made.Of which has access to the Request.ServiceType.
I am using Structure Map as my DI container and I would like to use this to setup some aspect oriented logging. (I am using version 4.7.0)
Using RealProxy I have created a 'DynamicProxy' class to intercept methods before and after they are executed and perform logging (in the example this is just writing to the console).
Logging class:
public class DynamicProxy<T> : RealProxy
{
private readonly T _decorated;
public DynamicProxy(T decorated)
: base(typeof(T)) =>
this._decorated = decorated;
private void Log(string msg, object arg = null)
{
Console.WriteLine(msg, arg);
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase as MethodInfo;
var inputMessage = new StringBuilder();
inputMessage.Append($"Before execution of: '{methodCall.MethodName}' ");
for (int i = 0; i < methodCall.ArgCount; i++)
inputMessage.Append($"Arg: '{methodCall.GetArgName(i)}' value = '{methodCall.GetArg(i)}'");
Log(inputMessage.ToString());
try
{
var result = methodInfo.Invoke(this._decorated, methodCall.InArgs);
var returnValue = methodInfo.ReturnType == typeof(void) ? "void" : result.ToString();
Log($"After execution of '{methodCall.MethodName}'. Return value was '{returnValue}'");
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
catch (Exception e)
{
Log(string.Format(
"In Dynamic Proxy- Exception {0} executing '{1}'", e),
methodCall.MethodName);
return new ReturnMessage(e, methodCall);
}
}
I have then created a helper method to create concrete implementations of interfaces wrappered in the Dynamic proxy:
public class Factory
{
public static InterfaceType CreateDynamic<InterfaceType, ConcreteType>(params object[] args) where ConcreteType : InterfaceType
{
var decorated = (ConcreteType) Activator.CreateInstance(typeof(ConcreteType), args);
var dynamic = new DynamicProxy<InterfaceType>(decorated);
return (InterfaceType) dynamic.GetTransparentProxy();
}
}
Using StructureMap I can then setup my container to return instances wrappered in my Proxy. For example I have the following working as expected:
This is the interface / implementation I have used to experiment with:
public interface IDoSomething
{
void Work1(string additional);
double Work2();
}
public class DoSomething : IDoSomething
{
private string message;
public DoSomething(string message)
{
this.message = message;
}
public void Work1(string additional)
{
Console.WriteLine("Method Work 1 :{0} {1}", this.message, additional);
}
public double Work2()
{
Console.WriteLine("Method Work 2 Makes Pi :{0}", this.message);
return Math.PI;
}
}
And this is my Program
class Program
{
static void Main(string[] args)
{
Console.WriteLine("DoSomething with proxy, created through DI:");
var container = new Container(_ =>
{
_.For<IDoSomething>().Use(x => Factory.CreateDynamic<IDoSomething, DoSomething>("message from DI"));
});
Console.WriteLine();
Console.WriteLine();
var somethingElse = container.GetInstance<IDoSomething>();
somethingElse.Work1("Hello");
Console.ReadLine();
}
}
It outputs as expected, showing me the messages from the proxy class and the message passed in on the constructor
However, there are some limitations to this approach that I am having trouble overcoming:
How do I setup my container so that every interface is created wrappered in the proxy?
This implementation fails when the concrete implementation itself requires an interface, so is there way of integrating this into StructureMap? I have seen this done with SimpleInjector (https://simpleinjector.readthedocs.io/en/latest/aop.html#interception) but I have not been able to see how this is done in StructureMap, but I imagine there must be a way of making this happen. Maybe using reflection and recursion? (I cannot use SimpleInjector because of its reliance on a single constructor and PostSharp is expensive).
I am using Autofac. Let's say I have an covariant interface
interface IOptionFactory<out T> where T : IOption
and specific implementations
class Option1Factory : IOptionFactory<Option1>
class Option2Factory : IOptionFactory<Option2>
I register them as
container.RegisterType<Option1Factory>.As<IOptionFactory<Option1>>();
container.RegisterType<Option2Factory>.As<IOptionFactory<Option2>>();
Is there a way, how to resolve all implementations of IOptionFactory? Because this is covariant, this should be legal in C# (am I right?). Something like:
var factories = container.Resolve<IEnumerable<IOptionFactory<IOption>>>();
The best solution is to wrap your code in a Reporting class with a private IEnumerable property of IOptionFactory<IOption>.
private class Reporting
{
private IEnumerable<IOptionFactory<IOption>> _allOptionsFactories;
public Reporting(IEnumerable<IOptionFactory<IOption>> allOptionsFactories)
{
if (allOptionsFactories == null)
{
throw new ArgumentNullException("Parameter:" + nameof(allOptionsFactories));
}
this._allOptionsFactories = allOptionsFactories;
}
public void Report()
{
foreach (var optionsFactories in _allOptionsFactories)
{
Console.WriteLine(optionsFactories.GetType());
}
}
}
And then you can register and use them with:
[TestMethod]
public void PassingParametersToRegister_NamedParameter()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<IOption1Factory1<SomeOption>>().As<IOptionFactory<IOption>>();
builder.RegisterType<IOption1Factory2<SomeOption>>().As<IOptionFactory<IOption>>();
builder.RegisterType<Reporting>();
using (var container = builder.Build())
{
container.Resolve<Reporting>().Report();
}
//OUTPUT:
//Enumerations + IOption1Factory1`1[Enumerations + SomeOption]
//Enumerations + IOption1Factory2`1[Enumerations + SomeOption]
}
Here is the entire code in my github
I currently wrote an Interceptor which code is below
public class TransactionalInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
using (var transaction = ...)
{
try
{
invocation.Proceed();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
}
}
}
but when register this interceptor it will apply to all methods. I have a service class with a repository injected having CRUD methods.
I don't want a transaction to be opened for query methods.
I read this link but I cannot figure out how to apply it to my code
http://docs.autofac.org/en/latest/advanced/adapters-decorators.html#decorators
I don't know who to refactor my TransactionalInterceptor (and register it) to use it in a class like this code
[Intercept(typeof(LoggerInterceptor))] //logger
public class SomeService : ISomeService
{
private readonly ISomeRepository someRepository;
public SomeService(SomeRepository someRepository)
{
this.someRepository = someRepository;
}
public IEnumerable<SomeDto> GetAll()
{
// code
}
public SomeDto GetById()
{
// code
}
[Transactional]
public int Create(SomeDto someDto)
{
// code to insert
}
}
The invocation parameter of the Intercept method contains a Method property which is a MethodInfo of the method currently intercepted.
You can use this property to do what you want.
For example by using the method name :
public void Intercept(IInvocation invocation)
{
if (invocation.MethodInvocationTarget.Name != nameof(ISomeService.Create))
{
invocation.Proceed();
return;
}
using (var transaction = ...)
{
try
{
invocation.Proceed();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
}
}
or based on an attribute from the target method :
if (!invocation.MethodInvocationTarget
.CustomAttributes
.Any(a => a.AttributeType == typeof(TransactionalAttribute)))
You can also use the IInterceptorSelector type but it requires more work to register it with Autofac
I solved the problem with ProxyGenerationHook. See the answer
Create your custom attribute for selecting which method to intercept. This attribute's target should be Method.
[System.AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
sealed class UseInterceptorAttribute : Attribute
{
public UseInterceptorAttribute()
{
}
}
Create your service interface and service class:
public interface ISomeService
{
void GetWithoutInterceptor();
[UseInterceptor]
void GetWithInterceptor();
}
public class SomeService
{
void GetWithoutInterceptor()
{
//This method will not be intercepted...
}
[UseInterceptor]
void GetWithInterceptor()
{
//This method will be intercepted...
}
}
Create your ProxyGenerationHook
public class SomeServiceProxyGenerationHook : IProxyGenerationHook
{
public void MethodsInspected()
{
}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
{
}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
return methodInfo
.CustomAttributes
.Any(a => a.AttributeType == typeof(UseInterceptorAttribute));
}
}
Don't use attributes for enabling interceptors. Enable it when
registering your service like this:
public class AutofacDependencyResolver
{
private readonly IContainer _container;
public AutofacDependencyResolver()
{
_container = BuildContainer();
}
private IContainer BuildContainer()
{
var proxyGenerationOptions = new ProxyGenerationOptions(new ProductServiceProxyGenerationHook());
builder.RegisterType<SomeService>()
.As<ISomeService>()
.EnableInterfaceInterceptors(proxyGenerationOptions)
.InterceptedBy(typeof(TransactionalInterceptor))
builder.Register(c => new TransactionalInterceptor());
return builder.Build();
}
public T GetService<T>()
where T:class
{
var result = _container.TryResolve(out T serviceInstance);
return serviceInstance ?? throw new Exception($"The service could not found: {nameof(T)}");
}
}
This solution is following this article
Also I uploaded the minimal example about this solution.
also can try, it is simple https://fs7744.github.io/Norns.Urd/index.html
public class AddTenInterceptorAttribute : AbstractInterceptorAttribute
{
public override void Invoke(AspectContext context, AspectDelegate next)
{
next(context);
AddTen(context);
}
private static void AddTen(AspectContext context)
{
if (context.ReturnValue is int i)
{
context.ReturnValue = i + 10;
}
else if(context.ReturnValue is double d)
{
context.ReturnValue = d + 10.0;
}
}
public override async Task InvokeAsync(AspectContext context, AsyncAspectDelegate next)
{
await next(context);
AddTen(context);
}
}
[AddTenInterceptor]
public interface IGenericTest<T, R> : IDisposable
{
// or
//[AddTenInterceptor]
T GetT();
}
I am probably missing something extremely simple.
I am just trying to write a very minimalistic example of usage of DynamicProxy - I basically want to intercept the call and display method name and parameter value. I have code as follows:
public class FirstKindInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("First kind interceptor before {0} call with parameter {1} ", invocation.Method.Name, invocation.Arguments[0]);
invocation.Proceed();
Console.WriteLine("First kind interceptor after the call");
}
}
public interface IFancyService
{
string GetResponse(string request);
}
public class FancyService : IFancyService
{
public string GetResponse(string request)
{
return "Did you just say '" + request + "'?";
}
}
class Program
{
static void Main(string[] args)
{
var service = new FancyService();
var interceptor = new FirstKindInterceptor();
var generator = new ProxyGenerator();
var proxy = generator.CreateClassProxyWithTarget<IFancyService>(service, new IInterceptor[] { interceptor } );
Console.WriteLine(proxy.GetResponse("what?"));
}
}
However, when I run it I get a following exception:
Unhandled Exception: System.ArgumentException: 'classToProxy' must be
a class Parameter name: classToProxy
What am I missing?
The error is that CreateClassProxyWithTarget needs to be a type of class not interface. CreateInterfaceProxyWithTarget uses an interface.