2

Does anybody know if it is possible to control the names of the types generated through Castle DynamicProxy? I was hoping to take advantage of the ability to persist the assembly generated by Castle to add some additional classes with some specific functionality to my project, but I would like to be able to control the names of these generated proxy types. Any help would be greatly appreciated.

I actually plan to persist instances of these classes as well as instances of the original classes that are the sources of the proxies with NHibernate. So, I need these names to be consistent across multiple generations of the assembly.

yonkz
  • 23
  • 2
  • 7

2 Answers2

3

I did some interesting digging. Specifying proxy names appears to be possible using an INamingScope, but it is far from straightforward to get the INamingScope wedged in. You would need to create your own ProxyFactoryFactory, which would create a ProxyFactory identical to NHibernate.ByteCode.Castle.ProxyFactory, except it would initilize ProxyGenerator:

public class CustomProxyFactory : AbstractProxyFactory {
    private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator(new CustomProxyBuilder());
    // remainder of code is identical
}

public class CustomProxyBuilder : DefaultProxyBuilder {
    public CustomProxyBuilder() : base(new CustomModuleScope()) {}
}

public class CustomModuleScope : ModuleScope {
    public CustomModuleScope() : base(false, false, new CustomNamingScope(), DEFAULT_ASSEMBLY_NAME, DEFAULT_FILE_NAME, DEFAULT_ASSEMBLY_NAME, DEFAULT_FILE_NAME) {}
}

public class CustomNamingScope : INamingScope {
    public CustomNamingScope() {}

    private CustomNamingScope(INamingScope parent) {
        ParentScope = parent;
    }

    public string GetUniqueName(string suggestedName) {
        // your naming logic goes here
    }

    public INamingScope SafeSubScope() {
        return new CustomModuleScope(this);
    }

    public INamingScope ParentScope { get; private set; }
}

I honestly haven't tried running or compiling any of this. Just digging through the NHibernate and Castle.Core source code. Hopefully it gives you some ideas...

James Kovacs
  • 11,549
  • 40
  • 44
  • I'll give this a shot in the next couple days and let you know how it goes. – yonkz Nov 18 '10 at 21:55
  • Sneaky very sneaky ;) You correctly noted __it is far from straightforward__ and for a reason. It was not exactly meant to be overriden. Anyway if you do, there's an assumption (don't remember if documented) that the naming scope will be consistent - for given `suggestedName` it will **always** return the same unique name (obviously it has to be unique so again, if you call the method twice, it should always return the same second value, and so on). Deserialization process depends on it. – Krzysztof Kozmic Nov 19 '10 at 11:35
  • Hi Krysztof, Will the default implementation of INamingScope in DynamicProxy always generate the same class name when proxying a given class, even on subsequent runs of the application, or will it generate a new name once the app domain has been unloaded and loaded again? Also, what if the class being proxied has been modified between runs? – yonkz Nov 19 '10 at 13:17
  • It only takes name and order into the account. It's best to run write a protorype and try to do whatever you need and see if it works with your scenario – Krzysztof Kozmic Nov 20 '10 at 00:52
  • I keep getting `System.ArgumentException: Duplicate type name within an assembly.` unless I return a randomly generated name, which goes against the documentation: "Implementers must return deterministic names, that is when `GetUniqueName` is called twice with the same suggested name, the same returned name should be provided each time. Non-deterministic return values, like appending random suffices will break serialization of proxies." – Rudey Jun 16 '18 at 20:16
  • If anyone else is running into `System.ArgumentException: Duplicate type name within an assembly.`, see [this GitHub issue](https://github.com/castleproject/Core/issues/380#issuecomment-399849756). – Rudey Jun 25 '18 at 09:11
0

Take a look at the ProxyGenerators project in NHContrib. It allows you to pre-generate NHibernate's lazy loading proxies.

http://nhforge.org/wikis/proxygenerators10/default.aspx

Whether you use the ProxyGenerators or not, you integrate your custom proxies into NHibernate via the Proxy Factory Factory. In hibernate.cfg.xml:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="proxyfactory.factory_class">YOUR_PROXY_FACTORY_FACTORY</property>
  </session-factory>
</hibernate-configuration>
James Kovacs
  • 11,549
  • 40
  • 44
  • I think you're misunderstanding my goal. I don't want to change how the NHibernate proxies work. I want another set of persistent classes derived from existing persistent classes with additional behavior. So if I have a class called Product, I want to generate a proxy class called ProductOverride that derives from Product, that will change behaviors, but also have slightly different database mappings. So, my question is more about DynamicProxy and not really about NHibernate at all. I realize I could accomplish this through some code generation, but I'd rather it happen at runtime. – yonkz Nov 18 '10 at 13:38
  • Why don't you use standard NHibernate inheritance mappings to accomplish this? Why do you even need to mess around with dynamic proxies? – James Kovacs Nov 18 '10 at 16:18
  • Because I don't want to maintain those classes. I'm not looking for an alternative design. I have several. Creating actual classes manually, creating actual classes through code generation. They all result in double the maintenance effort. I'm looking to avoid that. – yonkz Nov 18 '10 at 17:23
  • I'm confused. If you don't want to maintain those classes, where do you intend to place the code? You might be able to do this using AOP, though I'd need to know more about your usage scenarios. – James Kovacs Nov 18 '10 at 17:29
  • There will be no code, other than the interceptors and the code to generate the classes. I fully understand the capabilities of NHibernate, as well as how it uses Castle DynamicProxy. What I want is similar to AOP, in that I want to use interception, but I want to persist the proxies as first class entities, so that they can be rehydrated and used seperate from the classes they are based on. So, back to my original quesiton: Do you know if it is possible to control the naming of the proxies generated by Castle DynamicProxy? If it is not possible, it is not possible. – yonkz Nov 18 '10 at 17:56