3

I've been struggling to find anything online, so I thought I'd see if anyone else knows how to sort this little issue I'm having.

I've got a scenario where I want to create a proxy object so that various other interfaces can be added to the same object. So far, I've not had any issues with this. One of my other requirements is to be able to set an attribute on the proxy-generated class.

I've been able to do this successfully using Castle DynmaicProxy manually, using something along the lines of:

var serviceOptions = new ProxyGenerationOptions();

// Create MyAttribute
var args = new object[] { "SomeName" };
var constructorTypes = new[] { typeof(String) };
var constructorInfo = typeof(MyAttribute).GetConstructor(constructorTypes);
var attributeBuilder = new CustomAttributeBuilder(constructorInfo, args);

serviceOptions.AdditionalAttributes.Add(attributeBuilder);

However, I'm using windsor to resolve my dependencies through injection. Windsor does provide some proxy options, such as:

configurer.Proxy.AdditionalInterfaces(interfaces);
configurer.Proxy.MixIns(r => r.Component(type));

But it does not seem to offer options for custom attributes. Does anyone know how this can be achieved? Many thanks.

Adam Goss
  • 1,017
  • 3
  • 14
  • 22

2 Answers2

2

In the end, I found an alternative solution from taking Phil's idea and from scanning the Castle source.

I created a custom ProxyFactory class that extends the DefaultProxyFactory from the Castle.Windsor assembly. The only method I implemented was the CustomizeOptions method, which by default, is empty.

From here, I hook into the ExtendedProperties of ComponentModel to get a collection of CustomAttributeBuilder instances I add when registering my components.

Full code below:

internal const string PROXY_ATTRIBUTES_PROPERTY_KEY = "custom.proxy.attributes";

protected override void CustomizeOptions(ProxyGenerationOptions options, IKernel kernel, ComponentModel model, object[] arguments)
{
    if (model.ExtendedProperties.Contains(PROXY_ATTRIBUTES_PROPERTY_KEY))
    {
        var proxyAttributes = (IEnumerable<CustomAttributeBuilder>)model.ExtendedProperties[PROXY_ATTRIBUTES_PROPERTY_KEY];
        foreach (var attribute in proxyAttributes)
        {
            options.AdditionalAttributes.Add(attribute);
        }
    }

    base.CustomizeOptions(options, kernel, model, arguments);
}

configurer.ExtendedProperties(new Property(CustomProxyFactory.PROXY_ATTRIBUTES_PROPERTY_KEY, configurator.ProxySettings.CustomAttributes));
Adam Goss
  • 1,017
  • 3
  • 14
  • 22
1

The standard ProxyGroup provides access to a subset of the proxy generation options. However, it is relatively straight forward to create your own descriptor to modify other options and add it to the component registration. The trick is to use an extension method to retrieve the proxy options used by the built-in ProxyGroup registration helper.

public class ProxyCustomAttributeBuilderDescriptor : IComponentModelDescriptor
{
    public void BuildComponentModel(IKernel kernel, ComponentModel model)
    {
        var options = model.ObtainProxyOptions();    
        // ... do whatever you need to customise the proxy generation options
    }

    public void ConfigureComponentModel(IKernel kernel, ComponentModel model)
    {
    }
}

Then when you register your component simply add this descriptor:

configurer.AddDescriptor(new ProxyCustomAttributeBuilderDescriptor());
Phil Degenhardt
  • 7,215
  • 3
  • 35
  • 46