代码改变世界

WCF 第十三章 可编程站点 使用WebOperationContext

  DanielWise  阅读(4046)  评论(1编辑  收藏  举报
寄宿服务使用WebHttpinding绑定来读或者写HTTP上下文是很常见的。这可以使用WebOperationContext类实现。有很多理由来访问HTTP上下文。你可能想要读取自定义的认证信息头或授权信息头,控制缓存或者设置内容类型,例如。
  图片13.3 显示了一个在当前计算机上显示墙纸的网络应用程序。整个应用程序是使用一个WCF服务创建的而且可以使用网络浏览器访问。
图片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" %>
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示