body parameter 'width'. GET operations can

2019-04-29 04:42发布

问题:

Im trying to get an image from a wcf rest service like so:

[ServiceContract]
public interface IReceiveData
{
    [OperationContract]
    [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, UriTemplate = "picture/")]
    //this line is wrong though
    Stream GetImage(int width, int height);
}
public class RawDataService : IReceiveData
{
    public Stream GetImage(int width, int height)
    {
        // Although this method returns a jpeg, it can be
        // modified to return any data you want within the stream
        Bitmap bitmap = new Bitmap(width, height);
        for (int i = 0; i < bitmap.Width; i++)
        {
            for (int j = 0; j < bitmap.Height; j++)
            {
                bitmap.SetPixel(i, j, (Math.Abs(i - j) < 2) ? Color.Blue : Color.Yellow);
            }
        }
        MemoryStream ms = new MemoryStream();
        bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
        ms.Position = 0;
        WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
        return ms;
    }
}

In my host application:

class Program
    {
        static void Main(string[] args)
        {
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(RawDataService), new Uri(baseAddress));
            host.AddServiceEndpoint(typeof(IReceiveData), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
            host.Open(); // this line
            Console.WriteLine("Host opened");
            Console.ReadLine();

I get this error:

Operation 'GetImage' in contract 'IReceiveData' uses GET, but also has body parameter 'width'. GET operations cannot have a body. Either make the parameter 'width' a UriTemplate parameter, or switch from WebGetAttribute to WebInvokeAttribute.

Im not sure how you set the webinvoke/UriTemplate method for an image or how you get an image and return it. Can some one post the correct way to display an image in this example.

EDIT

If I try the below answer and use UriTemplate = "picture?w={width}&h={height}" as my UriTemplate when navigating to http://www.localhost.com:8000/Service/picture?width=50&height=40 I recieve an error in my code:

public Stream GetImage(int width, int height)
        {
            Bitmap bitmap = new Bitmap(width, height); // this line
            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    bitmap.SetPixel(i, j, (Math.Abs(i - j) < 2) ? Color.Blue : Color.Yellow);
                }
            }
            MemoryStream ms = new MemoryStream();
            bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            ms.Position = 0;
            WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
            return ms;
        }

Which states ArguementException was unhandled by user code:Parameter is not valid.

回答1:

In the attributes, you need to tell the runtime that you're expecting the width and height as an URL parameter.

At the moment, the runtime assumes that you're calling the URL without parameters, but the method being called expects parameters, so the runtime really doesn't know how to find the values to pass to your method for width and height.

This can look like

[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Xml, UriTemplate = "picture/{width}/{height}")]
Stream GetImage(string width, string height)
{
    int w, h;
    if (!Int32.TryParse(width, out w))
    {
        // Handle error: use default values
        w = 640;
    }
    if (!Int32.TryParse(height, out h))
    {
        // Handle error use default values
        h = 480;
    }

    ....
}

and you will need to call the URL like http://test.tld/picture/320/200.



回答2:

UriTemplate = "picture/"

Should be something like

UriTemplate = "picture?w={width}&h={height}"

This tells WCF how to get the width and height parameters from the URL.