简体   繁体   English

在没有合同接口的情况下从客户端应用程序使用证书调用WCF服务

[英]Calling a WCF service with certificate from a client application without having the contract interface

My particular problem is something like this: 我的特殊问题是这样的:

  • I am able to invoke WCF service dynamically, but i need to provide certificate. 我能够动态调用WCF服务,但是我需要提供证书。
  • We don't want to use app.config. 我们不想使用app.config。
  • Major issue is that WCF service is a 3rd party url. 主要问题是WCF服务是第三方URL。
  • Actually, i am getting an exception while invoke instance that certificate is not provided. 实际上,我在调用未提供证书的实例时遇到异常。
  • My code is something like this: 我的代码是这样的:

      try { // Define the metadata address, contract name, operation name, // and parameters. // You can choose between MEX endpoint and HTTP GET by // changing the address and enum value. Uri mexAddress = new Uri("http://Some3rdPartyURL.svc?wsdl");//Some 3rd party url // For MEX endpoints use a MEX address and a // mexMode of .MetadataExchange MetadataExchangeClientMode mexMode = MetadataExchangeClientMode.HttpGet; string contractName = "IService";//"";//3rd party service name string operationName = "SendMethod";//3rd party method name object[] args = new object[] { "", "", "0" };//3rd party required parameters //object[] operationParameters = new object[] { /*1, 2*/args }; // Get the metadata file from the service. MetadataExchangeClient mexClient = new MetadataExchangeClient(mexAddress, mexMode); mexClient.ResolveMetadataReferences = true; MetadataSet metaSet = mexClient.GetMetadata(); // Import all contracts and endpoints WsdlImporter importer = new WsdlImporter(metaSet); Collection<ContractDescription> contracts = importer.ImportAllContracts(); ServiceEndpointCollection allEndpoints = importer.ImportAllEndpoints(); // Generate type information for each contract ServiceContractGenerator generator = new ServiceContractGenerator(); var endpointsForContracts = new Dictionary<string, IEnumerable<ServiceEndpoint>>(); foreach (ContractDescription contract in contracts) { generator.GenerateServiceContractType(contract); // Keep a list of each contract's endpoints 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."); // Generate a code file for the contracts CodeGeneratorOptions options = new CodeGeneratorOptions(); options.BracingStyle = "C"; CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("C#"); // Compile the code file to an in-memory assembly // Don't forget to add all WCF-related assemblies as references 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 { // Find the proxy type that was generated for the specified contract // (identified by a class that implements // the contract and ICommunicationbject) Type clientProxyType = results.CompiledAssembly.GetTypes().First( t => t.IsClass && t.GetInterface(contractName) != null && t.GetInterface(typeof(ICommunicationObject).Name) != null); // Get the first service endpoint for the contract ServiceEndpoint se = endpointsForContracts[contractName].First(); //se = endpointsForContracts[contractName].First(); WSHttpBinding wsBinding = this.fillWsHttpBinding(); string encodeValue = "MIIFazCCBFO****"; // here we should use the encoded certificate value generated by svcutil.exe. X509Certificate2Collection supportingCertificates = new X509Certificate2Collection(); supportingCertificates.Import(Convert.FromBase64String(encodeValue)); X509Certificate2 primaryCertificate = supportingCertificates[0]; supportingCertificates.RemoveAt(0); EndpointIdentity.CreateX509CertificateIdentity(primaryCertificate, supportingCertificates); EndpointIdentity identity = EndpointIdentity.CreateX509CertificateIdentity(primaryCertificate); var endpoint = new EndpointAddress(mexAddress, identity); se.Binding = wsBinding; se.Address = endpoint; // Create an instance of the proxy // Pass the endpoint's binding and address as parameters // to the ctor object instance = results.CompiledAssembly.CreateInstance( clientProxyType.Name, false, System.Reflection.BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance, null, new object[] { se.Binding, se.Address }, CultureInfo.CurrentCulture, null); var methodInfo = instance.GetType().GetMethod(operationName); var methodParams = methodInfo.GetParameters(); int count = args.Count(); object[] args2 = new object[count]; int i = 0; foreach (var service1 in methodParams) { args2[i] = Convert.ChangeType(args[i], Type.GetType("System." + service1.ParameterType.Name)); i += 1; } Object retVal = instance.GetType().GetMethod(operationName).Invoke(instance, args2);/*Getting Error that certificate not provided???*/ } } catch (Exception ex) { string error = ex.ToString(); MessageBox.Show("Error Invoking Method: " + ex.Message); } 

    private WSHttpBinding fillWsHttpBinding() { 私人WSHttpBinding fillWsHttpBinding(){

      WSHttpBinding wsBinding = new WSHttpBinding(); wsBinding.CloseTimeout = new TimeSpan(0, 1, 0); wsBinding.OpenTimeout = new TimeSpan(0, 10, 0); wsBinding.ReceiveTimeout = new TimeSpan(0, 10, 0); wsBinding.SendTimeout = new TimeSpan(0, 5, 30); wsBinding.BypassProxyOnLocal = false; wsBinding.TransactionFlow = false; wsBinding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard; wsBinding.MaxBufferPoolSize = 524288L; wsBinding.MaxReceivedMessageSize = 10485760L; wsBinding.MessageEncoding = WSMessageEncoding.Text; wsBinding.TextEncoding = Encoding.UTF8; wsBinding.UseDefaultWebProxy = true; wsBinding.AllowCookies = false; wsBinding.ReaderQuotas.MaxDepth = 32; wsBinding.ReaderQuotas.MaxStringContentLength = 8192; wsBinding.ReaderQuotas.MaxArrayLength = 10485760; wsBinding.ReaderQuotas.MaxNameTableCharCount = 16384; wsBinding.ReliableSession.Ordered = true; wsBinding.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(10); wsBinding.ReliableSession.Enabled = false; wsBinding.Security.Mode = SecurityMode.Message; wsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows; wsBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None; wsBinding.Security.Transport.Realm = ""; wsBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate; wsBinding.Security.Message.NegotiateServiceCredential = true; wsBinding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic256; return wsBinding; } 

Where you are setting the certificate on the EndpointIdentity causes it to be used to validate the service's identity. EndpointIdentity上设置证书的位置会导致将其用于验证服务的身份。 You haven't set the client's credentials using instance.ClientCredentials.ClientCertificate.SetCertificate(...) . 您尚未使用instance.ClientCredentials.ClientCertificate.SetCertificate(...)设置客户端的凭据。 You'll have to get the ClientCredentials from the ClientBase<> using reflection. 您必须使用反射从ClientBase <>获取ClientCredentials。 See http://msdn.microsoft.com/en-us/library/ms732391%28v=vs.110%29.aspx . 请参阅http://msdn.microsoft.com/zh-cn/library/ms732391%28v=vs.110%29.aspx

var credentialProperty = instance.GetType().GetProperty("ClientCredentials");
var credentials = (ClientCredentials)credentialProperty.GetValue(instance, null);
credentials.ClientCertificate.SetCertficate(...);

You've also got two calls to EndpointIdentity.CreateX509CertificateIdentity , ignoring the output of one of them. 您还对EndpointIdentity.CreateX509CertificateIdentity了两次调用,忽略了其中之一的输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM