C# construit le combat de projet de service Web (2)

aperçu

Cet article montre comment accéder à la méthode WebService (formulaire de fichier .asmx) dans le projet C# ASP.NET via Ajax.

Pour la configuration du projet de cet article, veuillez vous référer à l'article précédent : C# construit un projet de service Web (1).

environnement

  • Visual Studio 2017 / VS2019

  • Win11 / Win10 similaire

  • .NET Framework 4.8 (côté serveur)

  • jQuery-3.6.0.min.js (côté client)

fichier .asmx

  • Le nom complet de .asmx est ASMXActive Server Methods

  • .asmx est un service Web ASP.NET (ASMX)

  • Le service basé sur .asmx appartient à la forme B/S, accessible par HTTP via SOAP, et renvoie les données au format XML par défaut.

  • Peut renvoyer des types de base et des types de structure PUBLIC

  • Sur la plate-forme Microsoft, un .asmx correspond généralement à un service Web .NET, et le fichier peut être écrit dans des langages tels que VB et C#.

SAVON (Encyclopédie Baidu)

Simple Object Access Protocol est une spécification de protocole pour l'échange de données. Il s'agit d'un protocole léger et simple basé sur XML (un sous-ensemble du langage de balisage général standard). Il est conçu pour échanger des données structurées sur le WEB et des informations solidifiées.

Remarque : Service Web + WSDL + SOAP constituent ensemble la spécification du framework de service Web .NET.

Ajax (JavaScript et XML asynchrones)

Javascript et XML asynchrones. Une technologie de navigateur client indépendante du serveur Web, comme son nom l'indique, elle peut aider le client à accéder au serveur de manière asynchrone sans recharger (rafraîchir) la page entière. Ajax est basé sur des technologies standard telles que JavaScript, XML, HTML et CSS.

AJAX est le rêve d'un développeur, grâce à Ajax peut :

  • Mettre à jour la page Web sans actualiser la page

  • Demander des données au serveur après le chargement de la page

  • Recevoir les données du serveur après le chargement de la page

  • Envoyer des données au serveur en arrière-plan

Selon la documentation en ligne de W3school :

  • AJAX n'est pas un langage de programmation.

  • AJAX est une technologie permettant d'accéder à un serveur Web à partir d'une page Web.

  • AJAX signifie JavaScript asynchrone et XML.

À propos de l'accès inter-domaines Ajax

  • Pour des raisons de sécurité, les navigateurs modernes n'autorisent pas l'accès cross-origin.

  • Cela signifie que la page Web et le fichier XML que vous essayez de charger via Ajax doivent se trouver sur le même serveur.

  • Le framework .NET peut prendre en charge l'accès inter-domaines Ajax via une configuration simple

accès inter-domaines

Dans cet exemple, l'application Web (site Web) créée par le projet C# dans cet exemple est accessible à partir du client Web d'un autre serveur interdomaine (hôte), c'est-à-dire que l'utilisateur doit accéder au site Web sur plusieurs domaines. Pour prendre en charge l'accès inter-domaines des clients Web, le contenu suivant doit être ajouté au fichier Web.config du projet.

Pour plus de commodité (copie), le code de configuration est joint.

<system.webServer>

<Documentpardéfaut>

<fichiers>

<clair />

<add value="WebService1.asmx"/>

</fichiers>

</defaultDocument>

<directoryBrowse enabled="true" />

<httpProtocole>

<en-têtespersonnalisés>

<add name="Access-Control-Allow-Origin" value="*" />

<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />

<add name="Access-Control-Allow-Headers" value="*" />

</customHeaders>

</httpProtocole>

</system.webServer>

服务端回顾

根据上一篇文章,我们通过VS2017利用C#创建了一个ASP.NET Web应用项目。然后,我们在项目中添加了一个Web服务,对应生成了一个.asmx文件(WebService1.asmx)。最后,我们通过各种配置操作完成了项目的发布,即通过Windows的IIS服务向Web用户提供相应的Web服务。

Web服务对应的代码如下。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Services;

namespace MyWebApp

{

/// <summary>

/// WebService1 的摘要说明

/// </summary>

[WebService(Namespace = ""http://sgin.pcl.ac.cn/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[System.ComponentModel.ToolboxItem(false)]

// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。

[System.Web.Script.Services.ScriptService]

public class WebService1 : System.Web.Services.WebService

{

[WebMethod]

public string HelloWorld()

{

return "Hello World";

}

[WebMethod(Description = "加法")]

public int Add(string a, string b)

{

int sum = 0;

sum = Convert.ToInt32(a) + Convert.ToInt32(b);

return sum;

}

[WebMethod(Description = "乘法")]

public int Multiply(string a, string b)

{

int rsult = 0;

rsult = Convert.ToInt32(a) * Convert.ToInt32(b);

return rsult;

}

}

}

可以看出,在上面的Web服务中,提供了三个服务:

  • HelloWorld服务:向客户端简单返回一个‘Hello World’字符串;

  • Add服务:客户端提供两个字符串,服务端将字符串转换为数字后,相加(做加法),然后将结果返回给客户端;

  • Multiply服务:客户端提供两个字符串,服务端将字符串转换为数字后,相乘(做乘法),然后将结果返回给客户端。

此外,根据服务端自动生成的代码中的提示,若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。取消该行注释后,务必重新生成解决方案,然后重新发布项目。

下面演示客户端通过各种方法(协议、标准及接口)访问服务端的相关服务。通过上面的跨域访问配置,客户端不用限于与服务端在一台主机上,客户端可以通过远程(跨域)访问服务端。

标准Ajax方式

本地访问(客户端和服务器端同一台主机或属于同一个域)

一、无参数的方法访问

客户端代码如下

<!DOCTYPE html>

<html lang="en">

<meta charset="utf-8" />

<script type="text/javascript" language="javascript">

function callHelloWorld() {

var xhttp = new XMLHttpRequest();

xhttp.onreadystatechange = function() {

if (this.readyState == 4 && this.status == 200) {

document.getElementById("helloworld").innerHTML = this.responseText;

}

};

xhttp.open("POST", ""http://localhost:8081/WebService1.asmx/HelloWorld", true);

xhttp.send();

}

</script>

<body>

<div id="helloworld">

<h2>点击获取服务端返回的测试字符串</h2>

<button type="button" οnclick="callHelloWorld()">调用</button>

</div>

</body>

</html>

注意用的是POST方法,GET方法没有尝试(按照服务端提示,应该是不支持GET方法)。

客户端(浏览器)界面:

点击‘调用’按钮,正确返回结果。

二、带参数的方法访问

客户端代码如下

<!DOCTYPE html>

<html lang="en">

<meta charset="utf-8" />

<script type="text/javascript" language="javascript">

function callAdd() {

var xhttp = new XMLHttpRequest();

xhttp.onreadystatechange = function() {

if (this.readyState == 4 && this.status == 200) {

document.getElementById("addValue").innerHTML = this.responseText;

}

};

xhttp.open("POST", ""http://localhost:8081/WebService1.asmx/Add", true);

xhttp.setRequestHeader("content-type", "application/json");

var params = {"a":"3", "b":"4"};

xhttp.send(JSON.stringify(params));

}

</script>

<body>

<div id="addValue">

<h2>点击执行服务端Add()方法</h2>

<button type="button" οnclick="callAdd()">调用</button>

</div>

</body>

</html>

本例中,由于客户端需要上传参数(数据)给服务端,所以需要显式指定‘content-type’,参数名称需要与Add方法中的参数名称保持一致。

客户端(浏览器)界面:

点击‘调用’按钮,正确返回结果。

注意:返回的结果是JSON格式的字符串。由此,建议当服务端方法需要返回多个结果值时,通过JSON格式返回是比较妥当的。

跨域访问(客户端和服务器处于不同的域)

一、无参数的方法访问

上述同样的客户端代码,跨域访问时不能正确访问,点击按钮页面没反应,经调试,xhttp(即Ajax的XMLHttpRequest对象)返回的状态为500。查询w3school(http://w3school.com.cn)官网,对应的解释为‘请求未完成。服务器遇到不可预知的情况。’

经各种网站问题的搜索查询尝试,发现是参数传递的问题,问题最终解决了,但中间的机理还值得深入探讨。

ASP.NET的服务框架基于SOAP协议,SOAP基于XML协议交换数据和指令,在C#默认给出的示例中也是给出了如何基于SOAP协议来访问服务端的接口。

实际应用中,客户端通常通过表单形式提供请求给服务器并返回结果,或者通过更流行的Ajax异步方式,其中由Ajax为客户端请求执行了所需的SOAP封装。

这个问题不深入讨论,一来自己也没有弄得特别清楚,二来有点太费功夫。直接说如何解决问题的(可参见本文的小结帮助解惑)。

  • 首先,需要在前述服务端回顾中按照VS2017自动代码框架生成的代码提示取消相关的注释以允许Ajax访问。

  • 其次,在Ajax的服务请求中添加相应的头部信息。

xhttp.open("POST", ""http://localhost:8081/WebService1.asmx/HelloWorld", true);

xhttp.setRequestHeader("Content-type", "application/json");

xhttp.send();

增加以上设置后,成功返回(JSON格式)结果。

数据名称为‘d’,是系统自动给出的,值为我们期望返回的‘Hello World’。

尝试了各种content-type,只有‘application/json’能够成功,其他尝试的包括:

  • text/xml

  • text/plain

  • text/html

  • application/xml

按理‘application/xml’应该是可以的,为何(跨域情况下)反倒是不支持?

经测试,当在本地调用服务时,不受客户端是否设置‘content-type’的影响,都能正确返回结果,只是在设置为‘application/json’返回的是JSON格式,其他设置下直接返回字符串。

也就是说,根据目前的测试,跨域访问的话,客户端只能且仅能将‘content-type’设置为‘application/json’才能正确获取结果。

说这么多,客户端是否能正确访问服务端的方法,跟HTTP请求的头封装密切相关,能够封装为正确的格式,就能获取内容。在跨域情况下,必须正确指定(格式化)相关请求头及请求参数(数据)。

二、带参数的方法访问

参见本地访问的例子。

JQuery + Ajax方式

本地访问

注意需要在客户端引入JQuery代码包(文件)。

利用JQuery + Ajax方式的好处:编写常规的 AJAX 代码并不容易,因为不同的浏览器对 AJAX 的实现并不相同。这意味着您必须编写额外的代码对浏览器进行测试。不过,jQuery团队为我们解决了这个难题,我们只需要一行简单的代码,就可以实现 AJAX 功能。(此处引用了网络原文描述,参见https://www.w3school.com.cn/jquery/jquery_ajax_intro.asp

注意:在JQuery + Ajax方式下,访问接口、参数及响应与JQuery版本密切相关,本例中的JQuery版本为jquery-3.6.0.min.js

本例中仅对JQuery + Ajax方式下的POST方法进行了测试和验证,jQuery ajax – post()方法接口定义如下:

jQuery.post(url,data,success(data, textStatus, jqXHR),dataType)

详细内容可参见链接:https://www.w3school.com.cn/jquery/ajax_post.asp

一、无参数的方法访问

客户端代码如下:

<!DOCTYPE html>

<html lang="en">

<meta charset="utf-8" />

<!-- 注意需要根据JQuery包(文件)的实际路径引入 -->

<script type="text/javascript" src="/lib/jquery-3.6.0.min.js"></script>

<body>

<script type="text/javascript" language="javascript">

$(document).ready(function(){

$("#btnCall").click(function(){

$.post("/WebService1.asmx/HelloWorld", function(data){

$("#HelloWorld").html(data);

alert(data);

});

});

});

</script>

<div id="addValue">

<h2 id="HelloWorld">点击获取服务端返回的测试字符串</h2>

<button id="btnCall" type="button">调用</button>

</div>

</body>

</html>

方法很简单,就是访问C# Web服务提供的无参数接口,然后通过alert方法测试返回的数据。

经测试,点击‘调用’按钮后,服务器返回了结果,在执行了‘$("#HelloWorld").html(data);’语句后,页面无反应,后续的‘alert(data);’语句未能执行。

注释掉语句‘$("#HelloWorld").html(data);’,alert结果如下。

提示返回一个[objectXMLDocument],即一个XMLDocument对象。

这也是‘JQuery+Ajax’方式下,与C# Web服务接口访问后默认返回的对象。

注意jQuery.post()方法的最后一个可选参数‘dataType’,分别指定为xml, json, script和html后的反应如下:

  • “xml”,返回XMLDocument对象。

  • “json”,调用失败,无法返回结果。

  • “script”,返回XML格式的字符串,该字符串通过‘$(selector).html(data);’方法解析后可直接在页面显示结果,即服务器返回的‘HelloWorld’字符串;通过‘$(selector).text(data);’方法则可直接显示原始的XML文本(字符串)。

  • “html”,与指定为”script”结果一样。

如果需要返回JSON格式数据,需要在客户端请求(post方法)中指定contentType为‘application/jsom’

跨域访问

同样的客户端代码,本地访问均测试通过,跨域完全没反应!

直接给出跨域访问的正确代码,细节请移步小结。

<!DOCTYPE html>

<html lang="en">

<meta charset="utf-8" />

<!-- 注意需要根据JQuery包(文件)的实际路径引入 -->

<script type="text/javascript" src="/lib/jquery-3.6.0.min.js"></script>

<body>

<script type="text/javascript" language="javascript">

$(document).ready(function(){

$("#btnCall").click(function(){

$.ajax({

type : "POST",

contentType : "application/json; charset:utf-8",

url : ""http://192.168.123.24:8081/WebService1.asmx/HelloWorld",

dataType : "json",

success : function (data) {

alert("success");

for(x in data) {

$("#HelloWorld").html(data[x]);

break; // retrieve only the first element

}

},

error : function(xhr) { // for test

alert("error");

$("#HelloWorld").html(xhr.responseText);

}

});

});

});

</script>

<div id="addValue">

<h2 id="HelloWorld">点击获取服务端返回的测试字符串</h2>

<button id="btnCall" type="button">调用</button>

</div>

</body>

</html>

带参数的访问:

<!DOCTYPE html>

<html lang="en">

<meta charset="utf-8" />

<!-- 注意需要根据JQuery包(文件)的实际路径引入 -->

<script type="text/javascript" src="/lib/jquery-3.6.0.min.js"></script>

<body>

<script type="text/javascript" language="javascript">

$(document).ready(function(){

$("#btnCall").click(function(){

var params = {"a":"3", "b":"4"};

$.ajax({

type : "POST",

contentType : "application/json; charset:utf-8",

url : ""http://192.168.123.24:8081/WebService1.asmx/Add"

data : JSON.stringify(params),

dataType : "json",

success : function (data) {

for(x in data) {

$("#HelloWorld").html(data[x]);

break; // retrieve only the first element

}

},

error : function(xhr) { // for test

alert("error");

$("#HelloWorld").html(xhr.responseText);

}

});

});

});

</script>

<div id="addValue">

<h2 id="HelloWorld">点击获取服务端返回的测试字符串</h2>

<button id="btnCall" type="button">调用</button>

</div>

</body>

</html>

小结

直接总结吧,中间试错的过程全部忽略,下面的总结仅针对跨域访问,本地访问形式灵活且支持的协议更多,可以参照前述的示例。

提示:

  • 由于软件、接口版本不同,本示例和总结仅针对前述环境一节中给出的各软件(或工具)版本。

  • 服务端是基于C#的ASP.NET Web服务应用,客户端基于JQuery+Ajax。

  • 关于本地和跨域访问,本地访问能够成功的代码,跨域会遇到各种各样的问题;反之,跨域能够执行的代码,本地均能执行。在JQuery + Ajax方式下,由于JQuery对Ajax进行了定制的封装,本地访问能够获取XML形式的结果,跨域通过Ajax访问只能获得JSON格式的数据。

总结要点:

  1. 根据服务端的服务提示,基于C#的Web服务(.asmx文件形式),服务端只接受来自客户端的POST方式的请求。

  1. 基于Ajax跨域访问服务端默认的‘contentType’为‘application/json’,切记!设置为其他类型访问将失败。

  1. 返回的data值与请求时设置的‘dataType’有关,dataType的设置不会影响对服务器的请求,其影响的是数据自服务器返回后JQuery执行的针对性的解析操作:

  • 默认(不设置),返回一个JSON对象;

  • dataType : “json”:dataType的默认值,返回一个JSON对象;

  • dataType : “xml”:调用服务成功,但在客户端本地解析数据将失败;

  • dataType : “html”:得到的结果为格式化了的JSON字符串;

  • dataType : “script”:调用服务成功,但在客户端本地解析数据将失败;

  • dataType : “text”:得到的结果为格式化了的JSON字符串。

总之,只要在客户端请求数据中正确指定了URL和contentType,则总能成功访问服务端接口(服务),客户端需要根据本地的需求正确指定dataType以便正确解析数据。

好记性不如烂笔头,谨记以备温习。

Je suppose que tu aimes

Origine blog.csdn.net/wangyulj/article/details/128676847
conseillé
Classement