Windows Vista Beta | WinVistaBeta.com - Message | Creating a HTTP Push type service using a single channel

October 15, 2008  
Subject: Creating a HTTP Push type service using a single channel
Group: microsoft.public.windows.developer.winfx.indigo
Date: 1/28/2008 10:32:58 PM
From: "news.microsoft.com" [Email Address Protection]

Hi,

I've got the following requirements for a WCF service...

* a push type service, ie a server which can send notifications to clients.

* able to be hosted in IIS 6.0 (ie without WAS in vista server, it must be
HTTP).

* uses a single channel to accomplish this - to simplify deployment of the
solution (ie a port should not have to be allocated on the client for the
callback from the server), that means I can't use wsDualHttpBinding with a
callbackchannel.

The Concept -

Return a long running stream of bytes to the client, with notifications
contained within the stream.

The service contract...

[ServiceContract]
public interface ITestNotifier
{
[OperationContract]
Stream GetNotification(string clientID);
}


Which is implemented as...

[ServiceBehavior]
public class TestNotifier : ITestNotifier
{
#region ITestNotifier Members

public Stream GetNotification(string clientID)
{
PumpStream retStream = new PumpStream();
return retStream;
}

#endregion
}


Pumpstream is a custom stream class...

public class PumpStream : Stream
{
int mPosition = 0;

public override bool CanRead { get { return true; }}
public override bool CanSeek { get { return false; }}
public override bool CanWrite { get { return false; }}
public override void Flush() { throw new
NotImplementedException(); }
public override long Length { get { return 2000000; } }
public override long Position { get { throw new
NotImplementedException();} set {throw new NotImplementedException();}}

public override int Read(byte[] buffer, int offset, int count)
{
// Proof of concept, real implementation would have a
EventWaitHandle
// which would be set when ever data becomes available
System.Threading.Thread.Sleep(2000);

for(int i=0; i<count; ++i)
buffer[offset+i] = 0;

mPosition += count;

return count;
}

public override long Seek(long offset, SeekOrigin origin) { throw
new NotImplementedException(); }
public override void SetLength(long value) { throw new
NotImplementedException();}
public override void Write(byte[] buffer, int offset, int
count){throw new NotImplementedException();}
}

The service config...

<basicHttpBinding>
<binding name="FSNotifierBinding" closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="23:59:59" maxBufferSize="256"
maxBufferPoolSize="524288" maxReceivedMessageSize="512"
messageEncoding="Text"
transferMode="Streamed">
<security>
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>

The client config...

<basicHttpBinding>
<binding name="FSNotifierEndpoint" closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="23:59:59" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="256" maxBufferPoolSize="524288"
maxReceivedMessageSize="512 "
messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>

The problem -

Getting control over the way WCF reads and sends data from the stream.
Ideally I would like it to read a single byte from the stream and then send
it directly to the client.

I've tried altering the maxBytesPerRead, maxReceivedMessageSize and the
maxBufferSize on both the client and the server and none of these settings
seems to affect the number of bytes being read from the stream before a
response is sent to the client.

Does anyone have ideas or alternative suggestions?

TIA

Michael



Back
Subject: Re: Creating a HTTP Push type service using a single channel
Group: microsoft.public.windows.developer.winfx.indigo
Date: 1/29/2008 3:40:48 PM
From: "Michael" [Email Address Protection]

My apologies for the name on the post, was a mistake.

To further elaborate on the issue when a call is made to the service WCF is
making a number of calls to the stream before sending a response to the
client, this is an example of the first few calls it makes...

PumpStream.Read(byte[] buffer = {byte[256]}, int offset = 0, int count =
256) Line 62 C#
PumpStream.Read(byte[] buffer = {byte[4096]}, int offset = 0, int count =
4096) Line 62 C#
PumpStream.Read(byte[] buffer = {byte[65536]}, int offset = 0, int count =
65536) Line 62 C#

The behaviour I want is for WCF to make a single call to the stream then
return the data to the client, I don't particularly care how many bytes it
reads, it's more important that it just makes a single call on the stream.

"news.microsoft.com" <mlang@nospamplease_spectrax.com> wrote in message
news:%23k7aphjYIHA.2268@TK2MSFTNGP02.phx.gbl...
> Hi,
>
> I've got the following requirements for a WCF service...
>
> * a push type service, ie a server which can send notifications to
> clients.
>
> * able to be hosted in IIS 6.0 (ie without WAS in vista server, it must be
> HTTP).
>
> * uses a single channel to accomplish this - to simplify deployment of the
> solution (ie a port should not have to be allocated on the client for the
> callback from the server), that means I can't use wsDualHttpBinding with a
> callbackchannel.
>
> The Concept -
>
> Return a long running stream of bytes to the client, with notifications
> contained within the stream.
>
> The service contract...
>
> [ServiceContract]
> public interface ITestNotifier
> {
> [OperationContract]
> Stream GetNotification(string clientID);
> }
>
>
> Which is implemented as...
>
> [ServiceBehavior]
> public class TestNotifier : ITestNotifier
> {
> #region ITestNotifier Members
>
> public Stream GetNotification(string clientID)
> {
> PumpStream retStream = new PumpStream();
> return retStream;
> }
>
> #endregion
> }
>
>
> Pumpstream is a custom stream class...
>
> public class PumpStream : Stream
> {
> int mPosition = 0;
>
> public override bool CanRead { get { return true; }}
> public override bool CanSeek { get { return false; }}
> public override bool CanWrite { get { return false; }}
> public override void Flush() { throw new
> NotImplementedException(); }
> public override long Length { get { return 2000000; } }
> public override long Position { get { throw new
> NotImplementedException();} set {throw new NotImplementedException();}}
>
> public override int Read(byte[] buffer, int offset, int count)
> {
> // Proof of concept, real implementation would have a
> EventWaitHandle
> // which would be set when ever data becomes available
> System.Threading.Thread.Sleep(2000);
>
> for(int i=0; i<count; ++i)
> buffer[offset+i] = 0;
>
> mPosition += count;
>
> return count;
> }
>
> public override long Seek(long offset, SeekOrigin origin) { throw
> new NotImplementedException(); }
> public override void SetLength(long value) { throw new
> NotImplementedException();}
> public override void Write(byte[] buffer, int offset, int
> count){throw new NotImplementedException();}
> }
>
> The service config...
>
> <basicHttpBinding>
> <binding name="FSNotifierBinding" closeTimeout="00:01:00"
> openTimeout="00:01:00"
> receiveTimeout="00:10:00" sendTimeout="23:59:59" maxBufferSize="256"
> maxBufferPoolSize="524288" maxReceivedMessageSize="512"
> messageEncoding="Text"
> transferMode="Streamed">
> <security>
> <message clientCredentialType="UserName" />
> </security>
> </binding>
> </basicHttpBinding>
>
> The client config...
>
> <basicHttpBinding>
> <binding name="FSNotifierEndpoint" closeTimeout="00:01:00"
> openTimeout="00:01:00"
> receiveTimeout="23:59:59" sendTimeout="00:01:00" allowCookies="false"
> bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
> maxBufferSize="256" maxBufferPoolSize="524288"
> maxReceivedMessageSize="512 "
> messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed"
> useDefaultWebProxy="true">
> <readerQuotas maxDepth="32" maxStringContentLength="8192"
> maxArrayLength="16384"
> maxBytesPerRead="4096" maxNameTableCharCount="16384" />
> <security mode="None">
> <transport clientCredentialType="None" proxyCredentialType="None"
> realm="" />
> <message clientCredentialType="UserName" algorithmSuite="Default" />
> </security>
> </binding>
> </basicHttpBinding>
>
> The problem -
>
> Getting control over the way WCF reads and sends data from the stream.
> Ideally I would like it to read a single byte from the stream and then
> send it directly to the client.
>
> I've tried altering the maxBytesPerRead, maxReceivedMessageSize and the
> maxBufferSize on both the client and the server and none of these settings
> seems to affect the number of bytes being read from the stream before a
> response is sent to the client.
>
> Does anyone have ideas or alternative suggestions?
>
> TIA
>
> Michael
>



Back