wcf的rest的帮助页、json、元数据、可靠的消息传递

勇哥注:

这里补充几个WCF REST的知识点。

rest到底要不要元数据?

rest的帮助页怎么弄?

rest怎么改成支持json消息?

rest支持可靠的消息传递吗?

rest服务怎么用webClient来访问?(其实就是模拟浏览器http的访问过程)


(一)元数据

wcf的rest服务不需要你指定元数据。


在WCF中,特别是当您创建REST服务时,关于元数据的处理与传统SOAP服务有所不同。

WCF REST服务通常不依赖于SOAP的WSDL(Web Services Description Language)元数据,

因为REST服务的设计哲学是基于HTTP的资源表示和状态转移,而不是像SOAP那样通过WSDL来描述服务接口。


<serviceMetadata> 元素在WCF中主要用于SOAP服务,

它允许客户端通过HTTP GET请求来检索WSDL文件,从而自动生成代理类或其他客户端代码。

然而,在REST服务中,通常不需要WSDL,因为REST服务通常通过HTTP方法(如GET、POST、PUT、DELETE)

和媒体类型(如application/json、application/xml)来定义其接口。


因此,当您尝试在WCF REST服务的配置中设置<serviceMetadata>时,它实际上不会对REST服务的客户端发现或调用产生直接影响。

客户端不需要WSDL来调用REST服务,而是需要知道资源的URI、HTTP方法和请求/响应的格式。


所以下面这样的定义是没有意义的。

<serviceBehaviors>
        <behavior name="NewBehavior0">
          <serviceMetadata httpGetUrl="http://192.168.216.129:3721/meta"
            httpsGetEnabled="true" />
        </behavior>
      </serviceBehaviors>


(二)帮助页

就是那句 <webHttp helpEnabled="true" />

此时访问地址就是:http://192.168.216.129:3721/employees/help

即:{终结点地址}/Help


<system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="NewBehavior1">
          <webHttp helpEnabled="true" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="Service.EmployeesService">
        <endpoint address="http://192.168.216.129:3721/employees" behaviorConfiguration="NewBehavior1"
          binding="webHttpBinding" contract="Contract.IEmployees" />
      </service>
    </services>
  </system.serviceModel>

默认的帮助页是下面这样的:

image.png


我们把契约的方法加上描述特性Description

 public interface IEmployees
    {
        [WebGet(UriTemplate = "all")]
        [Description("获取所有员工列表")]
        IEnumerable<Employee> GetAll();

        [WebGet(UriTemplate = "{id}")]
        [Description("获取指定ID的员工, 参数:(string id)")]
        Employee Get(string id);

        [WebInvoke(UriTemplate = "/", Method = "POST")]
        [Description("创建一个新的员工, 参数:(Employee employee)")]
        void Create(Employee employee);

        [WebInvoke(UriTemplate = "/", Method = "PUT")]
        [Description("修改现有员工信息, 参数:(Employee employee)")]
        void Update(Employee employee);

        [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
        [Description("删除指定ID的员工, 参数:(string id)")]
        void Delete(string id);
    }


现在的帮助页就是这样的:

image.png



(三)json

REST服务具有两种基本的消息格式(Xml和Json),默认会使用Xml消息格式。

下面我们改为Json格式:

首先把契约的方法的RequestFormat和ResponseFormat都改为json。

[WebGet(UriTemplate = "all",RequestFormat = WebMessageFormat.Json,ResponseFormat = WebMessageFormat.Json)]
[Description("获取所有员工列表")]
IEnumerable<Employee> GetAll();


这时候调用者直接收到的就是json格式消息。

image.png


还可以设置为系统自动选择,这个是有一套自动选择的规则的(主要是看调用者怎么选择)。

详细可以看:https://www.cnblogs.com/artech/archive/2012/02/07/wcf-rest-help-page.html


(四)rest支持可靠的消息传递吗?

WCF与REST

首先,WCF支持多种通信协议和消息格式,包括SOAP(Simple Object Access Protocol)和REST。

SOAP通常与复杂的、基于XML的消息传递相关联,

而REST则倾向于使用简单的HTTP方法和资源表示(如JSON或XML)来进行通信。


REST与可靠消息

REST本身并不直接提供“可靠消息”的保证。REST的设计哲学是倾向于简单性和无状态性,

这意味着每个请求都应该独立于其他请求,

服务器不应该保持客户端的会话状态。因此,REST通常不处理消息传递的可靠性、事务性或持久性等问题,

这些问题更多地是由应用层或中间件来解决的。


WCF中的可靠消息传递

然而,WCF提供了对可靠消息传递的支持,但这主要是通过SOAP协议和WS-ReliableMessaging(WS-RM)规范来实现的。

WS-RM为SOAP消息提供了一种可靠的、有序的、基于会话的传递机制,以确保消息在不可靠的网络环境中能够可靠地传递。


WCF REST服务的可靠消息传递

对于WCF REST服务,虽然REST本身不直接支持可靠消息传递,但你可以通过以下几种方式来实现或增强消息的可靠性:


应用层重试机制:

在客户端实现重试逻辑,当请求失败时自动重试。

这可以通过简单的重试策略(如固定间隔重试)或更复杂的策略(如指数退避重试)来实现。


持久化请求和响应:

将请求和响应存储在数据库中或其他持久化存储中,以便在出现网络故障或服务器故障时能够恢复它们。


使用中间件:

在WCF REST服务之前或之后部署中间件,该中间件可以提供消息队列、事务处理、消息重试等可靠性功能。


自定义协议或扩展:

虽然这通常不是首选方法,但在某些情况下,你可能需要自定义协议或扩展WCF REST服务以支持特定的可靠性要求。


结论

综上所述,WCF REST服务本身并不直接支持可靠消息传递,但你可以通过应用层重试机制、持久化请求和响应、

使用中间件或自定义协议等方法来增强消息的可靠性。这些方法可以根据你的具体需求和应用程序的复杂性来选择。



(五)演示代码


image.png


代码:

演示了使用webClient类进行Post, Put, Get, Delete的REST访问。

using Contract;
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;

namespace webClient
{
    public partial class Form1 : Form
    {
        private WebClient webClient = new WebClient();
        private string serverIP = "http://192.168.216.129:3721/employees";

        public Form1()
        {
            InitializeComponent();
        }

        private string Get(string contentType, string accept,string cmdURL)
        {
            if (!string.IsNullOrEmpty(contentType))
            {
                webClient.Headers.Add("Content-Type", contentType);
            }
            if (!string.IsNullOrEmpty(accept))
            {
                webClient.Headers.Add("Accept", accept);
            }
            using (StreamReader reader = new StreamReader(webClient.OpenRead(cmdURL)))
            {
                return reader.ReadToEnd();
            }
        }

        private string Post(string contentType, string accept, string cmdURL,string jsonStr)
        {
            if (!string.IsNullOrEmpty(contentType))
            {
                webClient.Headers.Add("Content-Type", contentType);
            }
            if (!string.IsNullOrEmpty(accept))
            {
                webClient.Headers.Add("Accept", accept);
            }
            byte[] data = Encoding.UTF8.GetBytes(jsonStr);
            return Encoding.UTF8.GetString(webClient.UploadData(cmdURL, data));
        }

        private string Delete(string contentType, string accept, string cmdURL)
        {
            if (!string.IsNullOrEmpty(contentType))
            {
                webClient.Headers.Add("Content-Type", contentType);
            }
            if (!string.IsNullOrEmpty(accept))
            {
                webClient.Headers.Add("Accept", accept);
            }
            return webClient.UploadString(cmdURL,"DELETE", "");
        }

        private string Put(string contentType, string accept, string cmdURL,string jsonStr)
        {
            if (!string.IsNullOrEmpty(contentType))
            {
                webClient.Headers.Add("Content-Type", contentType);
            }
            if (!string.IsNullOrEmpty(accept))
            {
                webClient.Headers.Add("Accept", accept);
            }
            byte[] data = Encoding.UTF8.GetBytes(jsonStr);
           // return webClient.UploadString(cmdURL, "PUT", jsonStr);
            return Encoding.UTF8.GetString(webClient.UploadData(cmdURL,"PUT", data));
        }

        private void BtnDisAll_Click(object sender, EventArgs e)
        {
            //send("application/json", "Content-Type = application/json; Accept = N/A:", $"{serverIP}all");
            var s1= Get("", "", $"{serverIP}/all");
            djson(s1);
            RtbMsg.Text = s1;
        }

        List<Employee> employeeBuff = new List<Employee>();
        private void djson(string jsondata)
        {
            employeeBuff.Clear();
            var list= JsonConvert.DeserializeObject<List<Employee>>(jsondata);
            comboBox1.Items.Clear();
            foreach(var m in list)
            {
                comboBox1.Items.Add(m.Id);
            }
            if (comboBox1.Items.Count > 0)
            {
                employeeBuff = list;
                comboBox1.SelectedIndex = 0;
            }
        }

        private void BtnAddNew_Click(object sender, EventArgs e)
        {
            if(TxtId.Text.Length<1 || TxtName.Text.Length<1 || TxtGrade.Text.Length<1 || TxtDepartment.MaxLength<1)
            {
                MessageBox.Show("检查id,name,grade,department是不是没填写");
                return;
            }
            var data = new Employee
            {
                Id = TxtId.Text,
                Name = TxtName.Text,
                Grade = TxtGrade.Text,
                Department = TxtDepartment.Text
            };
            string json = JsonConvert.SerializeObject(data);
            var s1 = Post("application/json", "", $"{serverIP}/", json);

            BtnDisAll_Click(null, null);
        }

        private void BtnDel_Click(object sender, EventArgs e)
        {
            var Id = comboBox1.Text;
            if (Id.Length < 1 )
            {
                MessageBox.Show("没选择Id");
                return;
            }

            var s1 = Delete("application/json", "", $"{serverIP}/{Id}");

            BtnDisAll_Click(null, null);
        }

        private void BtnModify_Click(object sender, EventArgs e)
        {
            var Id = comboBox1.Text;
            if (Id.Length < 1)
            {
                MessageBox.Show("没选择Id");
                return;
            }
            var data = new Employee
            {
                Id = TxtId.Text,
                Name = TxtName.Text,
                Grade = TxtGrade.Text,
                Department = TxtDepartment.Text
            };
            string json = JsonConvert.SerializeObject(data);
            Put("application/json", "Content-Type = application/json; Accept = N/A:", $"{serverIP}/", json);
            BtnDisAll_Click(null, null);
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            var Id = comboBox1.Text;
            if (string.IsNullOrEmpty(Id)) return;
            var idx=employeeBuff.FindIndex(s => s.Id == Id);
            if(idx>=0)
            {
                TxtId.Text = employeeBuff[idx].Id;
                TxtName.Text = employeeBuff[idx].Name;
                TxtGrade.Text = employeeBuff[idx].Grade;
                TxtDepartment.Text = employeeBuff[idx].Department;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            webClient.Dispose();
        }

      
    }
}


来看看抓包的结果


下面是GetAllEmployees,取所有信息。

image.png

下面是新增了一条记录,“张飞”

image.png

下面是一个put,张飞改名为“张飞2”

image.png

下面是删除了005的记录

image.png





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

发表评论:

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

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