Setting the service URL at runtime - c#

When I am adding the "Web Reference" we are giving the address to the asmx page to visual studio.
How Can I set this at run time?

I would have upvoted one of the other answers - they're almost correct.
using (YourService service = new YourService())
{
service.Url = "http://some.other.url/";
// Now you're ready to call your service method
service.SomeUsefulMethod();
}
If a using block is not used, and an exception is thrown, then resources like network connections can be leaked.

Just set the Url property of the object before you call any of the service methods:
YourService service = new YourService();
service.Url = "http://some.other.url/";
// Now you're ready to call your service method
service.SomeUsefulMethod();

YourWebService service = new YourWebService();
service.Url = "http://www.example.com/YourWebService.asmx";
service.CallMethod();

Related

Generated WCF SOAP client uses current user for windows authentication instead of given credentials

I'm kind of new to the whole WCF and SOAP topic so please be kind.
I'm using a generated SOAP Client with .net6. In another project we successfully worked with the same Web Service using the old .net Framework 2.0 Web References and the same credentials.
Strange enough everything seemed to work fine at first. Until I realized, that it does not use the given credentials to authenticate. Instead it authenticates with my own domain user.
I also tried to get it to work with explicitly setting the binding with a BasicHttpBinding but I only could get the same broken logic to work or I got various authentication/protocol/security errors.
So it seems the authentication is basically working. It just doesn't use the provided credentials. So my question is: How can I configure it to work with the provided identity?
I also found out that it might have anything to do with a cached Windows token. But how can I get rid of it. How to prevent caching in the first place?
EDIT:
Specified the variable types explicitly.
string url = "http://someServer/AdministrationService.asmx";
AdministrationServiceSoapClient client = new AdministrationServiceSoapClient(
AdministrationServiceSoapClient.EndpointConfiguration.AdministrationServiceSoap,
url);
WindowsClientCredential credential = client.ClientCredentials.Windows;
credential.ClientCredential.UserName = "username";
credential.ClientCredential.Password = "password";
credential.ClientCredential.Domain = "DOMAIN";
GetServerInfoRequest getServerInfoRequest = new GetServerInfoRequest
{
// some stuff set here
};
GetServerInfoRequest getServerInfoReply = await client.GetServerInfoAsync(getServerInfoRequest);
As far as I know, BasicHttpBinding has security disabled by default, but can be added setting the BasicHttpSecurityMode to a value other than None in the constructor. It can be configured according to the instructions in BasicHttpBinding and BasicHttpBinding Constructors.
By default, setting up client credentials involves two steps: determining the type of client credential required by the service and specifying an actual client credential, as described in this document.
After waiting a day it is working. It seems that the cached credentials became invalid somehow.
Strange enough the simple service creation from above is not working anymore. Instead I have to use the following.
var client = new AdministrationServiceSoapClient(
new BasicHttpBinding()
{
Security = new BasicHttpSecurity()
{
Mode = BasicHttpSecurityMode.TransportCredentialOnly,
Message = new BasicHttpMessageSecurity()
{
ClientCredentialType = BasicHttpMessageCredentialType.UserName,
},
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Windows,
ProxyCredentialType = HttpProxyCredentialType.Windows,
}
},
},
new EndpointAddress(url));

CRM Context Object persists connection even when creating new instance

I have a system in place for a WCF Service, in which I take in some credentials from the client. I then try to authenticate with CRM using these credentials. If the authentication fails, I use a pre-defined service account, with the credentials stored in web.config.
What I have found is, no matter what, the first set of credentials used persists for any further requests, no matter how much I tear down the first object. I even instantiate new objects, wrap each context in a using statement, etc.
I have watered the code down into a simple 'connect, retry' block, and this suffers the same issue. The code is as follows:
try
{
var connection = new CrmConnection();
connection.ServiceUri = new Uri("https://my.crm.dynamics.com/");
connection.ClientCredentials = new ClientCredentials();
connection.ClientCredentials.UserName.UserName = "removed1";
connection.ClientCredentials.UserName.Password = "removed1";
using (var crm = new CrmOrganizationServiceContext(connection))
{
var req = new Microsoft.Crm.Sdk.Messages.WhoAmIRequest();
var resp = (Microsoft.Crm.Sdk.Messages.WhoAmIResponse)crm.Execute(req);
}
}
catch (Exception ex) { }
try
{
var connection = new CrmConnection();
connection.ServiceUri = new Uri("https://my.crm.dynamics.com/");
connection.ClientCredentials = new ClientCredentials();
connection.ClientCredentials.UserName.UserName = "removed2";
connection.ClientCredentials.UserName.Password = "removed2";
using (var crm = new CrmOrganizationServiceContext(connection))
{
var req = new Microsoft.Crm.Sdk.Messages.WhoAmIRequest();
var resp = (Microsoft.Crm.Sdk.Messages.WhoAmIResponse)crm.Execute(req);
}
}
catch (Exception ex) { }
Assume that removed1 is incorrect and removed2 is correct. The second call will fail instantly with a token exception, saying invalid credentials. If removed1 is correct, and removed2 is not, the first will authenticate and get the WhoAmIRequest fine. Then, removed2 should fail, but it does not, as it seems to still hold the connection using the old credentials. The invalid credentials still allows the service to make requests. Not good!
The bizarre thing is, the code for the authentication is in a separate project. I have included this project in a simple console application, and everything works fine. I can only assume this is something to do with the WCF service and the way it holds connections. I've tried manually disposing, calling garbage collection, setting to null, etc. I've also tried using web config connection strings called by name (hard coded 2 test ones), tried manually creating the connection string settings with unique names, using CrmConnection.Parse(), etc.
I have even copy pasted the code i'm using directly into a console application, and it works fine. Due to this, I am convinced it is to do with the behavior of a WCF service, and not the code itself. I set the class to have the behavior of
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
But no luck. If it is of any importance, this code is running in a message inspector class which implements IDispatchMessageInspector.
How can I ensure that I can get a fresh session? Thanks.
You are using the default constructor of the CrmConnection class. When doing that, your connection is cached by name. This name is supposed to be the name of the ConnectionStringSettings, but using this constructor that property is never being set and keeps its default value, thus always returning the first connection object created.
Just use another overload of the constructors, e.g. that using a connection string or accepting the service url, credentials etc.
The CrmConnection class was designed to offer an easy way to create connectionstrings in config files, similar to database connection strings. It had its issues and has been removed from the Dynamics CRM 2016 SDK.

Acumatica Web Services API Login

I am attempting to perform some basic integration using Acumatica's web services. Unfortunatly, I'm having problems logging in. According to their documentation, this process should look something like:
apitest.Screen context = new apitest.Screen();
context.CookieContainer = new System.Net.CookieContainer();
context.AllowAutoRedirect = true;
context.EnableDecompression = true;
context.Timeout = 1000000;
context.Url = "http://localhost/WebAPIVirtual/Soap/APITEST.asmx";
LoginResult result = context.Login("admin", "E618");
Simple enough. However, after creating and importing a WSDL file from Acumatica into Visual Studio, I found I don't have a Screen object. I do, however have a ScreenSoapClient object, which has a similar Login() method.
ScreenSoapClient context = new Acumatica.ScreenSoapClient("ScreenSoap");
LoginResult result = context.Login("username", "password");
That part works. In fact, the LoginResult give me a session ID. However, if I try to make any calls to the service, such as:
CR401000Content cr401000 = context.CR401000GetSchema();
I get an error: System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> PX.Data.PXNotLoggedInException: Error #185: You are not currently logged in.
While the version of Acumatica we're using does appear to be slightly newer, I'm unsure why the Screen() object isn't available. Consequently, if I try a bad username/password, Login() does fail (as it should). From what I can the tell, the ScreenSoapClient class is using service model details from web.config, so it's getting the endpoint address and other details there.
Is there something I'm missing or doing wrong?
As i see, you use WCF to create your service reference.
So you should enable cookies in service binding:
var binding = new BasicHttpBinding()
{
AllowCookies = true
};
var address = new EndpointAddress("http://localhost/WebAPIVirtual/Soap/APITEST.asmx");
var c = new ServiceReference1.ScreenSoapClient(binding, address);
Or, you can use old asmx web service reference (http://msdn.microsoft.com/en-us/library/bb628649.aspx).
Then everything will be same as in Acumatica`s documentation.
As noted in a comment above, I was able to make contact with a representative from Acumatica. He had me remove then recreate the service references in our project and try again. That apparently did the trick and the "Error #185: You are not currently logged in" error went away.

PayPal SOAP API - Version is not supported

I use .Net, and Visual Studio 2010.
I downloaded the WSDLs and corrected the maxOccurs error, and adding the WSDL as a Web Reference works just fine.
The problem occurs when I call SetExpressCheckout. The error simply says, Version is not supported. I have checked the version of the WSDL, which is 76.0 - and should be correct AFAIK.
The Web Service endpoint being used is this: https://api.sandbox.paypal.com/2.0/
Is there anywhere I need to specify the version, or is the service endpoint being used wrong?
If anyone has the same problem, you need to specify the version:
PayPalAPIAASoapBinding api = new PayPalAPIAASoapBinding();
// Service Provider's API Credentials
api.RequesterCredentials = new CustomSecurityHeaderType();
api.RequesterCredentials.Credentials = new UserIdPasswordType();
api.RequesterCredentials.Credentials.Username = this.Username;
api.RequesterCredentials.Credentials.Password = this.Password;
api.RequesterCredentials.Credentials.Signature = this.ApiSignature;
// The merchant's PayPal e-mail address (3rd party authentication)
api.RequesterCredentials.Credentials.Subject = this.CustomerId;
SetExpressCheckoutReq req = new SetExpressCheckoutReq();
req.SetExpressCheckoutRequest = new SetExpressCheckoutRequestType();
req.SetExpressCheckoutRequest.SetExpressCheckoutRequestDetails = new SetExpressCheckoutRequestDetailsType();
req.SetExpressCheckoutRequest.Version = "74.0";
Right now the Sandbox runs in v 74.0, and production in 76.0. PayPal doesn't always run same versions across their environments.

Dynamically switch WCF Web Service Reference URL path through config file

How do you dynamically switch WCF Web Service Reference URL path through config file ?
Are you just wanting to override the URL that is in the config to a different url. Say you have a test service and a live service. You can just do this.
client.Endpoint.Address = new EndpointAddress(Server.IsLiveServer() ?
#"LiveUrl" : #"TestURl");
Where those url come from wherever you want
Just to expand on the answer from Erin: -
MyClient client = new MyService.MyClient();
client.Endpoint.Address = new EndpointAddress(new Uri("insert new url here"),
client.Endpoint.Address.Identity, client.Endpoint.Address.Headers);
client.Open();
HTH!
There is no dynamic switching. Each time you want to use another URL you must create new instance of service proxy (client) and pass EndpointAddress or enpoint configuration name to the constructor.
I have been trying to do the same thing but most of the accepted answers in various posts just change the address. Currently under .net 4.7, simply changing the address itself does not work. If you have two different servers and wanting it to switch from one to the other, you have to do this:
var client = new MyService.Service1Client();
var newAdrEndpoint = new EndpointAddress(new Uri("second server address"));
client = new MyService.Service1Client(client.Endpoint.Binding, newAdrEndpoint);
Essentially you need to create a new service using the same binding from the first server and passing in the new address. This is the simplest method I have found.
sure you can do this, have a look here: How to config clients for a wcf service?
it is absolutely normal to point to localhost in development and to change the address (url) in production in the web.config
you canĀ“t chance endpoint url after any calling.
E.G.
in that case, you will get answer from NEWURL:
MyClient client = new MyService.MyClient();
client.Endpoint.Address = new EndpointAddress("NEWURL");
client.Hello(); //return is hello response from NEWURL
but if you will call any method before changing url, the url will be used from app.config, like next example:
MyClient client = new MyService.MyClient();
client.Endpoint.Address = new EndpointAddress("NEWURL");
client.Hello(); //return is hello response from BASEURL

Categories