加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 使用反射动态调用WCF服务

发布时间:2020-12-15 22:07:55 所属栏目:百科 来源:网络整理
导读:我在使用反射调用时将泛型集合传递给WCF服务方法时遇到问题.具体而言,该集合的类型为List KeyValuePair string,string. 我的目标是能够在运行时动态执行WCF服务的方法,而无需在我的客户端应用程序中添加任何对服务的引用.用户应该能够在运行时添加服务,应用
我在使用反射调用时将泛型集合传递给WCF服务方法时遇到问题.具体而言,该集合的类型为List< KeyValuePair< string,string>>.

我的目标是能够在运行时动态执行WCF服务的方法,而无需在我的客户端应用程序中添加任何对服务的引用.用户应该能够在运行时添加服务,应用程序应该能够神奇地处理它.

服务接口

[ServiceContract]    
public interface ITestService
{
    [OperationContract]
    string ProcessSimpleType(string value);
    [OperationContract]
    string ProcessGenericCollection(List<KeyValuePair<string,string>> genericCol);
}

服务实施

public class TestService : ITestService
{
    public string ProcessSimpleType(string value)
    {
        return value;
    }
    public string ProcessGenericCollection(List<KeyValuePair<string,string>> genericCol)
    {
        return "Hello World!";
    }
}

客户代码

try
        {
            Uri mexAddress = new Uri("http://localhost:8732/TestService/?wsdl");
            MetadataExchangeClientMode mexMode = MetadataExchangeClientMode.HttpGet;
            string contractName = "ITestService";
            string operationName = "ProcessGenericCollection";

            List<KeyValuePair<string,string>> list = new List<KeyValuePair<string,string>>();
            list.Add(new KeyValuePair<string,string>("key","value"));


            object[] operationParameters = new object[] { list };

            MetadataExchangeClient mexClient = new MetadataExchangeClient(mexAddress,mexMode);
            mexClient.ResolveMetadataReferences = true;
            MetadataSet metaSet = mexClient.GetMetadata();

            WsdlImporter importer = new WsdlImporter(metaSet);
            Collection<ContractDescription> contracts = importer.ImportAllContracts();
            ServiceEndpointCollection allEndpoints = importer.ImportAllEndpoints();

            ServiceContractGenerator generator = new ServiceContractGenerator();
            var endpointsForContracts = new Dictionary<string,IEnumerable<ServiceEndpoint>>();

            foreach (ContractDescription contract in contracts)
            {
                generator.GenerateServiceContractType(contract);
                endpointsForContracts[contract.Name] = allEndpoints.Where(
                    se => se.Contract.Name == contract.Name).ToList();
            }

            if (generator.Errors.Count != 0)
                throw new Exception("There were errors during code compilation.");

            CodeGeneratorOptions options = new CodeGeneratorOptions();
            options.BracingStyle = "C";
            CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("C#");

            CompilerParameters compilerParameters = new CompilerParameters(
                new string[] { 
                "System.dll","System.ServiceModel.dll","System.Runtime.Serialization.dll" });
            compilerParameters.GenerateInMemory = true;

            CompilerResults results = codeDomProvider.CompileAssemblyFromDom(
                compilerParameters,generator.TargetCompileUnit);

            if (results.Errors.Count > 0)
            {
                throw new Exception("There were errors during generated code compilation");
            }
            else
            {
                Type clientProxyType = results.CompiledAssembly.GetTypes().First(
                    t => t.IsClass &&
                        t.GetInterface(contractName) != null &&
                        t.GetInterface(typeof(ICommunicationObject).Name) != null);

                ServiceEndpoint se = endpointsForContracts[contractName].First();

                object instance = results.CompiledAssembly.CreateInstance(
                    clientProxyType.Name,false,System.Reflection.BindingFlags.CreateInstance,null,new object[] { se.Binding,se.Address },CultureInfo.CurrentCulture,null);


                var methodInfo = instance.GetType().GetMethod(operationName);

                //Invoking the ProcessGenericCollection via reflection will throw an exception
                object retVal = methodInfo.Invoke(instance,BindingFlags.InvokeMethod,operationParameters,null);


                Console.WriteLine(retVal.ToString());
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

抛出的错误是:

{“Object of type
‘System.Collections.Generic.List1[System.Collections.Generic.KeyValuePair2[System.String,System.String]]’
cannot be converted to type
‘System.Collections.Generic.KeyValuePairOfstringstring[]’.”}

请记住,在对ProcessSimpleType(…)方法进行测试并传入一个简单类型时,这非常有效.我的问题只有ProcessGenericCollection(…).有没有人遇到过这个问题,如果有的话,你是怎么克服它的?

解决方法

感谢一位同事提供解决方案.对于那些有类似问题的人,我插入了以下内容:

...
...
        WsdlImporter importer = new WsdlImporter(metaSet);

        //BEGIN INSERT
        XsdDataContractImporter xsd = new XsdDataContractImporter();
        xsd.Options = new ImportOptions();
        xsd.Options.ImportXmlType = true;
        xsd.Options.GenerateSerializable = true;
        xsd.Options.ReferencedTypes.Add(typeof(KeyValuePair<string,string>));
        xsd.Options.ReferencedTypes.Add(typeof(System.Collections.Generic.List<KeyValuePair<string,string>>));

        importer.State.Add(typeof(XsdDataContractImporter),xsd);
        //END INSERT

        Collection<ContractDescription> contracts = importer.ImportAllContracts();
...
...

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读