如何:使用 WCF Web HTTP 编程模型创建返回任意数据的服务
有时,开发人员必须完全控制从服务操作返回数据的方式。 当服务操作必须以 WCF 不支持的格式返回数据时,就需要这样做。 本主题讨论如何使用 WCF WEB HTTP 编程模型来创建此类服务。 此服务具有一个返回流的操作。
实现服务协定
定义服务协定。 该协定名为
IImageServer
,具有一个名为GetImage
的方法,该方法返回 Stream。[ServiceContract] public interface IImageServer { [WebGet] Stream GetImage(int width, int height); }
由于该方法返回 Stream,因此 WCF 假定服务操作返回的字节由该操作完全控制,自己无需对返回的数据应用任何格式设置。
实现服务协定。 该协定只有一个操作:
GetImage
。 此方法生成一个位图,再以 .jpg 格式将其保存到 MemoryStream。 随后,操作将该流返回给调用方。public class Service : IImageServer { public Stream GetImage(int width, int height) { 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; } }
请注意代码的倒数第二行:
WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
这将内容类型标头设置为
"image/jpeg"
。 虽然此示例演示如何返回 .jpg 文件,但可以对其进行修改,以任意格式返回所需的任意类型的数据。 该操作必须检索或生成数据,然后将它写入流。
承载服务
创建用于承载服务的控制台应用程序。
class Program { static void Main(string[] args) { } }
在
Main
方法中创建一个变量以保存服务的基址。string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
为服务创建一个 ServiceHost 实例,指定服务类和基址。
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
使用 WebHttpBinding 和 WebHttpBehavior 添加一个终结点。
host.AddServiceEndpoint(typeof(IImageServer), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
打开服务主机。
host.Open();
等待用户按 Enter 终止服务。
Console.WriteLine("Service is running"); Console.Write("Press ENTER to close the host"); Console.ReadLine(); host.Close();
使用浏览器调用原始服务
运行该服务,你应看到来自它的以下输出:
Service is running Press ENTER to close the host
打开 Web 浏览器并输入
http://localhost:8000/Service/GetImage?width=50&height=40
。 你应看到一个黄色矩形,有蓝色对角线穿过其中心。
示例
下面列出了此主题的完整代码。
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Description;
using System.IO;
using System.Drawing;
namespace RawImageService
{
// Define the service contract
[ServiceContract]
public interface IImageServer
{
[WebGet]
Stream GetImage(int width, int height);
}
// implement the service contract
public class Service : IImageServer
{
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;
}
}
class Program
{
static void Main(string[] args)
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(IImageServer), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Service is running");
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
}
编译代码
编译示例代码时,引用 System.ServiceModel.dll 和 System.ServiceModel.Web.dll。