[C#]初探C#3.0

mikel阅读(702)

C#3.0已经推出好一段时间了,由于种种原因,一直没有去学习,这两天在园子中看到老赵的拯救C# 2.0,但是我们真做的到吗?。里面提到了些C#3.0的新特性和优势。勾起了我对3.0的兴趣,初探学习一下,分享给新手。

在C#2.0中,微软给我们带来了一些新的特性,例如泛型,匿名委托等。然而,这些新的特性多多少少会给人一种从别的语言中“抄”来的感觉(例如泛 型类似C++的模板,一些特性类似Java中的一些东西)。但是在C#3.0中,微软给我带来的一些新特性可能是以前所有开发语言都没有的特性。这无疑大 大的体现了C#3.0在开发语言中强大的优势。

Lambda表达式

Lambda 表达式是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。所有 Lambda 表达式都使用 Lambda 运算符 =>。关于Lambda更详细的讲解大家可以参看 MSDN。里面说的很清楚。

这里简单举个例子来说明Lambda的好处。Lambda在对匿名委托的处理上提供了更清楚的实施方式。例如在2.0中。我们可以写这样的代码:


public class Example
{
   
public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Func
<stringstring> convert = delegate(string s)
         { 
return s.ToUpper(); };
      
string name = "Dakota";
      outputBlock.Text 
+= convert(name) + "\n";
   }
}

在 C# 中将 Func<(Of <(T, TResult>)>) 委托与匿名方法一起使用。

在3.0中,我们可以使用Lambda来更清楚的进行参数的传递:


public class Example
{
   
public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Func
<stringstring> convert = s => s.ToUpper();
      
string name = "Dakota";
      outputBlock.Text 
+= convert(name) + "\n";
   }
}

Lambda 表达式的基础类型是泛型 Func 委托之一。这样能以参数形式传递 lambda 表达式,而不用显式将其分配给委托。尤其是,因为 System.Linq 命名空间中许多类型方法具有 Func<(Of <(T, TResult>)>) 参数,因此可以给这些方法传递 lambda 表达式,而不用显式实例化 Func<(Of <(T, TResult>)>) 委托。这样可以使我们的代码更加简洁,逻辑上更易于理解。 

对象的初始化

在C#中,对象的初始化也做了一些改进。一个新的功能就是提供了更方便的语法规则来声明变量的值。

假如我们声明一个Student对象:


public class Student
{
    
private string _stuName;
    
private string _stuAge;
    
private int _stuClass;
    
public Student() { }
    
public string StuName
    {
        
get { return _stuName; }
        
set { _stuName = value; }
    }
    
public string StuAge
    {
        
get { return _stuAge; }
        
set { _stuAge = value; }
    }
    
public int StuClass
    {
        
get { return _stuClass; }
        
set { _stuClass = value; }
    }
}

在C#2.0中,我们是这样声明变量并赋值的:

Student stu = new Student();
        stu.StuName 
= "Brian";
        stu.StuAge 
= "21";
        stu.StuClass 
= "1班";

而在C#3.0中,我们可以这样初始化对象:

Student stu2 = new Student 
        {
            StuName 
= "Brian",
            StuAge 
= "21",
            StuClass 
= "1班"
        };

从代码中不难看出,C#3.0给我们提供了很方便得方式来进行对象的初始化工作。

查询

这个想必大家都应该有所耳闻,那就是鼎鼎大名的Linq。这是C#3.0中最独特好用的新特性之一。Linq改变了我们写数据应用程序的方式,先 前,开发人员需要考虑并编写不用的代码来处理不同数据源中的数据(SQL Server ,XML ,Memory….)。LINQ很好的帮我们解决了这个烦人的问题。同时借助Lambda,我们可以更方便准确的查询我们想要的数据。

使用Linq简单的数据查询例子:


private void BindGridView(string criteria)
    {
        
string strConn = ConfigurationManager.ConnectionStrings["connstr"].ConnectionString;
        NorthwindDb db 
= new NorthwindDb(strConn);
        IEnumerable
<Employee> results;
        
if (criteria == string.Empty)
        {
            results
=db.Employee.ToArray();
        }
        
else
        {
            results 
= (from c in db.Employee
                          
where c.FirstName.Contains(criteria)
                          select c).ToArray();
            
        }
        GridView1.DataSource 
= results;
        GridView1.DataBind();
    }

 

变量声明

这里要说的是var。var是C#3.0中提供的用于声明变量的关键字,开发人员可以不考虑变量的类型就可以对变量进行声明(这一点用法非常类似JavaScript)。但是两者还是有些差异。

相同点:用var来声明任何类型的局部变量。

不同点:它仅仅负责告诉编译器,该变量需要根据初始化表达式来推断变量的类型,而且只能是局部变量。

我们可以这样声明变量:

var i= 10
var name 
= "edisundong"
var numbers 
= new int[] { 123 }; 

var仅仅是个关键字,它并不是C#3.0中的一种新的类型,而是负责告诉编译器,该变量需要根据初始化表达式来推断变量的类型,上面的语句相当于

int i= 10
string name = " edisundong "
int[] numbers = new int[] { 123 }; 

这里还需要注意几点:

1.在声明时必须同时赋值。

2.在使用var声明一个局部变量后,他仍然具备强类型。

var integer = 10;
integer = " edisundong ";
编译时会报Cannot implicitly convert type string to int错误。

3. 初始化器表达式的编译期类型不能够是空(null)类型。

4. var的声明仅限于局部变量

扩展方法

以前如果我们想扩展一个类的功能必须直接源自于它并且从学其中的方法,在C#3.0中,介绍了一种很快捷的扩展功能的方法。


public static class StudentExtensionMethods
    {
        
public StudentExtensionMethods()
        {
            
//
            
//TODO: 在此处添加构造函数逻辑
            
//
        }
        
public static string GetStudentInformation(this Student stu)
        {
            
return string.Format("Name: {0} {1} Age: {2}", stu.StuName,
            stu.StuAge, stu.StuClass);
        }
    }

定义一个类,其中定义一个方法,注意:这个类和方法都是static的,并且方法的参数是类Student。这样,Student类就可以扩展GetStudentInformation方法:


Student stu2 = new Student
            {
                StuName 
= "Brian",
                StuAge 
= "12",
                StuClass 
= "1班"
            };
            Console.WriteLine(stu2.GetPersonInformation());

 

小结:初学了下C#3.0,感觉带来了不少惊喜,其中有很多新的特性是以前所未知的。C#3.0的新特性应该还不止这些,还需继续学习研究。

[ASP.NET]系统缓存全解析

mikel阅读(713)

    有时候总听到网友说网站运行好慢,不知如何是好;有时候也总见到一些朋友写的网站功能看起来非常好,但访问性能却极其的差。没有“勤俭节约”的意识,势必会造成“铺张浪费”。如何应对这种情况,充分利用系统缓存则是首要之道。

     系统缓存有什么好处呢?举个简单的例子,你想通过网页查询某些数据,而这些数据并非实时变化,或者变化的时间是有期限的。例如查询一些历史数据。那么每个用户每次查的数据都是一样的。如果不设置缓存,ASP.NET也会根据每个用户的请求重复查询n次,这就增加了不必要的开销。所以,可能的情况下尽量使用缓存,从内存中返回数据的速度始终比去数据库查的速度快,因而可以大大提供应用程序的性能。毕竟现在内存非常便宜,用空间换取时间效率应该是非常划算的。尤其是对耗时比较长的、需要建立网络链接的数据库查询操作等。

缓存功能是大型网站设计一个很重要的部分。由数据库驱动的Web应用程序,如果需要改善其性能,最好的方法是使用缓存功能。

 

       系统缓存全解析文章索引

15.4.1      缓存的分类

     从分布上来看,我们可以概括为客户端缓存和服务器端缓存。如图15-1所示:

 

15-1  缓存的分类

 

客户端缓存—— 这点大家都有直观的印象。比如你去一个新的网站,第一次可能要花一阵子时间才能载入整个页面。而以后再去呢,时间就会大大的缩短,原因就在于这个客户端缓存。现在的浏览器都比较智能,它会在客户机器的硬盘上保留许多静态的文件,比如各种gif,jpeg文件等等。等以后再去的时候,它会尽量使用本地缓存里面的文件。只有服务器端的文件更新了,或是缓存里面的文件过期了,它才会再次从服务器端下载这些东西。很多时候是IE替我们做了这件事情。

 

服务器端缓存—— 有些东西没法或是不宜在客户端缓存,那么我们只好在服务器端想想办法了。服务器端缓存从性质上看,又可以分为两种。

(1)静态文件缓存

    好多页面是静态的,很少改动,那么这种文件最适于作静态缓存。现在的IIS 6.0这部分内容是直接存放在Kernel的内存中,由HTTP.SYS直接管理。由于它在Kernel Space,所以它的性能非常的高。用户的请求如果在缓存里面,那么HTTP.SYS直接将内容发送到network driver上去,不需要像以前那样从IISUser space的内存copyKernel中,然后再发送到TCP/IP stack上。Kernel level cache几乎是现在高性能Web server的一个必不可少的特性。

(2)动态缓存

     动态缓存是比较有难度的。因为你在缓存的时候要时刻注意一个问题,那就是缓存的内容是不是已经过时了。因为内容过时了可能会有很严重的后果。比如网上买卖 股票的网站。你给别人提供的价格是过时的,那人家非砍了你不可。缓存如何发现自己是不是过时就是一个非常复杂的问题。

 

    在ASP.NET中,常见的动态缓存主要有以下几种手段:

  Ø  传统缓存方式

  Ø  页面输出缓存

  Ø  页面局部缓存。

  Ø  利用.NET提供的System.Web.Caching 缓存。

  Ø  缓存依赖。

 

15.4.2  传统缓存方式

比如将可重复利用的东西放到Application或是Session中去保存。

 Session["Style"] = val;
 Application["Count"] = 0;

 

 

选自《亮剑.NET:.NET深入体验与实战精要》15

[Flex]FluorineFx + Flex视频聊天室案例开发

mikel阅读(653)

 本文将使用FluorineFx和Flex结合介绍一个简单的视频聊天室案例开发,希望通过此篇和大家交流FluorineFx和Flex的相关 技术,同时也希望本篇可以帮助到需要使用FluorineFx做及时应用开发的新手朋友。首先列举下本篇中所涉及到的开发环境和相关技术以及简单的需求定 义:

      1. Microsoft Visual Studio 2008(VS SP1)+.NET Framework 3.5(SP1)

      2. FluorineFx v1.0.0.15

      3. Adobe Flex Builder 3 + Flex SDK 3.2

      4. Microsoft Office Access 2003

      5. ADO.NET , Linq…..

 

      本篇的案例的功能需求定义如下:

      1. 用户注册/登录聊天室

      2. 成功登录聊天室后通过选择在线用户进行视频连接完成视频和文字聊天(一对一私聊)

      3. 提供小喇叭功能,实现全服务器发送消息(一对多,一人发送全聊天室的用户都可见)

      4. 提供聊天表情选择窗口,实现聊天表情的发送。

 

      1、服务器端开发

            本篇主要介绍了使用FluorineFx所提供的ApplicationAdapter来建立自己的及时通信应用Adapter,提供及时通信、实况流服务,以及通过远程共享对象管理在线用户列表的功能。

            详细请访问:FluorineFx + Flex视频聊天室案例开发—-服务器端

 

      2、客户端开发

            本篇主要介绍了使用Flex开发聊天室客户端,实现了用户注册、登录、在线视频+语音+文字聊天、发送小喇叭等功能。

            详细请访问:FluorineFx + Flex视频聊天室案例开发—-客户端

 

      3、应用程序部署

             本篇简单的介绍了FluorineFx程序的部署。

            详细请访问:FluorineFx + Flex视频聊天室案例开发—-应用部署篇

 

      本案例并不完善,还有许多地方都做得不到位。比如用户上线下线广播功能也没完成(内部我已经提供了接口和方法,只是没有调用而已),有兴趣的朋友可以下载源代码去参考或帮忙完成这些功能。

 

      本案例源代码下载:FluorineFx+Flex视频聊天室源代码

 

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

 

[Saas]SAAS(软件即服务)的时代即将来临吗?

mikel阅读(840)

在详细展开本文讨论之前,我们先来介绍两家公司:
1、37signals
http://www.37signals.com/
只要是RoR的fans没有不知道37signals的。这是一家位于芝加哥的创业型小公司,公司小到只有8个员工,但在业界享有盛誉。在芝加哥 办公室上班的有4个人,其余4个人分别在纽约,波特兰等城市soho办公。但是37signals公司基于web的小型商业软件产品的注册用户却超过了 100万。下图是该公司全部员工的合影(RoR作者DHH是左边稍靠后的那个人,貌似姿势挺猥琐):

37signals公司出版了一本名为《Getting Real》的书(中文名称《把握现实》),充分阐述了基于互联网web2.0商业创业的经验,可谓web2.0创业的圣经。
美国时代周刊记者采访了37signals公司,专门写了一篇稿件《Small Is Essential》,揭示了该公司的主要商业模式。
37signals公司主要提供基于互联网的小型商业软件租用服务:有提供项目管理和团队写作的BaseCamp(这也是导致RoR诞生的产 品);有小型客户关系管理系统Highrise;有即时团队在线交流系统Campfire;有信息组织,日历,工作安排软件Backpack等等。
用户在线注册37signals的系统,在线使用,每个月交纳12美元到149美元不等的月租费。37signals的在线软件租用服务对于小型商业公司具有很大的吸引力,功能好用,操作简单,价格便宜,无需维护,注册即可以使用。
2、salesforce
http://www.salesforce.com/
salesforce是业界赫赫有名的一家在线CRM厂商,其创始人来自前Oracle公司的高管。公司在2004年就上市了。 salesforce这两年处于一个飞速发展的阶段:2004年7月,Salesforce刚上市时,股票交易价为11美元。到2006年,它的股价到达 在40美元。成立7年多的Salesforce.com在全世界的2.48万个公司拥有超过50.1万个用户,并以每年80%的速度增长,客户满意度高达 97%。Salesforce在2006年二季度的收益从7190万美元增加到1.181亿美元左右。如今salesforce已经进入中国,提供在线 CRM系统。提供每人每年888元人民币软件租用服务费。
看完上面两家公司的介绍,你一定会说,他们做的不就是ASP(应用服务提供商)吗?是的,从某种程度上来说,他们就是ASP。其实ASP早就伴随第一次互联网浪潮的时候已经唱了一出狼来了的故事,但是现在ASP会卷土重来吗?让我们再来看看大公司的反映:
1、Google Apps
http://www.google.com/a/
不用多说了,Google Apps是google将其强大的互联网服务伸向企业应用领域的重要尝试之一。
2、Microsoft
Microsoft是典型的传统套装软件生产商,但是不意味着Microsoft不重视SAAS领域。附件是Microsoft的一系列关于SAAS文章当中的一篇。
Bill Gates今年访问中国之行,其中有一项重要的成果,就是和阿里巴巴达成的合作的协议。而这项合作的内容就是和阿里软件公司共同构建基于微软技术的SAAS平台战略。这项合作的意义可以说相当深远。
关于SAAS更多深入探讨,推荐大家看一下这篇文章:
http://www.donews.com/Content/200611/f4c23d1d6dc745f483df8e787ca0251d.shtm
SAAS的商业模式相比传统的套装软件有什么优势呢?对于软件供应商来说:
1、短开发周期,低成本,快速用户反馈
看看37signals就知道了,不再需要漫长的开发周期,可以尽快提供用户使用,搜集用户反馈,大大压缩软件开发成本,降低软件的市场风险,而且可以提高软件的市场需求适应程度的敏捷性。
2、相比卖套装软件来说,无需建设庞大的销售渠道,可以充分利用互联网长尾效应
这是一个伟大的进步,诞生于互联网的长尾效应真正要在企业应用领域发挥作用了。看看37signals和salesforce,数量庞大的中小企业购买他们的在线企业服务。这些中小企业在传统的软件营销渠道来说,都是处于被放弃的状态。
对于传统套装软件的销售来说,不管是Oracle,SAP还是RedHat,他们往往集中销售资源去攻克传统大客户,例如四大银行,电信,创造公 司超过一半的销售利润,另外通过合作伙伴建设销售渠道以分销的方式面向中小型客户。越是小型客户,越得不到重视,长尾末端的客户完全被放弃。
根据长尾效应我们知道,传统销售被放弃的那条长长的尾巴加起来其总市场价值等价于传统销售的市场价值。这也是Google赖以创造惊人利润的主要 原因。但是传统销售资源的有限性不允许他们对于尾巴用户投入资源。但是SAAS这种在线电子商务解除了资源限制。可以让长尾充分发挥了。
3、软件技术支持的成本大幅度降低
看看37signals,根本没有技术支持人员。互联网AJAX技术的兴起,使得基于浏览器的应用完全可以轻松处理复杂的企业应用操作。集中式的服务器使得软件在线升级几乎0成本。你还需要庞大的call center吗?你还需要庞大的技术工程师队伍吗?
对于客户来说,SAAS也带来了很多优势:
1、购买软件的风险大大降低了
你不用再担心花几十万购买的套装软件根本不合适,或者花几十万外包的项目开发出来的软件根本不符合需求。简单的注册流程之后,立刻开始使用,在试用期你就知道这个软件你应该不应该花钱购买了。
2、购买软件的成本大大降低了
不需要一次性付款,每个月按功能,按注册人数付费,就像分期付款一样,不会有浪费。如果你什么时候觉得软件不合适了,随时可以中止付费。
3、立即可用的软件
你不需要花很多时间去考察,去开发,去部署,当你需要,你就可以立刻使用,为你的公司争取了宝贵的时间。
但是SAAS没有一点问题吗?ASP是怎么倒下的?如果我们提供SAAS服务,那么会面临怎样的问题呢?
1、公司的信誉度的问题
如果你的公司明天就会倒闭的话,哪个客户敢用你的服务?如果你不是一个行业知名的大公司的话,很多客户不敢购买和使用你的服务,把自己公司业务押在你的身上。
2、安全和保密的问题
你怎么保证客户的资料不被外泄?你怎么保证你不会利用客户资料进行非法的勾当?客户为什么要信任你?
3、网络服务质量的问题
中国的电信运营商的网络安全保护水平实在令人担忧,如果你提供互联网服务,因为网络问题导致网站不能访问,网民最多诅咒几句,如果是你的客户把自己公司业务放在你的服务器上面,那么倒霉的就是客户了。
所以SAAS其实是很有高的门槛了,因为你必须有知名的品牌来让客户信任你,你必须有强大的资源来提供安全和可靠的服务。
salesforce是目前进入国内做SAAS服务比较早的一个,随后还有阿里软件。这里不得不提一句阿里软件,因为阿里软件有很大的优势:通过 阿里巴巴网站聚敛了几百万中小型商户;多年互联网经营建立的品牌信誉度;和Microsoft合作强强联合以求强大的技术支撑;全国部署的上万台服务器提 供了充分安全的网络质量和故障转移方案。可以说阿里软件想不成功都很困难,这里不得不佩服马云。当然除了阿里巴巴以外,国内的金蝶,用友,金算 盘,800CRM都盯着这个市场,我相信在未来的几年,SAAS会成为一股潮流。
作为技术人员的角度来看待SAAS,我觉得有两点值得一提:
1、互联网应用和企业应用的界限会越来越模糊
很多开发人员言必称超级复杂的企业应用,动辄分布式事务,消息中间件。确实,在传统的大客户大项目当中,这些超级复杂的企业应用还会长期存在。但 是不可否认的一个事实就是,企业应用的开发人员会越来越多被要求从事SAAS类型应用的开发当中来。在这个领域,不是超级复杂的企业应用游戏规则,而是互 联网游戏规则:快速开发,快速反馈,简单架构,小团队,随需应变。因此解决传统超级复杂问题的编程工具利器也许不那么有效了,在这个新的领域,需要的是轻 量级的超级快速编程工具利器。
2、你想做中国的37signals吗?
如果你可以开发出很酷很好用,而且市场很需要的在线软件产品,就去做吧,不论是面向小型企业,还是面向消费者个人群体,我都相信这种在线软件消费模式在未来会广阔的市场前景。

[JQuery]Jquery弹出层插件Thickbox使用心得

mikel阅读(853)

Jquery弹出层插件Thickbox使用心得

   前段时间在建设银行项目上用EXT完整做了个单页系统,太赶了,没有记录下任何东西,现在都忘了,怪可惜的。这次项目用JQuery做js的东西。主要用了个弹出层控件thickbox,自己也扩展和修改了一下。这里就记下来,也提供大家下载,希望对大家有用吧。

  thickbox官方网站(上面有例子和基本的使用方法):http://JQuery.com/demo/thickbox/

  就我使用过程中,thickbox常见问题:

  1。跨iframe的弹出层。

   症状:每次thickbox都只在frame中弹出,而不会整个屏幕覆盖

  原因和解决方法:

          thickbox使用tb_show()函数在body后面加入弹出层。可以使用window.top.tb_show()把弹出层加到页面上。我的tihickbox插件中修改如下:在tb_init()中把tb_show(t,a,g)替换如下

  if(a.indexOf('TB_iniframe'!= 1
     {  
          window.top.tb_show(t,a,g);  
     }  
     
else  
     {  
      tb_show(t,a,g);  
     }  

 这样只只要在原来的链接上加入TB_iniframe=true即可,如div.aspx?height=180&width=400&TB_iframe=true&TB_iniframe=true&modal=true

   2.thickbox只支持一层弹出,不可支持多层弹出。

       修改过的控件已经支持(不足:ie6下失效弹出层失效了,占时没解决,哈哈)

  3. 弹出层关闭后,文本框无法聚焦。

    症状:关闭弹出层后,原来页面上的文本框无法聚焦

    原因和解决方法:这个的原因不好说,很多人都认为是ie本身的bug。是由于iframe没有移除,即使移除了。内存上也么有清除造成的。 这也是我猜的。哈哈。解决方法是在tb_remove()中先手动移除iframe然后,在强制做垃圾回收,至少我是可以啦。哈哈。代码如下:

 1function tb_remove() {
 2    var seq=PopSeq();
 3     $("#TB_imageOff"+seq).unbind("click");
 4     $("#TB_closeWindowButton" + seq).unbind("click");
 5
 6     $("#TB_window" + seq).fadeOut("fast", function() {
 7         ///手动移除ifrmae,IE的一个bug
 8         $('#TB_iframeContent' + seq).remove();
 9         $('#TB_window' + seq + ',#TB_overlay' + seq + ',#TB_HideSelect' + seq).trigger("unload").unbind().remove();
10        ///自己调用垃圾回收,强制清楚iframe内存,解决文本框无法输入问题。
11         CollectGarbage();
12     }
);
13    if (typeof document.body.style.maxHeight == "undefined"{//if IE 6
14        $("body","html").css({height: "auto", width: "auto"});
15        $("html").css("overflow","");
16    }

17    document.onkeydown = "";
18    document.onkeyup = "";
19    return false;
20}

 

 4.在ASP.NET中如何动态设置需要的参数和关闭弹出层。

症状:thickbox提供的例子都是需要在input后a的class加thickbox,而且参数什么都是固定的。 而我们传递的参数一般需要动态。

解决方法,使用ASP.NET ajax,不多说了。直接看代码吧。

封装一个popup类,

 1public class Popup
 2{
 3    /// <summary>
 4    /// show the pop up div
 5    /// </summary>
 6    /// <param name="panel">container the button</param>
 7    /// <param name="url"></param>

 8    public static void ShowPopup(UpdatePanel panel, string url)
 9    {
10        ScriptManager.RegisterClientScriptBlock(panel, panel.GetType(), "ShowPopup""ShowPopup('" + url + "')"true);
11    }

12
13    /// <summary>
14    /// 
15    /// </summary>
16    /// <param name="panel"></param>
17    /// <param name="page">request page</param>

18    public static void ClosePopup(UpdatePanel panel)
19    {
20
21        string js = " self.parent.tb_remove();";
22
23       ScriptManager.RegisterClientScriptBlock(panel, panel.GetType(),"closepopup", js, true);
24    }

25}

 需要的js

1function ShowPopup(url) {
2    window.top.tb_show(null, url, false);
3
4}

 页面上例子

1///add按钮需要放在updatepanel里面   
2 protected void btnAdd_Click(object sender, EventArgs e)
3    {
4///自己组参数
5        string url = "aa.aspx?height=180&width=400&Type="+ddlType.SelectedItem.Value;
6        url += "&TB_iframe=true&TB_iniframe=true&modal=true";
7        Popup.ShowPopup(this.upButtons, url);
8    }

[MVC]融合思想:深入探索S#arp架构

mikel阅读(992)

开发Web应用程序是痛苦的。无论是组织与测试AJAX脚本,还是在无状态环境下模拟状态,开发Web应用程序需要在计划和开发的各个阶段中,全神贯注,专心致志。Web开发人员还要面对开发中的诸多挑战,例如对象与关系的不匹配;在纷繁复杂的选项中选择最合适的工具提高开发效率;在项目中应用良好的架构,在保证代码具有可维护性的同时,不至于影响项目的交付。种种问题都使得开发形势变得越发严峻。

一切都在发展之中。不断涌现出的技术与技能虽然正在逐步解决这些开发中的难题,但没有任何一个可以单独扮演银弹的角色。但是通过对各种技术的权衡,精心挑选技术与技能,还是可以在不牺牲质量的前提下,大幅度地提高开发效率与可维护性。本文关注于Web开发的主流发展方向,通过使用S#arp架构,这是基于ASP.NET MVC的一个框架,荟萃了这些技术与技能的精华,从而为客户贡献价值。

赢得关键阶段的技术趋势

如果要用一个词来描述软件开发这个行业,毫无疑问,这个词语就是“变化”。比起那些历史久远的学科如土木工程学,我们这个行业不过是刚刚兴起,还处于萌芽状态。我们正在成长,而成长的烦恼就是行业自身经历的大量变化,而且看起来这样的变化还会持续一段时间。

这种变化可谓屡见不鲜。一个例子是项目管理方法学,由于其走向误区而带来的惨痛经历,它经历了大起大落,从一棵冉冉升起的“明星”,迅速衰落至默默无闻。另一个例子是有关技术的兴衰,长江后浪推前浪,新技术总是后来居上,取代旧的技术。以ASP.NET中的MVP(Model View Presenter)模式为例,该设计模式虽然为ASP.NET引入了更好的可测试性,但却增加了复杂程度。最近,微软引入了ASP.NET MVC用 来取代ASP.NET,它将之前ASP.NET实现的可测试性提升了一个新的台阶。由于要考虑.NET web开发的可测试性,MVP模式总是将控制器逻辑放在ASP.NET页面后面的代码(code behind)中,而ASP.NET MVC则抛弃了MVP的这种做法。这并不是说MVP隐含的原则到现在已经无效,而是随着这项技术的出现,通过使用适当的关注分离,可以更好的简化MVP实 现可测试性的目标。

因此,虽然软件行业仍然变化莫测,但技术发展的特定趋势与设计理念,仍然构成了开发与交付高质量可维护项目的基础。或许,这些理念的实现会随着时间 的推移而发生变化,但理念本身却是成功软件的坚实基础,能够持续地影响着软件开发。下面,我将简要地回顾这些设计理念,它们在关键阶段所获得的成功,已被 开发社区所广泛接受,因而对未来的软件开发产生了深远的影响。

抽象的基础功能

在不久之前,我还在为一个新对象编写CRUD功 能而被搞得焦头烂额。这项工作就像重新粉刷我的房子一样,费力而不讨好。充斥的大量重复代码,也成为了错误的多发地带。从编写存储过程与ADO.NET的 适配器,到测试片断的JavaScript验证代码,我发现我每天都将大把精力投入到了这些基础功能细节的实现上,以至于在我写完这些代码之后,巴不得赶 尽将它们抛诸脑外。

范式的转换在过去十年间已经发展成熟,其中关于基础功能的实现细节,属于最底层的工作,最好能够交给专门的工具来完成。面临的挑战是需要为这项工作找到合适的工具,既要允许软件忽略这些实现细节,又要保证基础功能可以使用。NHibernate是 这类工具的典范。它能够处理普通的.NET对象与关系数据库之间的持久化。采用这种方式,它就能够让对象自身完全忽略如何实现持久化,又能够解决对象与关 系之间的不匹配。而且,它不需要编写任何一行ADO.NET代码或者存储过程。NHibernate是一个非常棒的工具,更重要的是它实现了一个远大目 标,通过提供一个固定的解决方案,避免乏味而又琐碎的基础功能实现。要知道,这些实现在过去可是开发活动的重要组成部分。

随着时间的推移,软件行业引入了大量成熟的工具与技术,对这些乏味无趣的基础设施构建进行抽象,然后在开发完成后再进行设置。例如,随着NHibernate的逐渐成熟,那些附加的插件,例如Fluent NHibernate具有自动映射的能力,完全能够减轻管理数据访问的负担。这一现象印证了Douglas Hofstandter著作Gödel, Escher, Bach中提到的预言,即:采用合理的抽象是软件开发的发展之道,需大力提倡。

松散耦合

遗留软件系统最常见的毒瘤是紧耦合。(我在这儿使用的“遗留”一词,指的是那些其他开发人员强加给你的破烂软件,或者是你自己在很多年前开发的破旧 系统)紧耦合的例子多不胜数,例如两个对象之间存在双向依赖;具体依赖于服务的对象如数据访问对象;还有在单元测试中,如果依赖的服务断开或不可用,就无 法测试服务的行为。紧耦合会导致脆弱的代码,使代码难以测试。修改紧耦合的代码,会让开发人员视如畏途,不战而降,甚至逃之夭夭。毫无疑问,一个成功软件 的关键就是松散耦合。

维基百科将松散耦合解释为“两个或多个系统之间的弹性关系。”因此,松散耦合带来的好处就是你能够修改编程关系的任何一方,却不会影响另外一方。举例说明,在我看来,没有哪个设计模式能够比接口隔离,别名为依赖倒置(不要与依赖注入混为一谈)更能够说明松散耦合的思想了。该技术通常会用于将数据访问层从领域层中分离。

例如,在一个MVC应用程序中,控制器或者应用服务需 要与数据访问的仓储(repository)对象通信,以获取数据库中的项目个数。(本例中的仓储指的是“服务”)要满足这一需求,最简单的办法是让控制 器建立一个新的仓储对象的实例。换句话说,控制器创建了一个指向仓储对象的具体依赖;例如通过new关键字。遗憾的是,这种方法会导致紧耦合的诸多不良后 果:

  • 没有真实的数据库支持对仓储的查询,就很难对控制器进行单元测试。要求真实的数据库,会导致单元测试变得脆弱,一旦数据被前 一次运行的测试所修改,就会带来问题。在测试控制器逻辑时,我们应集中关注验证控制器的行为,而不是它所依赖的仓储对象能否成功地与数据库进行通信。此 外,测试一个“真实的服务”,例如在刚才提及的例子中,与真实数据库通信的仓储服务,会使单元测试的运行变得像老牛拉破车一般的缓慢;结果会让开发人员停 止运行单元测试,从而损害了代码的质量。
  • 如果不修改实例化服务的控制器,就难以替换服务(仓储服务)的实现细节。假如你希 望将仓储从ADO.NET改为支持Web Service,由于包含了一个与前者之间的具体依赖,如果不对实例化以及使用它的控制器进行大量修改,就无法轻易地将其替换为后者。在多数情形下,一旦 变化发生,就会导致霰弹式修改——这是说明这一问题的另一种坏味道。
  • 无法确定控制器实际拥有的服务依赖的个数。换句话说,如果控制器正在调用一些服务依赖的创建功能,则开发人员很难确定其逻辑边界,或职责范围。作为替代,控制器的依赖可以通过其构造函数传入,这样就能够使开发人员更容易理解控制器的整个职责范围。

替代方案是把服务依赖作为控制器构造函数的参数。这种做法带来的关键改善就是控制器只需要了解服务依赖的接口,而不是具体的实现。为了进一步说明,可以比较下列两段在ASP.NET MVC应用程序中的控制器代码。

如下的控制器直接创建了它的服务依赖CustomerRepository,也就相应拥有了一个具体的依赖:

public class CustomerController {

   public CustomerController() {}

   public ActionResult Index() {

      CustomerRepository customerRepository = new CustomerRepository();

      return View(customerRepository.GetAll());

   }

}

相反,如下的控制器则将服务依赖作为接口参数传递给它的构造函数。也就是它与服务依赖形成了松耦合关系。

public class CustomerController {

   public CustomerController(ICustomerRepository customerRepository) {

      this.customerRepository = customerRepository;

   }

   public ActionResult Index() {

      return View(customerRepository.GetAll());

   }

   private ICustomerRepository customerRepository;

}

对比紧耦合的缺陷,这种清晰的分离方式带来了诸多好处:

  • 领域层对于如何创建仓储对象以及它的实现细节一无所知,它只需调用公开暴露的接口。因此,它不需要修改控制器自身,就能很容易地更换数据访问的实现细节(例如从ADO.NET切换到Web Service)。这基于一个假定,两者实现的接口是相同的。
  • 依赖于接口而不是具体实现,在单元测试时更容易将仓储的测试替身(test double)对象注入。这就保证了单元测试能够快速运行,避免维护数据库中的测试数据,从而将测试的注意力放到控制器的行为上,而不是与数据库的集成。

这里并没有详细阐述依赖注入必须支持一个分离的接口和其它松耦合技术。更详细的讨论请参考文章依赖注入实现松耦合。(注意,在这篇文章中描述的“仿(mock)”对象实际上是“桩(stub)”对象。它与“测试替身(test double)”的术语来源于Martin Fowler的Mocks不是Stubs)。此外,将服务依赖重构到接口隔离一文详细地介绍了如何将设计转为接口隔离设计模式。

测试驱动开发

简而言之,测试驱动开发(TDD)能够有效交付高质量、可维护的软件,全面地简化设计。作为一项开发技术,测试驱动开发绝不会是昙花一现;它受到了越来越多的吹捧,是能够决定软件开发成败的关键,推动了我们这个行业逐渐走向成熟。

TDD隐含的基本思想是带着疑问开始软件开发,在开发过程中要不停地询问系统。例如,倘若你正在开发一个银行系统,可能需要询问系统,它有能力成功 处理客户的存款业务吗?关键之处在于要在实现行为细节之前提出问题。随之而来的好处就是在编写系统之前,它能够让开发者将注意力放到系统要求的行为上。

若要遵循测试驱动开发的指导原则,需按照如下步骤进行编码:

  1. 假设目标对象以及要求的行为已经存在,编写测试。
  2. 编译解决方案,此时会看到编译失败。
  3. 编写足够的代码使程序通过编译。
  4. 运行单元测试,测试失败。
  5. 编写足够的代码使得单元测试通过。
  6. 若有必要,进行重构

测试驱动开发虽然没有什么变化,但在日常的开发活动中对它的应用却还在发展之中。例如,测试驱动开发最近的发展方向是行为驱动开发;该方法试图弥补“代码编写的技术语言与商务运用中的领域语言之间”的鸿沟。换句话说,行为驱动开发将TDD与后面介绍的领域驱动设计(或者是与你喜欢的其它方法)结合了起来。

领域驱动设计

从近日的发展趋势来看,领域驱动设计(DDD)可 谓风光无限。该方法将软件开发的注意力放在了领域与领域逻辑上,而不是技术以及支持技术方案的关系数据库模型。和行为驱动设计一样,DDD提出了大量的技 术与模式,以改善客户与开发团队的协作关系,在描述语言上达成一致。理想情况下,客户应该能够理解DDD应用程序的领域层,而编码逻辑也能够完整地反映客 户的业务逻辑。

我试验了各种方法,得出的结论是:领域驱动设计是早期编程方法的一种自然进化,例如针对数据库数据进行模型驱动开发,其对应的模型可以视为应用程序的核心,要做的工作就是操作数据。(Castle ActiveRecordADO.NET实体框架都是非常稳定和优秀的模型驱动设计工具。)相反,在DDD中,数据库则被视为一种必要的基础设施细节,能够支持领域及相关逻辑。事实上,正所谓“万法皆空”,在DDD中本来就没有数据库。虽然,领域驱动设计需要数据库,但关键在于领域对于持久化机制(实现数据存储与获取的机制)应该是一无所知的。

而且,领域驱动设计不仅仅是将数据持久化从领域中分离出来。它的主要目的是让领域对象自身拥有领域行为。例如,我们不能分离出 CustomerAccountLogic类,并由它来决定CustomerAccount是否取决于付款日期,而是要求CustomerAccount 自身维护这一信息。采用这种方式,领域的行为是与模型自身是合二为一的。

以上介绍仅仅是运用DDD进行软件开发技术的冰山一角。若要了解领域驱动设计的更多信息,可以阅读文档领域驱动设计快速入门,它是Eric Evans经典著作《领域驱动设计》的简明摘要。

在S#arp架构中融入这些思想

每个项目都其独特的需求,也没有哪个框架能够尽善尽美,对于开发Web应用程序而言,这是机会与挑战共存的局面。但是在面临众多选择时,开发人员很 难做出判断,哪些工具和技术适合给定的项目,并让开发中通常遇到的挑战能够迎刃而解。例如,如果你正在寻觅一个.NET依赖注入工具——或者说控制反转容器——可以选择Spring.NET(它远远不只是提供IoC功能)、UnityCastle WindsorNinjectStructureMap,以及更多。这还只是对于IoC的选择!让事情变得更糟糕的是,我们需要明智地规划,恰如其分地在架构中权衡各种工具与技术,这是一项极具挑战的工作。

在.NET Web开发中,至少在当前还缺乏一个通用的架构与基础,可以在程序开发中对各种技术与技巧进行最优组合,根据已经被证实的实践来选择最近的技术,以及由开源社区开发的优质工具。S#arp架构正是基于这样的前提应运而生。开源的S#arp架构试图利用本文介绍的业已证明行之有效的实践,谨慎地选择工具以提高开发效率,保证系统高质高量,以及良好的可维护性。

S#arp架构使用的工具与技术如下所示:

选择的这些技术与工具表明,虽然软件开发没有奇妙的银弹,但选择一个稳定的开发实践,并结合适当的工具,就能带来巨大的价值。

领域驱动架构将它们串联在一起

我认为,被封装到S#arp架构中的关键思想,就是颠倒领域与数据访问层之间关系的一种技术。在通常的应用架构中,尤其是与微软推荐的架构紧密相关的,其依赖关系都是从表示层开始自上而下,依赖于业务层,最后依赖于数据层。虽然这是对实现细节的过度简化,但它通常会建议将数据层作为最底层,被其他层依赖;这正是根据设计进行模型驱动。

虽然模型驱动方式自有其优势,也适用于众多解决方案,但却不符合本文提出的领域驱动的目标。让领域直接依赖于数据层,会造成另一种弊端,就是引入领 域对象与数据访问代码之间的双向依赖。我的前任教授Lang博士说道,只有不断犯错误,最后才能成为这个领域的专家。我正在努力成为一名专家,我已经认识 到领域对象与数据访问代码之间存在的双向依赖,它们正是麻烦的渊薮。(这个深刻教训使我在成为专家的道路上能够登堂入室。)

那么,我们该如何冲破这重重迷雾,让设计清晰地呈现这些思想呢?解决之道就是明确地分离各种应用关注点,颠倒领域与数据访问层之间的关系,也就是在 领域层定义分离的接口,让数据访问层进行实现。采用这种方式,则应用程序的所有层都只依赖于数据访问(或其它外部服务)层的接口,从而保证对实现细节的一 无所知。这会让设计变得松散耦合,更易于进行单元测试,而在项目开发的维护阶段,系统会变得更加地稳定。

下图演示了S#arp架构所主张的体系架构,使用接口隔离模式反转了传统的领域与数据访问层之间的依赖关系。每个box表示一个单独的物理程序集,箭头则表示了依赖关系及其依赖方向。

ddd

注意,图中的数据层定义了仓储的具体实现细节,它依赖于核心的领域层。在核心层中,除了定义领域模型和逻辑,还定义了仓储接口,该接口可以被其他各 层所调用,例如应用服务层会与仓储通信,这就保证了它独立于其实现细节。某些建议认为表示层(在图上方的YourProject.Web)不应直接依赖于 领域层。作为替代,可以引入数据传输对象(DTO),从而在数据传递给视图展现时,更好地将领域层从表示层中分离。

怎么做?

我们工作的底线是,软件交付专家们必须及时交付解决方案,且要符合客户的需求,并具有高质量和可维护性。很多实践都经过了千锤百炼,所谓“前人栽 树,后人乘凉”,在个人的应用程序中,我们不必重新创造,只需求助于经过验证而又真实的设计模式,以及基本工具的实现,就能够解决开发中的常见问题,例如 数据持久化和单元测试。真正的挑战在于要合理地制定计划,事先做出权衡,既要提高开发效率,又不能扼杀我们的能力,企图以创新的方式去迎合不切实际的需求 是不可取的。我希望本文所描述的技术与工具,以及S#arp架构对它们的组合,足以说明,虽然条条道路都能够通罗马,然而前车之鉴,若要避免重蹈覆辙,就必须从一开始就要汲取经验教训,并要有足够的智慧来赢得一个稳定的开端。

了解更多信息

S#arp架构项目已经开发了接近一年的时间,它为快速开发稳定的领域驱动程序提供了简单但又强大的架构基础。你可以从http://code.google.com/p/sharp-architecture下载S#arp架构的RC版本。1.0的GA版则与ASP.NET MVC 1.0密切相关。S#arp架构的论坛欢迎大家踊跃发言,畅谈自己的体验。

关于作者

http://devlicio.us

若要提到编写优美的软件,那么Billy McCafferty可以说是经验老到,久经沙场,偏生他又一味追求编程的罗曼蒂克,以至于无可救药。Billy目前身兼两职,一方面他负责管理一家小规模的培训与咨询公司Codai(很快会推出新的网站),同时又在Parsons Brinckerhoff带领开发人员与架构师团队。在发布S#arp架构1.0版本之后,Billy的生活又将重回正规,在不久的ALT.NET以及其他开发大会上,你能够见到他的身影。

[Tools]MyEclipse 7.0 破解版下载

mikel阅读(579)

MyEclipse7.0 下载地址:downloads.myeclipseide.com/downloads/products/eworkbench/7.0M1/MyEclipse_7.0M1_E3.4.0_Installer.exe
http://downloads.myeclipseide.com/downloads/products/eworkbench/7.0M1/MyEclipse_7.0M1_E3.4.0_Installer.exe
1、建立java Project,任意取个名字就行。
2、建立一个名字为MyEclipseGen的类文件,内容见附件。
3、运行该代码,在控制台中会出现:
please input register name:
×××××(你的name)
即生成序列号:
4、进入myeclipse,输入Subscriber和Subscription code即可。
附件:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class MyEclipseGen {
private static final String LL = "Decompiling this copyrighted software is a violation of both your license agreement and the Digital Millenium Copyright Act of 1998 (http://www.loc.gov/copyright/legislation/dmca.pdf). Under section 1204 of the DMCA, penalties range up to a $500,000 fine or up to five years imprisonment for a first offense. Think about it; pay for a license, avoid prosecution, and feel better about yourself.";
public String getSerial(String userId, String licenseNum) {
java.util.Calendar cal = java.util.Calendar.getInstance();
cal.add(1, 3);
cal.add(6, -1);
java.text.NumberFormat nf = new java.text.DecimalFormat("000");
licenseNum = nf.format(Integer.valueOf(licenseNum));
String verTime = new StringBuilder("-").append(
new java.text.SimpleDateFormat("yyMMdd").format(cal.getTime()))
.append("0").toString();
String type = "YE3MP-";
String need = new StringBuilder(userId.substring(0, 1)).append(type)
.append("300").append(licenseNum).append(verTime).toString();
String dx = new StringBuilder(need).append(LL).append(userId)
.toString();
int suf = this.decode(dx);
String code = new StringBuilder(need).append(String.valueOf(suf))
.toString();
return this.change(code);
}
private int decode(String s) {
int i;
char[] ac;
int j;
int k;
i = 0;
ac = s.toCharArray();
j = 0;
k = ac.length;
while (j < k) {
i = (31 * i) + ac[j];
j++;
}
return Math.abs(i);
}
private String change(String s) {
byte[] abyte0;
char[] ac;
int i;
int k;
int j;
abyte0 = s.getBytes();
ac = new char[s.length()];
i = 0;
k = abyte0.length;
while (i < k) {
j = abyte0[i];
if ((j >= 48) && (j <= 57)) {
j = (((j – 48) + 5) % 10) + 48;
} else if ((j >= 65) && (j <= 90)) {
j = (((j – 65) + 13) % 26) + 65;
} else if ((j >= 97) && (j <= 122)) {
j = (((j – 97) + 13) % 26) + 97;
}
ac[i] = (char) j;
i++;
}
return String.valueOf(ac);
}
public MyEclipseGen() {
super();
}
public static void main(String[] args) {
try {
System.out.println("please input register name:");
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String userId = null;
userId = reader.readLine();
MyEclipseGen myeclipsegen = new MyEclipseGen();
String res = myeclipsegen.getSerial(userId, "5");
System.out.println("Serial:" + res);
reader.readLine();
} catch (IOException ex) {
}
}
}
我运行后的结果:
please input register name:
sorc
Serial:fLR8ZC-855550-6654585354305964
注:private static final String LL = "Decompiling this copyrighted software is a violation of both your license agreement and the Digital Millenium Copyright Act of 1998 (http://www.loc.gov/copyright/legislation/dmca.pdf). Under section 1204 of the DMCA, penalties range up to a $500,000 fine or up to five years imprisonment for a first offense. Think about it; pay for a license, avoid prosecution, and feel better about yourself.";
此段代码常量不可变更 否则注册码无效

[MVC]在MVC下用XML实现breadcrumbs导航栏

mikel阅读(912)

转载:http://www.cnblogs.com/conan77/archive/2009/06/24/1509927.html

先看下样子image

像这种导航栏(breadcrumbs)在mvc下我们来实现他。我们采用XML来实现这个功能。

1.首先做个准备,我们编写rounting规则(顺便提一句,我们要用到rounting功能,所以规则必须写正确,不然出不来喔)

代码如下

 public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"inner",                                              // Route name
"resume/test/inner/{action}/{id}",                           // URL with parameters
new { controller = "inner", action = "Index", id = "" }  // Parameter defaults
);
routes.MapRoute(
"test",                                              // Route name
"resume/test/{action}/{id}",                           // URL with parameters
new { controller = "test", action = "Index", id = "" }  // Parameter defaults
);
routes.MapRoute(
"Default",                                              // Route name
"{controller}/{action}/{id}",                           // URL with parameters
new { controller = "Home", action = "Index", id = "" },
new { controller = "^(?!(test|inner)).*$", action = "^(?!test).*$" }
);
}

我们加了两个规则

/resume/test

和/resume/test/inner

2.编写用到的XML文件,注意是树形结构的

在models写个Navigator.xml

<?xml version="1.0" encoding="utf-8" ?>
<node Title="首页"  Description="潘峰的网站" Action="Index" Controller="Home">
<node Title="简历" Description="在线简历" Action="Index" Controller="Resume">
<node Title="Test" Description="Test" Action="Index" Controller="test">
<node Title="inner" Description="inner" Action="Index" Controller="inner">
</node>
</node>
</node>
</node> 

3.编写我们的类文件来实现Navigator

在models写个navigatorHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Web.Routing;
using System.Web.Mvc;
using System.IO;
using System.Text;
namespace conansoft.Helpers
{
public static class MenuHelper
{
private static HttpServerUtilityBase Server = null;
private static HttpRequestBase Request = null;
private static UrlHelper Url = null;
private static RouteValueDictionary RouteDictionary = null;
public static string Navigator(this HtmlHelper helper)
{
Server = helper.ViewContext.RequestContext.HttpContext.Server;
Request = helper.ViewContext.RequestContext.HttpContext.Request;
Url = new UrlHelper(helper.ViewContext.RequestContext);
RouteDictionary = helper.ViewContext.RequestContext.RouteData.Values;
string xmlPath = Server.MapPath(Url.Content("~/Models/Navigator.xml"));
XDocument doc = XDocument.Load(xmlPath);
XElement node = FindNode(doc.Root);
StringBuilder sb = new StringBuilder();
Stack<XElement> s = new Stack<XElement>();
while (node != null)
{
s.Push(node);
node = node.Parent;
}
//输出breadcrumbs.可以自行修改使之符合你的要求
while (s.Count() != 0)
{
node = s.Pop();
if (UrlEqual(node))
{
sb.AppendLine(string.Format("<li title='{1}'>{0}</li>", node.Attribute("Title").Value, node.Attribute("Description").Value));
}
else
{
sb.AppendLine(string.Format("<li><a href='{1}' title='{2}'>{0}</a></li>", node.Attribute("Title").Value,
Url.Action(node.Attribute("Action").Value, node.Attribute("Controller").Value),
node.Attribute("Description").Value));
sb.AppendLine("<span style='color:Black;font-weight:bold;'> > </span>");
}
}
return sb.ToString();
}
/// <summary>
/// 查找当前节点
/// </summary>
/// <param name="e">当前节点</param>
/// <returns>找到返回,找不到为空</returns>
private static XElement FindNode(XElement e)
{
XElement result = e;
if (UrlEqual(e))
{
return e;
}
else
{
if (e.HasElements)
{
foreach (XElement ee in e.Elements())
{
result = FindNode(ee);
}
}
else
{
return null;
}
return result;
}
}
/// <summary>
/// Url是否相等
/// </summary>
/// <param name="e">节点</param>
private static bool UrlEqual(XElement e)
{
string url1 = Url.Action(e.Attribute("Action").Value, e.Attribute("Controller").Value).ToLower();
string url2 = Url.RouteUrl(RouteDictionary).ToLower();
return url1 == url2;
}
}
}

解释一下我们利用xml文件来实现breadcrumbs,并且我们用action和controller来判断是否为当前路径[UrlEqual]

在网页中加入

  <%=Html.Navigator() %>

好了效果如下image

我的网站

image

image

[API]淘宝开放平台重装上阵

mikel阅读(1004)

淘宝开放平台( Taobao Open Platform, TOP ) ,面向第三方的开放式电子商务服务基础服务框架,重装上阵。前一段时间提前接触了一点这个项目,真是个非常有想象空间的事情。

可以肯定的是,这是"大淘宝"战略的一个重要环节。从最初的 Taobao.com 一个站点,现在是一个平台,将来再到一个更大的商业生态系统

Taobao TOP 蓝图
(上图出处)

去年下半年淘宝有过一次尝试("淘园"项目),与上次的初步尝试截然不同的是,这次已经不再通过阿里软件这一层进行接入,从开发者使用角度上看,减 少了交互环节,更加直接方便。此外,可供使用的应用程序接口愈加丰富,更贴近用户使用习惯。随着开发者社区的成熟和开发者规模的扩大,淘宝提供平台化的支 持也是可以想见的事情。

对于所有的开放平台开发者来说,最关心的问题莫过于盈利模式。现在 TOP 关于盈利模式主要有两种形式:一是淘宝客佣金模式,再一个是淘宝插件分成模式。还是比较清晰的。就我个人而言,更倾向于前者的模式。也期待淘宝运营人员能够根据实际情况制定更加有利于开发者的策略,积极促进与开发者之间的互动。胜,在于人。

与其在一些 SNS 网站捣鼓那些游戏插件,还不如来开发电子商务第三方应用呢。你说呢?