My particular problem is something like this:
- I am able to invoke WCF service dynamically, but i need to provide certificate.
- We don't want to use app.config.
- Major issue is that WCF service is a 3rd party 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 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. You haven't set the client's credentials usinginstance.ClientCredentials.ClientCertificate.SetCertificate(...)
. You'll have to get the ClientCredentials from the ClientBase<> using reflection. See http://msdn.microsoft.com/en-us/library/ms732391%28v=vs.110%29.aspx.You've also got two calls to
EndpointIdentity.CreateX509CertificateIdentity
, ignoring the output of one of them.