寄宿服务使用WebHttpinding绑定来读或者写HTTP上下文是很常见的。这可以使用WebOperationContext类实现。有很多理由来访问HTTP上下文。你可能想要读取自定义的认证信息头或授权信息头,控制缓存或者设置内容类型,例如。
图片13.3 显示了一个在当前计算机上显示墙纸的网络应用程序。整个应用程序是使用一个WCF服务创建的而且可以使用网络浏览器访问。
![2011060911114352.png](https://i-blog.csdnimg.cn/blog_migrate/e1373f51b3a0591bc29bdd29cc754370.png)
图片13.3 墙纸网络应用程序
图片13.12显示了WallpaperService服务的代码。有一个在一个HTML页上显示所有图片的Images操作。这个操作设置ContextType头以便于浏览器可以将输入理解成HTML。它也设置了Cache-Control头以便于额外的图片可以添加到应用程序中而不用浏览器缓存图像。最后,有一个将一个图像返回给浏览器的Image操作。这个操作设置ContextType和ETag头。
注意 从REST中获得.svc WCF服务使用.svc扩展在IIS中寄宿。这和常见的REST URI 命名经验不同。例如,列表13.12中的服务使如下URI访问:http://localhost/Wallpaper/WallpaperService.svc/images 你可以通过使用一个ASP.NET HttpModule(仅IIS 7.0)调用HttpContext.RewritePath去修改URI来移除.svc扩展名。这将允许URI采用下面格式: http://localhost/Wallpaper/WallpaperService/images |
列表13.12 Wallpaper图片服务
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.ServiceModel.Activation;
using System.Web;
using System.IO;
using System.Web.UI;
namespace EssentialWCF.WallpaperImage
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class WallpaperService
{
private static UriTemplate ImageUriTemplate =
new UriTemplate("/image/{name}");
private string ImagePath
{
get
{
return @"C:\Windows\Web\Wallpaper";
}
}
private Image GetImage(string name, Uri baseUri)
{
return new Image(name, ImageUriTemplate.BindByPosition(baseUri, new string[] { name }));
}
private void PopulateListOfImages(List<Image> list, Uri baseUri)
{
HttpContext ctx = HttpContext.Current; ;
DirectoryInfo d = new DirectoryInfo(ImagePath);
FileInfo[] files = d.GetFiles("*.jpg");
foreach (FileInfo f in files)
{
string fileName = f.Name.Split(new char[] { '.' })[0];
string etag = fileName + "_" + f.LastWriteTime.ToString();
list.Add(GetImage(fileName, baseUri));
}
}
[OperationContract]
[WebGet(UriTemplate = "/images")]
public void Images()
{
WebOperationContext wctx = WebOperationContext.Current; ;
wctx.OutgoingResponse.ContentType = "text/html";
wctx.OutgoingResponse.Headers.Add("Cache-Control", "no-cache");
Uri baseUri = wctx.IncomingRequest.UriTemplateMatch.BaseUri;
List<Image> listOfImages = new List<Image>();
PopulateListOfImages(listOfImages, baseUri);
TextWriter sw = new StringWriter(); ;
Html32TextWriter htmlWriter = new Html32TextWriter(sw);
htmlWriter.WriteFullBeginTag("HTML");
htmlWriter.WriteFullBeginTag("BODY");
htmlWriter.WriteFullBeginTag("H1");
htmlWriter.Write("wallpaper");
htmlWriter.WriteEndTag("H1");
htmlWriter.WriteFullBeginTag("TABLE");
htmlWriter.WriteFullBeginTag("TR");
int i = 0;
Image image;
while (i < listOfImages.Count)
{
image = listOfImages[i];
htmlWriter.WriteFullBeginTag("TD");
htmlWriter.Write(image.Name);
htmlWriter.WriteBreak();
htmlWriter.WriteBeginTag("IMG");
htmlWriter.WriteAttribute("SRC", image.Uri);
htmlWriter.WriteAttribute("STYLE", "width:150px;height:150px");
htmlWriter.WriteEndTag("IMG");
htmlWriter.WriteEndTag("TD");
if (((i + 1) % 5) == 0)
{
htmlWriter.WriteEndTag("TR");
htmlWriter.WriteFullBeginTag("TR");
}
i++;
}
htmlWriter.WriteEndTag("TR");
htmlWriter.WriteEndTag("TABLE");
htmlWriter.WriteEndTag("BODY");
htmlWriter.WriteEndTag("HTML");
HttpContext ctx = HttpContext.Current;
ctx.Response.Write(sw.ToString());
}
[OperationContract]
[WebGet(UriTemplate = "/image/{name}")]
public void GetImage(string name)
{
WebOperationContext wctx = WebOperationContext.Current;
wctx.OutgoingResponse.ContentType = "image/jpeg";
HttpContext ctx = HttpContext.Current;
string fileName = null;
byte[] fileBytes = null;
try
{
fileName = string.Format(@"{0}\{1}.jpg", ImagePath, name);
if (File.Exists(fileName))
{
using(FileStream fs = File.OpenRead(fileName))
{
fileBytes = new byte[fs.Length];
fs.Read(fileBytes, 0, Convert.ToInt32(fs.Length));
}
}
else
{
wctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
}
}
catch
{
wctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
}
FileInfo fi = new FileInfo(fileName);
wctx.OutgoingResponse.ETag = fileName + "_" + fi.LastWriteTime.ToString();
ctx.Response.OutputStream.Write(fileBytes, 0, fileBytes.Length);
}
}
// Use a data contract as illustrated in the sample below to add composite types to service operations.
[DataContract]
public class Image
{
string name;
string uri;
public Image()
{
}
public Image(string name, string uri)
{
this.name = name;
this.uri = uri;
}
public Image(string name, Uri uri)
{
this.name = name;
this.uri = uri.ToString();
}
[DataMember]
public string Name
{
get { return this.name; }
set { this.name = value; }
}
[DataMember]
public string Uri
{
get { return this.uri; }
set { this.uri = value; }
}
}
}
下面列表13.13中的配置用来寄宿WallpaperService服务。服务使用WebHttpBinding绑定和WebHttpBehavior终结点行为来寄宿。
列表13.13 Wallpaper图像服务配置
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service name="EssentialWCF.WallpaperImage.WallpaperService"
behaviorConfiguration="MetadataBehavior">
<endpoint address=""
behaviorConfiguration="WebBehavior"
binding="webHttpBinding"
contract="EssentialWCF.WallpaperImage.WallpaperService"/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
列表13.14 显示了用来在IIS中寄宿WallpaperService的.svc文件。
列表13.14 WallpaperService.svc
<%@ ServiceHost Language="C#" Debug="true"
Service="EssentialWCF.WallpaperImage.WallpaperService"
CodeBehind="~/App_Code/WallpaperImageService.cs" %>