Custom HTML Help Page for httpGet for an IIS6 Hosted WCF Service

Hi,

I am trying to get a custom HTML help page working for a WCF service hosted by IIS6 with ASP.NET compatiblity enabled by using thehttpHelpPageUrlattribute such as

<behaviors>

<serviceBehaviors>

<behaviorname="MXGet">

<serviceMetadatahttpGetEnabled="true" />

<serviceDebugincludeExceptionDetailInFaults="true"httpHelpPageEnabled="true"httpHelpPageUrl="/MyServiceHelp.htm" />

</behavior>

</serviceBehaviors>

</behaviors>

But whenever a value is assigned to thehttpHelpPageUrl attribute, an http request tohttp://localhost/Myservice.svc brings up the WSDL directly instead of the "you have created a service" default help page. I was expecting to see my custom help page, but it didn't show up.

Does anyone know how thehttpHelpPageUrl attribute is supposed to work, or how to get it to work? I could not find any sample that uses this attribute either.

Thanks,

Wenbin Zhang

[3213 byte] By [WenbinZhang] at [2008-1-8]
# 1
I believe the httpHelpPageUrl lets you move the default WCF help page to another location. If you want to host your own help page at the base address, you probably need to turn off httpGetEnabled and then at the service base address host your own http-GET WCF endpoint that serves up HTML content.
BrianMcNamara-MSFT at 2007-10-2 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 2

Brian, thanks for the quick response.

I'd really appreciate some sample code/configuration for that.

Thnaks,

Wenbin

WenbinZhang at 2007-10-2 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 3

Here is sample code:

Code Snippet

using System;

using System.ServiceModel;

using System.ServiceModel.Description;

using System.ServiceModel.Dispatcher;

using System.ServiceModel.Channels;

using System.Xml;

[ServiceContract]

public interface IMyContract

{

[OperationContract]

string echo(string s);

}

[ServiceContract]

public interface IMyHelpPageContract

{

[OperationContract(Action="*", ReplyAction="*")]

Message Help();

}

[ServiceBehavior(ConfigurationName = "foo")]

public class MyService : IMyContract, IMyHelpPageContract

{

public string echo(string s) { return s; }

public Message Help()

{

return new MyHelpPageMessage();

}

}

abstract class ContentOnlyMessage : Message

{

MessageHeaders headers;

MessageProperties properties;

protected ContentOnlyMessage()

{

this.headers = new MessageHeaders(MessageVersion.None);

}

public override MessageHeaders Headers

{

get

{

if (IsDisposed)

{

throw new ObjectDisposedException("blah");

}

return this.headers;

}

}

public override MessageProperties Properties

{

get

{

if (IsDisposed)

{

throw new ObjectDisposedException("blah");

}

if (this.properties == null)

{

this.properties = new MessageProperties();

}

return this.properties;

}

}

public override MessageVersion Version

{

get

{

return headers.MessageVersion;

}

}

protected override void OnBodyToString(XmlDictionaryWriter writer)

{

OnWriteBodyContents(writer);

}

}

class MyHelpPageMessage : ContentOnlyMessage

{

public MyHelpPageMessage()

: base()

{

}

protected override void OnWriteBodyContents(XmlDictionaryWriter writer)

{

// write the HTML you want on the help page here.could read from external file if you want

writer.WriteStartElement("HTML");

writer.WriteStartElement("HEAD");

writer.WriteRaw("");

writer.WriteEndElement(); //HEAD

writer.WriteRaw(@"

This is my own help page


I can put whatever content I want here

");

writer.WriteEndElement(); //HTML

}

}

public class Repro

{

public static void Main()

{

ServiceHost service = new ServiceHost(typeof(MyService));

service.Description.Behaviors.Remove<ServiceDebugBehavior>();// need to turn off default help page so as to get our own

service.Open();

Console.WriteLine("Service open at {0} - press a key to continue", service.BaseAddresses[0]);

Console.ReadKey();

ChannelFactory<IMyContract> cf = new ChannelFactory<IMyContract>("c1");

IMyContract proxy = cf.CreateChannel();

Console.WriteLine(proxy.echo("Hello World"));

((IClientChannel)proxy).Close();

service.Close();

Console.WriteLine("Done, press a key");

Console.ReadKey();

}

}

Here is the config:

Code Snippet

<?xml version="1.0" encoding="utf-8"?>

<configuration>

<system.serviceModel>

<services>

<service name="foo">

<host>

<baseAddresses>

<add baseAddress="http://localhost:8000/Service/"/>

</baseAddresses>

</host>

<endpoint address="E1"

binding="basicHttpBinding"

bindingConfiguration="b"

contract="IMyContract"/>

<endpoint address=""

binding="customBinding"

bindingConfiguration="helpPage"

contract="IMyHelpPageContract"/>

</service>

</services>

<client>

<endpoint address="http://localhost:8000/Service/E1"

binding="basicHttpBinding"

bindingConfiguration="b"

contract="IMyContract"

name="c1"/>

</client>

<bindings>

<customBinding>

<binding name="helpPage">

<textMessageEncoding messageVersion ="None" />

<httpTransport/>

</binding>

</customBinding>

<basicHttpBinding>

<binding name="b"/>

</basicHttpBinding>

</bindings>

</system.serviceModel>

</configuration>

Run it, and then hit the base address in a browser, and you'll see the custom help page.

See the sample http://msdn2.microsoft.com/en-us/library/aa395208.aspx for some more details on sending back arbitrary responses over HTTP GET.

(Doing this kind of stuff (GET/POX) will be much easier in Orcas.)

BrianMcNamara-MSFT at 2007-10-2 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 4
Thanks for snippet Brian.

Is there any way to call WriteRaw() directly? I'm getting "Text cannot be written outside the root element."

I tried with this:

Code Snippet

protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;

XmlWriter writer2 = XmlWriter.Create(writer, settings);

writer2.WriteRaw("<html><head></head><body>

Hi

</body></html>");
}


But the XmlWriter.Settings.ConformanceLevel is still set to "Document"

Also, I'm working with Orcas Beta 2, any idea if doing this is any easier with the new bits?

As far as I can tell, the webHttpBinding "WebMessageFormat" enum only has Json and Xml, no "Raw". I also tried implementing IXmlSerializable in a class so that I could put the HTML there but the "WebMessageBody" enum options always include some kind of wrapper around the body. Sad

Thanks

EdgardoRossetto at 2007-10-2 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 5
I have a custom message encoder than can spit out raw data - e.g. in our sample app it spits out arbitrary video streams.

ChristianWeyer at 2007-10-2 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...

Visual Studio Orcas

Site Classified