实现在GET请求下调用WCF服务时传递对象(复合类型)参数
WCF实现RESETFUL架构很容易,说白了,就是使WCF能够响应HTTP请求并返回所需的资源,如果有人不知道如何实现WCF支持HTTP请求的,可参见我之前的文章《实现jquery.ajax及原生的XMLHttpRequest调用WCF服务的方法》、《实现jquery.ajax及原生的XMLHttpRequest跨域调用WCF服务的方法》,在此就不作重述。
实现WCF支持HTTP请求调用容易,但要实现类似MVC的ACTION及WEB API那样的灵活,那就得花费点功夫,为什么这样说呢?因为如果WCF的参数为普通类型(即:值类型),那么调用很容易,也支持HTTP的多种请求方法,比如常见的:GET,POST,例如:
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "*", UriTemplate = "Get/{value}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
string GetData(string value);
}
public class Service1 : IService1
{
public string GetData(string value)
{
return string.Format("You entered: {0}", value);
}
}
我们只需要通过浏览器访问如:http://localhost:14719/Service1.svc/Get/test 注意我加深的部份,需要与该服务方法上约定的UriTemplate相匹配,与MVC的ROUTE URL类似,POST也很简单,在此就不再说明。
上面的调用成功了,你是否就认为这样就完了呢?有没有想过如果WCF的服务方法参数为对象(复合类型),例如:
[OperationContract]
[WebInvoke(Method = "*",RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
Point GetPoint(Point point);
Point定义:
[DataContract(Namespace="http://www.zuowenjun.cn/")]
public class Point
{
[DataMember]
public int X { get; set; } [DataMember]
public int Y { get; set; } [DataMember]
public string Value { get; set; }
}
public Point GetPoint(Point point)
{
if (point == null)
{
throw new ArgumentNullException("point");
}
return point;
}
你是否可以像上面那样来进行GET或POST请求呢?如果可以,那么该如何调用呢?本人(梦在旅途)是一个遇到了问题,就必需弄明白及必需解决的人,所以我进行了试验,首先试一下POST方法,示例代码如下:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="jquery-1.4.4.min.js" type="text/javascript"></script>
</head>
<body>
X:<input id="Text1" type="text" />
Y:<input id="Text2" type="text" />
Value:<input id="Text3" type="text" />
<input id="Button1" type="button" value="button" />
<fieldset>
<legend>结果输出:</legend>
<div id="resultbox"> </div>
</fieldset>
<script type="text/javascript">
$(function () {
$("#Button1").click(function () {
$.ajax({
url: "Service1.svc/GetPoint",
contentType:"application/json",
type: "post",
datatype: "json",
data: JSON.stringify({ 'point': { 'X': $("#Text1").val(), 'Y': $("#Text2").val(), 'Value': $("#Text3").val()} }),
success: function (r,s,x) {
$("#resultbox").append("<p>" + JSON.stringify(r) + "</p>");
}
});
});
});
</script>
</body>
</html>
经调用成功,结果如下图示:

也可以参见DUDU的文章:jQuery调用WCF服务时如何传递对象参数
这里顺便提醒一下,在POST请求WCF服务方法参数为对象时,注意AJAX请求的Data必需是JSON字符串,不能是JSON对象,如果不明白两者的关系,我这里简要说明一下,
{X:1,Y:2,Value:'test'} 、{'X':1,'Y':2,'Value':'test'}--这些不论KEY加不加引号,都是JSON对象,可以通过JSON.stringify方法转换成JSON字符串
"{X:1,Y:2,Value:'test'}"、"{'X':1,'Y':2,'Value':'test'}"--这些就是JSON字符串,可以通过$.parseJSON方法转换成JSON对象
然后就试一下GET方法,在此我就有点难了,该如何进行GET请求呢?参数该如何对应呢?我将AJAX的TYPE改为GET,然后调用,最后结果返回如下图:

一看就知道,调用失败,无法为WCF的服务方法参数point赋值,也就是WCF无法正确将请求的参数解析成POINT类型对象实例,我尝试着直接在浏览器中访问:
http://localhost:14719/Service1.svc/GetPoint?point={x=1&y=2&value=test},结果仍是报同样的错误,这个问题却是困扰了我几天,我也曾请教过DUDU,QQ群,博问:http://q.cnblogs.com/q/77775/,都没有人能回答我,有人说复合类型不支持GET,用不了GET就不要用之类的话,我就想,我的服务契约上定义的是Method = "*",而这里GET却不行,难道不能用*,我不放弃,经过多方查证,这篇文章给了我明确的思路:http://www.cnblogs.com/huangxincheng/p/4621971.html,可以通过自定义MessageFormatter来实现自己想要的解析,好了废话不多说,直接上代码。
自定义PointMessageFormatter:
public class PointMessageFormatter:IDispatchMessageFormatter
{
private IDispatchMessageFormatter innerFormatter; public PointMessageFormatter(IDispatchMessageFormatter innerFormatter)
{
this.innerFormatter = innerFormatter;
} public void DeserializeRequest(System.ServiceModel.Channels.Message message, object[] parameters)
{
innerFormatter.DeserializeRequest(message, parameters); if (message.Properties["HttpOperationName"].ToString().Equals("GetPoint",StringComparison.OrdinalIgnoreCase) && parameters.Count() > 0 && parameters[0] == null)
{
var request = message.Properties.Values.ElementAt(1) as HttpRequestMessageProperty;
if (request.Method.Equals("GET", StringComparison.OrdinalIgnoreCase))
{
parameters[0] = DeserializeFromQueryString(request.QueryString);
}
} } private object DeserializeFromQueryString(string queryString)
{
if (string.IsNullOrEmpty(queryString)) return null;
var t=typeof(Point);
var point = new Point();
foreach (var p in t.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
Regex regx = new Regex(string.Format(@"(?<={0}=)(.*?)(?=\&|$)", p.Name), RegexOptions.IgnoreCase);
string value = regx.Match(queryString).Groups[1].Value;
try
{
var pValue = Convert.ChangeType(value,p.PropertyType);
p.SetValue(point, pValue, null);
}
catch
{ } }
return point;
} public System.ServiceModel.Channels.Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
return innerFormatter.SerializeReply(messageVersion, parameters, result);
}
}
自定义MyOperationBehavior:
public class MyOperationBehavior : Attribute, IOperationBehavior
{
public int MaxLength { get; set; } public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{ } public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{ } public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.Formatter = new PointMessageFormatter(dispatchOperation.Formatter);
} public void Validate(OperationDescription operationDescription)
{ }
}
然后修改GetPoint服务方法实现:
[MyOperationBehavior]
public Point GetPoint(Point point)
{
if (point == null)
{
throw new ArgumentNullException("point");
}
return point;
}
其实方法实现内容没有变,就是在其方法上增加了一个特性:MyOperationBehavior,目的是:当请求调用该方法时,会使用我上面定义的PointMessageFormatter,从而实现了自定义解析。
最后我们再试验通过GET请求,这里我就直接通过浏览器访问:http://localhost:14719/Service1.svc/GetPoint?x=12&y=232&value=test,最后返回的结果如下:

可以看出,调用成功,已经能正常解析到我的参数了,当然我上面的实现可能比较粗糙,也有很多的限制,但我这里只是提供一种思路,一种解决方案,大家可以基于此思路实现更牛B的功能。其实WCF的可扩展的地方非常多,可以参见artech大牛关于WCF的系列文章,我感觉他的文章写得比较深入,但就是不易懂。这篇文章我也是花了很多精力来思考与解决,希望能帮助到大家,如果觉得不错,给个推荐吧,谢谢!
实现在GET请求下调用WCF服务时传递对象(复合类型)参数的更多相关文章
- cxf 调用 webservice服务时传递 服务器验证需要的用户名密码
cxf通过wsdl2java生成客户端调用webservice时,如果服务器端需要通过用户名和密码验证,则客户端必须传递验证所必须的用户名和密码,刚开始想通过url传递用户名和密码,于是在wsdl文件 ...
- AXIS 调用 webservice服务时传递 服务器验证需要的用户名密码
System.setProperty("javax.net.ssl.trustStore", T.class.getResource(".").getPath( ...
- 不要在using语句中调用WCF服务
如果你调用WCF服务时,像下面的代码这样在using语句中进行调用,需要注意一个问题. using (CnblogsWcfClient client = new CnblogsWcfClient()) ...
- 实现jquery.ajax及原生的XMLHttpRequest跨域调用WCF服务的方法
关于ajax跨域调用WCF服务的方法很多,经过我反复的代码测试,认为如下方法是最为简便的,当然也不能说别人的方法是错误的,下面就来上代码,WCF服务定义还是延用上次的,如: namespace Wcf ...
- 实现jquery.ajax及原生的XMLHttpRequest调用WCF服务的方法
废话不多说,直接讲解实现步骤 一.首先我们需定义支持WEB HTTP方法调用的WCF服务契约及实现服务契约类(重点关注各attribute),代码如下: //IAddService.cs namesp ...
- [转]学习 WCF (6)--学习调用WCF服务的各种方法
转自:http://www.cnblogs.com/gaoweipeng/archive/2009/07/26/1528263.html 作者这篇博文写得很全面. 根据不同的情况,我们可以用不同的方法 ...
- 学习之路十四:客户端调用WCF服务的几种方法小议
最近项目中接触了一点WCF的知识,也就是怎么调用WCF服务,上网查了一些资料,很快就搞出来,可是不符合头的要求,主要有以下几个方面: ①WCF的地址会变动,地址虽变,但是里面的逻辑不变! ②不要引用W ...
- WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理
原文:WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理 在前面一片文章(服务代理不能得到及时关闭会有什么后果?)中,我们谈到及时关闭服务代理(Service Proxy)在一个高并发环境 ...
- jquery或者JavaScript调用WCF服务的方法
/****************************************************************** * Copyright (C): 一心堂集团 * CLR版本: ...
随机推荐
- Knockoutjs 实践入门 (3) 绑定数组
<form id="form1" runat="server"> <div> <!--text ...
- 我的ORM之十一 -- 缓存
我的ORM索引 对某一个查询频繁重复,应该使用缓存. 缓存应该是可以配置. 配置 Web.config: <configuration> <configSections> &l ...
- mongodb(mongoose-redis-cache)
在传统的项目中,我们经常会用到缓存来优化数据库的读取,比如java中,我们利用spring的AOP能力,在读写数据库前增加对缓存的操作. 在node与mongodb的项目中也仍然会存在类似问题,本文参 ...
- Java设计模式8:迭代器模式
迭代器模式 迭代器模式又叫做游标(Cursor)模式,其作用是提供一种方法访问一个容器元素中的各个对象,而又不暴露该对象的内部细节. 迭代器模式结构 迭代器模式由以下角色组成: 1.迭代器角色 负责定 ...
- 人人都是 DBA(XV)锁信息收集脚本汇编
什么?有个 SQL 执行了 8 秒! 哪里出了问题?臣妾不知道啊,得找 DBA 啊. DBA 人呢?离职了!!擦!!! 程序员在无处寻求帮助时,就得想办法自救,努力让自己变成 "伪 DBA& ...
- Homework 1 -- The beginning
我是在北京在读的一位大学生.如果问我学的什么专业,我会用一个冷笑话回答你:我精通多种语言,在老家我说家乡话:跟北京我讲普通话:跟老外就玩English:我跟机器得敲代码.现在你知道我学的就是计算机了. ...
- FusionCharts简单教程(六)------加载外部Logo
一.加载外部文件Logo 在使用FusionCharts时,我们可能需要在加载图像的时候需要在图表中显示标识.图片等等.这里我们可以使用logoURL属性来实现.如: <chart ...
- jmx : ClientCommunicatorAdmin Checker-run
今天遇到一个问题: 执行bat,关闭jmx的时候,由于程序关闭之后又去连接了一次,cmd窗口报错,类似: 2013-7-11 15:58:05 ClientCommunicatorAdmin rest ...
- DDD~DDD从零起步架构说明
回到目录 看了传说中的弦哥对园子里.Net项目分层与文件夹结构大全(最佳架子奖,吐槽奖,阴沟翻船奖揭晓),我也来说说我的DDD架构吧,主要是看了微软NlayerApp之后,自己写的一个,以后将会应用到 ...
- Java程序员的日常 —— 《编程思想》持有对象
集合框架可以说是Java里面必备的知识点了,日常的使用中也会遇到各种情况需要使用到集合.下面就简单介绍下各种集合的使用场景: List List可以看做是数组,实现的方式有两种: ArrayList ...