0

Im looking for a way to always intercept an instance of a specific class as soon as its properties are used..

For instance if MyTestClass would be intercepted..this would trigger the interception:

var myObj = new MyTestClass();
var x = myObj.SomeProperty;

that would then intercept the method "get_SomeProperty".. however all the examples that I have seen using Unity requires me to "pipe" the creation of the instance of MyTestClass through container.Resolve();.. I would like to avoid that.. is it possible?.. Im pretty sure I have done something like this using Castle.DynamicProxy once before.. but my current application just so happened to have Unity installed so it seamed like a good idea to re-use Unity as far as possible.

Another reason for not using the container.Resolve() is that this instance of mine might as well be created inside an MVC action, which doesnt have a logical reference to the container.. and I dont think that injecting the MyTestClass as a paramter to the constructor would be a very good idea..

Br, Inx

Inx51
  • 1,911
  • 3
  • 24
  • 44

3 Answers3

2

Ok, so here goes...

First suppose we have this domain class definition:

public interface IInterceptableClass
{
    string FirstName { get; set; }
    string LastName { get; }
    string GetLastName();
}

public class InterceptableClass : IInterceptableClass
{
    public string FirstName { get; set; }
    public string LastName { get; private set; }

    public InterceptableClass()
    {
        LastName = "lastname";
    }

    public string GetLastName()
    {
        return LastName;
    }
}

And suppose you have a simple interceptor behavior defined like so:

internal class SampleInterceptorBehavior : IInterceptionBehavior
{
    public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    {
        // this invokes the method at the tip of the method chain 
        var result = getNext()(input, getNext);

        // method executed with no exceptions (yay)
        if (result.Exception == null)
        {
            //input.Target
            Console.WriteLine($"intercepting: target={input.Target.ToString()}, method={input.MethodBase.Name}");
        }
        else // boo..!
        {
            // handle exception here
            Console.WriteLine($"error! message={result.Exception?.Message}");
        }

        return result;
    }

    public IEnumerable<Type> GetRequiredInterfaces()
    {
        return Type.EmptyTypes;
    }

    public bool WillExecute { get { return true; } }
}

You would wire it up via Unity like this:

    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.AddNewExtension<Interception>();
        container.RegisterType<IInterceptableClass, InterceptableClass>(
            new Interceptor<TransparentProxyInterceptor>(),
            new InterceptionBehavior<SampleInterceptorBehavior>());

        var myInstance = container.Resolve<IInterceptableClass>();

        // just want to illustrate that privae sets are not supported...
        myInstance.FirstName = "firstname";
        var lastname = myInstance.GetLastName();

        Console.ReadLine();
    } 

Note that if you don't use Unity to wire up the interception, you would have to do this manually. For one-offs, some devs might prefer it that way, but in practice I've always found that path to be unsustainable, and with multiple intercepts, quite brutal. So always use Unity, if you can.

If you absolutely have to bypass Unity though, here's how you do it:

        var manualInstance = Intercept.ThroughProxy<IInterceptableClass>(
            new InterceptableClass(), // <-- this could be an already-existing instance as well...
            new TransparentProxyInterceptor(), 
            new IInterceptionBehavior[]
            {
                new SampleInterceptorBehavior()
            });

        manualInstance.FirstName = "firstname";
        var lastname = manualInstance.GetLastName();
code4life
  • 15,655
  • 7
  • 50
  • 82
  • Thanks :).. however.. that uses the container.Resolve to resolve the type/interface the idea was to simply some how tell unity to always intercept a specific type no matter if its created using Resolve(or any DI).. or not.. However I ended up using a simulair approach I guess.. – Inx51 Oct 02 '15 at 14:53
  • I'll update with the non-Unity approach. Just be warned, you have to manually set up the harnessing, so not very intuitive, IMHO. – code4life Oct 02 '15 at 15:47
0

From the docs:

You can use Unity interception as a stand-alone feature with no dependency injection container by using the Intercept class.

The syntax is ugly though.

Tim B
  • 2,340
  • 15
  • 21
  • yeah.. I was sort of hoping to make it as simple as possible.. since thats sort of the main reason for why I would like to use interception in the first place.. the idea is to add some new values to a few properties once they are used – Inx51 Oct 02 '15 at 13:39
0

This is what I ended up doing..

RegisterTypes in UnityConfig (MVC)

  container.RegisterType<IDependencyResolverFactory, DependencyResolverFactory>
                (
                    new InjectionConstructor(container)
                );
container.RegisterType<ISearchModel, SearchModel>(
                new Interceptor(typeof(VirtualMethodInterceptor)),
                new InterceptionBehavior(typeof(SearchModelInterceptionBehaviour)));

IDependencyResolverFactory

public interface IDependencyResolverFactory
    {
        TEntity Resolve<TEntity>();
    }

DependencyResolverFactory public class DependencyResolverFactory : IDependencyResolverFactory { private IUnityContainer _container;

    public DependencyResolverFactory(IUnityContainer container)
    {
        _container = container;
    }

    public TEntity Resolve<TEntity>()
    {
        return _container.Resolve<TEntity>();
    }

    public TEntity Resolve<TEntity>(TEntity type) where TEntity : class
    {
        return (TEntity)_container.Resolve(type.GetType());
    }
}

and then simply in my controller:

    private IDependencyResolverFactory _dependencyResolverFactory;

        public HomeController( IDependencyResolverFactory dependencyResolverFactory)
        {
            _dependencyResolverFactory = dependencyResolverFactory;
        }

public ActionResult Index()
        {
            var x = _dependencyResolverFactory.Resolve<SearchFormViewModel>();
            var p = x.Translations.Age;
            var a = x.Translations.FirstName;
            return View();
        }

hopefully that makes scens to someone except me :P

Inx51
  • 1,911
  • 3
  • 24
  • 44