wcf的条件获取(Conditional Retrieval)

勇哥注:

条件获取(Conditional Retrieval):

客户端访问一个资源会对它进行缓存,当再次访问这个资源的时候,如果资源相比缓存来说没任何变化,就不会返回真正的资源,而是回复一个“标识”,表明资源并没有改变。

这个特性是http天生带有的,因此像wsHttpBind, webHttpBind, basicHttpBind,REST服务等,都可以使用。


http的条件获取机制是这样的:

下面是两次读同一资源的过程,客户端与服务端按序号顺序进行。

客户端:

    1。发送请求

    3。从回复中取得Etag报头,缓存起来

    4。为http请求加If-None-Match报头(内容就是第3步取得的Etab报头)

   6。收第二次请求的结果,要么是304空内容,要么是有内容。


服务端:

   2。返回body+Etag报头

   5。通过If-None-Match确认当前要发送的资源是不是一致,如果一致发304(Not Modified)的空消息

        如果不一致,则返回body+新的Etag报头


下面这个例子演示读写IO。

当读IO时发现并没有位改变过的时候,返回一个资源没有改变的标识,否则的话返回新的数据。


服务端代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace ConsoleClient
{

    public class ReadWriteIO : IReadWriteIO
    {
        private static List<int> ioList = new List<int>() {1,1,1,1,1 };

        public IEnumerable<int> GetAll()
        {
            int hashcode= ioList.GetHashCode();
                    //立刻检查eTag,如果相同则会返回304错误
                    WebOperationContext.Current.IncomingRequest.CheckConditionalRetrieve(hashcode);
                    //到这里就是资源有变化了,返回etab+资源内容
                    WebOperationContext.Current.OutgoingResponse.SetETag(hashcode);
           return ioList;
        }

        public int GetBit(string bitno)
        {
            return ioList[int.Parse(bitno)];
        }

        public void WriteBit(WriteBitData data)
        {
            ioList[int.Parse(data.bitno)] = int.Parse(data.bitValue);
        }
    }

    [ServiceContract(Namespace ="www.skcircle.com")]
    public interface IReadWriteIO
    {
        [WebGet(UriTemplate ="all")]
        IEnumerable<int> GetAll();

        [WebInvoke(UriTemplate = "{bitno}", Method ="GET")]
        int GetBit(string bitno);

        [WebInvoke(UriTemplate = "/", Method = "POST", 
            RequestFormat = WebMessageFormat.Json, 
            ResponseFormat = WebMessageFormat.Json, 
            BodyStyle = WebMessageBodyStyle.Bare)]
        void WriteBit(WriteBitData data);
    }

    public class WriteBitData
    {
        public string bitno { get; set; }
        public string bitValue { get; set; }
    }

}

划重点:

  1.    private static List<int> ioList = new List<int>() {1,1,1,1,1 };

       ioList必须是static静态的。否则的话GetAll中每次取得的哈希码都不同。

  2.    检查etag的代码,见代码中的注释。



客户端代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;

namespace Client
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void BtnGetall_Click(object sender, EventArgs e)
        {
            eTag = "";
            GetAll();
            GetAll();
        }

        string eTag;
        private void GetAll()
        {
            Uri uri = new Uri("http://127.0.0.1:9998/ReadWriteIO/all");
            var req=HttpWebRequest.Create(uri);
            if(!string.IsNullOrEmpty(eTag))
            {
                req.Headers.Add(HttpRequestHeader.IfNoneMatch, eTag);
            }
            req.Method = "GET";
            try
            {
                var res= req.GetResponse();
                eTag = res.Headers[HttpResponseHeader.ETag];
                using (StreamReader read = new StreamReader(res.GetResponseStream(), Encoding.UTF8))
                {
                   RtbMsg.AppendText($"{read.ReadToEnd()}\r\n");
                }
            }
            catch(WebException ex)
            {
                var res = ex.Response as HttpWebResponse;
                if (res == null) throw;
                if(res.StatusCode== HttpStatusCode.NotModified)
                {
                    RtbMsg.AppendText("IO状态没有发生变化");
                    return;
                }
                throw;
            }

        }
    }
}

划重点:

因为是REST服务的调用,即然可以通过浏览器访问地址:http://127.0.0.1:9998/ReadWriteIO/all

那么当然也可以通过HttpWebRequest类得到一样的访问效果。

这种方式的好处是客户端不需要服务引用,整什么代理类,我只要知道一个域名就可以了。



客户端效果如下:

第二次取相同资源的时候,服务器抛出了异常。

表示资源没有变化。

image.png


本文源码下载:


链接:https://pan.baidu.com/s/12MscgB6MmppB8B5kOWgdeQ 

提取码:tv0y 

--来自百度网盘超级会员V6勇哥的分享



本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:
本帖最后由 勇哥,很想停止 于 2024-07-05 18:20:54 编辑

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864