简体   繁体   中英

Returning an Image from OperationContract method (WCF service)

I'm trying to get an Image from a WCF service.

I have an OperationContract function that returns an Image to the client, but when I call it from the client, I get this exception:

The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.9619978'.

Client:

private void btnNew_Click(object sender, EventArgs e)
{
    picBox.Picture = client.GetScreenShot();
}

Service.cs:

public Image GetScreenShot()
{
    Rectangle bounds = Screen.GetBounds(Point.Empty);
    using (Bitmap bmp = new Bitmap(bounds.Width,bounds.Height))
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
        }
        using (MemoryStream ms = new MemoryStream())
        {
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            return Image.FromStream(ms);
        }
    }
}

IScreenShot Interface:

[ServiceContract]
public interface IScreenShot
{
    [OperationContract]
    System.Drawing.Image GetScreenShot();
}

So why is this happening and how do I fix it?

I've figured it out.

  • First use TransferMode.Streamed or StreamedResponse (depends on your need).
  • Return the stream, and don't forget to set Stream.Postion = 0 so you start reading the stream from the beginning.

In the service:

public Stream GetStream()
{
    Rectangle bounds = Screen.GetBounds(Point.Empty);
    using (Bitmap bmp = new Bitmap(bounds.Width, bounds.Height))
    {
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
        }
        MemoryStream ms = new MemoryStream();
        bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
        ms.Position = 0;  // This is very important
        return ms;
    }
}

Interface:

[ServiceContract]
public interface IScreenShot
{
    [OperationContract]
    Stream GetStream();
}

On the client side:

public partial class ScreenImage: Form
{
    ScreenShotClient client;
    public ScreenImage(string baseAddress)
    {
        InitializeComponent();
        NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
        binding.TransferMode = TransferMode.StreamedResponse;
        binding.MaxReceivedMessageSize = 1024 * 1024 * 2;
        client = new ScreenShotClient(binding, new EndpointAddress(baseAddress));
    }

    private void btnNew_Click(object sender, EventArgs e)
    {
        picBox.Image = Image.FromStream(client.GetStream());
    }
}

You can use Stream to return large data/Images.

Sample Example(returning Image as Stream) from MSDN

You will need to define something that is serializable. System.Drawing.Image is, but not in the context of WCF (using DataContractSerializer ) by default. That could range from returning the raw bytes as an array, or serialization to a string (base64, JSON) or implementing a DataContract that is serializable and can carry the data with it.

As others have said, WCF supports streaming, but that's not the crux of the issue here. Depending on the size of the data you might wish to do this, and doing so will reduce the problem in itself since you would be streaming bytes (from an evident, top-level view).

You could also take a look at this answer to help you get the at the actual exception details, like a full stacktrace instead of just the fault info.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM