This sample demonstrates how a Micrososoft Silverlight 3 application can consume asynchronous data notifications from the server using the polling duplex protocol of Windows Communication Foundation (WCF). I am also discussing selected aspects of the implementation, in particular related to performance. The full source code and Visual Studio solution of the sample is available for download. Please also check the Silverlight development environment prerequisites.
The application follows a publisher/subscriber architecture and consists of three components:
- PubSubService.svc is a WCF web service that manages client subscriptions to topics and sending asynchronous notifications to clients when data is published to the topic they are subscribed to. The service exposes an endpoint with a binding based on the polling duplex protocol. The server side implementation of the protocol is available through the PollingDuplexHttpBinding class in the System.ServiceModel.PollingDuplex.dll .NET Framework 3.5 library shipped as part of Microsoft Silverlight 3 SDK.
- PubSubClient.aspx is an ASP.NET page that contains a Microsoft Silverlight 3 client application that can act as both a subscriber and a publisher. The application allows the user to subscribe to notifications related to a particular topic as well as publish data to that topic. The client communicates with the PubSubService.svc service using a WCF proxy and the client side implementation of the PollingDuplexHttpBinding, which ships as a Silverlight 3 extension assembly System.ServiceModel.PollingDuplex.dll within the Microsoft Silverlight 3 SDK.
- PublisherClient.aspx is an ASP.NET page that contains a Microsoft Silverlight 3 client application that can act as a publisher only. The application allows the user to start publishing data to a particular topic at specified frequency, therefore causing a stream of regular notifications to be sent to subscribed clients. The client communicates with the backend PubSubService.svc using the same mechanism as PubSubClient.aspx.
There are two key scenario types that can be demonstrated using this sample: collaboration and broadcast.
Collaboration Scenario
In the collaboration scenario we have a small set of clients (typically 2) acting as both publishers and subscribers of the same topic. An example of a collaboration scenario is a chat. In order to simulate the collaboration scenario, open the PubSubClient.aspx client application in two or more browser windows, subscribe to the same topic in each of them, and then start publishing to the topic by typing text in the provided text box in any of the clients. You should observe the text being propagated through notifications to all other clients.
Broadcast Scenario
In the broadcast scenario we have multiple clients subscribed to the same topic, and a small number of publishers (typically 1) publishing to the topic. An example of a broadcast scenario is propagating stock quotes from a single source to multiple client applications. In order to simulate the broadcast scenario, open the PubSubClient.aspx client application in multiple browser windows and subscribe to the same topic. Then open the PublisherClient.aspx client application in a single browser window and start publishing to the same topic you have subscribed to. You should observe periodic notifications arriving at all subscribed clients.
Key implementation aspects
Server
The PubSubService.svc encapsulates the pub/sub server logic. It is a WCF duplex service exposed over the PollingDuplexHttpBinding that shipped with Microsoft Silverlight 3. The binding implements a comet-style long polling protocol which enables firewall traversal by leveraging HTTP protocol to enable duplex communication.
A few implementation aspects of the service are worth calling out given their implications for performance of the service.
In the broadcast scenario or a collaboration scenario that involves more than 2 participants, identical messages are often sent to several clients. Given that a substantial portion of the cost of sending a message is related to serializing its content, it is worthwhile to pre-serialize a message once and then send a copy of it multiple times. In order to accomplish this, the callback contract of a pub/sub service should take a Message as a parameter as opposed to typed parameters. This allows the message to be pre-serialized and converted to a MessageBuffer using TypedMessageConverter. Then, for every notification to be sent, the MessageBuffer can be used to create a clone of the Message without incurring the serialization cost. This is how the WCF service contract of the pub/sub service looks like:
[ServiceContract(CallbackContract = typeof(INotification))]
public interface IPubSub
{
[OperationContract(IsOneWay = true)]
void Subscribe(string topic);[OperationContract(IsOneWay = true)]
void Publish(string topic, string content);
}
[ServiceContract]
public interface INotification
{
[OperationContract(IsOneWay = true,
AsyncPattern = true, Action="*")]
IAsyncResult BeginNotify(Message message,
AsyncCallback callback, object state);
void EndNotify(IAsyncResult result);
}[MessageContract]
public class NotificationData
{
public const string NotificationAction = "http://…";[MessageBodyMember]
public string Content { get; set; }
}
When a notification is to be sent to multiple clients over the INotification service contract, the message is first pre-serialized using a TypedMessageConverter:
TypedMessageConverter messageConverter =
TypedMessageConverter.Create(
typeof(NotificationData),
NotificationData.NotificationAction,
"http://…");
Message notificationMessage = messageConverter.ToMessage(
new NotificationData { Content = “hello” });
MessageBuffer notificationMessageBuffer =
notificationMessage.CreateBufferedCopy(65536);
Then a copy of the message is sent to all clients, thus avoiding the serialization cost on every send:
foreach (INotification callbackChannel in clientsToNotify)
{
try
{
callbackChannel.BeginNotify(
notificationMessageBuffer.CreateMessage(),
onNotifyCompleted, callbackChannel);
}
catch (CommunicationException) { }
}
Another aspect to emphasize in how the notifications are sent is related to the use of asynchronous API INotification.BeginNotify/EndNotify. Sending a large number of notifications is a high latency activity. Using asynchronous APIs to do so results in more efficient use of system resources compared to the use of synchronous APIs. Alternatively, synchronous APIs could be used if each of the notifications was scheduled to be sent on a separate worker thread from the thread pool. Measurements of both methods indicate the performance difference between them is negligible.
Finally, the concurrency mode of the WCF service is set to ConcurrencyMode.Multiple, and instance mode to InstanceMode.Single. This requires explicit synchronization code to be added around access to critical resources (i.e. data structures related to subscriptions), but the extra effort pays off in reduced contention of concurrent requests to the service:
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.Single)]
public class PubSubService : IPubSub
{
// …
}
There are several more performance considerations for setting up a pub/sub service based on the HTTP polling duplex protocol. I will cover them in an upcoming post dedicated to performance tuning of such scenario.
Client
The key implementation aspect of the pub/sub service client in the sample is the use of the Add Service Reference feature of Visual Studio to automatically generate a proxy to such a service. This is a major usability improvement from Silverlight 2 to Silverlight 3. After the proxy has been added to the client project using the Add Service Reference feature of Visual Studio (or the slsvcutil.exe command line tool offering corresponding functionality), consuming asynchronous notifications from the sever is as easy as hooking up events on the generated proxy:
PubSubClient client = new PubSubClient(
new PollingDuplexHttpBinding(),
new EndpointAddress(“http://…”));
this.client.NotifyReceived +=
new EventHandler<NotifyReceivedEventArgs>(NotifyReceived);
this.client.SubscribeAsync(“my topic”);
Thanks to this feature, the entire pub/sub client application is around 100 lines of C# code.

82 comments:
All I get is: ERROR: The remote server returned an error: NotFound.
What's that mean?
It's not performance I care about so much. I need a *scalable* server. Do you have any metrics related to this?
Hi,
About the NotFound error: there is missing a DLL: "The referenced component 'System.ServiceModel.PollingDuplex' could not be found." in the Asp.net project.
Thanks,
Vítor
Looking at the code, it uses a session-ful binding, a singleton instance and in-memory state - all this means that scaling it out in a server farm is kind of tedious.
What we really need is an enterprise/web-class pub/sub solution for SL and WCF.
Any comment on this?
Thanks.
I get this error: ERROR: The remote server returned an error: NotFound.
and I am not missing the .dll mentioned above.
Current implementation of the HTTP long polling in WCF requires sessionful WCF channels and therefore affinity to a specific backend for the lifetime of a single polling duplex session. If your load balancer cannot support such scenario (which requires content based routing), you will not be able to achieve scale-out of the service in a way that is completely transparent to the client. One possible mitigation of this problem is to have the client explicitly select the backend to communicate with based on configuration, data dynamically obtained from a backend, or a heuristic (e.g. the hash value of the "topic" the client wants to subscribe to).
Bydia, regarding the NotFound error, one thing to check is whether the PubSubService.svc is properly published and accessible. I suggest you set it as a start page in your project and check if the WCF service help page shows up in your browser when you start the solution.
If I run the .svc file directly in browser I get: The type 'System.ServiceModel.Configuration.PollingDuplexElement, System.ServiceModel.PollingDuplex' registered for extension 'pollingDuplex' could not be loaded
With this line in red: pollingDuplex maxPendingSessions="2147483647"
Found the problem. The install of v3 tools didn't remove the old install and the new install didn't register the pollingDuplex dll as global... so it was looking at the old dll. All compiled well and no errors... except at runtime.
I have the same problem as bydia. The assembly was not in the cache, so I installed it with gacutil from C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Server\.
It's now in the assembly cache with a public key token of 31bf386ad364e35, V3.0.0.0.
Starting the .svc file reports the same error as above.
Thoughts? :-)
Thanks!
Ok, I'm working now. I had to remove and re-add the reference copylocal to true.
Thanks!
theStarsMyDesitination, one does not need to GAC the System.ServiceModel.PollingDuplex assembly for the scenario to work. Once the assembly is deployed into the bin folder of the application, the service can expose an endpoint over the polling duplex binding. This also works fine in partial trust environment (offered in shared hosting situations).
I've been struggling with this sample solution for a while now, and could use some help. After downloading the sample solution, fixing the System.ServiceModel.PollingDuplex reference issue, everything is fine. I'm able to use 2 independent clients to publish / subscribe messages back and forth - life is good. However, if I simply navigate to the Silverlight PubSub client project, choose "Update Service Reference..." from within VS2008, all of the DuplexClientBase<> information in the proxy class is lost, and the proxy reverts back to a standard request/reply client (this also obviously breaks the project). Any ideas on what would be causing this behavior? I've manually looked at the WSDL, for the project on my machine _before_ updated the service reference, and it looks like the WSDL is missing all information required to convey the fact that this is a duplex service.
I'm using VS2008SP1, Silverlight 3 SKD / tools (and yes, Silverlight 2 is _completely_ uninstalled) on Vista Utlimate x64, and running the solutions using Cassini.
This is a bug in the sample, thank you for reporting it. I posted an updated version of the sample with a fix at http://janczuk.org/code/samples/PollingDuplexSample.zip.
The bug in the sample was related to a wildcard action on the INotification.Notify operation contract. This was preventing the WSDL generation logic to generate WSDL for the duplex contract, hence preventing the Update Service Reference in Visual Studio from completing its job. The fix was to specify the actual action used to send the notification to the client.
Thank you for the great sample code. I am trying to implement multiple call back contracts on the server side, so that the client can be notified about different events. The service contract will remain the same (Subscribe/Publish) but the callback contract needs to be extended in addition to "BeginNotify" method. I was not able to implement this successfully. The client would get an exception "channel was aborted" and no data would be received. It seems that only one callback channel can be implemented. What am I doing wrong? thank you.
There is a few things that need to happen I can think of to enable diffrent types of notifications: 1) add new service operations to INotification contract; make sure they use different action names, 2) add message contracts similar to NotificationData corresponding to the different notification types, 3) add new types of TypedMessageConverter for all those new message contracts to enable sending pre-serialized messages; make sure that a TypedMessageConverter for a given notification type uses the message action as the corresponding service operation on INotification interface, 4) don't forget to run Update Service Reference on the service reference in the PubSubClient.
Thank you very very much for the quick response. I've been strugling with this for two days now. I had everything implemented except the different actions. It is working great now. I am curious, however, on how this works behind the scenes, especially the action parameter in the [OperationContract] attribute. Again, thank you very much for your help.
The OperationContractAttribute.Action controls the WS-Addressing Action that will be generated on the message. This value allows the client to demultiplex incoming server notifications to the appropriate event handler on the client proxy.
Hi! I can build it, add one more service and run it by using Visual Studio Development Server, there is no error occured.. But when I tried to run it using my localhost.. There is an error "The remote server returned an error: Not Found", can you help me? (I run PubSubService.svc on my localhost finely)
Thanks in advance
Duc To
Duc To, is it the browser reporting the error because you cannot reach the *.aspx file, or is it is the Silverlight application reporting the error after the browser has finished loading the *.aspx file?
The aspx file is loaded ok, but when I press subscribe button, there is notification: "ERROR: The remote server returned an error: NotFound". It is really weird as I try to browse the svc file and it is loaded normally.. I am using IIS v.5.1. Do I have to modify anything to let it run with IIS, instead of development server?
Thanks
I found the reason why. In development server, it does not include project name so your format "http://" + ... + "/PubSubService.svc" is fine.. But when i switch it to localhost, the correct becomes "http://" + ... + "/PubSubService/PubSubService.svc" How fool I am.. I kept thinking on my mind that the issue is on web config or ISS configuration files side and do not look at the code lines..
Thanks for the sample, Tomasz.. It is great!
Duc To
If you get the 'System.ServiceModel.Configuration.PollingDuplexElement, System.ServiceModel.PollingDuplex' registered for extension 'pollingDuplex' could not be loaded error then your web project is referencing the silverlight 2 version of the polling dll. remove it and add the silverlight 3 version.
Hi
How could one have a windows application as a publisher?
Thanks
Q
PollingDuplexHttpBinding is not currently available as a client side component for .NET Framework. Please note that having a client that publishes notifications does not require duplex capability - it can be built as a separate request/response WCF service end exposed over a simple binding like BasicHttpBinding. For windows application clients that need to receive asynchronous notifiations over duplex contracts, consider using WsDualHttpBinding or NetTcpBinding, both of which offer duplex communication.
Thank you for sharing. Very useful exmaple.
"Please note that having a client that published notifications does not require duplex capability" Can you tell us more clearly, a hint or an example.. I want to publish notification from asp.net code behind but do not know how to do it
Thanks in advance
Duc To
Publishing a notification is achieved by sending multiple messages using callback channels of connected clients. It is up to the server's code to decide how the message to be published is generated: it can have been sent to the server from outside (this is what I was referring to as a "client that publishes notifications"), or the server could have generated it using mechanisms of its own. In scenarios where the content to be published is sent to the server by one of the clients (which is exactly what the sample demonstrates), it does not need to happen over the polling duplex protocol. A client could call a method on a WCF service exposed over BasicHttpBinding that accepts the content to be published, and as a result of that method invocation the WCF service could initatie sending notifications to clients that connected using the polling duplex binding. The fact that the sample reuses an existing connection to the server based on the polling duplex binding to send publish messages is an implementation detail.
I tried to call a method on a WCF service over basicHttpBinding but getting messages "Contract requires Duplex, but Binding "WsHttpBinding" doens't support it or isnt configured properly to support it :( Do you know why?
You will need to create a second WCF service with a simplex contract (e.g. one Publish method) and expose it over BasicHttpBinding. The IPubSub service contract in the sample is indeed a duplex contract and cannot be exposed over bindings that do not support duplex communication.
Could you post SL3 code which doesn't use proxy generation and uses the Channel Model instead?
(All existing samples, including MSDN ones no longer work after migrating to SL3)
Thanks.
Alex Mikunov
Alex, this pub\sub sample has been created with SL3, there should be no need to migrate it over. Can you explain the problem you are experiencing?
You have used Add Service/Proxy generation to create a SL 3 client code for your duplex example (look in your PollingDuplexSample\PubSubClient\Service References and PollingDuplexSample\PublisherClient\Service References\Proxy folders).
But if you do it via use of the Channel Model (a direct method, w/o proxy generation) then you will encounter a problem -- it simply doesn't work
More on use of Channel Model, etc. check this link on MSDN:
"How to: Access a Duplex Service with the Channel Model"
Alex Mikunov
Alex,
you can write an SL3 pub\sub client using channel model directly, it is just more work and code than an approach that uses proxy generation. This is because you have to use the more involved IAsyncResult-based async model, as well as handle notifications arriving on a non-UI thread.
First you need to manually declare the duplex contract, making sure the operations originating from the client (Subscribe and Publish) are asynchronous:
[ServiceContract]
public interface INotification
{
[OperationContract(IsOneWay = true, Action = NotificationData.NotificationAction)]
void Notify(Message message);
}
[ServiceContract(CallbackContract = typeof(INotification))]
public interface IPubSub
{
[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginSubscribe(string topic, AsyncCallback callback, object state);
void EndSubscribe(IAsyncResult result);
[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginPublish(string topic, string content, AsyncCallback callback, object state);
void EndPublish(IAsyncResult result);
}
Next you need to implement the INotification interface on the client side. The main user control is a convenient location:
public partial class MainPage : UserControl, INotification
//...
public void Notify(Message notification)
{
this.AddNotification("SERVER NOTIFICATION: " + notification.GetBody<NotificationData>().Content);
}
Then, instead of instantiating the generated proxy, you need to use DuplexChannelFactory<T> directly to create a proxy instance and call the asynchronous Subscribe method:
DuplexChannelFactory<IPubSub> factory = new DuplexChannelFactory<IPubSub>(
new InstanceContext(this),
new PollingDuplexHttpBinding { UseTextEncoding = true },
new EndpointAddress(new Uri(App.Current.Host.Source + "/../../PubSubService.svc")));
this.client = factory.CreateChannel();
this.client.BeginSubscribe(this.TopicName.Text, new AsyncCallback(this.OnSubscribed), null);
Similarly, you are using the IAsyncResult based async model to call Publish from the client:
this.client.BeginPublish(this.TopicName.Text, this.PublishText.Text,
new AsyncCallback(this.OnPublished), this.PublishText.Text);
Lastly, you need to implement the OnSubscribed and OnPublished callbacks and process any errors:
void OnSubscribed(IAsyncResult result)
{
try
{
this.client.EndSubscribe(result);
}
catch (Exception e)
{
this.OnError(e);
}
}
void OnPublished(IAsyncResult result)
{
try
{
this.client.EndPublish(result);
}
catch (Exception e)
{
this.OnError(e);
}
this.Dispatcher.BeginInvoke(delegate
{
this.AddNotification("CLIENT ACTION: Published to topic " + this.TopicName.Text + ": " + result.AsyncState);
});
}
void OnError(Exception e)
{
lock (this.syncRoot)
{
((IClientChannel)this.client).Close();
this.client = null;
}
this.Dispatcher.BeginInvoke(delegate
{
this.AddNotification("ERROR: " + e.Message);
this.TopicName.IsEnabled = this.SubscribeButton.IsEnabled = true;
this.PublishText.IsEnabled = false;
});
}
As you can see, this pattern is more involved that the event-based async model offered by the generated proxy.
Thank you for the response
Thanks.
Alex
I am pulling My hair out.
Through the process of Getting my application working, I have experienced many of the issues where the Service is invalid, such as"The type 'System.ServiceModel.Configuration.PollingDuplexElement, System.ServiceModel.PollingDuplex' registered for extension 'pollingDuplex' could not be loaded.
"
which is where I am at now. All of the answers here were helpful to me at avrious points and I got everything working.
At Some point when I went to update one of my service references because I made a Namespace change ( to remove the samples namespaces and bring things in line with our naming convetions)
So I try Bringing up my service in IE and I get the above error still. I don't know what is wrong or how I caused this to come back.
I have the following in my Web.config:
{system serviceModel}
{extensions}
{bindingElementExtensions}
{add name="pollingDuplex" type="System.ServiceModel.Configuration.PollingDuplexElement, System.ServiceModel.PollingDuplex"/}
{/bindingElementExtensions}
{/extensions}
{behaviors}
{serviceBehaviors}
{behavior name="PubSubServicesBehavior"}
{serviceMetadata httpGetEnabled="true"/}
{serviceDebug includeExceptionDetailInFaults="true"/}
{serviceThrottling maxConcurrentSessions="2147483647"/}
{/behavior}
{/serviceBehaviors}
{/behaviors}
{bindings}
{customBinding}
{binding name="pollingDuplexBinding"}
{binaryMessageEncoding/}
{pollingDuplex maxPendingSessions="2147483647" maxPendingMessagesPerSession="2147483647" inactivityTimeout="02:00:00" serverPollTimeout="00:05:00"/}
{httpTransport/}
{/binding}
{/customBinding}
{/bindings}
{services}
{service behaviorConfiguration="PubSubServicesBehavior" name="Redacted"}
{endpoint address="Redacted.com" binding="pollingDuplex" contract="Redacted.Interfaces.ISub"/}
{endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/}
{/service}
{service behaviorConfiguration="PubSubServicesBehavior" name="Redacted"}
{endpoint address="Redacted.com" binding="basicHttpBinding" contract="Redacted.Interfaces.IPub"/}
{endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/}
{/service}
{/services}
{/system serviceModel}
I split the service in half, so I can publish from a Windows Mobile Device and Subscribe from a Silverlight client hosted inside an aspx page, and had everything working.
Now I have the System.ServiceModel.PollingDuplex.dll File, the 3.0.0.0 Server Version referenced into my web project. It is not installed in my GAC, though I have also tried this.
I don't know what is wrong, can you point me in the right direction?
One of the weird things is that the SubService Works, and thats the One that uses Polling Duplex, but the PubService Gives the Errors about PollingDuplex but it uses basicHttpBinding!
Also, the {BindingDuplex} Sub element under custom binding is highlighted in blue and if I ouse over it says "the Element 'binding' has invalid child element 'pollingDuplex' List of elements expected........"
I have always had this error showing even when my project worked.
sdevlin,
one typical situation when one would get this error is when the server side System.ServiceModel.PollingDuplex.dll is not located in the bin subdirectly of the vroot where your web application is deployed. (The dll does not need to be GACed as you noted). Make sure the "Copy local" property of this DLL under References in your project is set to "True".
I undertand you have two *.svc files in your project right now. Are you able to access them directly from your browser? If not, what error do you get?
The blue line under the pollingDuplex element in your config indicates the configuration schema file installed in VS does not recognie the element. This is OK, since this is a config extension explicitly registered in your config file.
Copy Local is not an option in Web Project. I successfully set that property when I was working on the sample, but its just not there in a web project.
My error is :
Configuration binding extension 'system.serviceModel/bindings/pollingDuplex' could not be found. Verify that this binding extension is properly registered in system.serviceModel/extensions/bindingExtensions and that it is spelled correctly.
I have the File Referenced and it is Auto Update.
I have done this add remove of the ref many times. I don't know why but sometimes it adds:
{add assembly="System.ServiceModel.PollingDuplex, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf386ad364e35"/}
to {Compilations}{Assemblies}
and sometimes not. I think when I have referenced it when it was in the gac it adds that line, but if I ref a location otherwise, then not. I am currently trying to reference a local path ( in my TFS tree). So I added that line manually and I get:
Could not load file or assembly 'System.ServiceModel.PollingDuplex\, Version\=3.0.0.0\, Culture\=neutral\, PublicKeyToken\=31bf386ad364e35' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)
which I now assume is because when you add that line it is looking in the gac, but I don't have it loaded in the gac.
I feel like I am running in circles.
sdevlin,
If your WCF service is part of a web site (as opposed to a web application), you will need to manually add a "bin" folder to the web site project and copy System.ServiceModel.PollingDuplex.dll to that directory. The config loader will then able to find the assembly referenced in the WCF extensions section of the web.config file.
I have a Bin Folder, and It COntains System.ServiceModel.PollingDuplex.DLL
Can you confim this is the correct System.ServiceModel.PollingDuplex.dll? The SL3 SDK contains two: one is a client side for SL3, adn the other is server side for .NET 3.5. You need the server side one in the bin folder.
Tomasz, thank you for your help on this. I disappeared for a few days because in the processinf finding the solution, My machine basically died.I had to reinstall my development envirnomnat the OS on my handheld device, ActiveSync, and Fix some drivers for my usb Port. UGH. I didn't want to post this response until EVERYTHING was working and I coudl confirm that my found fix was true, and not only neccesary dur to a system corruption. I have now confirmed that to my satisfaction.
I made this Change:
{extensions}
{bindingElementExtensions}
{add name="pollingDuplex" type="System.ServiceModel.Configuration.PollingDuplexElement, System.ServiceModel.PollingDuplex"/}
{/bindingElementExtensions}
{bindingExtensions }
{add name="pollingDuplex" type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement, System.ServiceModel.PollingDuplex"/}
{/bindingExtensions}
{/extensions}
Where I added the Binding Extensions Section in addition to the BindingElementExtensions as Previously documented.
Hope that helps anyone else.
Can anyone please guide me with a sample as to how to consume this service in a windows form application?
Thank You
Best,
Alok Vad.
Alok, the client side of the polling duplex protocol does not have an implementation in .NET Framework, therefore it cannot be easily consumed from a windows forms application. One alternative to consider is adding an endpoint to the service that uses the NetTcpBinding, which provides duplex capability and is consumable from a .NET Framework client.
Thank you Tomasz for your guidance. I have one more question, I'm hosting ur solution under IIS 5.1 and IIS 5.1 does not support net.tcp binding. In this case how can I consume the duplex service in a windows form application.
Thank You
Best Regards,
Alok Vad.
Alok, you can also use WsDualHttpBinding. Keep in mind, however, that this binding will create an HTTP listener on the client side, so the firewall(s) must be configured to allow incoming HTTP traffic to the client machine.
Thank You Tomasz. I appreciate your guidance.
Best Regards,
Alok Vad.
I have written an application based on your code, it was very helpful. I am having intermitted issues with not found error. I am only running this locally in debug mode in Visual Studio. I believe my issue has to do with creation and destruction of objects. I am opening a Silverlight child window that registers for several different Pub/Sub events. When I click a button on the child window, I publish an event and close the child window. This will work several times then will fail with a NotFound error. I think it’s a timing issue between request response and the code is no longer running when a reply comes back.
Usually errors on
public void EndSubscribe(System.IAsyncResult result) {
object[] _args = new object[0];
base.EndInvoke("Subscribe", _args, result);
}
Or
public void EndPublish(System.IAsyncResult result) {
object[] _args = new object[0];
base.EndInvoke("Publish", _args, result);
}
I believe I am not disconnecting and connecting to the service correctly. Also my current design has each independent window subscribing for events and I am unsure that is a good decision.
This is not just a notfound issue the code does run; I think it’s a timing issue. I do not know a solid way to cleanup when I close my child window. I create a class that does all the registering and publishing and updates a local list that is displayed. I have written functions to close the connection but when and how to execute them? I just publish a message then want to close.
private void SetupPubSubClient()
{
_TableClient = new PubSubTableClient(
new PollingDuplexHttpBinding(),
new EndpointAddress(
"http://"
+ App.Current.Host.Source.DnsSafeHost
+ ":"
+ App.Current.Host.Source.Port.ToString(CultureInfo.InvariantCulture)
+ "/TableService.svc"));
_TableClient.PublishCompleted += new (TableClient_PublishCompleted);
_TableClient.NotifyReceived += new (TableClient_NotifyReceived);
_TableClient.SubscribeCompleted += (TableClient_SubscribeCompleted);
}
….
public void ClosePubSubClient()
{
if (_TableClient != null)
{
_TableClient.PublishCompleted -= TableClient_PublishCompleted;
_TableClient.NotifyReceived -= TableClient_NotifyReceived;
_TableClient.SubscribeCompleted -= TableClient_SubscribeCompleted;
_TableClient.CloseAsync();
_TableClient = null;
}
Any thoughts?
Steven, are your Subscribe and Publish methods one-way or request-response (i.e. do you have IsOneWay=true specified on the operation contract)? If the messages are one way, and if you are closing a window from which the message was sent immediately after sending it, chances are the Silverlight application will terminate before the HTTP stack has a chance to complete sending the message. I'd recommend one experiment: change the methods to be request-response (it is OK for the methods to return void), and then wait in the Silverlight application for the "response" before closing the window. I hope it helps.
Hi Tomasz,
Can I use HTTP poling duplex for a voice chat or video conference..?I mean will this model support real time data..?
Tony, polling duplex does not support streaming, I don't think it would be an appropriate technology for real time voice or video. Apart from that, Silverlight 3 does not offer device integration that would enable this scenario (web cam, mike).
If I can read real time data from a local process via silverlight local connection,How can I stream that data over HTTP...? does the windows media server support duplex streaming of custom binary data..?if so how can I interface a silverlight server appplication with windows media server..?I thinnk flash media server has that capability..what do you think..?
Thanks
Tony
Thanks for the code, I’ve been playing around with it. Thought making the ‘guts’ of your PubSubService.svc abstract and have specific implementations for each ServiceContract. It’s running ok. Of course there would be singleton instances for each operation contract on the server using this approach.
Bit tricky trying to get the ServiceContract interfaced (INotification) working in an abstract fashion, i.e. you can have specific ServiceContract interfaces inheriting this (and have the base class call BeginNotify) as they needs to explicitly specify the Action on the OperationContract. Just means each contract needs its only explicit ServiceContract interface. I just delegated the code that relies on the ServiceContract interface methods (BeginNotify and EndNotify) to the concrete implantations. It’s now seeming fairly flexible (until the point it’s totally inflexible LOL).
One point, in your implementation PubSubService.svc.cs, you wire up a couple of events on the current channel:
OperationContext.Current.Channel.Faulted += new EventHandler(this.Unsubscribe);
OperationContext.Current.Channel.Closed += new EventHandler(this.Unsubscribe);
How does these get unwired? Will this prevent the Current channel from being GC’ed?
(again thanks for the code :))
Keith
Tony, if you descriebed your scenario in more detail I would be able to better answer your question. What is the problem you need to solve? There are many more communication technologies available on the windows server than on the Silverlight client. It is also not entirely clear to me what you mean by "Silverlight local connection".
Anonymous, the goal of the subscription to the Faulted and Closed events is to clean up any in-memory state associated with a session the server may have. Keeping these subscribtions in place should not prevent the channel from being garbage collected whent he session is closed or faulted.
Hi Tomasz,
My scenario is like this.I have an application sharing program.It is implemented in client side as activeX controls.There is a sharing module and a viewing module.Both are running in browser.There is a central conference server .Both conference server and client support only TCP.The conference server is a custom implementation with limited scalablity.So I want to change the server to a .NET compatible low cost media server(or any other server including IIS which serve the purpose),by .NET compatible I mean I can write some code in .NET to make conferences etc and route the communication to conference members only.I also need duplex communication for remote controling the shared application.And most important I need HTTP support.So dear friend pls help me with your valuable advice
Thanks
Tony
Tomasz,
One more requirement, I need to use sliverlight in browser insted of my activeX control(mainly the viewer).I hope the sliverlight client can communicate with my activeX sharing component
Tony
Tony, currently Silverlight does not support real time communications (for example, it has no camera or microphone support). One Microsoft product that comes to mind that might satisfy your scenario is http://office.microsoft.com/en-us/communicationsserver/default.aspx. I am not an expert in live communication, you may be better off asking your question on one of the forums related to Live Communication Server or Live Meeting at http://www.microsoft.com/office/community/en-us/FlyoutOverview.mspx#14.
Ok Thanks Tomasz..
The live communication serevr is too costly to approach..One question, does silverlight client support TCP connection..?
Tony
Yes, Silverlight 3 supports TCP through the Socket class, although the port range number is limited. Check out http://msdn.microsoft.com/en-us/library/cc296248(VS.95).aspx.
Tomasz,
Thanks for the article. I have a working service using the duplex binding talking to SilverLight. I need it to also publish events to a windows service client. To do that I believe from your previous answers to Alok that I can use WsDualHttpBinding. What I don't understand is how to structure the project to support both bindings in the same web site. Is there an example of how such a project could be structured and/or could you steer me in the right direction?
Thanks!
- Art
Art, WCF has been designed to support exposing a single service over multiple endpoints, where each endpoint may be using different bindings. Adding an endpoint for WsDualHttpBinding to your service that already contains an endpoint for PollingDuplexHttpBinding is possible with configuration change - no change in code should be necessary. Check out the documentation at http://msdn.microsoft.com/en-us/library/ms751515.aspx for how to do it.
Unfortunately it looks like this method doesn't work in Opera 10...
Silverlight 3 does not support Opera. The list of supported platforms can be viewed at http://en.wikipedia.org/wiki/Microsoft_Silverlight#Operating_systems_and_web_browsers.
There is a bug where if the clients are closed before the publisher stops publishing the server never unsubscribes them. I can provide a zip file with the fix if you would like.
James, thank you for finding a bug. Could you describe it along with a workaround in a comment?
Thank you for your response from my last question. It was very helpful.
I have implemented your code for pub/sub client, and I need the client to be able to maintain connections.
The volume is low and inactivity would be an issue and I would like not miss messages.
Right now the client code gets an "InnerChannel_Faulted" error after 10 mins of inactivity.
Can you point me to what i might need to do to accomplish this.
Thanks,
Steven
Tomas, many thanks for the great series of articles you've been doing on Silverlight/WCF scalability. It's been very helpful.
I do have a question. We've been using Entity Framwork generated classes as our data transfer objects. They're a tad more heavyweight than I'd like, but they're also (reasonably) simple to use, and they seem to have worked well for us so far. However, I can't seem to figure out how to use them with the pre-serialized pattern that you're recommending. Specifically, it seems like your recommended approach is to share the file that contains the DTO definitions between the client and server, and of course, that won't work with EF-generated objects. Is there another way to do this that I'm just missing? Or if I want to take advantage of pre-serialized objects, do I need to switch to using a separate DTO layer on top of the EF classes?
Thanks again for your help.
Steven J, I just answered a similar question to yours related to my article about polling duplex scalability at http://tomasz.janczuk.org/2009/09/scale-out-of-silverlight-http-polling.html. Pasting below for convenience:
The bottom line is that the HTTP protocol does not provide any delivery guarantees, and polling duplex protocol inherits lack of this assurance. If your application requires delivery guarantees, you should take appropriate measures at the application level to provide it (for example, retries). When a TCP connection underlying an HTTP long poll is dropped, all WCF duplex session channels tunneled through that long poll request (i.e. all channels created to the same server scheme/host/port combination) will be faulted. The application logic on the client should ensure the channels are re-created if it is desired. Please also note that HTTP proxies sometimes decide to terminate inactive TCP connections, which will cause the behavior above. A mitigation built into the polling duplex protocol uses the ServerPollTimeout (default of 15 seconds) as a maximum period after which the server will respond to the long poll even if there are no messages to send to the client. Setting the ServerPollTimeout to a lower value will reduce the risk of dropped connections at the cost of increased network traffic.
Ken, the approach of sharing the data contract files I described works for simple types, typically authored by hand. Since Entity Framework classes cannot be used verbatim in Silverlight, the best approach I can think of is to generate a silverlight proxy to a WCF service that exposes them using Add Service Reference or slsvcutil.exe. This will generate data contract types on the Silverlight side that are wire compatible with the Entity Framework types on the server.
Thank you for the reply (and replay). I guess my real question: Is there a proper way for a client to close it's connections and reopen after a loss of communicaiton is detected(from the context of your sample).
Is a restart just:
client.CloseAsync();
new client();
client.SubscribeAsync("topic");
(Can you recommend a good book?)
Thanks again,
Steven
For other people: I believe some of my issues where because I was running in debugger.
Sorry for the last post,
I think I will just read your other article.
Steven.
Tomasz,
What about the reliability of the PollingDuplexHttpBinding?
Actually, I know it does not support realiability. Maybe my question would sound better: "What does an unreliable binding mean?".
There are people describing the lack of reliability like a "chaos":
- messages that are not delivered;
- the same message delivered more than once;
- unordered messaging;
On the other side, there are people saying there are very little applications that really need realiability.
I got a little confused; I don't know what to belive.
I need to use the PollingDuplexHttpBinding and I would like to know what are the risks of using this binding; I need to decide what is acceptable for my application and how much reliability do I have to implement at the application level.
Thank you !
Ernest
Ernest, as I said in response to a similar question a few answers back, the polling duplex binding in general has the same reliability gurantees (or lack thereof) as the underlying HTTP protocol. Despite the fact the programming model is based on WCF sessions, there is no gurantee that messages will arrive on the client in the same order they were sent from the server; there is no detection of lost messages; there is also no guranantee a message will be delivered only once. In practice, I have not seen lost messages other than in day-long stress runs (and "losing a message" in case of polling duplex protocol will be usually surfaced as a channel fault); I have also never seen out of order delivery or more than once delivery. In the vast majority of application scenarios I have seen I would expect these de-facto delivery "guarantees" to be sufficient. At the same time, in cases where losing a message, receiving a message more than once or out of order has unaccaptable consequences, I would definately devise a reliability messaging layer on top of the polling duplex protocol.
Hi Tomasz,
what are the steps(in all dimentions i.e silverlight client, ajax client and polling duplex service ) to make the service secure using ssl i.e using https instead of http.
thanks
Jamal.
dear sir
I m vivek from India and i m developing an Online Examination system in C#.Net and i need to copy few files on client machine so tht test should not break even if internet connection gets disconnected.
So my question is how can i copy files to client machine without actually acknowledging him or even he comes 2 know it, its ok
I dont know anything about WCF, will this be useful in my application
I m stuck for last 4 days. Plz help...
Hi Tomasz,
Can we make a none silverlight client program (such as WCF library and it's hosted by Windows Service) call the PubSubService.svc to publish a topic?
Hi Tomasz,
Can you add some other features into the demo?
1. add Unsubscribe in the service and expose it to the client
2. PubSubClient can change the topic at any time.
I try to add a unsubscribe service myself but has some problem. Each time when the same client call the service function, I will get different sessionID, I don't know to identify the client in a unique ID.
Never mind, I found the solution of my previous post.
Nice info.If you want to have your own website, it is necessary to host your website on a web server. Company that provides the web servers to host your website is called web hosting providers.
I am looking at this project with a co worker and I am beyond frustrated as I cannot get this sample to run successfully. I have tried the GAC with no success, and I have removed the App.Current.Host Calls as they seemed to not be working. Now when the system finally does run I am getting cross domain errors? Any ideas I am at my wits end in looking at this example. Also Silverlight 3 SDK is installed!
Same guy with regards to previous post. I finally got the thing to work, I had to do exactly this. http://www.wintellect.com/CS/blogs/pmehner/archive/2009/10/25/migrating-polling-duplex-binding-element-from-silverlight-v2-0-to-v3-0-for-wcf-services-in-the-cloud-code-samples.aspx
The Service project is referencing the old version but setting Copy Local to true was the only thing that worked after the new one was added.
Post a Comment