我正在使用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个方法需要向服务公开,将它们放入服务中需要大量输入。所以,从本质上讲,我希望可能有一种方法来传递一个类,返回所有方法,并将它们或多或少地“注入”到接口/类中。
答案 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)然后你拥有它:
f)如果您想在IIS中托管此服务,则必须提供自己的自定义ServiceHostFactory