Why InstanceContextMode.PerSession behave like PerCall when using wsHttpBinding?
Asked Answered
E

2

8

I have WCF service consumed by AJAX client using SOAP 1.2

Web.config:

<endpoint address="" binding="wsHttpBinding" 
contract="WcfService1.IService1" bindingConfiguration="wsHttpBin">

<wsHttpBinding>
  <binding name="wsHttpBin">
    <security mode="None"/>          
  </binding>
</wsHttpBinding>

From what I have read, I have to use <security mode="None"/> since a service exposed with “wsHttpBinding” binding implements WS-Security of WS-* family of web service specifications. As the binding uses security, the request will be rejected since AJAX doesn't support the security context.

My WCF service behavior is defined with InstanceContextMode.PerSession:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, 
                 InstanceContextMode = InstanceContextMode.PerSession)]

but when I consume it, the service behave as PerCall and every call starts a new WCF instance instead of using the current instance.

Why InstanceContextMode.PerSession behave like PerCall when using wsHttpBinding?

What can I do?

Ergotism answered 6/12, 2012 at 14:52 Comment(4)
possible duplicate: #4767602Agnusago
@Agnusago Thanks but using <reliableSession enabled="true" /> isn't an option for me since it won't work with my AJAX client.Ergotism
By itself wsHttpBinding doesn't support sessions.Agnusago
@Agnusago so what can I do to consume Wcf from Ajax and using sessions?Ergotism
D
4

Sessions, when used over HTTP, are only supported by WCF when using security sessions or reliable sessions. If you can't use either then you have to implement a session mechanism by yourself. If you control both the client and the server side, it would be quite easy to do it. Here's how:

Create a class that holds all the session data you need stored (let's call it SessionData), plus an additional DateTime for when the session was last used. Then add to your service class (or any other class) a static ConcurrentDictionary<string, SessionData>.

When a client makes a call to your service, require it to pass a unique string that identifies the session (it can be randomly generated on the client side). Whenever a client calls you service, look up the session string in the dictionary and retrieve the session data (and update its content as needed). If it doesn't exist, create a new entry in the dictionary. Also, every time you access the SessionData object, update the 'last used' DateTime to the current time. A background task should periodically clear out old sessions that haven't been used in a while.

That's it - you've implemented sessions on your own. You can now useInstanceContextMode.Single and not worry about WCF correctly creating instances of your service class per session.

EDIT: If you're writing your WCF service with .NET 4.5 and you web application only targets modern browsers, you can use NetHttpBinding on the server side and WebSocket on the client side. NetHttpBinding supports session (when specifying SessionMode.Required).

Duodenal answered 9/12, 2012 at 16:29 Comment(6)
+1: Not saying your suggestion flawed to start with, but to implement a production ready session mechanism there is a whole bag of issues to consider or take care of: like session hijacking (accidental or on purpose), the actual session timeouts that make sense for your application, session (data) persistence/resilience, in case the server restarts (planned or unplanned/crash), concurrent modification of the session (data) by multiple, concurrent requests, etc.Basset
@Christian.K: Very true. I don't believe the last two things are provided by WCF at all though. Security is indeed an issue to take into consideration, and as for thread safety I assumed each client would generate a unique session key and would perform at most one call to the service at any given time, but if that's not the case that thread safety and correctness also needs to be taken care of.Duodenal
@AllonGuralnek isn't using InstanceContextMode.Single will have major impact on my performance?Ergotism
@Dor: Not if you use ConcurrencyMode.Multiple. Your service should only be using data from the SessionData object anyway since (if you're not using Single) any instance fields are per-call (so they might as well be local variables/parameters). Which is why Single make sense in your case - everything is either local or in the SessionData, instances of your service class are meaningless.Duodenal
So why not using InstanceContextMode.PerCall? at that way I can use static variables and it will has better performance, what do you think?Ergotism
Again, instances don't matter in your case. You can't have any instance fields or properties. So that class will just have methods, and creating instances of such a class is a waste of time. In your case it will actually be slower to have anything other than Single. Also InstanceContextMode has nothing to do with accessing statics.Duodenal
D
0

This link gives You pretty much all You need to know about this (in general of course).

But to precise. Msdn says about WCF session:

They are explicitly initiated and terminated by the calling application

I must say that I don't know about any JS code/framework that would allow You to store explicitly opened WCF communication channel to keep Your "session" alive. (You haven't provided your client code so I must make some assumptions). WCF session is not "cookie-based". It doesn't work "out of the box" from your browser like it would for ASP.NET web application.

Setting InstanceContextMode.PerSession makes Your WCF service "session-ready" but it is not enough to "force" a session.

Deficiency answered 9/12, 2012 at 16:52 Comment(1)
What do you mean about "cookie-based" for ASP.NET? if I will add <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> so can I use it? can I have "out of the box" solution.Ergotism

© 2022 - 2024 — McMap. All rights reserved.