反映A类,在接口和实现类中重现方法?

时间:2013-12-06 21:59:48

标签: c# wcf reflection

我正在使用WCF,它使用接口,操作契约和所有爵士来公开相关方法。

但是,如果假设一个单独的类包含所有方法,而不是基本上在实现所述接口的接口/类上编写相同的方法签名,那么它会使用一些voodoo自动使这些方法在接口/类。例如,请考虑以下事项:

[ServiceContract]    
public interface IService {

    [OperationContract]
    List<Foo> SelectAllFoo(string id);    
}    

public class Service : IService {

    public List<Foo> SelectAllFoo(string id)
    {
        // this just calls same method from Helpers class, same sig    
        return Helpers.SelectAllFoo(id);
    }    
}

我有500个方法需要向服务公开,将它们放入服务中需要大量输入。所以,从本质上讲,我希望可能有一种方法来传递一个类,返回所有方法,并将它们或多或少地“注入”到接口/类中。

1 个答案:

答案 0 :(得分:3)

使用Reflection:

可以解决您的问题

a)使用Reflection来枚举您感兴趣的类中的所有公共方法,例如:

var methods = typeof(SomeClass).GetMethods(BindingFlags.Instance | BindingFlags.Public);

b)使用此列表为您的服务生成字符串

的源代码
StringBuilder source = new StringBuilder();
source.AppendLine("using System;");
source.AppendLine("using System.ServiceModel;");
source.AppendLine("[ServiceContract]");
source.AppendLine("public class DynamicService {");
// Here for each MethodInfo from list generate a method source like
foreach (var method in methods)
{
    if (method.ReturnType == typeof(void))
        continue;
    string parameters = string.Join(", ", method.GetParameters().Select(pi => string.Format("{0} {1}", pi.ParameterType.Name, pi.Name)));
    string arguments = string.Join(", ", method.GetParameters().Select(pi => pi.Name));
    source.AppendFormat("[OperationContract]");
    source.AppendFormat("public {0} {1}({2})", method.ReturnType.Name, method.Name, parameters);
    source.AppendFormat("{{   return ConsoleApplication.Helpers.{0}({1}); }}", method.Name, arguments);
}
source.AppendLine("}");

注意:您需要在此处进行一些过滤,例如过滤掉ToString等。例如,我绕过了所有的void方法。

c)使用CSharpCodeProvider编译服务来源:

CSharpCodeProvider codeProvider = new CSharpCodeProvider();
System.CodeDom.Compiler.CompilerParameters param = new CompilerParameters();
param.GenerateExecutable = false;
param.GenerateInMemory = true;
param.ReferencedAssemblies.Add("System.Runtime.Serialization.dll");
param.ReferencedAssemblies.Add("System.ServiceModel.dll");
param.ReferencedAssemblies.Add("System.dll");
param.ReferencedAssemblies.Add("ConsoleApplication.exe");
CompilerResults result = codeProvider.CompileAssemblyFromSource(param, source.ToString());

注意:在这里,您可以在我的示例中添加对包含帮助程序类ConsoleApplication.exe的程序集的引用。

d)将您的动态服务用作普通服务。例如,您可以自行托管它:

if (!result.Errors.HasErrors)
{
    Type type = result.CompiledAssembly.GetType("DynamicService");
    var instance = Activator.CreateInstance(type);

    Uri baseAddress = new Uri("http://localhost:80/hello");
    using (ServiceHost host = new ServiceHost(type, baseAddress))
    {
        ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
        smb.HttpGetEnabled = true;
        smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
        host.Description.Behaviors.Add(smb);

        host.Open();

        Console.WriteLine("The service is ready at {0}", baseAddress);
        Console.WriteLine("Press <Enter> to stop the service.");
        Console.ReadLine();

        // Close the ServiceHost.
        host.Close();
    }
}

e)然后你拥有它:

enter image description here

f)如果您想在IIS中托管此服务,则必须提供自己的自定义ServiceHostFactory