深入Atlas系列:Web Sevices Access in Atlas示例(6) - 在客户端隐藏服务器端类型信息

简介:
深入Atlas系列:Web Sevices Access in Atlas示例(3) - 在Web Services方法中使用多态 》里用过的例子,不过它的内容是使用CTP版本的Atlas,已经过期,因此还是需要一些改变。这个示例会分成好几步进行,我们一点点地来看它的实现:


1、定义需要的类型

  首先,我们定义一下所需的类型。我们的目标是计算某种类型员工的工资,于是,我们先定义一个员工的抽象类:
namespace  Jeffz.HiddenTypes
{
    
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元工资:
namespace  Jeffz.HiddenTypes
{
    
public   class  Intern : Employee
    {
        
public   override   int  CalculateSalary()
        {
            
return   2000 ;
        }
    }
}

  然后是签第三方公司的合同工,底薪5000,每年增加1000:
namespace  Jeffz.HiddenTypes
{
    
public   class  Vendor : Employee
    {
        
public   override   int  CalculateSalary()
        {
            
return   5000   +   1000   *  (Years  -   1 );
        }
    }
}

  最后是正式员工(全职工),底薪12000,每年增加2000:
namespace  Jeffz.HiddenTypes
{
    
public   class  FulltimeEmployee : Employee
    {
        
public   override   int  CalculateSalary()
        {
            
return   12000   +   2000   *  (Years  -   1 );
        }
    }
}


2、制作一个不隐藏服务器端类型的应用

  首先,自然是定义一个Web Service,我们将其命名为ExposedRealTypesService.asmx
[WebService(Namespace  =   " [url]http://tempuri.org/[/url] " )]
[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:
< asp:ScriptManager  ID ="ScriptManager"  runat ="server" >
    
< 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代码如下:
function  calculateSalary()
{
    
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吧:
[WebService(Namespace = "http://tempuri.org/")]
[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的使用方式吧。如下:
internal   class  WebServiceData : JavaScriptTypeResolver
{
    ……

    
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引用,如下:
< asp:ScriptManager  ID ="ScriptManager"  runat ="server" >
    
< Services >
        
< asp:ServiceReference  Path ="HiddenRealTypesService.asmx"   />
    
</ Services >
</ asp:ScriptManager >

  再用Fiddler看一下传输内容吧,如下:


  嘿,这样就不会把服务器端的具体类型暴露给别人了,不是吗?嗯,我们再多想想……:)



4、隐藏客户端代码调用时使用的具体信息

  我们还有相当的路要走。有没有发现,我们在调用中带有了非常“明显”的类型信息。我们的方式其实和下面的差不多:
var  emp  =   new  Jeffz.HiddenTypes.Intern();
……
HiddenRealTypesService.CalculateSalary(emp, onComplete);

  “Jeffz.HiddenTypes.Intern”?这不还是服务器端的具体类型吗?那么该怎么办呢?其实“new Jeffz.HiddenTypes.Intern()”操作也只是返回了一个普通的Object对象,不过它带有“__type”这个信息,其值为服务 器端具体类型的ID。因此我们其实只要像下面这么做,也能得到同样的效果了。

  首先,将<select />元素改成如下的形式:
< select  id ="comboStatus"  style ="width:150px;" >
    
< option  value ="Intern" > Intern </ option >
    
< option  value ="Vendor" > Vendor </ option >
    
< option  value ="FTE" > FTE </ option >
</ select >

  这样就不会暴露出服务器端的具体类型了。然后我们相应地修改JavaScript代码,如下:
function  calculateSalary()
{
    
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的定义,它会在请求的一开始被调用。代码如下:
void  Application_BeginRequest( object  sender, EventArgs e)
{
    
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方法。如下:
var  proxy  =  {
    _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中的客户端支持 》有比较详细的分析。


  到现在,我们终于完全隐藏了服务器端的类型信息,不过这是靠编写更多的代码而换来的(不过似乎还算好)。孰优孰劣,孰轻孰重,就只能请大家自己判断了。:)

  点击这里下载代码。



本文转自 jeffz 51CTO博客,原文链接:http://blog.51cto.com/jeffz/60657,如需转载请自行联系原作者

相关文章
|
6天前
|
移动开发 数据挖掘 开发者
服务器发送事件(SSE)在现代Web开发中的关键作用
服务器发送事件(SSE)是HTML5标准协议,用于服务器主动向客户端推送实时数据,适合单向通信场景。相比WebSocket,SSE更简洁高效,基于HTTP协议,具备自动重连、事件驱动等特性。常见应用场景包括实时通知、新闻推送、数据分析等。通过Apipost等工具可轻松调试SSE,助力开发者构建高效实时Web应用。示例中,电商平台利用SSE实现秒杀活动通知,显著减少延迟并简化架构。掌握SSE技术,能大幅提升用户体验与开发效率。
|
18天前
|
存储 弹性计算 安全
阿里云服务器付费类型、地域、镜像、存储、带宽和安全组设置与选择注意事项参考
在我们通过自定义购买的方式购买阿里云服务器器ECS时,会有多个选项,有的新手用户可能并不是很清楚这些选项是什么,选择或设置时需要注意什么,本文将从付费类型、地域与可用区、镜像、存储、带宽和安全组等多个方面,为您详细解析云服务器购买过程中各个参数与配置的选择注意事项,以供参考。
144 66
|
4月前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
189 62
|
3月前
|
安全 编译器 Linux
深入解析与防范:基于缓冲区溢出的FTP服务器攻击及调用计算器示例
本文深入解析了利用缓冲区溢出漏洞对FTP服务器进行远程攻击的技术,通过分析FreeFlow FTP 1.75版本的漏洞,展示了如何通过构造过长的用户名触发缓冲区溢出并调用计算器(`calc.exe`)。文章详细介绍了攻击原理、关键代码组件及其实现步骤,并提出了有效的防范措施,如输入验证、编译器保护和安全编程语言的选择,以保障系统的安全性。环境搭建基于Windows XP SP3和Kali Linux,使用Metasploit Framework进行攻击演示。请注意,此内容仅用于教育和研究目的。
119 4
|
4月前
|
弹性计算 开发工具 git
2分钟在阿里云ECS控制台部署个人应用(图文示例)
作为一名程序员,我在部署托管于Github/Gitee的代码到阿里云ECS服务器时,经常遇到繁琐的手动配置问题。近期,阿里云ECS控制台推出了一键构建部署功能,简化了这一过程,支持Gitee和GitHub仓库,自动处理git、docker等安装配置,无需手动登录服务器执行命令,大大提升了部署效率。本文将详细介绍该功能的使用方法和适用场景。
2分钟在阿里云ECS控制台部署个人应用(图文示例)
|
4月前
|
缓存 监控 Linux
Python 实时获取Linux服务器信息
Python 实时获取Linux服务器信息
|
4月前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
87 2
|
4月前
|
XML 前端开发 JavaScript
PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑
本文深入探讨了PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑;Ajax则通过异步请求实现页面无刷新更新。文中详细介绍了两者的工作原理、数据传输格式选择、具体实现方法及实际应用案例,如实时数据更新、表单验证与提交、动态加载内容等。同时,针对跨域问题、数据安全与性能优化提出了建议。总结指出,PHP与Ajax的结合能显著提升Web应用的效率和用户体验。
106 3
|
4月前
|
安全 开发工具 Swift
Swift 是苹果公司开发的现代编程语言,具备高效、安全、简洁的特点,支持类型推断、闭包、泛型等特性,广泛应用于苹果各平台及服务器端开发
Swift 是苹果公司开发的现代编程语言,具备高效、安全、简洁的特点,支持类型推断、闭包、泛型等特性,广泛应用于苹果各平台及服务器端开发。基础语法涵盖变量、常量、数据类型、运算符、控制流等,高级特性包括函数、闭包、类、结构体、协议和泛型。
97 2
|
4月前
|
存储 关系型数据库 MySQL
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
1814 2

热门文章

最新文章