谈一谈调用远程服务的几种实现方式
也许在我们过往的项目开发过程当中,或多或少都会遇到过针对于现有系统信息进行整合,使用的需求,或是调用人家接口或是给人家提供服务,今天就简单的和大家一起分享一些可用的远程调用服务的方法:
1.webservice方法
Web Service 是一种新的web应用程序分支,他们是自包含、自描述、模块化的应用,可以发布、定位、通过web调用。Web Service可以执行从简单的请求到复杂商务处理的任何功能。一旦部署以后,其他Web Service应用程序可以发现并调用它部署的服务。
实际上,WebService的主要目标是跨平台的可互操作性。为了达到这一目标,WebService完全基于XML(可扩展标记语言)、XSD(XMLSchema)等独立于平台、独立于软件供应商的标准,是创建可互操作的、分布式应用程序的新平台。
我相信大家都会有很多使用webservice的经验,首先说一下在web端调用同域下的webservice:
新建一个webservice,默认生成一个helloWord方法:
[WebMethod] public string HelloWorld() { return "Hello World"; }
之后我没在web端调用此服务:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script src="jquery.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $('#a_post').click(function () { postFun(); }); }); function postFun() { $.ajax({ type: "POST", //访问WebService使用post方式请求 contentType: "application/xml", //WebService会返回json类型 url: "http://localhost:1719/testaaa/MyWebService.asmx/HelloWorld", //调用WebService的地址和方法名称组合 dataType: "xml", success: function (data) { var html; if (typeof data == "string") { html = new ActiveXObject("Microsoft.XMLDOM"); html.loadXML(data); } else { html = data; } var $result = $(html).find("string"); var result = $result.text(); alert(result); } }) } </script> </head> <body> <input type="button" id="a_post" value="获取"/> </body> </html>
于是我们可以得到如下:
说明我们在web端调用同域下webservice成功。
于是我们会想是否可以以这种方法调用远程(不同域)下的webservice呢?
我明确的告诉你非常不容易,我一般的处理方式是在C#后台代码中调用这个服务,web端调用同域下的那个调用远程服务的后台服务就可以了,这其实是一种服务代理的方法,如果大家有什么好的实现web端调用远程webservice的方法,希望大家能够告诉我哦。
于是大家就会想:难道真的没有实现跨域调用服务的方法了吗?
方法还是有的,听我慢慢道来:
2:Jsonp
什么是JSONP JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
Jsonp原理:
由于我们知道<script>标签是可以跨域的,所以我们就以动态生成<script>脚本的形式实现跨域请求:
首先在客户端注册一个callback, 然后把callback的名字传给服务器。
此时,服务器先生成 json 数据。
然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp.
最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)
由于jsonp传送的形式是json形式,所以我们修改远程的服务:
using System; using System.Web; public class Handler : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; string callback = context.Request["callback"]; string response = string.Format("'value1':'{0}','value2':'{1}'", context.Request.QueryString["p1"], context.Request.QueryString["p2"]); string call = callback + "({" + response + "})"; context.Response.Write(call); } public bool IsReusable { get { return false; } } }
web端调用:
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <script src="jquery.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function () { $('#a_post').click(function () { postFun(); }); }); var postFun = function () { jQuery.ajax({ type: "get", //url: "Jsonp_learn.aspx", url: "http://localhost:1719/testaaa/Handler.ashx", dataType: "jsonp", jsonp: "callback", data: "p1=1&p2=2", success: function (msg) { alert("value1:" + msg.value1 + " value2:" + msg.value2); } }); } </script> </head> <body> <input type="button" id="a_post" value="获取"/> </body> </html>
实现的结果:
OK,至此我们已经可以实现了我们的一些要求,当然程序员的特点就是永远希望找到最好的东西,并且与一切不简单,不美好的东西作斗争,我们思考一下以上两种实现方法的特点:
webservice:是以soap协议,xml形式调用的,web端调用我们需要将结果处理成xml;
jsonp:这是程序员思考的结晶,可是并没有一些官方的标准;
其实我们回想:何必这么麻烦不就是请求一个结果吗,一个字符串不久可以了?
3.restful
RESTful Wcf是一种基于Http协议的服务架构风格。 相较 WCF、WebService 使用 SOAP、WSDL、WS-* 而言,几乎所有的语言和网络平台都支持 HTTP 请求。
RESTful的几点好处:
1、简单的数据通讯方式,基于HTTP协议。避免了使用复杂的数据通讯方式。
2、避免了复杂的客户端代理。
3、直接通过URI资源定向即可把服务暴露给调用者。
REST 架构风格的流行。REST是一种简洁的设计风格,通过URL来设计系统,以URI来抽象各种资源,以HTTP协议的PUT,DELETE,GET,POST来对应对资源的各种操作。
于是我们决定用这种:既简单,由有一定的规范值得参考:
我们的实现可以依照wcf,具体实现大家可以google之,我们简单说一下.net的实现restful的比较好的方法webAPI:
我们通过vs傻瓜式的就建立了一个webapi:
Model:
public class TestUseMode { public string ModeKey{get;set;} public string ModeValue { get; set; } }
Controller:
MVC WebAPI中的Controllers和普通MVC的Controllers类似,不过不再继承于Controller,而改为继承API的ApiController,一个Controller可以包含多个Action,这些Action响应请求的方法与Global中配置的路由规则有关,在后面结束Global时统一说明.
public class TestController : ApiController { public static List<TestUseMode> allModeList = new List<TestUseMode>(); public IEnumerable<TestUseMode> GetAll() { return allModeList; } public IEnumerable<TestUseMode> GetOne(string key) { return allModeList.FindAll((mode) => { if (mode.ModeKey.Equals(key)) return true; return false; }); } public bool PostNew(TestUseMode mode) { allModeList.Add(mode); return true; } public int Delete(string key) { return allModeList.RemoveAll((mode) => { if (mode.ModeKey == key) return true; return false; }); } public int DeleteAll() { return allModeList.RemoveAll((mode) => { return true; }); } public int PutOne(string key, string value) { List<TestUseMode> upDataList = allModeList.FindAll((mode) => { if (mode.ModeKey == key) return true; return false; }); foreach(var mode in upDataList) { mode.ModeValue = value; } return upDataList.Count; } }
Global:
默认情况下,模板自带了两个路由规则,分别对应于WebAPI和普通MVC的Web请求,默认的WebAPI路由规则如下
1 routes.MapHttpRoute(
2 name: "DefaultApi",
3 routeTemplate: "api/{controller}/{id}",
4 defaults: new { id = RouteParameter.Optional }
5 );
简单使用JS调用上面提供的数据接口:
function getAll() { 2 $.ajax({ 3 url: "api/Test/", 4 type: 'GET', 5 success: function (data) { 6 document.getElementById("modes").innerHTML = ""; 7 $.each(data, function (key, val) { 8 var str = val.ModeKey + ': ' + val.ModeValue; 9 $('<li/>', { html: str }).appendTo($('#modes')); 10 }); 11 } 12 }).fail( 13 function (xhr, textStatus, err) { 14 alert('Error: ' + err); 15 }); 16 } 17 18 19 20 function add() { 21 22 $.ajax({ 23 url: "api/Test/", 24 type: "POST", 25 dataType: "json", 26 data: { "ModeKey": document.getElementById("txtKey").value, "ModeValue": document.getElementById("txtValue").value }, 27 success: function (data) { 28 getAll(); 29 } 30 }).fail( 31 function (xhr, textStatus, err) { 32 alert('Error: ' + err); 33 }); 34 35 } 36 37 function find() { 38 39 $.ajax({ 40 url: "api/Test/" + document.getElementById("txtFindKey").value, 41 type: 'GET', 42 success: function (data) { 43 document.getElementById("modes").innerHTML = ""; 44 $.each(data, function (key, val) { 45 var str = val.ModeKey + ': ' + val.ModeValue; 46 $('<li/>', { html: str }).appendTo($('#modes')); 47 }); 48 } 49 }).fail( 50 function (xhr, textStatus, err) { 51 alert('Error: ' + err); 52 }); 53 } 54 55 function removeAll() { 56 $.ajax({ 57 url: "api/Test/", 58 type: 'DELETE', 59 success: function (data) { 60 document.getElementById("modes").innerHTML = ""; 61 getAll(); 62 } 63 }).fail( 64 function (xhr, textStatus, err) { 65 alert('Error: ' + err); 66 }); 67 } 68 69 function remove() { 70 $.ajax({ 71 url: "api/Test/"+document.getElementById("txtRemoveKey").value, 72 type: 'DELETE', 73 success: function (data) { 74 document.getElementById("modes").innerHTML = ""; 75 getAll(); 76 } 77 }).fail( 78 function (xhr, textStatus, err) { 79 alert('Error: ' + err); 80 }); 81 } 82 83 function update() { 84 $.ajax({ 85 url: "api/Test/", 86 type: 'PUT', 87 dataType: "json", 88 data: { "key": document.getElementById("txtUpdateKey").value, "value": document.getElementById("txtUpdateValue").value }, 89 success: function (data) { 90 document.getElementById("modes").innerHTML = ""; 91 getAll(); 92 } 93 }).fail( 94 function (xhr, textStatus, err) { 95 alert('Error: ' + err); 96 }); 97 }
这样就实现了最基本的CRUD操作。
目前来看有这几种比较成熟的方法,个人比较喜欢最后一种。
使用BizTalk实现RosettaNet B2B So Easy
biztalk rosettanet 自定义 pip code
Debatching(Splitting) XML Message in Orchestration using DefaultPipeline
Modifying namespace in XML document programmatically
IIS各个版本中你需要知道的那些事儿
关于IHttpModule的相关知识总结
开发设计的一些思想总结
《ASP.NET SignalR系列》第五课 在MVC中使用SignalR
《ASP.NET SignalR系列》第四课 SignalR自托管(不用IIS)