wcf的条件更新(Conditional Update)

勇哥注:

条件获取:可以避免相同数据的重复传输,进而提高性能。

条件更新:用于解决资源并发操作问题。

    当我们对一个资源 进行修改或者删除的进修,通过条件更新的信息,我们可以知道在这之前该资源是否被其它人改动过。



条件更新的流程:

服务端:

   2。返回body+(对等性判断值的)Etag报头

   5。通过Etag报头与If-Match比较一致性,不一致就表示 被修改/删除的资源 已经被修改了,
         这时回复一个412(Precondition Failed)的空消息


客户端:

    1。发送请求

    3。从回复中取得Etag报头

    4。 修改:直接对资源修改,并提交修改后的资源

         删除:向服务端发删除请求,为http请求加If-Match报头(内容就是3取得的Etab报头)

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


解决方案:

其中writeioData是个DTO,用来给post指令提供参数。

所以把它抽出来共享了。

image.png


服务端代码:

1。 post方法WriteBit的参数需要两个,一个是位号,一个是值,REST的post方法不允许有多个参数,因此使用一个calss WriteBitData来包装参数,并且使用json方式进行序列化传参。
2。 ComputeHashCode是用来取ioList变化后的HashCode(哈稀码)。

     你不能直接用ioList.GetHashCode()来表达内容变化的列表,实际上这样取得的HashCode是完全一样的。

     HashCode内部算法是跟对象的地址相关的,并不是跟对象的内容相关的。
     ComputeHashCode函数就是取得随着列表内容变化的HashCode。

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

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)
        {
            //在执行WriteBit之前模拟已经被其它线程改了值了。
            ioList[1] = 0;

            WebOperationContext.Current.IncomingRequest.CheckConditionalUpdate(ComputeHashCode(ioList));
            WebOperationContext.Current.OutgoingResponse.SetETag(ComputeHashCode(ioList));

            //因为上面会抛异常,实际上执行不到修改数据这里的
            ioList[int.Parse(data.bitno)] = int.Parse(data.bitValue);
        }

        public static int ComputeHashCode<T>(List<T> list) where T : IEquatable<T>
        {
            unchecked // 允许溢出  
            {
                int hash = 17;
                foreach (var item in list)
                {
                    hash = hash * 23 + EqualityComparer<T>.Default.GetHashCode(item);
                }
                return hash;
            }
        }
    }

    [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);
    }

 

}


客户端代码:

GetAll是演示条件获取 的。
WriteIO是演示条件更新的。

image.png


using Newtonsoft.Json;
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;
using WriteioData;

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

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

        private void WriteIO(int bitno,int data)
        {
            Uri uri2 = new Uri("http://127.0.0.1:9998/ReadWriteIO/all");
            var req2 = HttpWebRequest.Create(uri2);
            req2.Method = "GET";
            var res2 = req2.GetResponse();


            Uri uri = new Uri("http://127.0.0.1:9998/ReadWriteIO/");
            var res=HttpWebRequest.Create(uri);
            res.Method = "POST";
            res.ContentType = "application/json";
            try
            {
                var writeBitData = new WriteBitData
                {
                    bitno = "0",
                    bitValue = "0"
                };
                string jsonData = JsonConvert.SerializeObject(writeBitData);

                byte[] buffer = Encoding.UTF8.GetBytes(jsonData);
                res.GetRequestStream().Write(Encoding.UTF8.GetBytes(jsonData), 0, buffer.Length);
                res.Headers.Add(HttpRequestHeader.IfMatch, res2.Headers[HttpResponseHeader.ETag]);
                RtbMsg.AppendText($"正准备写IO数据\r\n");
                res.GetResponse();
            }
            catch(WebException ex)
            {
                var response = ex.Response as HttpWebResponse;
                if (null == response)
                {
                    throw;
                }
                if (response.StatusCode == HttpStatusCode.PreconditionFailed)
                {
                    RtbMsg.AppendText("服务端数据已发生变化\r\n");
                }
                else
                {
                    throw;
                }
            }
        }

        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;
            }

        }

        private void button1_Click(object sender, EventArgs e)
        {
            WriteIO(0, 0);
        }
    }
}



本文原代码下载:


链接:https://pan.baidu.com/s/1uirGJS2Cy0dVGRfGm3x4Cg 

提取码:0f7i 

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



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

发表评论:

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

会员中心
搜索
«    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