I have made a C#-project where I am trying to connect to my Business Central cloud sandbox.
In Business Central, I have made an extension with a new codeunit, which has a function that I call "MHSTest". It just returns a text.
In Visual Studio, I have made the service reference that connects to the SOAP URL in Business Central. So I can see the name of my function, "MHSTest", in Visual Studio.
When I write this in Visual Studio, I get an error, because it tries to connect anonymously:
var client = new MHSTest.CSharpCodeunit_PortClient();
myTextBox.Text = client.MHSTest();
If I try the below instead, I get an error message saying that "https" is not valid. It has to be "http".
string endpoint = "">api.businesscentral.dynamics.com/.../CSharpCodeunit";
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
binding.MaxBufferSize = 999999;
binding.MaxReceivedMessageSize = 999999;
var client = new MHSTest.CSharpCodeunit_PortClient(binding, new EndpointAddress(endpoint));
myTextBox.Text = client.MHSTest();
How do I connect to Business Central and get (or set) data?
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Debitorer_Binding">
<security mode="Transport" />
</binding>
<binding name="Debitorer_Binding1" />
<binding name="CSharpCodeunit_Binding">
<security mode="Transport" />
</binding>
<binding name="CSharpCodeunit_Binding1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="api.businesscentral.dynamics.com/.../2999befa-1255-4304-a79a-67de0e24f090/Sandbox/WS/CRONUS%20Danmark%20A%252FS/Page/Debitorer?tenant=msneua5672t92712555&aid=FIN"
binding="basicHttpBinding" bindingConfiguration="Debitorer_Binding"
contract="BCCustomer.Debitorer_Port" name="Debitorer_Port" />
<endpoint address="api.businesscentral.dynamics.com/.../2999befa-1255-4304-a79a-67de0e24f090/Sandbox/WS/CRONUS%20Danmark%20A%252FS/Codeunit/CSharpCodeunit?tenant=msneua5672t92712555&aid=FIN"
binding="basicHttpBinding" bindingConfiguration="CSharpCodeunit_Binding"
contract="MHSTest.CSharpCodeunit_Port" name="CSharpCodeunit_Port" />
</client>
</system.serviceModel>
</configuration>
The problem is solved. I just needed to add this code after defining my client variable:
System.ServiceModel.Security.UserNamePasswordClientCredential cre = client.ClientCredentials.UserName;
cre.UserName = " ";
cre.Password = " ";
Use the Export-NAVData cmdlet to export data from a Business Central database. You can export company-specific data, and you can choose to include global data, application data, and application objects. When you export data from a Business Central database, the data is stored in a file with the extension .
Related
I'm trying to configure a script component with a service reference to my WSDL file inside this boiler plate method.
public override void CreateNewOutputRows()
{
//create instance of service client
}
However I'm running into problems with the configuration file app.config which is complaining about an invalid contract attribute contract="ServiceReference1.IClientService1
All attempts to change this manually have failed. Similar posts suggest using a fully qualified name Service.MyService but I'm not having any success so far. Is there a way to specify the binding programmatically?
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IClientService1">
<security mode="Transport" />
</binding>
<binding name="BasicHttpBinding_IClientService11" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://server/services/ClientService1.svc/soap"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IClientService1"
contract="ServiceReference1.IClientService1" name="BasicHttpBinding_IClientService1" />
</client>
</system.serviceModel>
</configuration>
Stub code looks like following
public override void CreateNewOutputRows()
{
string endpoint = "https://server/services/ClientService1.svc";
ClientService1Client client = new ClientService1Client(endpoint);
client.ClientCredentials.UserName.UserName = "";
client.ClientCredentials.UserName.Password = "";
Output0Buffer.name = client.GetActiveClients()[1].name.ToString();
}
I believe your issue may be due to having /soap in your endpoint address
<endpoint address="https://server/services/ClientService1.svc/soap"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IClientService1"
contract="ServiceReference1.IClientService1" name="BasicHttpBinding_IClientService1" />
I think it should just be:
address="https://server/services/ClientService1.svc"
As for creating the binding programmatically this should work or get you started:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
EndpointAddress address = new EndpointAddress("https://server/services/ClientService1.svc");
ClientService1Client client = new ClientService1Client(binding, address);
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 have created following test application to retrieve data from Service Now.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace ServiceNowConnection
{
class Program
{
static void Main(string[] args)
{
Service_Now_Reference.getRecords records = new Service_Now_Reference.getRecords();
records.sys_user = "XXXXXXX";
Service_Now_Reference.ServiceNowSoapClient proxyUser = new Service_Now_Reference.ServiceNowSoapClient();
proxyUser.ClientCredentials.UserName.UserName = "XXXXXX";
proxyUser.ClientCredentials.UserName.Password = "XXXXXX";
Service_Now_Reference.getRecordsResponseGetRecordsResult[] result = proxyUser.getRecords(records);
foreach (var item in result)
{
Console.WriteLine(item.sys_created_by);
}
Console.ReadLine();
}
}
}
This connects to the service now application correctly with no errors, but when I try to print retrieved data it gives me keys instead string type answers.
For some properties it gives correct values (example sys_updated_by)
how can I avoid this situation.
The way you need to do it.
If you are using RESTfull API in C# of cause you can do it by sending direct HTTPS call to service now.
But things getting complicated when you are using SOAP api
While you're importing web service to your program it includes following XML codes to the App.config or Web.config depending on your application intention(Web application or stand alone Application).
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceNowSoap">
<security mode="Transport" />
</binding>
<binding name="ServiceNowSoap1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://XXXXXXXX.service-now.com/service_subscribe_sys_user_list.do?SOAP"
binding="basicHttpBinding" bindingConfiguration="ServiceNowSoap"
contract="ServiceReference1.ServiceNowSoap" name="ServiceNowSoap" />
</client>
</system.serviceModel>
First of all if you are expecting to have big set of records to be retrieved you need to increase the size of Max Received Message Size.
for that you need to edit the tag like following
<binding name="ServiceNowSoap" maxReceivedMessageSize="2000000000">
Next part is adding displayvalue=all to the URL.
We can't edit end point url withing the XML it self instead you can remove the URL and add it as a key value. But still you cant add parameters to the url with & sign you need to store values as separate keys and combine it withing the program to get the full URL
Final XML will be like this
<configuration>
<appSettings>
<add key="serviceNowUrl"
value="https://XXXXXXXX.service-now.com/service_subscribe_sys_user_list.do?"/>
<add key="displayvalue" value="displayvalue=true"/>
<add key="protocol" value="SOAP"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceNowSoap" maxReceivedMessageSize="2000000000">
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="Basic"
realm="">
<extendedProtectionPolicy policyEnforcement="Never" />
</transport>
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
<binding name="ServiceNowSoap1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint binding="basicHttpBinding" bindingConfiguration="ServiceNowSoap"
contract="Service_Now_Reference.ServiceNowSoap" name="ServiceNowSoap" />
</client>
</system.serviceModel>
</configuration>
You can assemble the url as follow
string url = ConfigurationSettings.AppSettings["serviceNowUrl"];
string protocol = ConfigurationSettings.AppSettings["protocol"];
string displayvalue = ConfigurationSettings.AppSettings["displayvalue"];
System.ServiceModel.EndpointAddress endpoint = new System.ServiceModel.EndpointAddress(string.Format("{0}{1}{2}", url, protocol, displayvalue));
If you update the URL you are using to get the WSDL and make requests to, to include 'displayvalue=all' the response will include display names as well as sys_id values (think foreign_key) of referenced records.
For more info check out: http://wiki.servicenow.com/?title=Direct_Web_Services#Return_Display_Value_for_Reference_Variables&gsc.tab=0
Thanks,
Bryan
I have several web services that I am connecting to from a Visual Studio C# project using service references. Two of the service references were created and work without a problem, and one of them took quite a lot of effort to get imported, and now seems to not be working.
I believe the problem lies in the app.config file since it is getting a "Could not find endpoint element" error when I try to create the client.
Here is the app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
</configSections>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="RateQuoteSoap">
<security mode="Transport" />
</binding>
<binding name="RateQuoteSoap1" />
<binding name="QuoteSoap" />
<binding name="WebservicePrimusSoapBinding" />
</basicHttpBinding>
<customBinding>
<binding name="QuoteSoap12">
<textMessageEncoding messageVersion="Soap12" />
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint
address="https://webservices.rrts.com/rating/ratequote.asmx"
binding="basicHttpBinding"
bindingConfiguration="RateQuoteSoap"
contract="RoadRunnerService.RateQuoteSoap"
name="RateQuoteSoap" />
<endpoint
address="http://services.echo.com/Quote.asmx"
binding="basicHttpBinding"
bindingConfiguration="QuoteSoap"
contract="EchoService.QuoteSoap"
name="QuoteSoap" />
<endpoint
address="http://services.echo.com/Quote.asmx"
binding="customBinding"
bindingConfiguration="QuoteSoap12"
contract="EchoService.QuoteSoap"
name="QuoteSoap12" />
<endpoint
address="http://api.shipprimus.com/"
binding="basicHttpBinding"
bindingConfiguration="WebservicePrimusSoapBinding"
contract="PrimusService.WebservicePrimusServicePort"
name="WebservicePrimusServicePort" />
</client>
</system.serviceModel>
</configuration>
The PrimusService is the one that is not working correctly, and the full error when I try to initialize the client like WebservicePrimusServicePortClient serviceClient = new WebservicePrimusServicePortClient("WebservicePrimusServicePort"); is
System.InvalidOperationException: Could not find endpoint element with name 'WebservicePrimusServicePort' and contract 'PrimusService.WebservicePrimusServicePort'in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element.
I have also tried to simply initialize a BasicHttpBinding object using the binding name and the endpoint name with no luck (short variable names for readability)
BasicHttpBinding a = new BasicHttpBinding("QuoteSoap"); // Works fine
BasicHttpBinding b = new BasicHttpBinding("WebservicePrimusSoapBinding"); // Fails
BasicHttpBinding c = new BasicHttpBinding("WebservicePrimusServicePort"); // Fails
It throws no error for binding a, but binding b and c fail with the error:
System.Collections.Generic.KeyNotFoundException: No elements matching the key 'WebservicePrimusSoapBinding' were found in the configuration element collection.
While not a direct solution, I ended up just taking the information from the app.config and creating my own BasicHttpBinding and EndpointAddress objects in code. This is more of a workaround than a fix for the problem, and I still don't know why I couldn't access the information in the app.config directly.
I followed the solution in this answer about how to consume a service without using the app.config file.
I created my BasicHttpBinding like
BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = "PrimusServiceBinding"; // Completely Unnecessary
and my endpoint like
EndpointAddress endpoint = new EndpointAddress("http://api.shipprimus.com/");
and could connect to the service and retrieve information without a problem, even providing as little information as I did (basically just the address).
I added the WCF service reference to my project. Next step is to create a channel from the code.
WSHttpBinding bindingDialingType = new WSHttpBinding();
EndpointAddress endingPointDialingType = new EndpointAddress("http://wsvc.corporate.my.com/International/DialingService.svc");
ChannelFactory<IDialingService> iDialingServiceChannelFactory = new ChannelFactory<IDialingService>(bindingDialingType, endingPointDialingType);
IDialingService instanceIDialingService = iDialingServiceChannelFactory.CreateChannel();
Because I met an exception, so I guess that something wrong with my channel factory code.
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.
To capture the exception, I had the code.
My app.config is:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_iLuCRE" />
</basicHttpBinding>
<wsHttpBinding>
<binding name="WSHttpBinding_IDialingService">
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://wsvc.corporate.my.com/LuCRE/LuCRE.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_iLuCRE"
contract="LuCRE.iLuCRE" name="BasicHttpBinding_iLuCRE" />
<endpoint address="http://wsvc.corporate.my.com/International/DialingService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IDialingService"
contract="DialingService.IDialingService" name="WSHttpBinding_IDialingService" />
</client>
</system.serviceModel>
I used WCFTestClient to test it, however the service does work. I added the service reference to my project and I don't know the code details.
Updated:
If I used the code
DialingServiceClient client = new DialingServiceClient();
Then call the method through client, then everything is fine. Why?
Your binding element security is None. You need to also mention it when defining programmatically.
WSHttpBinding bindingDialingType = new WSHttpBinding
{ Security = new WSHttpSecurity { Mode = SecurityMode.None } };