I'm new to .NET and have been following this tutorial (http://johnwsaunders3.wordpress.com/2009/05/17/how-to-consume-a-web-service/) to consume a simple weather web service. My small console application essentially asks the user for a ZIP code, fires that to the web service then returns to response in the console. At least, that's the way it should work.
The web service I am using is:
http://wsf.cdyne.com/WeatherWS/Weather.asmx
The problem with this is there are multiple endpoints for different ways of consuming the service:
SOAP 1.1
SOAP 1.2
HTTP GET
HTTP POST
Because of this, when I run the console application, I am presented with the following error:
Unhandled Exception: System.InvalidOperationException: An endpoint configuration section for contract 'Service1Reference.WeatherSoap'
could not be loaded because more than one endpoint configuration for that contract was found. Please indicate the preferred endpoint configuration section by name.
My question is, how do I specify that my call to the web service should use one of the SOAP endpoints?
My code so far can be found below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsoleApplication1.Service1Reference;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.Write("Enter ZipCode: ");
var line = Console.ReadLine();
if (line == null)
{
return;
}
WeatherSoapClient svc = null;
bool success = false;
try
{
svc = new WeatherSoapClient();
var request = line;
var result = svc.GetCityForecastByZIP(request);
Console.WriteLine("The result is:");
Console.WriteLine(result);
Console.Write("ENTER to continue:");
Console.ReadLine();
svc.Close();
success = true;
}
finally
{
if (!success && svc != null)
{
svc.Abort();
}
}
}
}
}
Any help with this would be greatly appreciated.
Edit:
The contents of my App.config file can be found here:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WeatherSoap" />
</basicHttpBinding>
<customBinding>
<binding name="WeatherSoap12">
<textMessageEncoding messageVersion="Soap12" />
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://wsf.cdyne.com/WeatherWS/Weather.asmx"
binding="customBinding" bindingConfiguration="WeatherSoap12"
contract="Service1Reference.WeatherSoap" name="WeatherSoap12" />
</client>
</system.serviceModel>
</configuration>
It seems as though .NET is trying to be helpful in generating a SOAP 1.2 binding for you when you probably don't need it (see this question for more information).
To work around this you can explicitly tell the service client which binding to use when you instantiate it by specifying the endpoint name to use:
svc = new WeatherSoapClient("WeatherSoap");
Where "WeatherSoap" is the value of the name attribute on your endpoint node.
Related
I have tried what seems like a million ways, and I might have confused myself to the point of too much frustration. I am very much a beginner in terms of WSDL. Ran through a calculator tutorial.
The task at hand is connecting to a WSDL Webservice from a Danish state department. (since the addresses are publicly available, so I see no reason to hide them.)
I have confirmed that the Soap webservice is working and is functional by using SoapUI 5.5.0, by following a guide from the department.
To begin with what I have been trying to do is create a very simple console application with hardcoded information, just to test out the C# code / the workflow. The final product is either going to be a MVC .Net or Blazor server.
I have removed the Username and password from the code and the request information which is a 10 digit code in string format. They have been replaced with ".....".
This Is the wsdl address: https://ws.fvst.dk/service/CHR_dyrWS?WSDL
All the information I have gathered. The steps for using a webservice is adding it via connected services and instantiating it, adding user information and calling the request function in the webservice and lastly fixing the config to using authentication.
But no matter what I do it seems like I cannot make it work, it throws a validation error or a Security.MessageSecurityException.
The code I currently have
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp5.ServiceReference1;
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
CHR_dyrWSClient client = new CHR_dyrWSClient();
var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
basicHttpBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
client.ClientCredentials.UserName.UserName = ".....";
client.ClientCredentials.UserName.Password = ".....";
ServiceReference1.CHR_dyrHentCkrOplysningerRequest requestInfo = new ServiceReference1.CHR_dyrHentCkrOplysningerRequest();
requestInfo.Request.CkrNr = ".....";
var responseInfo = client.hentCkrOplysninger(requestInfo);
Console.WriteLine(responseInfo.Response);
client.Close();
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpsBinding>
<binding name="CHR_dyrWSPortBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpsBinding>
</bindings>
<client>
<endpoint
address="https://ws.fvst.dk:443/service/CHR_dyrWS"
binding="basicHttpsBinding"
bindingConfiguration="CHR_dyrWSPortBinding"
contract="ServiceReference1.CHR_dyrWS"
name="CHR_dyrWSPort" />
</client>
</system.serviceModel>
</configuration>
I would really like to know where I need to go from here. I am really unsure if I’m connecting to the webservice wrong? The thing that I am most unsure about is the way you need to connect to this web service.
Any help or links would be greatly appreciated!
Kind regards
I have figured it out. I needed to send the optional information in the soap request too.
and i needed to specify a header in the app.config file.
To make it work i copied to header information from SoapUI in the http log.
Pasted it in the header information in the app.config. The username token can be removed and will still work.
The entire program code
Config file
Console output
I am wondering if anyone has encountered this same error, and if so, can point me in the right direction to try and fix it. The error reads:
Value cannot be null. Parameter name: key.
It seems like this error can stem from many different things.
I am trying to send data that is read from a CSV file to a SOAP web service. Below is the code I am using in the script task:
BasicHttpBinding CostCenterSoap = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
EndpointAddress remoteAddress = new EndpointAddress("https://example.com/services/CostCenter.asmx");
CostCenterSoapClient client = new CostCenterSoapClient(CostCenterSoap, remoteAddress);
CostCenterProperties[] costcenters = new CostCenterProperties[list.Count];
for (var c = 1; c < list.Count; c++) {
costcenters[c] = new CostCenterProperties
{
InteropID = list[c].CostCenter,
CompanyInteropID = companyInteropID,
Name = list[c].CostCenter,
Description = list[c].CostCenter
};
try
{
client.Save(CostCenters: costcenters, SharedSecret: sharedSecret);
}
catch (Exception e)
{
errorList.Add(e.Message);
MessageBox.Show("Errors from adding cost center: " + e.Message);
}
}
What is even more confusing is that this same logic works perfectly fine for another web service in another script task. When using SoapUI to test, I can pass data to the web service just fine, so the issue must be reside with my script.
Screenshot of error from the StackTrace:
Here is my app.config file that is part of my script task:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.net>
<defaultProxy useDefaultCredentials="true">
<proxy usesystemdefault="True" bypassonlocal="True"/>
</defaultProxy>
</system.net>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="CostCenterSoap">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://www.example.com/services/CostCenter.asmx"
binding="basicHttpBinding" bindingConfiguration="CostCenterSoap"
contract="CostCenterService.CostCenterSoap" name="CostCenterSoap" />
</client>
</system.serviceModel>
</configuration>
I've recently noticed that using Service References(WCF) causes problems with plain old SOAP API's. I thought that the newer more improved approach was to use Service References because WCF is more flexible and modern. Can anyone detect how I can make this work with WCF in VS2013?
It is a simple console app trying to consume RxNav (free) api
URL: http://mor.nlm.nih.gov/axis/services/RxNormDBService
After adding a "Service Reference" to the solution I entered the following code:
Program.cs
static void Main(string[] args)
{
var client = new RxNavAPI.DBManagerClient();
try
{
var matches = client.getDrugs("aspirin");
foreach (var conceptGroup in matches)
{
foreach (var concept in conceptGroup.rxConcept)
{
Console.WriteLine(String.Format("Name: {0}, Syn: {1}", concept.STR, concept.SY));
}
}
client.close();
}
catch (TimeoutException ex)
{
Console.WriteLine("Timeout occurred while accessing RxNav API");
Console.WriteLine(ex.Message);
throw;
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="RxNormDBServiceSoapBinding" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://mor.nlm.nih.gov/axis/services/RxNormDBService"
binding="basicHttpBinding" bindingConfiguration="RxNormDBServiceSoapBinding"
contract="RxNavAPI.DBManager" name="RxNormDBService" />
</client>
</system.serviceModel>
</configuration>
One thing that I have noticed is when added as a Web Reference the client is called like:
var client = new RxNavAPI.DBManagerService();
while when using Service Reference it is like:
var client = new RxNavAPI.DBManagerClient();
EDIT: The error I am receiving is
System.InvalidOperationException : "RPC Message
getProprietaryInformationRequest1 in operation
getProprietaryInformation1 has an invalid body name
getProprietaryInformation. It must be getProprietaryInformation1"
Awesome!
#John Saunders answering everywhere.
This is the same issue noted over 5 years ago. WCF: Svcutil generates invalid client proxy, Apache AXIS Web Service, overload operations
Now I'm having the same issue and there is still no fix, only workarounds for this.
I've setup a Service Reference (WCF Client) to call a Java Web Service from a Console Application I've setup for testing. It is using HTTPS. I have Fiddler setup and can see the proper values being sent and returned from the service (in Fiddler). But no matter what method I call, the returned values, regardless if it is a String or an object, comes back as Null.
I'm not sure if the proxy client mapping isn't working or if I need to change a configure value in app.config.
app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="ResultsSOAP12Binding">
<textMessageEncoding messageVersion="Soap12" />
</binding>
<binding name="ResultsSOAP12Binding1">
<textMessageEncoding messageVersion="Soap12" />
<httpsTransport />
</binding>
<binding name="ResultsSOAP12Binding2">
<textMessageEncoding messageVersion="Soap12" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://services.acme.com/results"
binding="customBinding" bindingConfiguration="ResultsSOAP12Binding1"
contract="ResultsServiceReference.Result
</client>
</system.serviceModel>
</configuration>
Code:
static void CallResults()
{
var resultsRequest = new ResultsServiceReference.ResultsRequest();
var client = new ResultsServiceReference.ResultsPortTypeClient("ResultsSOAP12BindingQSPort");
Console.WriteLine("Call Results Service");
ResultsServiceReference.ResultsBatch result = client.latestResults(resultsRequest);
Console.WriteLine(result.Status);
Console.ReadLine();
}
In this code the variable result is null, even though when you look in Fiddler you can see the XML. No error is displayed until you try to use result.
BTW, I tried setting a breakpoint inside the latestResults method in the proxy class reference.cs, but the debugger doesn't reach it.
You may want to configure and enable WCF diagnostic event tracing and message logging, then rerun the test transaction and review the service trace log file. The following link demonstrates how to enable tracing and message logging.
http://msdn.microsoft.com/en-us/library/ms751526.aspx
In our experience, service discrepancies which otherwise show no obvious error, often show up in the service trace file.
Note: The breakpoint inside the proxy class reference.cs may not be reached because the following attribute has been set:
[System.Diagnostics.DebuggerStepThroughAttribute()]
Most probably the WSDL has a mistake and the schema inside it does not match the actual response XML. You can publish the WSDL (and any referenced XSD) here together with the SOAP response (or mail them to me so I will try to look). Or you can set up a WCF service stub from the exact same WSDL (or from the client contract you already generated) and compare the response WCF sends to the one the actual service sends.
You want to look for differences in XML namespaces (and understand delicate parts like if this is default namespace or prefixed one) and in the name of the first element under the body.
I know how can I read information from the config file in the activities by using C#
var servicesSection = (ClientSection)WebConfigurationManager.GetSection("system.serviceModel/client");
ChannelEndpointElement endpoint = servicesSection.Endpoints[0];
But when I try to read this information in the if statement of the workflow service, it doesn't work.
I tried the following code to read the endpoint information from the web.config file.
((ClientSection)WebConfigurationManager.GetSection("system.serviceModel/client")).Endpoints[0].toString().Equals("");
but it doesn't work.
some how, it doesn't understand the type casting and I can't convert the GetSection output to a clientSection object. do you know how can I do that in the if statement of the workflow service?( check something from the config file before calling some other activities)
I had similar requirement, after some prototyping, I managed following way. Hope this will help you and others.
/* Using in System.ServiceModel.dll */
using System.ServiceModel.Configuration;
using System.Web.Configuration;
/* Inside any method */
var clientSection = ((ClientSection)(WebConfigurationManager.GetSection("system.serviceModel/client")));
if (clientSection != null)
{
foreach (ChannelEndpointElement endPoint in clientSection.Endpoints)
{
..... endPoint.Name / endPoint.Address etc.
}
}
You can read any element from configuration and cast it to appropriate element type.
To read endpoint, binding and other sections from app.config, there are defined set of Section classes that help us read settings.
For example, to read list of bindings, we could simply use,
private void GetNetTcpBindingName()
{
Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(appConfig);
BindingsSection oBinding = serviceModel.Bindings;
List<BindingCollectionElement> bindingCollection = oBinding.BindingCollections;
NetTcpBindingCollectionElement netTCPBindingCollectionElement = (NetTcpBindingCollectionElement)bindingCollection.Where(obj => obj.BindingName.Equals("netTcpBinding")).SingleOrDefault();
if (netTCPBindingCollectionElement != null)
{
Console.WriteLine(netTCPBindingCollectionElement.ConfiguredBindings.ElementAt(0).Name);
}
}
Given the following app.config XML (section of interest in bold),
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITrainerManagement" />
</basicHttpBinding>
**<netTcpBinding>
<binding name="NetTcpBinding_ILiveStream">
<security mode="None" />
</binding>
</netTcpBinding>**
</bindings>
<client>
<endpoint address="net.tcp://sever-pc/PST.TS.LiveStream/LiveStream.svc"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ILiveStream"
contract="LiveStreamServiceReference.ILiveStream" name="NetTcpBinding_ILiveStream" />
<endpoint address="http://10.5.50.115/PST.TS.TrainerService/TrainerManagement.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITrainerManagement"
contract="TrainerManagementServiceReference.ITrainerManagement"
name="BasicHttpBinding_ITrainerManagement" />
</client>
</system.serviceModel>
Hope this helps. This can be used to read any standard settings.