深入Atlas系列:Web Sevices Access in Atlas示例(6) - 在客户端隐藏服务器端类型信息...
1、定义需要的类型
首先,我们定义一下所需的类型。我们的目标是计算某种类型员工的工资,于是,我们先定义一个员工的抽象类:
{
public abstract class Employee
{
private int _Years;
public int Years
{
get
{
return this._Years;
}
set
{
this._Years = value;
}
}
public string RealStatus
{
get
{
return this.GetType().Name;
}
}
public abstract int CalculateSalary();
}
}
然后定义一下可怜的实习生,不管干多少年,永远只有2000元工资:
{
public class Intern : Employee
{
public override int CalculateSalary()
{
return 2000;
}
}
}
然后是签第三方公司的合同工,底薪5000,每年增加1000:
{
public class Vendor : Employee
{
public override int CalculateSalary()
{
return 5000 + 1000 * (Years - 1);
}
}
}
最后是正式员工(全职工),底薪12000,每年增加2000:
{
public class FulltimeEmployee : Employee
{
public override int CalculateSalary()
{
return 12000 + 2000 * (Years - 1);
}
}
}
2、制作一个不隐藏服务器端类型的应用
首先,自然是定义一个Web Service,我们将其命名为ExposedRealTypesService.asmx
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class ExposedRealTypesService : System.Web.Services.WebService
{
[GenerateScriptType(typeof(Intern))]
[GenerateScriptType(typeof(Vendor))]
[GenerateScriptType(typeof(FulltimeEmployee))]
[WebMethod]
public string CalculateSalary(Employee employee)
{
return "I'm " + employee.RealStatus + ", my salary is " + employee.CalculateSalary() + ".";
}
}
在这里我们使用了GenerateScriptTypeAttribute来告诉这个Web Service:“我们可能会使用这些类来作为参数传递给你,请注意JSON字符串里的__type标志”,于是我们就能使用了。我们来看一下我们需要的HTML:
<Services>
<asp:ServiceReference Path="ExposedRealTypesService.asmx" InlineScript="false" />
</Services>
</asp:ScriptManager>
<div>Years:<input type="text" id="txtYears" /></div>
<div>
Status:
<select id="comboStatus" style="width:150px;">
<option value="Jeffz.HiddenTypes.Intern">Intern</option>
<option value="Jeffz.HiddenTypes.Vendor">Vendor</option>
<option value="Jeffz.HiddenTypes.FulltimeEmployee">FTE</option>
</select>
</div>
<input type="button" onclick="calculateSalary()" value="Calculate!" />
<h1>Result:</h1>
<div id="result"></div>
所需的JavaScript代码如下:
{
var emp = eval("new " + $get("comboStatus").value + "()");
emp.Years = parseInt($get("txtYears").value, 10);
ExposedRealTypesService.CalculateSalary(emp, onComplete);
}
function onComplete(result)
{
$get("result").innerHTML = result;
}
由于comboStatue的value就是客户端的类名,因此我使用了拼接字符串并且eval的方法生成客户端的类,并作为参数传递过去。其余的代码应该非常简单,我们就来看一下使用效果吧:
打开页面,先选择Intern,输入工龄为2,点击“Calculate!”按钮:
再选择FTE,输入工龄为5,点击“Calculate!”按钮:
嘿,这说明我们客户端传了不同的服务器对象给Web Service方法了。
3、隐藏客户端的__type信息
我们打开Fiddler看看请求的内容吧:
嗯?看到了JSON字符串里的信息了不?明明白白地写着“Jeffz.HiddenTypes.Intern”!哎,怎么能把我们服务器端的类型信息给暴露出去呢?这样是不是太危险了一点?不过没有关系,我们可以这么做。首先,修改一下Web Service方法,我们这里就另存为HiddenRealTypesService.asmx吧:
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class HiddenRealTypesService : System.Web.Services.WebService
{
[GenerateScriptType(typeof(Intern), ScriptTypeId="Intern")]
[GenerateScriptType(typeof(Vendor), ScriptTypeId = "Vendor")]
[GenerateScriptType(typeof(FulltimeEmployee), ScriptTypeId = "FTE")]
[WebMethod]
public string CalculateSalary(Employee employee)
{
return "I'm " + employee.RealStatus + ", my salary is " + employee.CalculateSalary() + ".";
}
}
注意到了在使用GenerateScriptTypeAttribute时我们改变了什么吗?对了,就是我们设置了“ScriptTypeId”的值。这是什么?我们来看一下GenerateScriptTypeAttribute的使用方式吧。如下:
{
……
private void ProcessIncludeAttributes(GenerateScriptTypeAttribute[] attributes)
{
foreach (GenerateScriptTypeAttribute attribute1 in attributes)
{
if (!string.IsNullOrEmpty(attribute1.ScriptTypeId))
{
this._typeResolverSpecials[attribute1.Type.FullName] = attribute1.ScriptTypeId;
}
……
this.ProcessClientType(type1);
}
}
……
}
这段代码就是ASP.NET AJAX用于处理Web Service的WebServiceData类,当然它也提供了许多功能。在ProcessIncludeAttributes方法中会处理所有的GenrateScriptTypeAttribute,可以看到在这里为每个Attribute的ScriptTypeId与Type的FullName进行了映射。这种映射是不是让你想到了JavaScriptTypeResovler?没错,WebServiceData类就是继承了JavaScriptTypeResolver,它辅助了ASP.NET AJAX客户端访问Web Service方法时的序列化与反序列化工作。关于这一点,在我之前的文章《深入Atlas系列:探究序列化与反序列化能力(上) - 客户端支持,JavaScriptTypeResolver与JavaScriptConverter》里有比较详细的描述。
我们来看一下效果,当然在这之前还需要修改一下页面中ScriptManager的Service引用,如下:
<Services>
<asp:ServiceReference Path="HiddenRealTypesService.asmx" />
</Services>
</asp:ScriptManager>
再用Fiddler看一下传输内容吧,如下:
嘿,这样就不会把服务器端的具体类型暴露给别人了,不是吗?嗯,我们再多想想……:)
4、隐藏客户端代码调用时使用的具体信息
我们还有相当的路要走。有没有发现,我们在调用中带有了非常“明显”的类型信息。我们的方式其实和下面的差不多:
……
HiddenRealTypesService.CalculateSalary(emp, onComplete);
“Jeffz.HiddenTypes.Intern”?这不还是服务器端的具体类型吗?那么该怎么办呢?其实“new Jeffz.HiddenTypes.Intern()”操作也只是返回了一个普通的Object对象,不过它带有“__type”这个信息,其值为服务器端具体类型的ID。因此我们其实只要像下面这么做,也能得到同样的效果了。
首先,将<select />元素改成如下的形式:
<option value="Intern">Intern</option>
<option value="Vendor">Vendor</option>
<option value="FTE">FTE</option>
</select>
这样就不会暴露出服务器端的具体类型了。然后我们相应地修改JavaScript代码,如下:
{
var emp = { '__type' : $get("comboStatus").value };
emp.Years = parseInt($get("txtYears").value, 10);
HiddenRealTypesService.CalculateSalary(emp, onComplete);
}
再使用一下代码,一切正常,我们需要知道的只是服务器端具体类型的ID。这下完美了吧!再等等,再想想……
5、取消使用Service代理
我们还使用了ASP.NET AJAX为Web Service生成的代理,我们服务器端具体类型的信息都在那里,这不行,赶快取消!当然,在取消的同时不能破坏了Web Service方法的正常使用。我们该怎么做呢?
事实上,Web Service代理是通过访问XXXXX.asmx/js(Release模式)或者XXXXX.asmx/jsdebug输出的。我们必须禁止它。在这里我选择的方式是在Global.asax提供Application_BeginRequest的定义,它会在请求的一开始被调用。代码如下:
{
string pathInfo = this.Context.Request.PathInfo;
if ("/js".Equals(pathInfo, StringComparison.OrdinalIgnoreCase) ||
"/jsdebug".Equals(pathInfo, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("You can't get the proxy script!");
}
}
我们判断了请求地址的PathInfo,如果为“/js”或者“/jsdebug”时,则抛出异常,这样就禁止获得了任何的Web Service的Proxy信息,当然您也可以有选择地禁掉部分而不是全部。
哎,这样我们不就不能使用Web Service的Proxy了吗?没错,所以我们还必须修改一下JavaScript代码,使用一种相对“原始”的方式访问Web Service方法。如下:
_get_path : function(){ return "HiddenRealTypesService.asmx" },
get_defaultFailedCallback : function(){},
get_defaultUserContext : function(){},
get_timeout : function(){ return 0; /* unlimited */ }
};
function calculateSalary()
{
var emp = { '__type' : $get("comboStatus").value };
emp.Years = parseInt($get("txtYears").value, 10);
Sys.Net._WebMethod._invoke(
proxy, // proxy
"CalculateSalary", // method name for calling
"CalculateSalary", // method name for showing
false, // do not use HTTP GET
{ employee : emp }, // parameters
onComplete // onSuccess
);
}
这里定义了一个Proxy,这是使用Sys.Net._WebMethod所必须的。上面代码的原理,在我以前的文章《深入Atlas系列:Web Sevices Access in Atlas(7) - RTM中的客户端支持》有比较详细的分析。
到现在,我们终于完全隐藏了服务器端的类型信息,不过这是靠编写更多的代码而换来的(不过似乎还算好)。孰优孰劣,孰轻孰重,就只能请大家自己判断了。:)
点击这里下载代码。
深入Atlas系列:Web Sevices Access in Atlas示例(6) - 在客户端隐藏服务器端类型信息...相关推荐
- 深入Atlas系列:Web Sevices Access in Atlas示例(4) - 使用HTTP GET调用Web Services方法...
在之前的例子里,由于Atlas客户端在调用Web Services方法时总是使用了Sys.Net.ServiceMethod类,因此始终使用了HTTP POST方法与服务器端进行交互.POST方法有其 ...
- 深入Atlas系列:探究Application Services(2) - 自定义服务器端Profile Service支持
在上一篇文章中,我们讨论了使用ASP.NET AJAX默认的Profile Service.一般来说,它已经能够迎合大多数应用的需要了.不过除此之外,ASP.NET AJAX还提供了让我们自定义Pro ...
- 深入Atlas系列:探究序列化与反序列化能力(下) - JavaScriptSerializer
在ASP.NET AJAX中,客户端的序列化与反序列能力由Sys.Serialization.JavaScriptSerializer类的serialize和deserialize两个静态方法提供.在 ...
- Atlas系列一:Atlas功能特点FAQ
1:Atlas是否支持多字符集? 支持,可以在test.cnf中指定. #默认字符集,设置该项后客户端不再需要执行SET NAMES语句 charset = utf8 2:Atlas是否支持事物操作? ...
- return error怎么定义_SpringBoot 系列 web 篇之自定义返回 Http Code 的 n 种姿势
200105-SpringBoot 系列 web 篇之自定义返回 Http Code 的 n 种姿势 虽然 http 的提供了一整套完整.定义明确的状态码,但实际的业务支持中,后端并不总会遵守这套规则 ...
- boot返回码规范 spring_SpringBoot 系列 web 篇之自定义返回 Http Code 的 n 种姿势
200105-SpringBoot 系列 web 篇之自定义返回 Http Code 的 n 种姿势 虽然 http 的提供了一整套完整.定义明确的状态码,但实际的业务支持中,后端并不总会遵守这套规则 ...
- WEB前后端交互原型通用元件库、常用组件、信息输出、信息输入、信息反馈、综合系列、页面交互、首页、分类页、内容详情、用户中心、注册登录、找回密码、元件库、web元件库、rplib、axure
WEB前后端交互原型通用元件库.常用组件.信息输出.信息输入.信息反馈.综合系列.页面交互.首页.分类页.内容详情.用户中心.注册登录.找回密码.元件库.web元件库.rplib.axure原型 we ...
- 基于PaddleHub一键部署的图像系列Web应用服务
基于PaddleHub一键部署的图像系列Web应用服务 思路过程 相关资源 1.Github源码:https://github.com/livingbody/AutoCutout 2.CSDN文章:h ...
- Zabbix监控学习系列(2):agent的安装与Server端添加客户端
Zabbix监控学习系列(2) 简介描述 1. windows的客户端安装 1. 1手动安装包安装,安装过程中配置 1. 2免安装压缩包,解压后修改配置文件 2. Linux的客户端安装 3.在Zab ...
最新文章
- 报名 | 计算机视觉讲座:师兄带你从菜鸟到实战!
- Bash 文件夹操作
- 《Spring设计思想》AOP设计思想与原理(图文并茂)
- c语言稀疏矩阵做除法,稀疏矩阵的除法
- shell获取ip的值
- java开发环境jdk1.8_linux 搭建 jdk1.8 java开发环境
- RISC-V正在采取行动,避免MIPS类的碎片化
- 前端技术基础(一):浏览器相关
- Windows Phone 7 文件下载进度和速度显示
- 马云谈 5G 危机;腾讯推出车载版微信;Ant Design 3.22.1 发布 | 极客头条
- Vue父组件访问子组件属性和方法、父子组件双向绑定(两种方法)
- excel教程自学网_超实用!良心推荐15个神级自学网站,内容全面质量又高
- python随手记自动记账_简化记账——我的“随手记”
- 【简历】不带简历就是潇洒?醒醒吧
- RS232/RS485转4G DTU 上传基于Modbus协议的温湿度传感器数据到远程TCP服务器
- 手把手教你php调用短信接口(smsapi)实现发送短信验证码
- 2012百度移动开发者大会汇报
- 一次win10更新引发的Grub Rescue
- nape.dynamics.InteractionGroup
- Natural Sea Beauty以色列护肤品NSB外星人面膜,为肌肤赋予能量