I have to create a WCF web service that proxies an IMAP service (so that it can be consumed by a SL application).
The IMAP service requires that first the Login(credentials) method is called, to authenticate with the IMAP server. After the Login method is called the connection is kept open and other operations can be performed.
Does anybody know how can achieve this with a WCF service?
One solution I want to avoid is the proxy to login for every operation it has to perform (as the login operation usually takes 1-2 seconds). And I would have to pass the credentials every time: GetMail(credentials), GetFolders(credentials), etc.
I know it is highly recommended that WCF services not to be stateful, but it seems I need to keep the state of IMAP connection for every client. How can I do this?
Thanks!
This is one of those rather rare cases where I think using WCF sessions makes sense:
your first call that calls the IMAP Login method starts a WCF session
any subsequent call will be using the same session
some final call (e.g. something like a Done or Logout) will terminate that session
With a session in WCF, your service class on the server stays in memory for the duration of the entire session, i.e. it's not constantly re-created, and thus you can keep the IMAP connection "live" inside your service class.
Resources:
Sessions, Instancing, and Concurrency (MSDN)
Using Sessions (MSDN)
WCF Sessions - a brief introduction
WCF Sessions
Per-Session Instance Management in WCF
Be aware: WCF sessions are NOT ASP.NET sessions - those are two totally different things! Just to be clear from the get-go.
Also: only a handful of WCF bindings support sessions - netTcpBinding, wsHttpBinding and netNamedPipeBinding (as far as I know)
Related
I'm developing a UWP client project which need to consume some services of a WCF server. I uses the "add service reference" tool of Visual Studio to auto generate service clients(proxies). The binding type is NetTcpBinding. Below is some code snippet which create the service client:
NetTcpBinding tcpBinding = new NetTcpBinding();
tcpBinding.Security.Mode = SecurityMode.None;
tcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
tcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
MainServiceClient = new MainServiceClient(tcpBinding, new EndpointAddress("net.tcp://localhost:8773/MyWCF/MainService/tcp"));
The question is do I need to call OpenAsync() method of MainServiceClient? It seems the service client can be auto opened when it is first called. But I read from this article that auto-opened service client would have some performance penalty. The article was written in 2007. I just wonder if this mechanism have changed today, especially in UWP project. Can anyone share more light on this topic? Thanks!
To explain this case, you should know three ways to do WCF instance management. WCF has provided three ways by which you can control WCF service instances:Per call, Per session, Single instance.
When we configure a WCF service as per call, new service instances are created for every method call you make via a WCF proxy client.
Very often we need to maintain state between method calls or for a particular session. For those kinds of scenarios, we will need to configure the service per session. In per session, only one instance of a WCF service object is created for a session interaction.
Often we would like to create one global WCF instance for all WCF clients. To create a single instance of a WCF service, we need to configure the WCF service as Single instance mode.
And there are three ways by which you can handle concurrency for each service instance in WCF :single, multiple, and reentrant.
Single: A single request has access to the WCF service object at a given moment of time. So only one request will be processed at any given moment of time. The other requests have to wait until the request processed by the WCF service is completed.
Multiple: In this scenario, multiple requests can be handled by the WCF service object at any given moment of time. In other words, requests are processed at the same time by spawning multiple threads on the WCF server object. So you have great throughput here but you need to ensure concurrency issues related to WCF server objects.
Reentrant: A single request thread has access to the WCF service object, but the thread can exit the WCF service to call another WCF service or can also call a WCF client through callback and reenter without deadlock.
In "Instance mode = Per Session and Concurrency = Single" combination, one WCF service instance is created for every WCF client session because the WCF instance mode is set to per session. All the method are executed in a sequential manner one by one. In other words, only one thread is available for all method calls for a particular service instance.
For the above scenario, you should always open WCF client proxy explicitly before you are making any calls. Because it will maintain service state between method calls and obtain high performance.
For more detail you could refer to "WCF Concurrency (Single, Multiple, and Reentrant) and Throttling" and "Three ways to do WCF instance management".
I am using wsHttpBinding to call a WCF web service. When I look into the Fiddler2, I see multiple calls to the server before calling my actual OperationContract.
From this post I understood what these service calls are doing.
However, I want to know if there is any way to avoid these calls after first successful service call.
In my application, the web service is called so frequently that 3-4 additional calls per actual call to web service operation will not be accepted.
As you mentioend what happens is that WCF negotiates for a key. More details in here.
You have a few options:
set negotiateServerCredential and establishSecurityContext to false (this would require the client to have the server certificate out of band)
change to a different security mechanism (user name auth, or transport with SSL)
stay with the current situation. Once the negotiation is established no more extra calls are made. They happen once per proxy generation.
There is no way to make the negotiation process shorter. It consists of several message exchanges since this is the WS-Trust protocol.
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.
If I set my servis instance as Per Session or Single can I send some data between services instance in session? It should be done in Asp.net session - HttpContext.Current.Session
or wcf have own session ?
As I said - WCF is not ASP.NET and its session handling is vastly different. While ASP.NET sessions and WCF sessions are called the same - they are vastly different in their purpose and usefulness.
Read the MSDN page Using Sessions in WCF for more details.
One sentence reads: There is no general data store associated with a WCF session. - so the answer is no - sessions in WCF are not meant for data storage.
WCF sessions are merely to "tie together" several messages into a conversation. By default, with the "per-call" model, each WCF service request would get its own, freshly instantiated service class instance to handle the request, and that service class instance will be freed after returning the answer. Using sessions avoids this - the service class instance handling the first call of a session will stay alive on the server side (and thus also taking up memory on the server) and will handle all subsequent requests within the same session.
WCF and web services in general should however preferably be stateless, so sessions are a bit of an oddball architecture in a proper SOA environment - and that's most likely why sessions in WCF are also not nearly as useful as ASP.NET sessions are for web apps.
To remain stateless and support the per-call method (the preferred best practice), if you need to store data between calls, store it in a persistent store (e.g. a database) and fetch it back from there when needed later on.
If you're hosting services in IIS, you can enable ASP.Net Compatability mode. This will allow you to use ASP.Net session state, just like you would in a web application.
Here is my scenario, and it is causing us a considerable amount of grief at the moment:
We have a vendor web service which provides base level telephony functionality. This service has a SOAP api, which we are leveraging to build up a custom UI that is integrated into our in house web apps. The api functions on 2 levels. You make standard client calls into the service to initiate actions, such as Login, Place Call, Hang Up, etc. On a different thread, the service sends events back to the client to alert the user of things that are occurring on the system (agent successfully logged in, call was disconnected, etc).
I implemented a WCF service to sit between the web server and the vendor service. This WCF service operates in duplex mode, establishing a 2 way connection with the web server. The web server makes outbound calls to the WCF service, which routes them to the vendor's web service. Events are received back to the WCF service, which passes them onto the web server via a callback channel on the WCF client. As events are received on the web server, they are placed into a hash table with the user's name as the key, and a .NET queue as the value to hold the event. Each event is enqueued to the agent who owns it.
On a 2 second interval, the web page polls the web server via an ajax request to get new events for the logged in user. It hits the hash table for the user key, dequeues any events that are present, and serializes them back up to the web page. From there, they are processed in order and appropriate messages are displayed to the user.
This implementation performs well in a single user scenario. The second I put more than 1 user on the system, I start getting frequent timeouts with the following CommunicationException:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
We are running Windows Server 2008 R2 both servers. Both the web app and WCF service are running on .NET 3.5. The WCF service is running under the net.tcp protocol in duplex mode. The web app is ASP.NET MVC 2.
Has anyone dealt with anything like this scenario? Is there a more efficient way (or a widely accepted pattern) to implement this?
EDIT: One thing I forgot to mention - my thought is that the increased traffic (adding additional users) with only 1 dedicated callback channel is causing locking, which then triggers the timeout. There can be up to 10 consecutive callbacks from the service within any 5 second interval.