What is the best / most flexible way to have WCF o

2019-05-23 10:09发布

问题:

What is the best / most flexible way to have WCF output XHTML? If there is no "WCF Way" (tm) to do XHTML output - is there any common tooling out there for it? Or do I need to roll my own?

回答1:

I don't believe there is an "official" WCF way to return XHTML, as of .NET 3.5 SP1. Aaron Lerch suggested having WCF apply a default XSLT stylesheet in July 2007, but something like this hasn't yet been adopted by the WCF team.

As other answers noted, you can roll your own XHTML support using samples from the WCF Starter Kit or using the raw programming model described by Carlos Figueira. Some of the WCF sample code provided online by Michele Leroux Bustamante as part of her Learning WCF book are helpful if you decide to do it yourself.

We return XHTML as well as JSON and XML from our WCF-based web service. While I'm not sure that our approach is the best way, it does work.

Our approach is to use the DataContractSerializer to generate XML, then apply a Complied XSLT transform and return the result stream, which should now contain XHTML. Here's a simplified version of our code:

public Stream GetItemAsHtml(string id) {
    Item obj = GetItem(objectId);
    Stream xml = GetXmlStream(obj);    
    return TransformXmlStream(xml, defaultTransform);
}        

public static Stream GetXmlStream(IXmlSerializable item) {
    MemoryStream stream = new MemoryStream();
    using (XmlWriter writer = XmlWriter.Create(stream, new XmlWriterSettings { Encoding = Encoding.UTF8 })) {
        if (writer != null) {
            DataContractSerializer dcs = new DataContractSerializer(item.GetType());
            dcs.WriteObject(writer, item);

            writer.Flush();
            writer.Close();
        }
    }
    stream.Seek(0, SeekOrigin.Begin);
    return stream;
}

public static Stream TransformXmlStream(Stream xml, string xsltFile) {
    XmlReader reader = XmlReader.Create(xml);

    XslCompiledTransform trans = new XslCompiledTransform();
    trans.Load(xsltFile);

    MemoryStream stream = new MemoryStream();
    using (XmlWriter writer = XmlWriter.Create(stream, trans.OutputSettings)) {
        if (writer != null) {
            trans.Transform(reader, writer);

            writer.Flush();
            writer.Close();
        }
    }
    stream.Seek(0, SeekOrigin.Begin);
    return stream;
}

It does the job, but I don't think it's a scenario the designers of WCF anticipated. :-)



回答2:

WCF is concerned with the transfer of data. It allows you to setup a service contract for a client/host to talk through. It abstracts away your transport so that you can easily configure your service, be it over HTTP/TCP/NamedPipes/Tibco EMS/whatever you want. The messages over the wire themselves, in my experience, are all serialized into SOAP by default, but that is certainly configurable as well. XHTML is presentation (yea you could argue that CSS is the real presentation and XHTML is your data representation). You basically want to return your data in a way that, among others, can be presented by a web browser.

The reason this doesn't make sense to me is that you seem to be trying to place a WCF service in place where a web server would belong.

But let's see how it can be done:

Do you want the WCF infrastructure to actually format the message as XHTML over the wire? If so and you want to send REST style requests to the service, start with the WCF REST Starter Kit.

The main challenge is serialization. I know that WCF in .Net 3.5 SP1 allows one to run WCF with the JsonDataContractSerializer, instead of the standard DataContractSerializer, which serializes objects into XML. You could write your own XHTMLDataContractSerializer. However, the resulting XHTML will be very much your own. Here's a thread to get your started.

EDIT: Just found this. I think this is definitely an option. And it seems rather easy to implement.



回答3:

WCF is a component technology - you write interfaces and their implementations and then instruct WCF how to handle security, transport, etc.

Returning XHTML from a WCF component would be the same as returning WCF from any other .NET component - probably as a string. As long as you can return data from your component in base types or via valid Data Contracts you should be cool.

You may want to check out Chapter 3 in Programming WCF Services by Juval Lowy - it's all about data contracts and what all you can spit out from your components. Maybe you're looking for some neato way to deserialize data after a client gets something back from your component... If so, Lowy shows you how.

So, short answer is return XHTML from your component however you'd like. So far as I know, there's no special way to emit XHTML from a WCF component.