I am connecting to a 3rd party API. They have provided me with a WSDL file which i have added by using a web reference. Is it possible to connect via SOAP and send multiple messages across the same connection?
I have created the client from the proxy classes but there doesn't appear to be a Open() or a Close() method. Does the client connect and disconnect when a method is called?
SampleService client = new SampleService
client.SampleMethod();
Edit:
I have added a "Service Reference" from the WSDL file. The client is constructed from the "PortType" in the WSDL file. There inst a Close() or a Abort() method. The only method on SampleService.client is SampleMethod()
They have provided me with a WSDL file which i have added by using a web reference.
In such case you are not using WCF but ASP.NET WebServices client. In your case it is probably not a big difference but ASP.NET WebServices are mostly for backward compatibility when moving legacy code to new version of .NET framework. Today you should rather use Add Service Reference to use WCF as other also recommended.
SOAP Connection WCF
There is nothing like SOAP connection. SOAP is application protocol tunneled through some transport protocol. In your case the transport protocol is HTTP.
I have created the client from the proxy classes but there doesn't
appear to be a Open() or a Close() method. Does the client connect and
disconnect when a method is called?
You don't need to call Open or Close. This is all handled in low level layer of communication stack. By default all HTTP client applications use something called persistent connection. It means that when you access some host for the first time TCP connection is established between your client computer and server hosting target resource. Subsequent calls reuse the same connection. If the connection is not in use for some predefined time (both client and server can have different timeouts) the connection is closed and next time the client wants to call the server it will create a new connection (again you don't need to bother with this).
So calling the method on SOAP proxy in your application can automatically open connection if no one exists. You don't need to explicitly close the connection but you should dispose the proxy to release its resources. Connection itself can live after the proxy was disposed and can be reused by another proxy.
You should add a service reference (WCF) instead of using the outdated Web Reference.
Then follow the bellow pattern:
try
{
SampleServiceClient client = new SampleServiceClient();
client.SampleMethod();
//... Make as many calls to as many methods as you like.
client.SampleMethod();
client.Close();
}
catch (Exception e)
{
//client is unusable once an exception occurs.
...
client.Abort();
throw;
}
You need to use the Add Service Reference rather than Add Web Reference. And once added you can invoke the service as shown:
using(SampleServiceClient client = new SampleServiceClient())
{
var response = client.SampleMethod();
}
Hope that helps.
Related
What Works
I built a DataSnap web service in Delphi-XE2, which uses the TDSServer and TDSHTTPService components. Clients attach to the server (web service) and run DataSnap server methods to retrieve data. The server uses TDSLifeCycle.Session for all connections. I want to continue to use Session if possible because I store session information in thread variables...
I can use Internet Explorer to authenticate to and retrieve data from the DataSnap server. If I don't let IE sit idle for 30 seconds (or it disconnects from the server), it will reuse the same connection for every method request.
I can use a simple Delphi app that uses TIdHTTP to connect to the DataSnap server. Adding keep-alive to its Request.Connection property makes it stay connected forever and reuse the one connection for all method calls.
.
Problem
A 3rd party company is building a WCF app to access the DataSnap service. They can't get WCF app to use only one connection to the service. The initial authentication request and 1st method call use the same connection, but subsequent requests create new connections, evident by running netstat on their computer and seeing new ESTABLISHED connections from their app to my service using multiple source ports. New connections create new threads in the DataSnap server, which can't access the authenticated thread's session variables.
.
Possible Workaround
I know that I can change the DataSnap server to an Invocation model, making it unnecessary to maintain one persistent connection per client, and will do this if needed. Before doing so, I thought it prudent to see if anyone else knows how solve the problem.
.
My Question
Is it possible for a WCF client app to create a single persistent connection to a non-WCF server (DataSnap server) that it uses for all method calls without it creating new connections? How is this done? Is it as simple as adding the right [decoration] to the C# WCF project in Visual Studio?
Any suggestions are greatly appreciated!
.
FYI - I don't have access to the 3rd party's code, so I can't provide samples of the WCF code.
Your Delphi application provides a stateful web service (using session variables), and WCF web services are stateless by default, including WCF clients.
Maybe this answer points to the correct configuration (wsHttpBinding and SessionMode of the ServiceContract).
From the MSDN ocumentation:
For example, if the SessionMode property is set to
SessionMode.Required and the InstanceContextMode property is set to
PerSession, clients can use the same connection to make repeated calls
to the same service object.
(highlighting by me)
However, as DataSnap is not primarily designed for interoperability with WCF it might be easier to re-design the Delphi side to use a stateless web service model instead of stateful. This would require authentication with every service request, but internally the Delphi web service could some cache data to reduce lookup times, similar to the current session state.
I am not sure this is even possible to be honest,
I am wondering if there is a way of removing the use of the config file without having to override the creation of the client proxy. Let me give an example:
In a client app we have a WCF DAL project. This is a wrapper for their WCF Server for the client app to consume. At present the client app would need all the bindings and endpoints given in the config file and would normally (in our projects) do something like the following to wrap the WCF service:
public MyObject GetMyObject(int id)
{
using(var service = new MyObjectDataServiceClient())
{
return service.GetMyOBject(id);
}
}
This would create the call to the server and get an object back. If the client app didn't have the bindings and endpoints it would blow up. We could change each creation of the data service client to create the binding and endpoint, or create our own chanelfactory to do this for us but this means changing the current WCF DAL layer code.
My goal is to try and create a way of inserting a process into the WCF DAL layer that will handle the bindings and endpoints without the consuming code having to change, whilst removing the need for the config file.
My thoughts so far were to try and use a TT file so that it would create a partial class of the data service client and override the channel factory part. This failed because of the constructor call for the data service client goes straight into the abstract class (System.ServiceModel.ClientBase<T>) and tries to get the config stuff out. I could not find a way of stopping it looking in the config via this partial class and not changing the WCF DAL service layer.
If you have the binding and the endpoint at the DAL, you can use a different constructor of the client class (one which takes the binding + endpoint address). That constructor completely bypasses configuration, so you don't need to have anything in config.
I am using WebClient to download some resource in following way:
Stream stream;
try
{
WebClient webClient = new webClient();
stream = webClient.OpenRead(MyResourceUri);
}
catch (Exception)
{
return null;
}
return stream;
When I do this in a WPF application, it works fine and proper stream is obtained.
When I do this in a WCF service call, it doesn't work. A WebException is thrown with message "Unable to connect to remote server". (It works for files hosted on my machine or within company network, however it fails for any resource on web). The service is hosted on IIS7.
Investigation so far reveals the difference is because of the webproxy. The webclient.proxy in WPF application refers to the proxy settings as set in IE, whereas the one in WCF is having none.
Why is it so? And more importantly, how can I make the WebClient in WCF use similar proxy settings?
EDIT: I set the proxy on WebClient and it worked in WCF service
webClient.Proxy = new WebProxy(ProxyAddressFromIE);
Here I have hardcoded the proxy addess. What method/APIs are there to obtain one? And still why its different in WCF service & in WPF application?
To answer one of your questions, the reason there is a difference between your WPF application and your IIS hosted WCF service is this.
WPF applications run in an actual Windows session (your user session to be exact). This means there is a user profile loaded for that session and that session contains, amongst other things, the proxy settings as configured in IE.
WCF services hosted in IIS do not run in a Windows session. They are run as a service and therefor do not have a Windows session (they actually run in session 0, but that's just an implementatio detail). This means there is no proxy configuration.
To reliably solve this, you could have your own configuration for a proxy, perhaps in web.config.
Another option is to configure the proxy through netsh.exe.
I needed to do the exact same thing, and I found the answer here: Get the URI from the default web proxy. Basically, you need to dynamically read the proxy using WebRequest.GetSystemWebProxy() and by determining the proxy using a test proxied url.
Hope this helps!
Consider handling the call using sources other than the highly abstracted WebClient. From the higher to lower level, this means exploring WebRequest and WebResponse objects all the way down to programming off the socket. The reason is the WebClient method is tightly coupled to choices in Internet Explorer, as much of the high level Internet stack is in windows. If you want to get around this, you need to dig deeper.
I would love to point a finger at precisely where to dig, but I have not incurred this particular issue and have no experience solving. I know where to look for the answer, but no specifics on "X marks the spot". Because of the high level, highly abstracted nature of WebClient, however, I am not sure you can easily get around the implicit creation of the stack and/or the coupling with IE, without more headaches than punting and using an object that gives more explicit control of HTTP communication.
Happy hunting.
I have a WCF service that works perfectly fine unless I attempt to use a proxy in the communication stream such as:
AnonClient anonService = new AnonClient();
var bindHttp = anonService.Endpoint.Binding as BasicHttpBinding;
bindHttp.ProxyAddress = new Uri("http://149.169.227.131:3127");
bindHttp.BypassProxyOnLocal = false;
bindHttp.UseDefaultWebProxy = false;
As soon as the proxy is introduced - and it can be any proxy - IIS immediately rejects the request with a 405 error. There is no authentication occurring at the IIS level - I take of everything in code - anonymous access is enabled - so what is wrong with my IIS configuration?
Just to close this loop, the issue was using an Open Proxy with a WCF service which, by default, emits SOAP. Most open proxies block SOAP and were shutting things down. The solution is actually simple - add JSON attributes on top of the WCF service calls and run over the RESTful interface
Short Version:
When I've created a Channel using ChannelFactory on a client which uses duplex communication, do I need to keep the channel open in order to receive the callback or can I call ChannelFactory.Close()?
Long Version:
I'm developing my first WCF service and I've created my own ClientProxy Class, which implements and amalgamates a few different services into one. I use a ChannelFactory to create each channel, and my general reading on the net has indicated I should cache the ChannelFactory, but I should only open and close the actual channel when its needed.
So I call ChannelFactory.Open to open a channel and perform a duplex operation (a one-way operation which later calls a callback). Should I close this channel by calling ChannelFactory.Close after I've requested the operation, and if I do, will I still receive the callback?
Basic testing seems to indicate I will receive the callback if I close the connection however I just want to be sure. Also, is this method of caching the ChannelFactory correct?
Thanks
You should keep the client side proxy open while you wish to receive callbacks and when done you should close the channel.
Here's a quote from the great book Programming WCF Services by Juval Lowy (I suggest you to read the whole chapter about callbacks):
5.3.4. Callback Connection Management
The callback mechanism supplies nothing like a higher-level protocol for managing the connection between the service and the callback endpoint. It is up to the developer to come up with some application-level protocol or a consistent pattern for managing the life cycle of the connection. As mentioned previously, the service can only call back to the client if the client-side channel is still open, typically done by not closing the proxy. Keeping the proxy open will also prevent the callback object from being garbage-collected. If the service maintains a reference on a callback endpoint and the client-side proxy is closed or the client application itself is gone, when the service invokes the callback, it will get an ObjectDisposedException from the service channel. It is therefore preferable for the client to inform the service when it no longer wishes to receive callbacks or when the client application is shutting down. To that end, you can add an explicit Disconnect( ) method to the service contract. Since every method call carries with it the callback reference, in the Disconnect( ) method the service can remove the callback reference from its internal store.