views:

1894

answers:

3

I have a WCF chat service that accepts duplex tcp connections. A single duplex tcp connection can be used to send and receive messages for more than one user (so I can have multiple chat servers that all connect to each other).

Now I want to add Web users into the mix, to let them chat with the desktop users. This is for a live-support type thing. Basically I'm trying to find out the best way to do "out of band" communications from ASP.Net to this chat service.

I was thinking that I could have a static/global duplex connection to one of the chat servers and I could use that for all requests to that ASP.Net server. Would this work? The duplex connection is ALL one-way calls, can I use this WCF channel without locking access to it?

UPDATE: Thanks for your suggestions so far. I should have noted: My chat service is self-hosted, it's not running in IIS. So, I'm mainly concerned with how I can make IIS hold a connection open until the application unloads. The connection from web browser to IIS will be silverlight, flash, ajax, iframes, anything.

A: 

This may not answer you question, but you might be able to have silverlight do this and use similar code that your desktop version uses.

NotDan
Thank you, I do plan to do a silverlight client I can't wait to get to that part :)
wizlb
A: 

One possibility to consider is to serve up a Silverlight 2 application as part of the ASP.NET page that the Web users navigate to.

This Silverlight application could make use of the WCF Polling Duplex support in the System.ServiceModel.PollingDuplex.dll assemblies (one for Silverlight app one for WCF server) that come with the Silverlight 2 SDK.

I have a few blog posts and a sample application that demonstrate how to 'push' Stock updates from a Console Application that self-hosts a WCF service with two endpoints as follows:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace StockServer
{
    public class StockServiceHost : ServiceHost
    {
     public StockServiceHost(object singletonInstance, params Uri[] baseAddresses)
      : base(singletonInstance, baseAddresses)
     {
     }

     public StockServiceHost(Type serviceType, params Uri[] baseAddresses)
      : base(serviceType, baseAddresses)
     {
     }

     protected override void InitializeRuntime()
     {
      this.AddServiceEndpoint(
       typeof(IPolicyProvider),
       new WebHttpBinding(),
       new Uri("http://localhost:10201/")).Behaviors.Add(new WebHttpBehavior());

      this.AddServiceEndpoint(
       typeof(IStockService),
       new PollingDuplexHttpBinding(),
       new Uri("http://localhost:10201/SilverlightStockService"));

      this.AddServiceEndpoint(
       typeof(IStockService),
       new WSDualHttpBinding(WSDualHttpSecurityMode.None),
       new Uri("http://localhost:10201/WpfStockService"));

      base.InitializeRuntime();
     }
    }
}

WPF clients connect to the WSDualHttpBinding endpoint and Silverlight clients connect to the PollingDuplexHttpBinding endpoint of the same WCF service. The app also shows how to handle the Silverlight client access policy requirements.

Clients (Silverlight or WPF) can add notes against a Stock in their UI and these notes propagate back to the server to be pushed to all other clients. This demonstrates communication in either direction and hopefully performs most of the necessary communication required for a chat application.

You can see a screenshot of the demo application running here.

Peter McGrattan
I am definitely going to make a Silverlight client before I'm through, but that is the connection from web-client to IIS. I am struggling with finding the best solution for connecting IIS to my self hosted service without doing a wcf connection per web user.
wizlb
I see what you're getting at now you've updated the question. Note that the server side does not have to be IIS with Silverlight polling duplex.
Peter McGrattan
+1  A: 

Your best bet is to implement a bi-directional message queue at the app level, indexing messages by a user and a session identifier. Then you could have the app level WCF service (aka peer) pop and push based on wait objects. Access to the queue will be need to be locked, but this is relatively low cost. WCF service will do the heavy lifting. At some point, though, I would expect the app to experience bottlenecks if only a single proxy is being used for sending messages. It seems to me that having a dedicated channel proxy per session might be more efficient, thereby keeping things less stateful. I would also allow for non-duplex connections, since all messages are one way operations.

EnocNRoll
You're right. I will have to do a bi-directional message queue or two separate message queues per connection to the duplex service. I was also thinking of using a ReaderWriterLockSlim to guard a POOL of wcfDuplexClients that grow and shrink and are stored in a static/global collection.
wizlb
Each wcfDuplexClient in the pool could have it's own in/out message queue. So, I could read-lock the ReaderWriterLockSlim, grab a wcfDuplexClient, lock(wcfDuplexClient.sendLock){ wcfDuplexClient.Send(myCommand); }, etc.
wizlb
Still thinking about a dedicated channel per session. That might be the best way yet.
wizlb
Having a single ServiceHost that is hosting the queued incoming messages on its endpoint(s) and which also sends out queued messages to by connecting back to other chat ServiceHosts on the network could be set up to use a thread pool and then instantiate the thin proxies for sending messages.
EnocNRoll
A pool of channel proxies might end up being a good approach, too: http://jack.whyyoung.com/blog/weblogs-asp-net-rawmainfeed-aspx/WCF-Client-Channel-Pool--Improved-.htm
EnocNRoll
A dedicated channel per session will increase the footprint of the app for N users, but will offer the best speed once the memory initialization penalty is factored out. The in/out message queue per pool object is heavier, but it seems easier to manage and debug.
EnocNRoll