Generated client code from wsdl does not work - c#

I am creating client for soap service on .Net Core. Code was generated from wsdl
https://testfinance.post.ee/finance/erp/erpServices.wsdl
Code which should send request
var client = new ErpDataExchangeClient(
ErpDataExchangeClientBase.EndpointConfiguration.ErpDataExchangeSoap11);
var eInvoiceRequest = new EInvoiceRequest()
{
authPhrase = "10****:rskzsbkqdlmlmaeoyhmzeyttacozypxbbwqudna***********",
E_Invoice = GetEinvoice()
};
var result = client.EInvoiceAsync(eInvoiceRequest).Result;
GetEinvoice() - returns XMl document
On runtime I get an exception:
System.InvalidOperationException: 'Contract requires Duplex, but
Binding 'BasicHttpBinding' doesn't support it or isn't configured
properly to support it.'
Service should be fine. This is a big company API.
Nothing was changed, used only automatically generated code.
What should I do to be able make API calls for this SOAP service

Related

Can I call a WCF endpoint from ASP.Net Web API?

I have a web api with controller methods that use rest http(post/get calls).
Clients consume this API with normal httpclient calls and I pass an http response back.
My use case is I have a legacy method that needs to make a call to another server. This method currently uses WCF and contract binding but I don't want to use WCF in this API project.
Is there a way that I can still call these methods using just WEB API or do I have to mix architectures (Web api with WCF)?
Here is the normal method call
First I initialize the proxy
var proxy = GetAccountProxy();
public static AcountClient GetAccountProxy()
{
var client = new AccountClient();
client.ClientCredentials.ClientCertificate.SetCertificate(...);
return client;
}
I connect to a method on the other server through the proxy
var accountInfo = proxy.GetAccountInfo(xmlAccount);
public string AccountInfo(string sXml){
AccountLookup val = new AccountLookup();
val.Body = new AccountLookupRequestBody();
val.Body.XML = sXML;
AccountLookupResponse retVal = ((AccountLookupResponse)(this)).AccountLookup(val);
return retVal;
}
In my webconfig the endpoints look like this
<endpoint address="https://www.mylookup.com/AccountLookupWS/AccountLookupWS.svc/wshttp" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IAccountLookupWS" contract="AccountLookupWS.IAccountLookupWS" name="WSHttpBinding_IAccountLookupWS1" />
So my question is can I just call this endpoint using a normal rest httpclient call and have the same result?
Uri baseUrl = new Uri("https://www.mylookup.com/AccountLookupWS/AccountLookupWS.svc/wshttp");
IRestClient client = new RestClient(baseUrl);
IRestRequest request = new RestRequest("GetAccountInfo", Method.GET)
request.AddParameter("XmlAccount", sXml);
IRestResponse<dynamic> response = client.Execute<dynamic>(request);
if (response.IsSuccessful)
{
response.Data.Write();
}
else
{
Console.WriteLine(response.ErrorMessage);
}
Console.WriteLine();
In general it is possible to access wcf with webrequest, but it depends on the wcf service implementation. Check out the WebGet and/or WebInvoke attributes https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.web.webgetattribute?view=netframework-4.8 and start from there.
It is work to be done on WCF side, after it is done properly, you can access your wcf as normal rest services.
It depends on your WCF server bindings. You see, HTTP/s protocol implementation is just possible module of WCF, a part, just like any other protocol out there - it is just called binding. Different bindings means same bindings should be on client side, otherwise they don't understand each other.
For example if server tells:
use gzip on my data which I send over wire
then I xor my data with 666 if first bit is set true
then use SSL to protect it
then send it over TCP
Then client should do the same thing in reverse. This is WCF and it's flexibility for you which opened hell gates for researchers and developers.
As I said, if your server supports HTTP bindings, without extra stuff - you are good. Use http client or billion other HTTP classes. If not - port your server protocol bindings to NET Core and use them.

How can I get/create the request structure from Soap service?

I have the wsdl of a web soap service and I have added it as a service reference with visual studio. I have notice that it doesn't have a request class for a method which I need to use. The reason I need it is because I have to store that request as xml and I have always used the request class to serialize. Is there a way to generate that request xml?
Simple representation:
var client = new SoapServiceCliente();
var request = new RequestClass(); <-- This is what soap service is missing.
var response = new ResponseClass();
response = client.theMethod(request);
Before calling the method I serialize the request to xml and after getting the response I serialize it too.

Consuming J2EE web service signing request but receiving unsigned response

I'm consuming a third party J2EE web service that requires sign the request with a certificate, but the web service is responding an unsigned response.
This is the way I'm doing the request:
public static WcfServiceNamespace.ResponseType GetResponse(X509Certificate2 certificate)
{
var request = GetExampleRequest();
var endPoint = new EndpointAddress($"https://endPoint.url/contoso");
var binding = GetCustomBinding();
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
using (var client = new WcfServiceNamespace.ServicePortTypeClient(binding, endPoint))
{
client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
client.ClientCredentials.ClientCertificate.Certificate = certificate;
return client.ProcessRequest(request);
}
}
private static Binding GetCustomBinding()
{
var c = new CustomBinding();
var version = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
var sec = SecurityBindingElement.CreateCertificateOverTransportBindingElement(version);
sec.EnableUnsecuredResponse = true;
sec.AllowInsecureTransport = true;
sec.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
c.Elements.Add(sec);
c.Elements.Add(new TextMessageEncodingBindingElement() {MessageVersion = MessageVersion.Soap11});
c.Elements.Add(new HttpsTransportBindingElement() { RequireClientCertificate = true });
return c;
}
The java web service is responding correctly the request without any header:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<!-- correct response -->
</soapenv:Body>
</soapenv:Envelope>
But WCF client is throwing an exception when it tries to process the response:
System.ServiceModel.Security.MessageSecurityException: 'Cannot find a token authenticator for the 'System.IdentityModel.Tokens.X509SecurityToken' token type. Tokens of that type cannot be accepted according to current security settings.'
I already tried this configuration:
WCF - Cannot find a token authenticator for X509SecurityToken
But it does not resolve my problem because the header of the response is totally empty as I explained before and the endpoint is using https but has no certificate to trust.
My question is:
Is there any way to configure WCF to correctly sign the request but ignore the response security?
Edit:
I already tried this questions:
IBM DataPower 3.7.1.x issues with WCF clients
WCF error calling WS-Security web service: Cannot find a token authenticator for the X509SecurityToken
But the answers don't help
Edit:
I make it work with WSE3 but I want use a newer technology. If it works in WSE3, Why not in WCF?
Can we use the below tools to generate the SOAP client, with which we can call the service like the below method?
https://learn.microsoft.com/en-us/dotnet/framework/wcf/servicemodel-metadata-utility-tool-svcutil-exe
It is a built-in tool in Visual Studio, and we can generate the client proxy class and the compatible custom binding and security mode configuration by using the SVCUtil command. the client proxy will automatically use the configuration compatible with the server to create the request when instantiating.
Alternatively, we could generate the client proxy by means of the Add service reference menu.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/accessing-services-using-a-wcf-client
I have never called the J2EE web service, please let me know if it helps.

Unable to send Object while using Web Service

I am trying to send the object through a method api of web service. As service is binded by BasichttpBinding.
OneClickOrder OneClick = new OneClickOrder();
OneClick.Mobile = Session["Mobile"].ToString();
OneClick.OrderDetailsList = OrderDetailsList.ToArray();
OneClick.OrderId = 10000;
OneClick.PromoSiteId = PromoSiteId;
OneClick.TotalPrice = Convert.ToInt32(lblafterDiscount.Text);
var OrderResponse = service.OneClickOrder(OneClick);
While using service API, I got an SOAP exception
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:order. The InnerException message was 'Error in line 1 position 588. 'EndElement' 'order' from namespace 'http://tempuri.org/' is not expected. Expecting element 'Mobile'.'. Please see InnerException for more details.
I didn't get what could be wrong. Is this a problem of Service Side or client side? And i am currently working at client side.
The Problem is that your DataContract class OneClickOrder is not same on both server and client.
At client it is different from Server. So, Check your OneClickOrder DataContract Class, Is both are same on server and client.

$.getJSON equivalent in Silverlight

I'm making the following call in jQuery, using jsonp as my data format, that I'd like to make directly in Silverlight:
$.getJSON('https://api.wordstream.com/authentication/login?callback=?',
{ 'username': un,
'password': pw
}, function (loginResults) {
API_SESSION_ID = loginResults['data']['session_id'];
$.getJSON('https://api.wordstream.com/keywordtool/get_keywords?callback=?',
{ 'session_id': API_SESSION_ID,
'seeds': keyword,
'max_results': 20
}, function (keywordResults) {
for (i = 0; i < +keywordResults['data'].length; i++) {
Keywords[i] = keywordResults['data'][i][0];
}
return(Keywords);
});
});
I tried something like this to handle the first $.getJSON (authenticating & returning my auth token):
WebClient downloader = new WebClient();
WebRequest.RegisterPrefix("https://", System.Net.Browser.WebRequestCreator.ClientHttp);
var client = new WebClient();
client.Credentials = new NetworkCredential("username", "password");
client.UseDefaultCredentials = false;
client.DownloadStringCompleted += new
DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(loginEndpoint);
When I try and run this I get the following error inside my downloadstringcompleted eventhandler:
{System.Security.SecurityException: Security error.
at System.Net.Browser.ClientHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.ClientHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
at System.Net.Browser.AsyncHelper.<>c__DisplayClass4.<BeginOnUI>b__1(Object sendState)}
I've used WCF Ria Services in EF & SOAP services via .asmx files in the past, so I'm not a total stranger to the idea of web services. I am not sure if I need to be using the clientaccesspolicy or crossdomain files or not.
Any ideas on how to proceed?
Thanks,
Scott
What you trying to do in this series of questions has become clearer to me now.
Unless api.wordstream.com includes a ClientAccessPolicy xml (or the Flash equivalent) you will not be able to make requests to this api from Silverlight.
You have two options:
Call into Javascript to make these requests on behalf of the Silverlight app.
Create WCF service to on your server to make these requests on behalf od the Silverlight app.
I would recommend the first approach, however don't use getJSON. Instead use the standard ajax api in JQuery to fetch the JSON content asynchronously. When the final JSON content is available (still in string form) call into Silverlight from Javasript passing in the string.
What would be preferable is to create the appropriate set of .NET classes and collections that match the data from the api. You could then use DataContractJsonSerialializer to deserialize the received string into instances of your classes.
Sometimes creating a class structure can be a bit of a burden. Another approach is to use the set of objects in the System.Json namespace starting with JsonValue.Parse to load up the set of JsonObjects from the string. You can now navigate around the returned data using these `son objects and Linq where necessary.
Did a little digging and a test.
When you are calling an external domain, the cross-domain issue will occur and that's why you are seeing the Security error.
Remember that this is a Web application after all, it does run inside the browser!
To enable Silverlight to reach outside it's domain, give this article a try if you are doing a self hosted app.
http://blogs.msdn.com/b/carlosfigueira/archive/2008/03/07/enabling-cross-domain-calls-for-silverlight-apps-on-self-hosted-web-services.aspx

Categories