Returning an image from a RESTful WCF service

2020-06-19 09:39发布

问题:

I have this very simple DTO:

[DataContract]
public class DTO
{
    [DataMember]
    public byte[] Image {get; set; }
}

And this very simple service:

[ServiceContract]
public interface IFooService
{
    [WebGet(
        UriTemplate = "", 
        RequestFormat = WebMessageFormat.Json, 
        ResponseFormat = WebMessageFormat.Json)]
    List<DTO> GetDTOs();
}

In my global.asax, I have:

RouteTable.Routes.Add(new ServiceRoute("foo", 
    new WebServiceHostFactory(), typeof(FooService)));

Now, when I call this from my browser, I am getting an array of bytes in JSON format. Good so far. Now, how do I turn that array of bytes into an image?

Or, is there a better way of going about this? I tried changing byte[] to Stream, but then when I call the service from Firefox, the response is empty despite an HTTP status code of 200. I am using Firebug and Fiddler.

I don't think it's relevant, but since too much information never hurt anybody who wasn't a robot, here's the web.config:

<?xml version="1.0"?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior>
                    <serviceMetadata httpGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
            <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        </modules>
    </system.webServer>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
</configuration>

Ultimately, I guess the question is: how do you return a bitmap from a WCF RESTful service so JavaScript running in the browser can throw it up on the screen?

回答1:

Good so far. Now, how do I turn that array of bytes into an image?

Since you have tagged your question with javascript I assume that this is what you use to consume the service and you want to display the image in the browser. If this is the case you may take a look at the Data URI scheme which would allow you to show the image given the bytes you get from the service.

Here's an example how you could consume such service using jQuery and show the image:

$(function () {
    $.getJSON('/foo/', function (dtos) {
        $.each(dtos, function (index, dto) {
            var str = String.fromCharCode.apply(String, dto.Image);
            $('<img/>', {
                alt: '',
                src: 'data:image/png;base64,' + $.base64.encode(str)
            }).appendTo('body');
        });
    });
});

The $.base64.encode function comes from this plugin.



回答2:

The problem with using WCF to do this is that web service frameworks (and WCF in particular), make a lot of assumptions on the resulting response. When you request an image from a server, the HTTP response content type is usually different than that of an API request.

This is why I don't think such a job should be implemented using WCF. I just answered a similar question asking the same, but with WebAPI rather than WCF:

ASP .Net Web API downloading images as binary

You'd be much happier if you just implement a custom HTTP handler. APIs are for structured data, and images are not structured data - they are binary. They have their own place in HTTP and I think decoupling them from the API is a good idea.