views:

123

answers:

1

I'm creating an interface based on an existing interface for WCF concerns, but I have the "DefineParameter" not setting the parameter names (method parameters of the created type have no name).
Can you see a reason why?

    public static Type MakeWcfInterface(Type iService)
    {
        AssemblyName assemblyName = new AssemblyName(String.Format("{0}_DynamicWcf", iService.FullName));
        String moduleName = String.Format("{0}.dll", assemblyName.Name);
        String ns = iService.Namespace;
        if (!String.IsNullOrEmpty(ns)) ns += ".";

        // Create assembly
        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

        // Create module
        var module = assembly.DefineDynamicModule(moduleName, false);

        // Create asynchronous interface type
        TypeBuilder iWcfService = module.DefineType(
            String.Format("{0}DynamicWcf", iService.FullName),
            TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract
            );

        // Set ServiceContract attributes
        iWcfService.SetCustomAttribute(ReflectionEmitHelper.BuildAttribute<ServiceContractAttribute>(null,
            new Dictionary<string, object>() { 
                { "Name", iService.Name },
                }));

        iWcfService.SetCustomAttribute(ReflectionEmitHelper.BuildAttribute<ServiceBehaviorAttribute>(null,
            new Dictionary<string, object>() {
                    { "InstanceContextMode" , InstanceContextMode.Single }
                })
        );

        foreach (var method in iService.GetMethods())
        {
            BuildWcfMethod(iWcfService, method);
        }

        return iWcfService.CreateType();
    }


    private static MethodBuilder BuildWcfMethod(TypeBuilder target, MethodInfo template)
    {
        // Define method
        var method = target.DefineMethod(
            template.Name,
            MethodAttributes.Abstract | MethodAttributes.Virtual
             | MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.VtableLayoutMask | MethodAttributes.HideBySig,
            CallingConventions.Standard, 
            template.ReturnType,
            template.GetParameters().Select(p => p.ParameterType).ToArray()
            );

        // Define parameters
        foreach (ParameterInfo param in template.GetParameters())
        {
            method.DefineParameter(param.Position, ParameterAttributes.None, param.Name);
        }

        // Set OperationContract attribute
        method.SetCustomAttribute(ReflectionEmitHelper.BuildAttribute<OperationContractAttribute>(null, null));

        return method;
    }
+1  A: 

I got it, so I let you know.
The answer is in the way I used the DefineParameter function.
The GetParameters function returns info about the parameters of a provided method.
But the DefineParameter function set parameter info for all parameters (including return parameter), so postions shift : using DefineParameter, position 0 references the return parameter, and call parameters begin at postion 1.

See the fix :

method.DefineParameter(param.Position+1, ParameterAttributes.None, param.Name);

STFM (see the fu.... manual) :

MethodBuilder.DefineParameter Method @ MSDN

Cheers :)

fredlegrain