 |
|
 |
Hello,
I've got an Exception when using this dynamic proxy on methods that contains more than 6 parameters. ( void myMethod(String a,String b,String c,String d,String e,String f,String g) )
The Exception is in method CreateType() from ProxyFactory: retVal = typeBuilder.CreateType();
The message is: {"Branche à un octet en position 9 non conforme. La branche demandée était : 136."} (sorry it's in french but in english it's something like " Division one byte in position 9 non-compliant. The division requested was: 136.")
And the stackTrace is: à System.Reflection.Emit.ILGenerator.BakeByteArray() à System.Reflection.Emit.MethodBuilder.CreateMethodBodyHelper(ILGenerator il) à System.Reflection.Emit.TypeBuilder.CreateTypeNoLock() à System.Reflection.Emit.TypeBuilder.CreateType() à Management.ProxyFactory.CreateType(IProxyInvocationHandler handler, Type[] interfaces, String dynamicTypeName) à Management.ProxyFactory.Create(IProxyInvocationHandler handler, Type objType, Boolean isObjInterface) à Management.Proxy.NewInstance(Type typeObject, String name, MBeanManager mBeanManagerP, NamedGenericValueType[] propertiesXml)
Is any body has the same problem? And is any body find a solution?
Thank you very much.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
hi, this is caused by the type of OpCodes.Br_S which represents a short type and is not sufficent when the generated code is too long. just switch it to OpCodes.Br (remove the _S) in both places (to solve it for void methods also solved by nightjester)
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
I used this code to make a class that uses generics and anonymous delegates to build a simple class that does all of the boilerplate InvokeRequired, Invoke stuff that seems to clog up GUI code. Make sure to apply the fix provided by nightjester for void functions since most real interfaces have atleast some void functions. I had tried to something something similar using attributes but that ended up being too complex and ugly.
The main limitation to this is that you need to make sure the syncObject you pass in is valid over the lifetime you plan on using the proxy. If you have a number of forms you may need to partition your interface into a number of interfaces where everything in an interface can share the same sync object.
Here is the implementation:
public class InvokingProxy : IProxyInvocationHandler { private ISynchronizeInvoke mSyncObject; private Type mObject; private InvokingProxy(Type aObject, ISynchronizeInvoke aSync ) { mObject = aObject; mSyncObject = aSync; }
public static Type NewInstance(Type obj, ISynchronizeInvoke aSync) { return (Type)ProxyFactory.GetInstance().Create( new InvokingProxy(obj, aSync), typeof(Type), true); }
public Object Invoke(Object proxy, System.Reflection.MethodInfo method, Object[] parameters) { if (mSyncObject.InvokeRequired) { return mSyncObject.Invoke((Del0)delegate() { method.Invoke(mObject, parameters); }, null); } else { return method.Invoke(mObject, parameters); } }
private delegate void Del0(); }
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Hi, there is less complex solution for proxy. Something like this:
using System; using System.Runtime.Remoting.Proxies; using System.Runtime.Remoting.Messaging; using System.Reflection;
namespace ConsoleApplication2 { public sealed class TransparentProxy : RealProxy { private object _instance;
private TransparentProxy( object mo, Type type ) : base( type ) { this._instance = mo; }
public override IMessage Invoke( IMessage msg ) { MethodCallMessageWrapper mc = new MethodCallMessageWrapper((IMethodCallMessage)msg);
MethodInfo method = mc.MethodBase as MethodInfo;
object res = method.Invoke( this._instance , ( ( method.Attributes & MethodAttributes.SpecialName ) == MethodAttributes.SpecialName ) ? mc.InArgs : mc.Args );
return new ReturnMessage( res, mc.Args, mc.Args.Length, mc.LogicalCallContext, mc ); }
public static T CreateProxy<T>( object instance ) { if( instance != null ) { T ret = ( T )new TransparentProxy( instance, typeof( T ) ).GetTransparentProxy( ); return ret; } return default( T ); } } }
Logic of proxy can be implemented in Invoke method
Sergey
|
| Sign In·View Thread·PermaLink | 2.13/5 |
|
|
|
 |
|
 |
I tried to correct code to class proxy but get error 'invalid cust', why it can happen ?
and how to corectly implement such a way, if it possible?
thanks
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
hi - great solution, thanks for the cool idea!
i've looked into the code and made some measurements. especially comparing different solutions of the problem at hand. the results:
measurements: ------------- proxy type: (no payload) creation execution overhead - plain implementation: .000 31.250 .000 .0% - static direct wrapper: .000 31.250 .000 .0% - static interface proxy (adorned): .000 218.750 187.500 600.0% - static interface proxy (transp.): .000 203.125 171.875 550.0% - static delegate proxy (adorned): .000 796.875 765.625 2450.0% - static delegate proxy (transp.): .000 781.250 750.000 2400.0% - dynamic code-gen proxy (adorned): 31.250 218.750 187.500 600.0% - dynamic code-gen proxy (transp.): .000 203.125 171.875 550.0% - dynamyc remoting proxy (adorned): .000 1093.750 1062.500 3400.0% - dynamyc remoting proxy (transp.): .000 1046.875 1015.625 3250.0%
proxy type: (heavy payload) creation execution overhead - plain implementation: .000 2187.500 .000 .0% - static direct wrapper: .000 2203.125 15.625 .7% - static interface proxy (adorned): .000 2531.250 343.750 15.7% - static interface proxy (transp.): .000 2515.625 328.125 15.0% - static delegate proxy (adorned): .000 3109.375 921.875 42.1% - static delegate proxy (transp.): .000 3078.125 890.625 40.7% - dynamic code-gen proxy (adorned): .000 2500.000 312.500 14.3% - dynamic code-gen proxy (transp.): .000 2500.000 312.500 14.3% - dynamyc remoting proxy (adorned): .000 3500.000 1312.500 60.0% - dynamyc remoting proxy (transp.): .000 3484.375 1296.875 59.3%
notes on how to read the stats above: 1) - plain implementation: a simple implementation of the interfaces functionality - static direct wrapper: another coded implementation that simply delegates each call to another implementation - static interface proxy: a coded implementation that calls the handler interface in each method - static delegate proxy: a coded implementation that calls a c# delegate in each method - dynamic code-gen proxy: a dynamic implementation according to your solution - dynamic remoting proxy: a dynamic implementation using RealProxy which uses the .net remoting mechanism under the hood 2) adorned vs. transparent: 'adorned' adds some debugging information on each call whereas 'transparent' just performs pure delegation without any overhead of its own. 3) - result times: milliseconds - creation: the time measured for instantiating a proxy note: this normally just occurs once in the test program, so its meaningfulness is low - execution: the time measured for 10'000 iterations of invoking every method of the proxied interface once. - overhead: the time difference between an implementation compared to the plain worker implementation (in ms and percent). 4) no payload vs. heavy payload: without payload the plain implementation only incurs a very low cost whereas the heavy payload performs some expensive computation. this allows to measure the call overhead (no payload) in relation to the real life situation where the proxied object has 'something to do' (heavy payload).
my conclusions: --------------- I) c# delegates are surprisingly costly :-( II) the remoting mechanism is expensive as expected, but might be justified in situations where transparent behavior is desired over multi-tier boundaries and the like. III) the code generation approach need not be any slower than a hand coded solution :-)
further suggestions: -------------------- a) i have replaced the method lookup table in the MetaDataFactory with another approach. for each method of the interface, the generated type gets a static readonly field which gets initialized in a static constructor. that field is then directly used in the method's implementation instead of having to look it up first. this results in a class which can stand entirely on its own and additionally bears the benefit of being somewhat quicker too. b) instead of having to specify whether the given type is an interface or a class by giving an according parameter, the System.Type.IsInterface property should be used. c) the generated interface method implementations should be marked as explicit, thus avoiding problems when an interface combines multiple interfaces with conflicting methods (which would lead to ambiguities). d) the generated code should perform either of a cast or an isinst instruction before returning the result of the handler to the caller of the proxy. this allows for detection or at least defensive behavior in case a handler behaves incorrectly.
problems identified: -------------------- A) the provided implementation has a problem when an interface inherits from another interface which in turn has a base interface: with the recursive approach, the base interface gets implemented twice (as the System.Type.getInterfaces() method already returns an array with all base interfaces). this results in an 'invalid program' exception at runtime when the generated class get loaded by the type loader. B) the provided implementation generates invalid byte code for methods that have parameters but no return type (void).
problem solutions: ------------------ A) in method CreateType() instead of:
if ( isObjInterface ) { type = CreateType( handler, new Type[] { objType }, typeName ); } else { type = CreateType( handler, objType.GetInterfaces(), typeName ); }
use something like:
Type[] interfacesToImplement = null; if ( objType.IsInterface ) { // gets _all_ parent interfaces! Type[] baseInterfaces = objType.GetInterfaces(); if ( baseInterfaces != null ) { interfacesToImplement = new Type[ baseInterfaces.Length + 1 ]; // iterate through the parent interfaces and add them to the // list of interfaces to implement for ( int i = 0; i < baseInterfaces.Length; i++ ) { interfacesToImplement[ i ] = baseInterfaces[ i ]; } // add the given type interfacesToImplement[ baseInterfaces.Length ] = objType; } else { interfacesToImplement = new Type[] { objType }; } } else { interfacesToImplement = objType.GetInterfaces(); } if ( interfacesToImplement == null || interfacesToImplement.Length == 0 ) { throw new ArgumentException( objType.FullName + " has no interfaces to implement", "objType" ); } type = CreateType( handler, interfacesToImplement, typeName );
and remove the recursive call in GenerateMethod() to itself.
B) instead of using OpCodes.Stloc_0/1 and OpCodes.Ldloc_0/1 hard coded in GenerateMethod() we should use a variable which gets initialized correctly in a way similar to:
bool hasReturnValue = !methodInfo.ReturnType.Equals( typeof( void ) ); OpCode opCodeLoadParamArray = hasReturnValue ? OpCodes.Ldloc_1 : OpCodes.Ldloc_0; OpCode opCodeStorParamArray = hasReturnValue ? OpCodes.Stloc_1 : OpCodes.Stloc_0;
code availability: ------------------ i can make the solution available which i have now if anybody desires it. it's not yet on production level from a coding view but already incorporates some of the suggested changes. the solution contains the test program which i used to generate the stats at the beginning. it also contains the various approaches used in the test program.
|
| Sign In·View Thread·PermaLink | 4.25/5 |
|
|
|
 |
|
|
 |
|
 |
There seems to be a problem in generating the proxy if the interface defines a method with many object parameters (for example seven strings) and a return type (string), e.g. string foo(string foo1, string foo2, string foo3, string foo4, string foo5, string foo6, string foo7).
Unfortunately I can't give the correct error message, as the .NET framework is not currently showing it in english..
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
Decent article and a quick and dirty approach to proxy generation, although the feature is called "Reflection Emit" and isn't specific to C#, but to all managed languages that support reflection.
Microsoft MVP, Visual C# My Articles
|
| Sign In·View Thread·PermaLink | 4.00/5 |
|
|
|
 |
|
|
 |
|
 |
Using the CodeDOM which allows you to produce code for any source language. The .NET Framework includes code COMs for C# and VB.NET and the only difference between writing the two (barring a few constructs that aren't supported in each) is instantiating the right code provider class.
Read Generating and Compiling Source Code Dynamically in Multiple Languages[^] and Fun with CodeDOM[^] for more information.
FYI, this is what Visual Studio does to generate typed DataSets and other ADO.NET classes for your projects (using a code provider for the current project language), Web Service clients, and much more. That's how source code is generated for what you do in the designers, wizards, and tools.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer Developer Division Customer Product-lifecycle Experience Microsoft
[My Articles] [My Blog]
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Oke but why go through code dom when you want to generate runtime code?
I get the concept of generating the code in designtime, but what is the benefits of using code dom when generating runtime code?
//Roger
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
When creating abstract (not like an abstract class, but in the general sense) constructs that proxy calls, create objects, etc., you'll typically find it easier to use CodeDOM vs. programming all the explicit IL instructions yourself. This may not always be true, but it typically will be. This is one reason VS uses CodeDOM to generate web service proxies, DataSets, and many other ADO.NET and other classes. It's also used because 1) source code is needed to compile into the same output assembly for your project, 2) people may want to edit the generated source, and 3) it allows languages that have implemented the CodeDOM interfaces to be used to generate source code for that language without having to know about it first. The most generic constructs (all the things necessary for CLI-compliant languages, and maybe a few more things) are best to use so that languages where some constructs don't work (ex: C# supports native pointers while VB.NET does not) aren't violated when generating source code.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer Developer Division Customer Product-lifecycle Experience Microsoft
[My Articles] [My Blog]
|
| Sign In·View Thread·PermaLink | 4.00/5 |
|
|
|
 |
|
|
 |
|
 |
I modify your code:
public interface ITest { void TestFunctionOne(int a, string b); int TestFunctionTwo(int a, string b ); }
The method TestFunctionOne don't work ... Throws a error: "Common Language Runtime detected an invalid program." ... Only if return type is void and parameters not is object. TestFunctionTwo works fine!
Thanks!
Batiati
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
allaog wrote: I have this error!!!! is possible to correct this?
Unfortunately, this error seems to occur when one or more parameters are passed to a method/function that has a void return type.
If anyone knows the 'fix' to correct the emitted assembly to fix the problem, please email or post it.
(of course, if I find it, I'll reply it back to myself).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
In the ProxyFactory.GenerateMethod IL code region, there is an error if a method has a void return value and parameters. When building the parameter array, the IL code uses a local variable at index 1 to temporarily store the array. If the method has a return type, index 0 is the variable that holds the return value. For methods with a void return, there is no return variable and the array variable is at index 0 instead. This causes the array loading section to attempt addressing a variable that does not exist.
My updated code for the IL handler region is included below. I have made 3 changes: 1) declare parameter array variable first - so it is always at index 0 2) Update references to indexes 0 or 1 as appropriate. 3) Added an else block to the block dealing with a null handler. (previously there was no action taken on void methods with null handler- code would throw exception when it attempted to use the handler.)
/// Start code snip here ///
#region( "Handler Method IL Code" ) ILGenerator methodIL = methodBuilder.GetILGenerator(); methodIL.DeclareLocal(typeof(System.Object[]));
if ( !methodInfo.ReturnType.Equals( typeof( void ) ) ) { methodIL.DeclareLocal( methodInfo.ReturnType ); if ( methodInfo.ReturnType.IsValueType && !methodInfo.ReturnType.IsPrimitive ) { methodIL.DeclareLocal( methodInfo.ReturnType ); } }
Label handlerLabel = methodIL.DefineLabel(); Label returnLabel = methodIL.DefineLabel();
methodIL.Emit( OpCodes.Ldarg_0 ); methodIL.Emit( OpCodes.Ldfld, handlerField ); methodIL.Emit( OpCodes.Brtrue_S, handlerLabel );
if (!methodInfo.ReturnType.Equals(typeof(void))) { if (methodInfo.ReturnType.IsValueType && !methodInfo.ReturnType.IsPrimitive && !methodInfo.ReturnType.IsEnum) { methodIL.Emit(OpCodes.Ldloc_0); } else { methodIL.Emit(OpCodes.Ldnull); } methodIL.Emit(OpCodes.Stloc_0); methodIL.Emit(OpCodes.Br_S, returnLabel); } else { methodIL.Emit(OpCodes.Br_S, returnLabel); } methodIL.MarkLabel( handlerLabel ); methodIL.Emit( OpCodes.Ldarg_0 ); methodIL.Emit( OpCodes.Ldfld, handlerField ); methodIL.Emit( OpCodes.Ldarg_0 ); methodIL.Emit( OpCodes.Ldstr, interfaceType.FullName ); methodIL.Emit( OpCodes.Ldc_I4, i ); methodIL.Emit( OpCodes.Call, typeof( DynamicProxy.MetaDataFactory ).GetMethod( "GetMethod", new Type[] { typeof( string ), typeof( int ) } ) );
methodIL.Emit( OpCodes.Ldc_I4, numOfParams ); methodIL.Emit( OpCodes.Newarr, typeof( System.Object ) ); if ( numOfParams > 0 ) { methodIL.Emit(OpCodes.Stloc_0); for (int j = 0; j < numOfParams; j++) { methodIL.Emit(OpCodes.Ldloc_0); methodIL.Emit(OpCodes.Ldc_I4, j); methodIL.Emit( OpCodes.Ldarg, j + 1 ); if ( methodParameters[j].IsValueType ) { methodIL.Emit( OpCodes.Box, methodParameters[j] ); } methodIL.Emit( OpCodes.Stelem_Ref ); } methodIL.Emit(OpCodes.Ldloc_0); }
methodIL.Emit( OpCodes.Callvirt, typeof( DynamicProxy.IProxyInvocationHandler ).GetMethod( "Invoke" ) ); if ( !methodInfo.ReturnType.Equals( typeof( void ) ) ) { if ( methodInfo.ReturnType.IsValueType ) { methodIL.Emit( OpCodes.Unbox, methodInfo.ReturnType ); if ( methodInfo.ReturnType.IsEnum ) { methodIL.Emit( OpCodes.Ldind_I4 ); } else if ( !methodInfo.ReturnType.IsPrimitive ) { methodIL.Emit( OpCodes.Ldobj, methodInfo.ReturnType ); } else { methodIL.Emit( (OpCode) opCodeTypeMapper[ methodInfo.ReturnType ] ); } } methodIL.Emit(OpCodes.Stloc_1); methodIL.Emit( OpCodes.Br_S, returnLabel ); methodIL.MarkLabel( returnLabel ); methodIL.Emit(OpCodes.Ldloc_1); } else { methodIL.Emit( OpCodes.Pop ); methodIL.MarkLabel( returnLabel ); } methodIL.Emit( OpCodes.Ret ); #endregion
///End code snip here ///
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
This code is not working when the return type of a method is an object. This is because there is no cast before assigning the return value from the Invoke method to the result variable.
Fix: Locate that code:
if ( methodInfo.ReturnType.IsValueType ) { ... }
and insert an else statement:
if ( methodInfo.ReturnType.IsValueType ) { ... } else { methodIL.Emit(OpCodes.Castclass, methodInfo.ReturnType); }
That should do it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Great article, I'm wondering if it's also possibly to proxy an interface without using a base implementation? I tried to modify your example, but get a cast error. E.g.:
interface ISomething { void DoIt(); }
public class SomethingProxy : IProxyInvocationHandler { public static object NewInstance() { return ProxyFactory.GetInstance().Create(new SomethingProxy(), typeof(ISomething)); }
public object Invoke(object proxy, System.Reflection.MethodInfo method, object[] parameters) { System.Console.WriteLine("Proxy for method " + method.Name); return null; } }
public void Test() { ISomething = (ISomething) SomethingProxy.NewInstance(); // Cast error }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Found solution, needed to add third argument "true" to the Create() call in NewInstance(). Works like a charm!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi,
I was thinking of using the dynamic proxy approach for lazy-loading. However, there are 2 problems here. First it's quite ridiculous to add interfaces to all business classes ... interfaces are good only where really applicable, forcing this approach for the writing of all business classes is a little bit too much. Second, proxying classes that don't implement interfaces is certainly doable(I managed to tweak your code for the methods only), but it requires that all public properties/methods have to be declared virtual, otherwise upon downcasting the proxy to the original class the original methods are getting called only. So I guess both approaches are not quite suitable for lazy-loading What are your thoughts on this?
Best regards, Deyan Petrov
|
| Sign In·View Thread·PermaLink | 3.50/5 |
|
|
|
 |
 | Great!  Deyan Petrov | 3:52 14 Jan '04 |
|
 |
Hi,
First of all, great code, 10x for sharing it!
I would like to modify your code so that I am able to generate a proxy of any business class in my code(they are not sealed, but don't implement interfaces with all the public methods in them). What would be the effort to do that and can you give me some hints?
10x in advance!
Deyan Petrov
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
You should look into RealProxy and __TransparentProxy.
Those types are built into the framework to support Remoting, and provide exactly the functionality that you were expecting.
Basically, a TransparentProxy can be created to any MBRO (MarshalByRefObject), and the runtime will allow it to be cast to the type for which it proxies.
It then intercepts all method calls through the proxy via an Invoke method which takes an IMessage parameter
|
| Sign In·View Thread·PermaLink | 3.73/5 |
|
|
|
 |