This project has moved. For the latest updates, please go here.

How to overcome current Out and Ref parameters limitation?

Coordinator
Aug 6, 2011 at 6:27 PM

i've an idea that will allows to have the syncwcf library work correctly with methods that have out and ref parameters, but this will require to generate proxy of a such complexity that is probably better to use a stable and tested library  such castle.core

originally the idea of this project was to not have dependency other than the basic silverlight assemblies.

how important is for you to have the out and ref parameter managed correctly ? is it worth to add a reference to castle.core and then create a dependency between the two projects?

Anyone have another idea to solve the issue?

I think that include the source code of castle.core directly in the syncwcf is not a good idea, itlooks like stole the great work of the castle team....

the problem is the following:

susppose the wcf service interface exposes a method with out and/or ref parameters:

public interface IService
{
   int Operation(int a, out int b, out ref c);
}

assuming this is implemented at server side as following

class Service : IService
{
    public int Operation(int a, out int b, ref int c)
    {
       //kust to modify b, and c, it could be anything!
       c ++;
       b = a - c;
       return a + b + c;  
    }
}

 

if we call this using sync wcf it will become

int a = 1;
int b;
int c = 3;

service.ExecuteAsync(
     ws=>ws.Operation(a,out b, ref c),
     result => 
     {
         //do something with result....
         //but b and c are the same as they was when the
         //method was called!
         //no mather if the webservice have changed them!
         //here 
         //a is 1 (correctly as is by value)
         //b is still unasigned (not correct)
         //c is 3 (depends of what the webservice does)
     });

i would like to have b and c correctly modified in the "result" lambda.

  that's quite triky...

my current idea is:

compile the expression for the invokation of the operation : i should obtain a function or an action depends if  the operation returns something or not, it's not important, the point is that it takes an argument of type TSync, i call this delegate "syncOperation" for reference.

then i perform the normal workflow implemented in the library but at the moment of the dispatching of the returned value, i'll take out the array of modified parameters from the asynchonous EndOperation version of the WCF proxy, then i'll create a new special proxy that implements the synchronous interface (that the delegate syncOperation obtained before can handle).

this special proxy takes also the array of objects returned by the webservice call, and its work is to assign the correct value to the correct parameter of the method Operation when this is called.

at this point i'll invoke syncOperation delegate on my special proxy. it will in turn assign the returned values to b and c and at the end i will call the "result" lambda.

at that moment b and c will have the correct value....

what you think about it? do you see an easier way ?

 

 

Coordinator
Aug 9, 2011 at 9:44 AM

ok i have analyzed the situation and i have several choiches.

  • creating a simple proxy that implement the interface of the service: work probability 100%, medium implementation complexity, very bug prone
  • transform the invokationRequest in a dynamic expression and pass a dynamic object that act as aproxy: work probability 90%, mid - low implementation complexity, almost bug free
  • create a proxy using the DLR and allow casting of this proxy to a given interface intercepting the calls: work probability 15%, mid-high implementation complexity, bug free and reusable.there is also a 4th option that is use

the expression.CompileToMethod, that is similar to 1 but reduce the error probability. unfortunately there are still limitation in the API and it is not possible compile to instance method. and this makes this option useless for our purposes :( sad.

i think i'll try with 2 first and in case switch back to 1

any idea?

 

Coordinator
Aug 10, 2011 at 9:57 AM

ah! i've found 2 solution that works (both tested).

now i've to choose the best one and every one has pro and cons

  1. emit a proxy that implements the interface, and derives from a base proxy class. all the code in the instance method is auto generated and simply forwards the call to a "static" version of the method itselfs that takes as first argument an object of the base type of the proxy. this allows me to use "CompileToMethod" and therefore have 100% checked code that work for sure: done yesterday, it work
  2. taking the expression tree of the remote method invokation eextract the argument find out which are "by ref", then create a lambda with a code block and insert as many assignment operation as the by ref argument are, by assigning constant. also this works

1 is faster

2 is elegant

anyway i don't know what to choose. i think i'll use 2 first and then if some problem arise will witch to 1, as 2 looks much more secure interms of code generation: i don't have to outpunt any opcode with this solution, moreover, Expression.Compile code is garbage-collectable and therefore no issue of running out of ram, just some performance penalty... but  considering this will happen at return of an async call of a method over the wire.... it may be that the introduced delay will be irrilevant inthe common case: if i have time i'll do a perf test to verify this.

again... any ideas? :)

 

Coordinator
Aug 10, 2011 at 12:23 PM

solution 2 implemented in the last release :) solution 1 ready in the test bay :)