美祺's profileEden of HexagonPhotosBlogListsMore ![]() | Help |
|
November 30 PetShop数据访问层之消息处理——From www.brucezhang.comPetShop数据访问层之消息处理
在进行系统设计时,除了对安全、事务等问题给与足够的重视外,性能也是一个不可避免的问题所在,尤其是一个B/S结构的软件系统,必须充分地考虑访问量、数据流量、服务器负荷的问题。解决性能的瓶颈,除了对硬件系统进行升级外,软件设计的合理性尤为重要。
在前面我曾提到,分层式结构设计可能会在一定程度上影响数据访问的性能,然而与它给设计人员带来的好处相比,几乎可以忽略。要提供整个系统的性能,还可以从数据库的优化着手,例如连接池的使用、建立索引、优化查询策略等等,例如在PetShop中就利用了数据库的Cache,对于数据量较大的订单数据,则利用分库的方式为其单独建立了Order和Inventory数据库。而在软件设计上,比较有用的方式是利用多线程与异步处理方式。 在PetShop4.0中,使用了Microsoft Messaging Queue(MSMQ)技术来完成异步处理,利用消息队列临时存放要插入的数据,使得数据访问因为不需要访问数据库从而提供了访问性能,至于队列中的数据,则等待系统空闲的时候再进行处理,将其最终插入到数据库中。 PetShop4.0中的消息处理,主要分为如下几部分:消息接口IMessaging、消息工厂MessagingFactory、MSMQ实现MSMQMessaging以及数据后台处理应用程序OrderProcessor。 从模块化分上,PetShop自始自终地履行了“面向接口设计”的原则,将消息处理的接口与实现分开,并通过工厂模式封装消息实现对象的创建,以达到松散耦合的目的。 由于在PetShop中仅对订单的处理使用了异步处理方式,因此在消息接口IMessaging中,仅定义了一个IOrder接口,其类图如下: 在对消息接口的实现中,考虑到未来的扩展中会有其他的数据对象会使用MSMQ,因此定义了一个Queue的基类,实现消息Receive和Send的基本操作: public virtual object Receive() { try { using (Message message = queue.Receive(timeout, transactionType)) return message; } catch (MessageQueueException mqex) { if (mqex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout) throw new TimeoutException(); throw; } } public virtual void Send(object msg) { queue.Send(msg, transactionType); } 其中queue对象是System.Messaging.MessageQueue类型,作为存放数据的队列。MSMQ队列是一个可持久的队列,因此不必担心用户不间断地下订单会导致订单数据的丢失。在PetShopQueue设置了timeout值,OrderProcessor会根据timeout值定期扫描队列中的订单数据。 MSMQMessaging模块中,Order对象实现了IMessaging模块中定义的接口IOrder,同时它还继承了基类PetShopQueue,其定义如下: public class Order:PetShopQueue, PetShop.IMessaging.IOrder 方法的实现代码如下: public new OrderInfo Receive() { // This method involves in distributed transaction and need Automatic Transaction type base.transactionType = MessageQueueTransactionType.Automatic; return (OrderInfo)((Message)base.Receive()).Body; } public OrderInfo Receive(int timeout)
{ base.timeout = TimeSpan.FromSeconds(Convert.ToDouble(timeout)); return Receive(); } public void Send(OrderInfo orderMessage)
{ // This method does not involve in distributed transaction and optimizes performance using Single type base.transactionType = MessageQueueTransactionType.Single; base.Send(orderMessage); } 所以,最后的类图应该如下: 注意在Order类的Receive()方法中,是用new关键字而不是override关键字来重写其父类PetShopQueue的Receive()虚方法。因此,如果是实例化如下的对象,将会调用PetShopQueue的Receive()方法,而不是子类Order的Receive()方法: PetShopQueue queue = new Order(); queue.Receive(); 从设计上来看,由于PetShop采用“面向接口设计”的原则,如果我们要创建Order对象,应该采用如下的方式: IOrder order = new Order(); order.Receive(); 考虑到IOrder的实现有可能的变化,PetShop仍然利用了工厂模式,将IOrder对象的创建用专门的工厂模块进行了封装: 在类QueueAccess中,通过CreateOrder()方法利用反射技术创建正确的IOrder类型对象: public static PetShop.IMessaging.IOrder CreateOrder() { string className = path + ".Order"; return PetShop.IMessaging.IOrder)Assembly.Load(path).CreateInstance(className); } path的值通过配置文件获取: private static readonly string path = ConfigurationManager.AppSettings["OrderMessaging"]; 而配置文件中,OrderMessaging的值设置如下: <add key="OrderMessaging" value="PetShop.MSMQMessaging"/> 之所以利用工厂模式来负责对象的创建,是便于在业务层中对其调用,例如在BLL模块中OrderAsynchronous类: public class OrderAsynchronous : IOrderStrategy { private static readonly PetShop.IMessaging.IOrder asynchOrder = PetShop.MessagingFactory.QueueAccess.CreateOrder(); public void Insert(PetShop.Model.OrderInfo order) { asynchOrder.Send(order); } } 一旦IOrder接口的实现发生变化,这种实现方式就可以使得客户仅需要修改配置文件,而不需要修改代码,如此就可以避免程序集的重新编译和部署,使得系统能够灵活应对需求的改变。例如定义一个实现IOrder接口的SpecialOrder,则可以新增一个模块,如PetShop.SpecialMSMQMessaging,而类名则仍然为Order,那么此时我们仅需要修改配置文件中OrderMessaging的值即可: <add key="OrderMessaging" value="PetShop.SpecialMSMQMessaging"/> OrderProcessor是一个控制台应用程序,不过可以根据需求将其设计为Windows Service。它的目的就是接收消息队列中的订单数据,然后将其插入到Order和Inventory数据库中。它利用了多线程技术,以达到提高系统性能的目的。 在OrderProcessor应用程序中,主函数Main用于控制线程,而核心的执行任务则由方法ProcessOrders()实现: private static void ProcessOrders() { // the transaction timeout should be long enough to handle all of orders in the batch TimeSpan tsTimeout = TimeSpan.FromSeconds(Convert.ToDouble(transactionTimeout * batchSize)); Order order = new Order();
while (true) { // queue timeout variables TimeSpan datetimeStarting = new TimeSpan(DateTime.Now.Ticks); double elapsedTime = 0; int processedItems = 0;
ArrayList queueOrders = new ArrayList();
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required, tsTimeout))
{ // Receive the orders from the queue for (int j = 0; j < batchSize; j++) { try { //only receive more queued orders if there is enough time if ((elapsedTime + queueTimeout + transactionTimeout) < tsTimeout.TotalSeconds) { queueOrders.Add(order.ReceiveFromQueue(queueTimeout)); } else { j = batchSize; // exit loop } //update elapsed time
elapsedTime = new TimeSpan(DateTime.Now.Ticks).TotalSeconds - datetimeStarting.TotalSeconds; } catch (TimeoutException) { //exit loop because no more messages are waiting j = batchSize; } } //process the queued orders for (int k = 0; k < queueOrders.Count; k++) { order.Insert((OrderInfo)queueOrders[k]); processedItems++; totalOrdersProcessed++; } //batch complete or MSMQ receive timed out
ts.Complete(); } Console.WriteLine("(Thread Id " + Thread.CurrentThread.ManagedThreadId + ") batch finished, " + processedItems + " items, in " + elapsedTime.ToString() + " seconds.");
} } 首先,它会通过PetShop.BLL.Order类的公共方法ReceiveFromQueue()来获取消息队列中的订单数据,并将其放入到一个ArrayList对象中,然而再调用PetShop.BLL.Order类的Insert方法将其插入到Order和Inventory数据库中。 在PetShop.BLL.Order类中,并不是直接执行插入订单的操作,而是调用了IOrderStrategy接口的Insert()方法: public void Insert(OrderInfo order) { // Call credit card procesor ProcessCreditCard(order); // Insert the order (a)synchrounously based on configuration
orderInsertStrategy.Insert(order); } 在这里,运用了一个策略模式,类图如下所示: 在PetShop.BLL.Order类中,仍然利用配置文件来动态创建IOrderStategy对象: private static readonly PetShop.IBLLStrategy.IOrderStrategy orderInsertStrategy = LoadInsertStrategy(); private static PetShop.IBLLStrategy.IOrderStrategy LoadInsertStrategy() { // Look up which strategy to use from config file string path = ConfigurationManager.AppSettings["OrderStrategyAssembly"]; string className = ConfigurationManager.AppSettings["OrderStrategyClass"]; // Using the evidence given in the config file load the appropriate assembly and class
return (PetShop.IBLLStrategy.IOrderStrategy)Assembly.Load(path).CreateInstance(className); } 由于OrderProcessor是一个单独的应用程序,因此它使用的配置文件与PetShop不同,是存放在应用程序的App.config文件中,在该文件中,对IOrderStategy的配置为: <add key="OrderStrategyAssembly" value="PetShop.BLL" /> <add key="OrderStrategyClass" value="PetShop.BLL.OrderSynchronous" /> 因此,以异步方式插入订单的流程如下图所示: Microsoft Messaging Queue(MSMQ)技术除用于异步处理以外,它主要还是一种分布式处理技术。分布式处理中,一个重要的技术要素就是有关消息的处理,而在System.Messaging命名空间中,已经提供了Message类,可以用于承载消息的传递,前提上消息的发送方与接收方在数据定义上应有统一的接口规范。 MSMQ在分布式处理的运用,在我参与的项目中已经有了实现。在为一个汽车制造商开发一个大型系统时,分销商Dealer作为.Net客户端,需要将数据传递到管理中心,并且该数据将被Oracle的EBS(E-Business System)使用。由于分销商管理系统(DMS)采用的是C/S结构,数据库为SQL Server,而汽车制造商管理中心的EBS数据库为Oracle。这里就涉及到两个系统之间数据的传递。 实现架构如下: 首先Dealer的数据通过MSMQ传递到MSMQ Server,此时可以将数据插入到SQL Server数据库中,同时利用FTP将数据传送到专门的文件服务器上。然后利用IBM的EAI技术(企业应用集成,Enterprise Application Itegration)定期将文件服务器中的文件,利用接口规范写入到EAI数据库服务器中,并最终写道EBS的Oracle数据库中。
上述架构是一个典型的分布式处理结构,而技术实现的核心就是MSMQ和EAI。由于我们已经定义了统一的接口规范,在通过消息队列形成文件后,此时的数据就已经与平台无关了,使得在.Net平台下的分销商管理系统能够与Oracle的EBS集成起来,完成数据的处理。 Moments——Ayumi HamasakiMoments
心が焦げ付いて 焼ける匂いがした それは夢の終わり 全ての始まりだった 憧れてたものは
美しく思えて 手が届かないから 輝きを増したのだろう 君の砕け散った夢の破片が
僕の胸を刺して 忘れてはいけない痛みとして刻まれてく 花のように儚いのなら
君の元で咲き誇るでしょう そして笑顔見届けたあと そっとひとり散って行くでしょう 君が絶望という
名の淵に立たされ そこで見た景色はどんなものだったのだろう 行き場所を失くして彷徨ってる
剥き出しの心が 触れるのを恐れて 鋭い刺張り巡らせる 鳥のようにはばたけるなら
君の元へ飛んでいくでしょう そして傷を負ったその背に 僕の羽根を差し出すでしょう 花のように儚いのなら
君の元で咲き誇るでしょう そして笑顔見届けたあと そっとひとり散って行くでしょう 鳥のようにはばたけるなら
君の元へ飛んでいくでしょう そして傷を負ったその背に 僕の羽根を差し出すでしょう 風のように流れるのなら
君の側に辿り着くでしょう 月のように輝けるなら 君を照らし続けるでしょう 君がもうこれ以上
二度とこわいものを 見なくてすむのなら 僕は何にでもなろう ☆°.· ∴終わる°★. ☆°∴·
╰>刹那 迫切的渴望散发出阵阵香味 悲伤的终点是一切的起点 憧憬的事物总是充满美好的感觉 伸出手却又摸不到 反而给了你一场凋谢 在这一个场景里 让我遗忘胸口的刺 来取代哭泣的深深痛楚 如果说我就像花一样虚惘 我只愿在你身旁绽放 当我欢展笑颜之后 我又将独自一人凋落 你曾说过那一个等待已久的地方充满绝望 在那里所看见的景色究竟是怎么样的呢 茫然等待着遗失的目的地 赤裸的心害怕被人抚摸 于是你将身上尖锐的刺全部竖起 如果说我能像鸟一样飞翔 我只愿飞到你的身旁 当我的背上遍体鳞伤 我会交出我的翅膀 如果说我就像花一样虚惘 我只愿在你身边绽放 当我欢展笑颜之后 我又将独自一人凋落 如果说我能像鸟一样飞翔 我只愿飞到你的身旁 当我的背上遍体鳞伤 我会交出我的翅膀 如果说我能像风一样流浪 最后我一定会到达你的身旁 如果说我能像月一样发光 我一定会永远将你身旁照亮 如果你已经不想再看到那些令你恐惧的事物 我又将会化身成什么 November 29 使用ASP.NET 2.0 Profile存储用户信息(9)——转自msdn列表17中显示调查的结果,该页面中有一个显示ProfileInfo对象集合的GridView控件,该ProfileInfo对象集合是由 ProfileManager的GetAllProfiles方法获得的。当你点击GridView中的任意一行的Select链接时,你将会看到对这个问题的调查结果,该调查结果是由Profile类的GetProfile方法获得的。
图5 显示调查结果 列表 17. SurveyResults.aspx (Visual Basic .NET)
<%@ Page Language="VB" %>
<script runat="server"> Sub Page_Load()
ResultsGrid.DataSource = _ ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All) ResultsGrid.DataBind() End Sub Sub DisplayProfileDetails(ByVal s As Object, ByVal e As EventArgs) Dim SelectedProfile As ProfileCommon SelectedProfile = Profile.GetProfile(ResultsGrid.SelectedValue) lblLanguage.Text = SelectedProfile.FavoriteLanguage lblEnvironment.Text = SelectedProfile.FavoriteEnvironment End Sub </script> <html>
<head> <title>Survey Results</title> </head> <body> <form id="form1" runat="server"> <h2>Survey Results</h2> <asp:GridView id="ResultsGrid" DataKeyNames="UserName" AutoGenerateSelectButton="true" OnSelectedIndexChanged="DisplayProfileDetails" SelectedRowStyle-BackColor="LightYellow" Runat="Server" /> <p> </p> <h2>Survey Details</h2> <b>Favorite Language:</b> <asp:Label id="lblLanguage" Runat="Server" /> <br /> <b>Favorite Environment:</b> <asp:Label id="lblEnvironment" Runat="Server" /> </form>
</body> </html> 列表 17. SurveyResults.aspx (C#) <%@ Page Language="C#" %>
<script runat="server"> void Page_Load()
{ ResultsGrid.DataSource = ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All); ResultsGrid.DataBind(); } void DisplayProfileDetails(Object s, EventArgs e) { ProfileCommon SelectedProfile = Profile.GetProfile(ResultsGrid.SelectedValue.ToString()); lblLanguage.Text = SelectedProfile.FavoriteLanguage; lblEnvironment.Text = SelectedProfile.FavoriteEnvironment; } </script> <html>
<head> <title>Survey Results</title> </head> <body> <form id="form1" runat="server"> <h2>Survey Results</h2> <asp:GridView id="ResultsGrid" DataKeyNames="UserName" AutoGenerateSelectButton="true" OnSelectedIndexChanged="DisplayProfileDetails" SelectedRowStyle-BackColor="LightYellow" Runat="Server" /> <p> </p> <h2>Survey Details</h2> <b>Favorite Language:</b> <asp:Label id="lblLanguage" Runat="Server" /> <br /> <b>Favorite Environment:</b> <asp:Label id="lblEnvironment" Runat="Server" /> </form> </body> </html> 总结 当建立Web应用程序时,我依旧花费了大量的时间和精力用于做一些大伤脑筋的事情。其中的一个任务就是写一些用于从数据库存储和获得用户信息的代码。虽然 Profile对象引入的都是asp.net 1.0中可以实现的功能,但是这个新特性帮助我们从乏味的编码工作中解脱出来,这样也能让我们在写Web应用程序的过程中,把更多的精力放在我们更感兴趣的事情上。 使用ASP.NET 2.0 Profile存储用户信息(8)——转自msdn在列表12中的profile配置中,包含了一个defaultProvider特性,这个特性指向一个叫MyProfileProvider的 profile provider,而这个provider定义是在profile标记的<providers>节中完成的。 MyProfileProvider则使用一个叫MyConnectionString的连接字符串完成数据库连接,并保存profile信息到数据库中。MyConnectionString可以在位于web.config开头的<connectionStrings>节中找到。
管理profile并生成profile报告
Profile会对象自动保存用户profile信息,这既是好事业是坏事。说它是好事,是因为你不需要写存储信息的所有逻辑代码,说它是坏事,是因为这样可能造成一大堆无用的信息被保存在数据库中。 幸运的是,ASP.NET 2.0框架包含一个叫做ProfileManager的类,你可以使用它来管理profile信息。它包含了相当多的方法使你能够有效地管理profile并且生成profile报表,下面列出了一些该类的重要方法:
DeleteInactiveProfiles. 删除一个特定日期之前的所有profile
DeleteProfile. 删除特定用户的profile DeleteProfiles. 删除一个profile集合 FindInactiveProfilesByUserName. 返回一个ProfileInfo对象的集合,该集合表示的profile是匹配一个某个名字,并且是从某个特定日期开始一直未被使用
FindProfilesByUserName. 返回一个ProfileInfo对象集合,该集合与某个用户名相关联 GetAllInactiveProfiles. 返回一个ProfileInfo对象集合,该集合表示的profile是从某个特定日期开始一直未被使用的profile GetAllProfiles. 返回一个ProfileInfo对象集合,该集合表示所有的profile
GetNumberOfInactiveProfiles. 返回从某个特定日期开始一直未被使用的profile的数量
GetNumberOfProfiles. 返回profile总数 这些方法中,虽然所有的方法都返回一个ProfileInfo对象集合,但没有一个返回一个真正的profile。ProfileInfo对象包含以下profile属性 IsAnonymous. 表示该profile是否为匿名profile
LastActivityDate. 最后一次profile被访问的时间和日期
LastUpdatedDate. 最后一次profile被升级的时间和日期 Size. 表示profile的大小,这是在profile provider存储profile信息时记录的 UserName. 与profile关联的用户名 ProfileManager有几个方法提供了额外的参数用于支持分页。例如,GetAllProfiles方法的一个重载版本就提供了专门用于设置页面索引、页面大小、总共的记录数的参数,这些参数在需要分页的页面中十分有用。 ProfileManager既可以在asp.net页面下使用,也可以在其它程序中使用。例如,你可能需要做一个控制台程序用于每天清除长时间未使用的 profile。列表14的控制台程序会删除七天未使用的profile,你可以使用Windows计划任务(Windows Scheduled Tasks)来安排该程序的执行时间。
列表 14. DeleteInactiveProfiles (Visual Basic .NET)
Imports System.Web.Profile
Public Class DeleteInactiveProfiles
Public Shared Sub Main() Dim deleted As Integer deleted = ProfileManager.DeleteInactiveProfiles( ProfileAuthenticationOption.All, DateTime.Now.AddDays(-7)) Console.WriteLine("Deleted " & deleted & " profiles" ) End Sub End Class 列表 14. DeleteInactiveProfiles (C#) using System;
using System.Web.Profile; public class DeleteInactiveProfiles
{ public static void Main() { int deleted = 0; deleted = ProfileManager.DeleteInactiveProfiles( ProfileAuthenticationOption.All, DateTime.Now.AddDays(-7)); Console.WriteLine("Deleted " + deleted.ToString() + " profiles" ); } } 你可以通过一下的命令行指令对列表14进行编译 [Visual Basic .NET]
C:\WINDOWS\Microsoft.NET\Framework\v2.0.40607\vbc /r:System.Web.dll DeleteInactiveProfiles.vb [C#]
C:\WINDOWS\Microsoft.NET\Framework\v2.0.40607\csc DeleteInactiveProfiles.cs 你还可以使用ProfileManager类生成profile信息报表。例如,如果你打算生成一个用户调查的报表,你可以把用户调查保存在profile中,这样就可以轻易的使用ProfileManager生成你需要的报表。 列表15中的web.config中有三个属性:SurveyCompleted、FavoriteLanguage 和 FavoriteEnvironment
Listing 15. Web.Config
<anonymousIdentification enabled="true" /> <profile>
<properties> <add name="SurveyCompleted" type="Boolean" allowAnonymous="true" /> <add name="FavoriteLanguage" allowAnonymous="true" /> <add name="FavoriteEnvironment" allowAnonymous="true" /> </properties> </profile> </system.web> </configuration> 列表16中的页面演示了一个简单的用户调查。该页面包含两个Panel控件,第一个控件中有两个调查问题,当用户完成调查后,第一个控件会自动隐藏,而第二个会显示出来,第二个Panel有一段表示感谢的文字。 列表 16. Survey.aspx (Visual Basic .NET)
<%@ Page Language="VB" %>
<script runat="server"> Sub SaveSurvey(ByVal s As Object, ByVal e As EventArgs)
Profile.FavoriteLanguage = rdlLanguage.SelectedItem.Text Profile.FavoriteEnvironment = rdlEnvironment.SelectedItem.Text Profile.SurveyCompleted = True End Sub Sub Page_PreRender() If Profile.SurveyCompleted Then pnlSurvey.Visible = False pnlSurveyCompleted.Visible = True Else pnlSurvey.Visible = True pnlSurveyCompleted.Visible = False End If End Sub </script> <html>
<head> <title>Survey</title> </head> <body> <form id="form1" runat="server"> <asp:Panel ID="pnlSurvey" Runat="Server"> What is your favorite programming language? <br /> <asp:RadioButtonList id="rdlLanguage" runat="Server"> <asp:ListItem Text="VB.NET" Selected="True" /> <asp:ListItem Text="C#" /> <asp:ListItem Text="J#" /> </asp:RadioButtonList> <p> </p> What is your favorite development environment? <br /> <asp:RadioButtonList id="rdlEnvironment" runat="Server"> <asp:ListItem Text="VS.NET" Selected="True" /> <asp:ListItem Text="Web Matrix" /> <asp:ListItem Text="Notepad" /> </asp:RadioButtonList> <p> </p> <asp:Button Text="Submit Survey" Onclick="SaveSurvey" Runat="Server" /> </asp:Panel> <asp:Panel ID="pnlSurveyCompleted" Runat="Server"> Thank you for completing the survey! </asp:Panel> </form> </body> </html> 列表 16. Survey.aspx (C#) <%@ Page Language="C#" %>
<script runat="server"> void SaveSurvey(Object s, EventArgs e)
{ Profile.FavoriteLanguage = rdlLanguage.SelectedItem.Text; Profile.FavoriteEnvironment = rdlEnvironment.SelectedItem.Text; Profile.SurveyCompleted = true; } void Page_PreRender() { if (Profile.SurveyCompleted) { pnlSurvey.Visible = false; pnlSurveyCompleted.Visible = true; } else { pnlSurvey.Visible = true; pnlSurveyCompleted.Visible = false; } } </script> <html> <head> <title>Survey</title> </head> <body> <form id="form1" runat="server"> <asp:Panel ID="pnlSurvey" Runat="Server"> What is your favorite programming language? <br /> <asp:RadioButtonList id="rdlLanguage" runat="Server"> <asp:ListItem Text="VB.NET" Selected="True" /> <asp:ListItem Text="C#" /> <asp:ListItem Text="J#" /> </asp:RadioButtonList> <p> </p> What is your favorite development environment? <br /> <asp:RadioButtonList id="rdlEnvironment" runat="Server"> <asp:ListItem Text="VS.NET" Selected="True" /> <asp:ListItem Text="Web Matrix" /> <asp:ListItem Text="Notepad" /> </asp:RadioButtonList> <p> </p> <asp:Button ID="Button1" Text="Submit Survey" Onclick="SaveSurvey" Runat="Server" /> </asp:Panel> <asp:Panel ID="pnlSurveyCompleted" Runat="Server"> Thank you for completing the survey! </asp:Panel> </form> </body> </html> 使用ASP.NET 2.0 Profile存储用户信息(7)——转自msdn在很多情况下,你需要把匿名profile迁移到认证profile状态,如果你需要迁移profile属性值的话,你可以利用 ProfileModule类的MigrateAnonymous事件完成该任务,该事件只能在Global.asax文件中进行处理。列表11中的 Global.asax演示了你如何才能实现FavoriteColor属性的迁移。
列表 11. Global.asax (Visual Basic .NET)
<%@ Application Language="VB" %>
<script runat="server"> Sub Profile_MigrateAnonymous(ByVal s As Object, _
ByVal e As ProfileMigrateEventArgs) Dim anonProfile As ProfileCommon = _ Profile.GetProfile(e.AnonymousId) Profile.FavoriteColor = anonProfile.FavoriteColor End Sub </script> 列表 11. Global.asax (C#) <%@ Application Language="C#" %>
<script runat="server"> void Profile_MigrateAnonymous(Object s,
ProfileMigrateEventArgs e) { ProfileCommon anonProfile = Profile.GetProfile(e.AnonymousId); Profile.FavoriteColor = anonProfile.FavoriteColor; } </script> 通过Profile类的GetProfile()方法你可以获得匿名profile,该方法接收一个唯一识别号,并且返回与唯一识别号对应的profile。ProfileMigrateEventArgs对象包含一个匿名识别号。 配置Profile Provider
默认情况下,profile被保存在sqlserver 2005 express数据库,它位于App_Data目录中,这或许在你开发一些普通的asp.net应用程序时是没有问题的,但很有可能,你需要把你的应用程序的profile保存在另一个数据库中,比如一个完整版的SqlServer 2005的实例中,而该数据库又位于你局域网的某个位置。 Profile使用Provider模式,通过修改web.config或machine.config的设置来告诉系统把信息存储在哪里。
ASP.NET本身配了一个profile provider,叫SqlProfileProvider。如果你感到困惑,你可以通过继承ProfileProvider基类来创建一个自己的 provider。例如,你可以创建一个基于Oracle数据库或MySql数据库的Provider。在这里,我们将只讨论最简单的方法,即通过SqlServer数据库来保存profile信息。 要使用Microsoft SQL Server存储profile信息,必须完成两个步骤。首先,你必须安装SQL Server数据库,然后你必须重新设置配置文件。
ASP.NET 2.0框架提供了一个用于配置SQL Server来存储Profile信息的工具,该工具叫做aspnet_regsql,它位于Windows\Microsoft.NET\ Framework\[.NET版本号]。执行该工具后,你会看到图4中的ASP.NET SQL Server安装向导。
图4 使用ASP.NET SQL Server安装程序
SQL Server安装向导会指导你完成必要的步骤,完成这些步骤后,向导会自动创建用于存储profile信息的存储过程和表结构。
在你完成SQL Server数据库的配置后,你需要修改web.config或machine.config中的数据库连接设置来指向服务器上的SQL Server数据库,本例中该数据库的实例名为MyServer,列表12列出了该配置文件。
列表 12. Web.Config
<configuration> <connectionStrings> <add name="myConnectionString" connectionString= "Server=MyServer;Trusted_Connection=true;database=MyDatabase" /> </connectionStrings> <system.web> <anonymousIdentification enabled="true" /> <profile defaultProvider="MyProfileProvider"> <providers> <add name="MyProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="myConnectionString" /> </providers> <properties> <add name="FirstName" allowAnonymous="true" /> <add name="LastName" allowAnonymous="true" /> </properties> </profile> </system.web> </configuration> 使用ASP.NET 2.0 Profile存储用户信息(6)——转自msdn列表10中有一个包含两个按钮的页面,分别是login和logout按钮,其中还有一个用于更新FavoriteColor属性的表单。
列表10. Anonymous.aspx (Visual Basic .NET) <%@ Page Language="VB" %>
<script runat="server">
Sub Login(ByVal s As Object, ByVal e As EventArgs)
FormsAuthentication.SetAuthCookie("Bill", False) Response.Redirect(Request.Path) End Sub Sub Logout(ByVal s As Object, ByVal e As EventArgs)
FormsAuthentication.SignOut() Response.Redirect(Request.Path) End Sub Sub UpdateProfile(ByVal s As Object, ByVal e As EventArgs)
Profile.FavoriteColor = txtFavoriteColor.Text End Sub Sub Page_PreRender() lblUsername.Text = Profile.UserName lblFavoriteColor.Text = Profile.FavoriteColor End Sub </script> <html>
<head> <title>Anonymous</title> </head> <body> <form id="form1" runat="server"> <asp:Button ID="Button1"
Text="Login" OnClick="Login" Runat="Server" /> <asp:Button ID="Button2" Text="Logout" OnClick="Logout" Runat="Server" /> <hr /> <asp:TextBox id="txtFavoriteColor" Runat="Server" /> <asp:Button ID="Button3" Text="Update Profile" OnClick="UpdateProfile" Runat="Server" /> <hr /> <b>Username:</b> <asp:Label id="lblUsername" Runat="Server" /> <br /> <b>Favorite Color:</b> <asp:Label id="lblFavoriteColor" Runat="Server" /> </form> </body> </html> 列表10. Anonymous.aspx (C#) <%@ Page Language="C#" %>
<script runat="server">
void Login(Object s, EventArgs e)
{ FormsAuthentication.SetAuthCookie("Bill", false); Response.Redirect(Request.Path); } void Logout(Object s, EventArgs e)
{ FormsAuthentication.SignOut(); Response.Redirect(Request.Path); } void UpdateProfile(Object s, EventArgs e)
{ Profile.FavoriteColor = txtFavoriteColor.Text; } void Page_PreRender() { lblUsername.Text = Profile.UserName; lblFavoriteColor.Text = Profile.FavoriteColor; } </script> <html>
<head> <title>Anonymous</title> </head> <body> <form id="form1" runat="server"> <asp:Button
Text="Login" OnClick="Login" Runat="Server" /> <asp:Button ID="Button1" Text="Logout" OnClick="Logout" Runat="Server" /> <hr /> <asp:TextBox id="txtFavoriteColor" Runat="Server" /> <asp:Button Text="Update Profile" OnClick="UpdateProfile" Runat="Server" /> <hr /> <b>Username:</b> <asp:Label id="lblUsername" Runat="Server" /> <br /> <b>Favorite Color:</b> <asp:Label id="lblFavoriteColor" Runat="Server" /> </form> </body> </html> 当你打开第一个页面时,UserName的值是一个随机生成的唯一识别号(见图3)。当你按下Login按钮后,你就完成了身份认证,它是通过用户票据(User Bill)完成的。 图3 使用匿名和认证profile 列表10的页面中包含一个用于更新FavoriteColor的表单,要注意的是,在你登录登出的时候,会分别生成两个不同的profile。例如当你先登录,后登出的话,那么系统会生成一个随机的唯一识别号。 使用ASP.NET 2.0 Profile存储用户信息(5)——转自msdn在列表8中的Web.config包含一个从UserInfo类继承而来的profile,通过该声明,新的profile可以获得UserInfo类的所有属性。
列表 7. UserInfo (Visual Basic .NET) Imports Microsoft.VisualBasic
Imports System.Web.Profile Public Class UserInfo
Inherits ProfileBase Private _FirstName As String
Private _LastName As String Public Property FirstName() As String
Get Return _FirstName End Get Set(ByVal value As String) _FirstName = value End Set End Property Public Property LastName() As String
Get Return _LastName End Get Set(ByVal value As String) _LastName = value End Set End Property End Class
列表 7. UserInfo (C#) using System;using System.Web.Profile;public class UserInfo : ProfileBase{ private string _FirstName; private string _LastName; public string FirstName { get { return _FirstName; } set { _FirstName = value; } } public string LastName { get { return _LastName; } set { _LastName = value; } }} using System;
using System.Web.Profile; public class UserInfo : ProfileBase
{ private string _FirstName; private string _LastName; public string FirstName
{ get { return _FirstName; } set { _FirstName = value; } } public string LastName { get { return _LastName; } set { _LastName = value; } } } 列表 8. Web.Config <configuration>
<system.web> <anonymousIdentification enabled="true" /> <profile inherits="UserInfo" /> </system.web> </configuration> 迁移匿名Profile设置
Profile对象既可用于匿名用户也可以用于已认证用户。然而,当用户从匿名用户状态转换为已认证用户状态时,Profile对象能够以一种令人难以理解的方式完成任务。 当匿名用户使用Profile对象时,用户profile是与一个随机生成的号码相关联的,该号码是根据每个用户唯一生成的,它保存在浏览器的cookie中,无论何时该用户返回应用程序,该用户的Profile设置会被自动加载。 如果匿名用户通过认证的话,所有与该用户相关的profile就会丢失,同时系统会生成一个新的profile。这时该Profile信息将与用户名相关联,而非唯一识别号。 要想理解所有这些工作,最好的方法就是看看下面的例子。列表9中的web.config定义了一个profile,该profile只有一个FavoriteColor属性。 列表 9 Web.config
<configuration>
<system.web> <authentication mode="Forms" /> <anonymousIdentification enabled="true" /> <profile> <properties> <add name="FavoriteColor" allowAnonymous="true" defaultValue="Red" /> </properties> </profile> </system.web> </configuration> 使用ASP.NET 2.0 Profile存储用户信息(4)——转自msdn在列表5中有一点值得注意,那就是ShoppingCart和CartItem类都加上了可序列化的特性,这一点对于他们能否被序列化十分重要,只有这样才能保存在Profile对象中。
最后,列表6的页面显示了可以被添加到购物篮中的产品。购物篮是通过BindShoppingCart方法从Profile对象中载入,该方法把购物篮中的对象绑定到一个GridView对象上,这些对象可以通过ShoppingCart类的CartItems属性获得。 图2 在profile中存储购物篮 AddCartItem方法用于在购物篮中添加一个产品,该方法中包含了检测Profile是否存在ShoppingCart的代码。对于Profile中存储的对象,你必须自己实例化这些对象,他们不会自动实例化。
RemoveCartItem方法用于从购物篮中移除一个产品,该方法只是简单地通过调用Profile中的ShoppingCart对象的RemoveItem方法。 列表 6 - Products.aspx (Visual Basic .NET)
<%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load()
If Not IsPostBack Then BindShoppingCart() End If End Sub Sub BindShoppingCart() If Not Profile.ShoppingCart Is Nothing Then CartGrid.DataSource = Profile.ShoppingCart.CartItems CartGrid.DataBind() lblTotal.Text = Profile.ShoppingCart.Total.ToString("c") End If End Sub Sub AddCartItem(ByVal s As Object, ByVal e As EventArgs) Dim row As GridViewRow = ProductGrid.SelectedRow Dim ID As Integer = CInt(ProductGrid.SelectedDataKey.Value)
Dim Name As String = row.Cells(1).Text Dim Price As Decimal = CDec(row.Cells(2).Text) If Profile.ShoppingCart Is Nothing Then Profile.ShoppingCart = New ShoppingCart End If Profile.ShoppingCart.AddItem(ID, Name, Price) BindShoppingCart() End Sub Sub RemoveCartItem(ByVal s As Object, ByVal e As EventArgs) Dim ID As Integer = CInt(CartGrid.SelectedDataKey.Value) Profile.ShoppingCart.RemoveItem(ID) BindShoppingCart() End Sub </script> <html>
<head> <title>Products</title> </head> <body> <form id="form1" runat="server"> <table width="100%">
<tr> <td valign="top"> <h2>Products</h2> <asp:GridView ID="ProductGrid" DataSourceID="ProductSource" DataKeyNames="ProductID" AutoGenerateColumns="false" OnSelectedIndexChanged="AddCartItem" ShowHeader="false" CellPadding="5" Runat="Server"> <Columns> <asp:ButtonField CommandName="select" Text="Buy" /> <asp:BoundField DataField="ProductName" /> <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="ProductSource" ConnectionString= "Server=localhost;Database=Northwind;Trusted_Connection=true;" SelectCommand= "SELECT ProductID,ProductName,UnitPrice FROM Products" Runat="Server" /> </td> <td valign="top"> <h2>Shopping Cart</h2> <asp:GridView ID="CartGrid" AutoGenerateColumns="false" DataKeyNames="ID" OnSelectedIndexChanged="RemoveCartItem" CellPadding="5" Width="300" Runat="Server"> <Columns> <asp:ButtonField CommandName="select" Text="Remove" /> <asp:BoundField DataField="Name" HeaderText="Name" /> <asp:BoundField DataField="Price" HeaderText="Price" DataFormatString="{0:c}" /> <asp:BoundField DataField="Quantity" HeaderText="Quantity" /> </Columns> </asp:GridView> <b>Total:</b> <asp:Label ID="lblTotal" Runat="Server" /> </td> </tr> </table> </form> </body> </html> 列表 6. Products.aspx (C#)
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Globalization" %> <script runat="server"> void Page_Load() {
if (!IsPostBack) BindShoppingCart(); } void BindShoppingCart() { if (Profile.ShoppingCart != null) { CartGrid.DataSource = Profile.ShoppingCart.CartItems; CartGrid.DataBind(); lblTotal.Text = Profile.ShoppingCart.Total.ToString("c"); } } void AddCartItem(Object s, EventArgs e) { GridViewRow row = ProductGrid.SelectedRow; int ID = (int)ProductGrid.SelectedDataKey.Value;
String Name = row.Cells[1].Text; decimal Price = Decimal.Parse(row.Cells[2].Text, NumberStyles.Currency); if (Profile.ShoppingCart == null) Profile.ShoppingCart = new ShoppingCart(); Profile.ShoppingCart.AddItem(ID, Name, Price); BindShoppingCart(); } void RemoveCartItem(Object s, EventArgs e) { int ID = (int)CartGrid.SelectedDataKey.Value; Profile.ShoppingCart.RemoveItem(ID); BindShoppingCart(); } </script> <html>
<head> <title>Products</title> </head> <body> <form id="form1" runat="server"> <table width="100%">
<tr> <td valign="top"> <h2>Products</h2> <asp:GridView ID="ProductGrid" DataSourceID="ProductSource" DataKeyNames="ProductID" AutoGenerateColumns="false" OnSelectedIndexChanged="AddCartItem" ShowHeader="false" CellPadding="5" Runat="Server"> <Columns> <asp:ButtonField CommandName="select" Text="Buy" /> <asp:BoundField DataField="ProductName" /> <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="ProductSource" ConnectionString= "Server=localhost;Database=Northwind;Trusted_Connection=true;" SelectCommand= "SELECT ProductID,ProductName,UnitPrice FROM Products" Runat="Server" /> </td> <td valign="top"> <h2>Shopping Cart</h2> <asp:GridView ID="CartGrid" AutoGenerateColumns="false" DataKeyNames="ID" OnSelectedIndexChanged="RemoveCartItem" CellPadding="5" Width="300" Runat="Server"> <Columns> <asp:ButtonField CommandName="select" Text="Remove" /> <asp:BoundField DataField="Name" HeaderText="Name" /> <asp:BoundField DataField="Price" HeaderText="Price" DataFormatString="{0:c}" /> <asp:BoundField DataField="Quantity" HeaderText="Quantity" /> </Columns> </asp:GridView> <b>Total:</b> <asp:Label ID="lblTotal" Runat="Server" /> </td> </tr> </table> </form> </body> </html> 继承一个profile 你也可以通过从一个已经存在的profile类中继承一个profile来完成对profile的定义,这种特性能够帮助你在多个应用程序中使用相同的profile。 例如,列表7中列出了一个拥有多个用户属性的类,该类是从ProfileBase类继承而来的(你可以在System.Web.Profile中找到) 使用ASP.NET 2.0 Profile存储用户信息(3)——转自msdn列表4 Web.config
<configuration>
<system.web> <anonymousIdentification enabled="true" />
<profile> <properties> <add name="ShoppingCart" type="ShoppingCart" serializeAs="Binary" allowAnonymous="true" /> </properties> </profile> </system.web> </configuration> 列表5 中有一个简单购物篮的实现代码,该购物篮拥有添加和删除项(item)的方法(method),同时它还拥有两个属性(property),一个是用于获得该购物篮中的所有项的,一个是用于表示所有商品的总价的。 列表5 ShoppingCart (Visual Basic.NET)
Imports Microsoft.VisualBasic
<Serializable()> _
Public Class ShoppingCart Public _CartItems As New Hashtable() ' Return all the items from the Shopping Cart
Public ReadOnly Property CartItems() As ICollection Get Return _CartItems.Values End Get End Property ' The sum total of the prices
Public ReadOnly Property Total() As Decimal Get Dim sum As Decimal For Each item As CartItem In _CartItems.Values sum += item.Price * item.Quantity Next Return sum End Get End Property ' Add a new item to the shopping cart
Public Sub AddItem(ByVal ID As Integer, _ ByVal Name As String, ByVal Price As Decimal) Dim item As CartItem = CType(_CartItems(ID), CartItem) If item Is Nothing Then _CartItems.Add(ID, New CartItem(ID, Name, Price)) Else item.Quantity += 1 _CartItems(ID) = item End If End Sub ' Remove an item from the shopping cart
Public Sub RemoveItem(ByVal ID As Integer) Dim item As CartItem = CType(_CartItems(ID), CartItem) If item Is Nothing Then Return End If item.Quantity -= 1 If item.Quantity = 0 Then _CartItems.Remove(ID) Else _CartItems(ID) = item End If End Sub End Class
<Serializable()> _
Public Class CartItem Private _ID As Integer
Private _Name As String Private _Price As Decimal Private _Quantity As Integer = 1 Public ReadOnly Property ID() As Integer
Get Return _ID End Get End Property Public ReadOnly Property Name() As String
Get Return _Name End Get End Property Public ReadOnly Property Price() As Decimal
Get Return _Price End Get End Property Public Property Quantity() As Integer
Get Return _Quantity End Get Set(ByVal value As Integer) _Quantity = value End Set End Property Public Sub New(ByVal ID As Integer, _
ByVal Name As String, ByVal Price As Decimal) _ID = ID _Name = Name _Price = Price End Sub End Class 列表5 ShoppingCart (c#)
using System;
using System.Collections; [Serializable]
public class ShoppingCart { public Hashtable _CartItems = new Hashtable(); // Return all the items from the Shopping Cart
public ICollection CartItems { get { return _CartItems.Values; } } // The sum total of the prices
public decimal Total { get { decimal sum = 0; foreach (CartItem item in _CartItems.Values) sum += item.Price * item.Quantity; return sum; } } // Add a new item to the shopping cart
public void AddItem(int ID, string Name, decimal Price) { CartItem item = (CartItem)_CartItems[ID]; if (item == null) _CartItems.Add(ID, new CartItem(ID, Name, Price)); else { item.Quantity++; _CartItems[ID] = item; } } // Remove an item from the shopping cart
public void RemoveItem(int ID) { CartItem item = (CartItem)_CartItems[ID]; if (item == null) return; item.Quantity--; if (item.Quantity == 0) _CartItems.Remove(ID); else _CartItems[ID] = item; } }
[Serializable]
public class CartItem { private int _ID; private string _Name; private decimal _Price; private int _Quantity = 1; public int ID
{ get { return _ID; } } public string Name
{ get { return _Name; } } public decimal Price
{ get { return _Price; } } public int Quantity
{ get { return _Quantity; } set { _Quantity = value; } } public CartItem(int ID, string Name, decimal Price) { _ID = ID; _Name = Name; _Price = Price; } } 如果你把列表5中的代码添加到应用程序的App_Code目录中,购物篮会自动被编译。 使用ASP.NET 2.0 Profile存储用户信息(2)——转自msdn列表 2. Simple.aspx (Visual Basic .NET) Sub Page_Load() <html> </form>
void Page_Load() { <html> </form>
如果你多次访问列表2中的页面,你会注意到PageVisits在不断增大。如果你关闭的浏览器,并在一周之后调用该页面,PageVisits属性仍然会保留原值。从这一点可以看出Profile为每个用户自动保存一个副本。
尽管你仅可以为一个应用程序定义一个profile,但如果你需要让几个profile属性一起工作,把它们放在组中,会让你觉得它们更易管理。 例如,在列表3中,有一个带有两个组的profile,这两个组分别是Address和Preferences
列表3. Web.Config [Visual Basic .NET] Profile.Address.City = "Modesto" [C#] Profile.Address.City = "Modesto"; 使用复杂的profile属性 到目前为止,我们已经介绍了声明包含简单类型(如string或整型)属性的profile,其实你也可以在profile中声明复杂属性。
使用ASP.NET 2.0 Profile存储用户信息(1)——转自msdn概要:许多ASP.NET应用程序需要跨访问的用户属性跟踪功能,在ASP.NET1.1中,我们只能人工实现这一功能。但如今,使用 ASP.NET 2.0的Profile对象,这个过程变得异常简单。Stephen Walther将验证该对象,并向你展示如何使用Profile来跟踪用户属性、创建一个购物篮,及其他一些例子。 总目录 Microsoft ASP.NET 2.0支持被称为Profile的新对象,它可以自动在多个Web应用程序的访问之间存储用户信息。一个User Profile中可以存储各种类型的信息,这些信息既可以是简单的string和integer类型,也可以是复杂的自定义类型。例如,你可以存储用户的姓、购物篮、用户属性或网站使用情况统计。 User Profiles总揽 profile使用provider模式来存储信息,默认情况下,user profile的内容会保存在SQL Server Express数据库中,该数据库位于网站的App_Data目录。然而,在本文的后半部分,你将了解如何使用其他数据提供者(data provider)来存储信息,如完整版的SQL Server中的一个数据库或者一个Oracle数据库。 与Session不同,Profile是强类型的,Session对象仅仅是一个项集合而已,而profile对象则有强类型属性。
定义user profile 列表1 <configuration> <system.web> <authentication mode="Forms" /> <anonymousIdentification enabled="true" /> <profile> <properties> <add name="FirstName" defaultValue="??" allowAnonymous="true" /> <add name="LastName" defaultValue="??" allowAnonymous="true" /> <add name="PageVisits" type="Int32" allowAnonymous="true"/> </properties> </profile> </system.web> </configuration> 由于该profile需要同时被匿名用户和已认证用户使用,因此我们在web.config文件中增加包含一个< anonymousIdentification>元素,有了这个元素,系统就会自动为匿名用户生成唯一的ID。仔细看的话我们会发现,每一个 profile属性都有一个allowAnonymous特性,该特性表明这个profile属性是否允许被匿名用户使用。
默认的profile属性类型是System.String类型。列表1中,由于没有为FirstName和LastName这两个profile属性增加type特性,那么系统默认它们是string类型,而PageVisits属性则指定了type特性为Int32,因此该profile属性可用于表示一个整型值。 最后,注意FirstName和LastName属性都有defaultValue特性。你可以为简单的数据类型设置defaultValue特性,但你不能为复杂类型设置defaultValue特性。 [Visual Basic .NET]
Profile.FirstName = "Bill" [C#] Profile.FirstName = "Bill";
任何在web.config中定义的profile属性都会在Profile对象中呈现。
图1 使用简单的profile November 28 PetShop4.0 工厂模式及Profile Provider实现——转载,顺便帮助记忆以下第一部份:工厂模式 一、项目名称及描述:(实现步骤为:4-3-6-5-2-1) 三、实现步骤 注意: 第二部份:Profile的使用(也是工厂方法) 一、项目名称及描述 二、项目引用关系 三、实现步骤 注意事项: November 27 Because of You——Ayumi, 一首适合冬天听的歌:)今天又听了回Ayumi的歌,觉得暖暖的,大概其人也是那种给人以火热情怀的人吧:)
Because of You——Ayumi
目と目合ってそして言葉を交わした
胸が高鳴って笑顔で隠した 君を知らなかった頃に戻れなくなりそうで 風がもう冷たくなったね
笑い声が白く滲む 訳もなく泣けてくるのは 冬のせいかも知れない 出会った夜を
今でも覚えてる 目と目合ってそして言葉を交わした
胸が高鳴って笑顔で隠した 君を知らなかった頃に戻れなくなりそうで 少しずつ知っていくのに
急に全部わからなくなる 叫んでもいい
伝わるまで伝えて 会えない時間に想いが募った
届かない声に心が痛んだ 君を知らなかった頃に戻れなくなっていた どうかそんな風に
悲しげな瞳で 壊れそうに消えそうに笑わないで ねえ僕には何ができる 会えない時間に想いが募った
届かない声に心が痛んだ 君を知らなかった頃に戻れなくなっている どうして時々素直に言えない
どうして時々優しくなれない どうして時々傷つけ合ってる
どうして時々確かめ合ってる どうして時々こんなに苦しい
どうしていつでもこんなに愛しい 君じゃなきゃだめで 君じゃなきゃだめで ☆°.·∴終わる°★. ☆° ∴· November 25 高校本科评估,中国高等教育的一场闹剧——强贴转载我国高等教育改革畏缩不前、无所作为,甚至开倒车。尤其表现在近年来全国规模的本科教育评估等方面,用千篇一律、事无巨细的评估条款约束高等教育的手脚,对所有的高校采用相同的琐碎的、低劣模式进行评价,简直就是扼杀本来就缺乏生机的中国高等教育。 更为奇怪的是,二OO五年四月二十一日教育部公布了2004年接受评估的54所高校的评估结论:其中30所高校“优秀”、19所高校“良好”、5所高校“合格”。整个一个倒置的的金字塔,优秀的比良好的多,良好的比合格的多,不合格没有,中国高等教育果真好到这种“无可挑剔”的程度了吗? 其实,用不着列举太多的理由,大家都很明白,教育部评估标准出台在后,评估的时段在前(教育评估时间跨度是最近三年),要想让已成的事实符合“后生”的评估标准,只有造假一条路。我们可以毫不犹豫得断言,在这种情况下,能够在评估中获得“优秀”成绩的高校,无一例外都是造假高手,成绩良好的高校,也大多逃不过这种判断。 有些学校口口声声要“以评促建”,并要求所属院系必须确保本科评估万无一失,促使下属部门造假无所不用其极。而造假的结果是较高的评估成绩和更有保障的发展资源(资金、荣誉、生源等)。在这区区小利的感召下,在中国社会的良心地带,在二十一世纪的中国高校轮番上演了一场场有组织、有计划的、轰轰烈烈、名正言顺的造假运动。 曲阜某大学,据说他们有一届毕业生培养计划上的一门课没有开,为了补充上这些学生的这门课程的试卷,就安排下一届的学生造试卷,并且必须造出学校要求的分数,当然事先校方提供了标准答案。这种闹剧实在不在少数。某经贸大学,由于以前没有规定优秀毕业论文至少达到5000字,结果现在要求带毕业设计的老师,替学生把论文补足5000字。以前从来不给本科生上课的某些教授,通过“重建”文字档案,就被“造成”了每学年都给本科生上课的“标准”高校教师。 这就是教育部的本科教学评估活动产生的效应,中国大学是在传承知识、塑造后人吗,这不是在糟蹋中国的未来吗? 没有什么也不能没有骨气,中国教育界缺少的恰恰就是骨气。做人没有骨气,做事不用大脑,整个一个大脑注水。没有骨气、没有健康的人格,哪来的健康的学术和健康的文化。中国没有一流大学理所应当,如果万里有一,出了一个世界一流大学,那可就真奇了怪了。 面对本科教学评估中出现的种种怪现象,在小利面前,中国教育界表现出义无反顾地大脑集体注水、集体失语。呜呼,中国高等教育;呜呼,中国文化;呜呼,中国人。本科教学评估可以休矣。 高校本科评估,中国高等教育的一场闹剧! 我是一名高校教师。跟许多高校的教师们一样,正在为学校的“生存发展”奉献着一种奇怪的力量。因为国家教育部的普通高校本科教学评估专家组将于明年莅临我校。而我们已经从几个月前就开始了各种造假行动。 我们可以理解教育部关于教学评估的初衷,那一定是一个非常美好的愿望,而且我们知道,他们在每一次总结中也会让这种愿望变成一种“美好的”结果:那就是“以评促改、以评促建、以评促管、评建结合、重在建设”,为我国高等教育的规范、改革、创新、进步(等等诸如此类的“美好”修饰词)起到了促进作用,极大地推动了我国高等教育的发展,取得了丰硕成果……等等。而且我们还知道,教育部的领导们也都在被这种“伟大的成果”欢欣鼓舞着,并且将此作为自己的一项政绩,可以“载入史册”。 事实怎样呢? 离评估还有一年多的时间,我们的教师们已经开始夜以继日地工作了,而且工作的主要内容就是造假,原本没有的规章制度造出来,这一点似乎能体现出“以评促建”的宗旨,但是如果把原本没有的工作成绩造出来,把从未改革过的教学改革成果造出来,把从未搞过的学生座谈记录造出来,把没听过课的听课记录造出来,把没有过的教案、讲稿造出来……一切的一切,都要造出来,不是只造一份,而是要造三年的,每个学期都有一份(有的是几份)。如果仅仅是教师们夜以继日地造假也就罢了,学生们“为了学校的利益”也都轰轰烈烈地参与其中,评估要求有三年的试卷、作业存档,那就发动现在的学生答几年前的试卷,写上别人的姓名,老师在煞有介事地批改打分,几年前的试卷因此诞生。作业也是如此。 为了能在评估中取得比较好的成绩,学校各级各部门都非常重视,校长亲自挂帅,三天两头开会,在“一把手问责”制的重压之下,各学院、部系也都立即行动起来,纷纷到已经通过评估的学校学习造假经验,把握专家脉搏,于是,各种“经验”都在本校传播:某高校仅造假试卷一项就耗资20多万元;某高校连接待专家的司机都进行了培训,让他们说起学校的好处便头头是道;某高校学生每人一个手册,必须倒背如流,在专家组驻校期间,任何人只能按这一小册回答问题;某高校在课程安排上完全打乱原有的程序,让最好的老师在专家驻校期间讲课…… 一切为评估让路,评估是重中之重,谁在评估中出了一点问题,谁就是学校的罪人。 像一场大跃进,又像一场大浩劫,教师们苦不堪言,但还要“为了学校的利益”加班加点,唯有那些经历过文/革,平日无所事事的行/政人员目光如炬,似乎找到了温暖的感觉,“创造性”地想出各种对付专家组的招数,让教师们进行准备。实际的教学质量如何,已经无人问津,剩下的只有各种表格、各种总结、各种汇报材料……有的,要改成需要的样子,没有的,就要制造出来!大量的人力物力财力就在这场造假运动中消耗着。 然而,静下来想一想,我们在感到无奈的同时,更大的还是悲哀。尽管教育部说严禁在评估过程中造假,严禁为了迎评影响正常的教学秩序,然而,就如今的评估方法,可能不造假吗?可能不影响正常的教学秩序吗?而且,就已经评估过的高校来看,谁的造假水平高,谁就能得到优秀,谁能重视到“一切工作都让路”的程度,谁才能取得好成绩。 那些“专家们”看不出造假的痕迹还是睁一只眼闭一只眼?这个问题的回答或许出人意料,但是却非常真实:他们看的就是你造假的水平。因为提前通知学校要在一年后进行评估,并让你拿出三年间的所有东西来,就是给你时间来造假的。 那么,评估还有什么意义?就现在的方式,不仅无意义,而且贻害无穷。破坏了正常教学秩序不说,把学生们都纳入造假行列,这是怎样的罪孽?我们还如何教育学生诚实守信? 或许这样一次铭心刻骨的经历会消解掉我们所有的“育人”成果。 如果再往更深处探讨,我们不得不说,这是中国教育的悲哀,是中国知识分子的悲哀。如果所有的高校每5年(加上准备阶段只有4年)都要经历这样一次浩劫,几乎所有的在校本科生都会有一次经历,我们不是在集体教学生造假、应付吗? 尤令人悲哀的是,全国高校都在进行着这样的“浩劫”,从2004年迄今已经通过评估的高校已有几百所,却没有一位有影响的专家学者站出来,说出事情的真相,提出异议,这说明了什么?只能说明我们的知识分子已经丧失了正直的良心,已经没有了说真话 November 23 只因女婿是VB程序员,刚见面就被未来岳父轰出家门——转贴今天看了此文,深深庆幸自己是C#,Java两栖代码工:)呵呵
michael是一家科技公司的程序员,他好不容易找到了一个女朋友,趁假日与女友一同去会见未来岳父,在愉快的气氛中双方展开了对话
tom您好!我是michael!
Ohh,michael你好,听我女儿说你也是程序员,嗯,想不到我们是同行 呵呵,幸会幸会,还望前辈多多指教. 哪里哪里,先进来坐吧 michael,你什么时候来到上海的?
嗯,大概五年前 为什么要来这个地方? 嗯~~~~我想在这里应该会有更多人生的机会,更多的选择。况且上海是一个很有吸引力的城市。 tom:据说只要有四条腿以上,就有这个共识。老鼠和蟑螂如果能说话,恐怕他们也有相同的答案. michael自嘲一笑:对城管而言,街上四条腿不动的就有可能是一窝蟑螂。 两人会心一笑,tom忽然意识到自己坐着不动,于是给michael倒了一小杯酒,问:你的工作主要做什么? 指纹识别系统。 挺厉害的,都自己写? 不是,我主要是写外围的 让我猜猜,你是VB程序员? michael心里一惊:对,你怎么知道? tom回答说,请恕我直言,我建议你不要去学VB. 为什么?michael感到很奇怪 tom笑了一笑,如果你是城管,你最讨厌什么? 蟑螂~~~~~~?! 对! 这跟VB有什么关系吗? 当然有,谈到VB,你会想到什么? Easy,容易, Basic!michael回答说:可是不能因为VB简单就认为它是垃圾,这是语言上的种族主义! You are right! tom笑了笑,编程语言上的种族主义者固然有不少,但人们并不完全都是这样. 那是什么?michael不解的问 世界上每个城市都会有小贩,tom顿了一下说,VB是程序世界里的小贩,拉几个控件你就能做出一陀能用的播放器,满足用户的胃口。 michael忽然意识到tom想说什么,此类话语已听过不少,于是打断说:这不代表VB就是低俗的,VB也能面向对象,也可以构建大系统,小贩也有自己的人格,小贩也可能做成大商人. tom笑了一声,给michael倒满了酒,干杯! michael仍不服气的说,难道C#就很好吗?C#也能拉个控件做播放器,差别在哪里,前辈你给个指教! tom静静的听着:从学术上来说,VB和C#的在程序本质上没什么差别。虽然我们是第一次见面,但我认为,这应该是最后一次见面了! michael大惑不解:为什么?难道仅仅因为我是VB程序员吗? tom:可以这么说。 michael嘲讽的笑道:哈哈,想不到你作为前辈居然是这么浮浅!....无语! tom:你想知道为什么吗? 为什么? tom:你为什么不问问自己为什么学VB呢? michael:因为VB容易学,可是容易学并不是一个罪名 tom:对,的确不是罪名,但可以说,学VB的人基本上属于自私的功利主义者. michael:啊?不会吧? tom: 为什么有人要学VB?是因为有人不想付出太多就想得到回报,我说得对不对? michael:呃!不对!有些人是因为条件限制,基础太差所以才学VB! tom: 事实上,学VB的只有两种人,一种是功利主义者,一种是水平差的人。所以,用VB的基本上都是程序界的垃圾,这个结论可否正确? michael:前辈,你这么说我不客气了!老板直接给员工下指令就能得到代码,这么说的话,老板不就更垃圾? tom: 呵呵,员工的工作是制造代码,老板的工作是得到代码,混淆这一点,并不能说服我。 michael: 即使我是功利主义者,这也不是我的错,而且我并不自私! tom: 你如何知道你不是自私者?学了VB就是加入了自私者的俱乐部!简单来说,开源世界里有各种各样的代码,但它们绝大多数是perl,php,c/c++/java/c#的C体系写出来的,VB写的开源软件很少!原因很简单,学VB的动机源自功利主义,只懂享受不懂付出,所以说,学VB的都是以自私的人为主,对世界毫无贡献。 michael: 前辈,认清现实吧!这个世界不需要理想主义者!只有功利主义者能生存!况且我们成为功利主义者也是被老板所逼! tom: VB程序员喜欢找理由欺骗自己和别人,例如被老板所逼,其实他们就像拉磨的驴,前面挂一个胡萝卜就能让他们团团转,原因很简单,他们很贪婪,越想快点得到好处就跑得越快,他们认为自己聪明,事实上他们还是驴。因为贪婪,所以他们选择VB michael: 可是我们才刚见面,你怎么知道我就一定是这样的人呢? tom: 我们素未谋面,我却可以一眼看清你的本质,原因很简单,我是C#程序员,从C家族一路走来,我们身经百战,坚持正直和真理,所以我们改变了整个世界。而VB程序员自私,功利,短视的本质特点却从未有过变化,VB一直被这个世界所改变,像蟑螂一样苟且偷生。所以,一个人学什么语言就知道他属于什么样的人 michael:啊~~ belly: michael,我们分手吧! michael:难道仅仅因为我是VB程序员? belly: 对不起,michael,我只相信C家族的程序员! michael: 这不能成为一个理由! belly: 你知道有品味的女孩都只找C#程序员!我不合适你! michael: 我发誓再也不用VB了!5555555555555555555~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ November 22 雷德·奥尔巴赫[1917-2006]:红衣主教,邪恶的父亲,或者黑暗中的帝王特此转贴,表达我对死者的崇敬之情. 死者的名字叫做雷德·奥尔巴赫。2006年10月最后一个周六,这个老头永远熄灭了他的雪茄。与整整四十年前,1966年的夏天,他那光辉的引退不同,这一次,这个庞大的阴影,邪恶的帝王,黑暗的老头,是真的如四十年前畏惧他、诅咒他的人们所言,离开了这已被他征服与厌倦了的世界。 传说海森堡提出不确定性原理时,曾经为自己设了一个墓志铭。“他躺在此处的某个地方”。借用这个格式,雷德·奥尔巴赫,红衣主教,雪茄教练,老怪物。无论你怎么称呼他,对他而言,也许最适合的祭奠是将墓碑立在波士顿花园,立在16面冠军旗帜下。在墓碑上书写“他躺在花园的某个地方”。或者,套用被他击败过无数次的湖人主教练的名言:“我恨不能把那雪茄塞进他喉咙里。” 1994年,湖人与凯尔特人,这两支NBA总决赛史上最常见的佳客在为挂了16面冠军旗帜的波士顿花园进行了最后一战。然后,凯尔特人队搬去了北岸银行球馆。想象一只戴满戒指的手悄然关上了门,挥别了过去的盛世华年。彼时的雷德·奥尔巴赫笼罩在雪茄的烟雾之中,生活在波士顿凯尔特人那些令人恐惧的录象带里,生活在NBA专家们孜孜不倦书写的传记里。在马路上溜达时,没有人会知道从他们身边擦过的这个175公分高的老头,是遍布美国的、各类大幅宣传海报所标榜的,世界上最好篮球联盟的历史上,最为可怕的统治者。 11月1日,NBA的2006-07季开始的那一天,奥尔巴赫在华盛顿下葬。那些帝王级的巨星们——鲍勃·库西、比尔·拉塞尔、凯文·麦克海尔——看着这个对他们吼叫了一生的老人埋入黑暗的大地。为他送葬的有大约150人——很符合他的生涯。你要知道,在他带领波士顿不知疲倦年复一年拿下冠军时,波士顿花园都几乎没有坐满过。 华盛顿 很多人会遗忘奥尔巴赫在华盛顿的一切。1946年,这个俄罗斯移民的后裔年满29岁,他周围的世界经历了一战——那时他在襁褓中——大萧条和二战。那是一个五光十色、旋转、梦想破灭而又重建、迷惘的一代开始变老的年份,欧洲还是废墟,而美国人经历了战争,开始希望找些乐子。那时的NBA还是一个没有24秒限时、三秒区狭窄、全白人运动员、没有三分球、法尔克斯以场均30%的命中率和不足24分的场均得分拿到得分王的篮球联盟。 而奥尔巴赫就是这样开始的。他领着华盛顿国会队开始了执教生涯。那时的他已经显露出后来波士顿传奇的一部分性格——一个犹太人对金钱的敏感,精力充沛,性格粗暴,现实主义。华盛顿国会队是一支强队——60年后身在中国的我们当然对此没什么感知——但奥尔巴赫在国会的三年中,华盛顿两次拿到常规赛分区首位,一次常规赛冠军。1948-49季,国会队甚至进入了总决赛。在那里,奥尔巴赫遇到了他一生的夙敌。明尼阿波利斯湖人队依靠着NBA史上第一个超级中锋乔治·麦肯解决了国会队。 我不知道175公分的奥尔巴赫看到208公分的麦肯统治篮球场、蹂躏国会队时的想法。那是奥尔巴赫第一次接近成功的颠峰——即使那时NBA总冠军并不如现在那样有百余个国家的媒体会予以关注——但他被彻底的击败了。一个完美的、泰坦一般的巨人,带领着湖人击败了奥尔巴赫。这像一个意味深长的预言和伏笔。 乔治·麦肯没有等到奥尔巴赫击败他的那一天就退役了。在明尼阿波利斯寒冷的球馆里,那巨大的影子给予了奥尔巴赫某一些指示。湖人队主教练昆德拉是NBA史上第一个名帅。有舆论认为他并不具有才华,仅仅依靠着麦肯、波拉德等名将才能够拿下五个总冠军。但奥尔巴赫对昆德拉的评价是:“许多纸面上强大的球队,他们一无所获。而昆德拉,他使湖人队成为了一支强大的球队,他为此完成了伟大的工作。” 记住这段话的关键词,那是奥尔巴赫为数不多的失败后,给予他对手的褒扬中最重要的部分:球队。 库西、沙曼和24秒 1950年,凯尔特人请来了奥尔巴赫,而33岁的他很不情愿的接受了鲍勃·库西——凯尔特人在一次抽签中失去了一个高中锋,得到了185公分的、以杂耍般的绚丽运球与精美传送著称的白人后卫。奥尔巴赫这样说:“我并不想贬低谁,无论是库西还是其他人。我只关心能力,而鲍勃还没有向我证明他的能力。我绝不会因为他是本地人就做出选择。库西花哨的球风所能带来的观众不会超过12个。真正能不断吸引观众的是一支总能获胜的球队。这也是我的目标……” 这是他一贯的语言风格,简单,直接,独裁甚至粗暴。从这一年开始,在极漫长的岁月里,波士顿花园中就只有这一个独裁者的声音。 1954年夏天,乔治·麦肯退役,湖人王朝结束。也就是在这年秋天,NBA开始实行24秒限时。巨大而缓慢的中锋们受到了限制。奥尔巴赫敏锐的抓住了这一点。精于计算的犹太人脑子里先于其他所有人的判断出了未来世界的走向。凯尔特人队拥有两个185公分高的白人后卫,8届助攻王的鲍勃·库西和11年内7次荣膺罚球命中率王的神射手比尔·沙曼:他们的身上浓缩着凯尔特人——毋宁说是奥尔巴赫——的哲学:传递,智慧,投射。 奥尔巴赫比同时代的任何人都了解篮球这项运动——这个175公分高的白人在场边呼啸怒骂,像愤怒的骑士驱驭着他的骏马,而库西、沙曼在他的吼声中闪电般奔向对方的篮筐。库西的存在使凯尔特人获得了观众的青睐,但奥尔巴赫的怒吼又显然会使一些观众反感。而当50年代的观众看到这个教练居然大逆不道的从选秀大会上摘来了黑人运动员,而且喝令这些黑人上场比赛,与白人同场竞技,他们只能瞠目结舌。马丁·路德·金要到1968年才发表《我有一个梦》的反种族歧视宣言,而在十几年前,奥尔巴赫已经在冒天下之大不韪的任用黑人。对这个犹太人而言,也许没有任何事比现实和数字更重要。他的眼里从来没有肤色之分。他像一个商人,一个棋手,一个将军,一个玩拼图游戏的孩子一样编织着一支球队——那支像昆德拉曾经带领过的所向披靡的湖人队一样,强大的球队。 那是50年代。苏联在筹划载人宇宙飞船,艾森豪威尔继续对欧洲的援助,猫王出了他第一张唱片,海明威作为一战“迷惘的一代”的代表拿下诺贝尔文学奖,美国人开始收看黑白电视机。而奥尔巴赫,这个固执的步入中年的家伙,将他的妻子和两个女儿扔在华盛顿,废寝忘食、不知疲倦的筹划着他的王朝大梦。他的狂热能够令球迷、裁判和NBA的官方都感到惊讶。他洞烛先机,身体力行,坚决的相信自己,并且使凯尔特人队成为他意志的一部分。 他只关心胜利,关心胜负表上的数字。 凯尔特人队开始蜕变成一种可怕的植物,他们缄默、坚韧,蓬勃生长,一如他们的球衣一样生生不息。波士顿花园成为了一个巨大的怪物森林,而奥尔巴赫是那里的魔鬼领袖。他咄咄逼人的呵斥裁判和对手,愤怒的朝那些比他高一个头的职业球员挥舞拳头,吐出脏字,随时鼓励队员,手舞足蹈的指挥着凯尔特人的进攻浪潮。 以及,做出胜利的预言。 预言的实现 1956年,奥尔巴赫说:“我们马上就要有一个人来改变一切了。” 在此之前,他已经拥有了罗斯库托夫、沙曼、库西、拉姆西等球员。1956年夏天,他选中了汤姆·海因索恩和KC琼斯。而受他嘱托、寻找伟大中锋的莱因哈特给出了一个答案:一个206公分高、进攻能力极不完善的家伙。而明尼阿波利斯湖人队正在争取他。 奥尔巴赫果决的——就像此后几十年他反复做的一样——运用手腕得到了这个年轻的中锋。他那时也许并不知道这会在多大程度上影响时代的走向。而我们在多年以后的历史年表上记下这个名字,比尔·拉塞尔,凯尔特人队6号。 “我们马上就要有一个人来改变这一切了。” 这是库西的回忆。他说他看到了一个高大、黝黑、结实犹如山峰的巨人。这个人像一只大蜘蛛一样紧跟着每一个切入者,在对方投篮时把球盖下来——他经常在比赛里的前5分钟盖掉3个投篮。而2006年NBA的盖帽王每场比赛也差不多是这个数字——然后球落在库西的手里。“接下来,就是著名的波士顿快攻。” 而奥尔巴赫如是评价拉塞尔: “他很特别,因为他反应奇快,而且聪明;他不会被人连续骗过两次。他还有完美的长臂,他热爱防守。和那些爱得分的大个子们完全相反;拉塞尔更喜欢队友去投篮。” 比尔·拉塞尔在他的职业生涯场均22.5个篮板,而他的每次盖帽和篮板便是凯尔特人快攻的第一刀。奥尔巴赫在这个年轻人到队的第一天便告诉他,安心防守和抓篮板,他的得分数据不会影响到他签合同时的工资数额。从那一天开始,拉塞尔成为了另一个奥尔巴赫——一个骄傲的、凶狠的、除了胜利之外对其他任何事都不关心的机器。 胡比·布朗——如今已年过七十的前灰熊主教练——说: “拉塞尔作为伟大的后盾,奥尔巴赫可以打出他所喜爱的比赛---快攻,防守。他们的比赛组织有序,你知道,保持优秀的表现有多么困难,所以我感觉奥尔巴赫有激发每个球员潜力的能力---他知道如何驱动他的球员,让他们对球队有所帮助。而且看起来这种能力随着一批批球员的变更而不断流传下来。 这是宿命的相逢。如果没有彼此,奥尔巴赫和拉塞尔可能都无法如今天般名垂后世。1956-57季的冬天,拉塞尔加入球队,凯尔特人队成为了一个恐怖的怪兽——所有的球队面对着堡垒一般屹立的拉塞尔,被闪电般的沙曼、库西掩袭,被拉姆西、海因索恩等追杀。而奥尔巴赫在场边持续吼叫着,喝令着他的队员们对对方予以毫不留情的残忍打击。 NBA的其他球队一度联名向官方申诉,认为拉塞尔的盖帽属于非法干扰球。当然,奥尔巴赫寸步不让的与他们论争,然后毫无悬念的获得了胜利。他比任何一个人都了解规则。他能带着规则手册,拍在联盟官员的面前,用一通雷鸣般的怒吼来给他们上课,把他们训得像胆怯的小学生。 1957年夏天,凯尔特人队杀入总决赛,对上了鹰队。而奥尔巴赫对上了秃鹫汉纳姆。拉塞尔对上了11年10度NBA第一阵容的史上最强前锋之一佩蒂。比赛战到第七场,凯尔特人队在波士顿花园依靠拉塞尔的19分32个篮板和海因索恩的37分23个篮板,125比123险胜了鹰队,拿到了他们队史上的第一个总冠军。奥尔巴赫的预言实现了。这些年轻人在更衣室里狂洒香槟,庆祝他们第一次登上颠峰。 而他们都没料到——我猜想奥尔巴赫也没有料到——这仅仅是波士顿花园魔咒的开始。 王朝 1957-58赛季,汉纳姆的鹰队夺回了总冠军。但秃鹫教练随即痛心疾首的发现,NBA进入了历史上最癫狂、最荒诞、最匪夷所思的一段时间。 在那个灰暗、破旧的波士顿花园的地板上,年复一年奔跑着拉塞尔和他的凯尔特人们。有人离开了。1961年,总决赛,沙曼对上了湖人的44号,未来的湖人教父,NBA商标的运球剪影杰瑞·韦斯特。他拿下了自己的第4个冠军戒指,没有给韦斯特、罗伯特森、格里尔们打败他的机会,作为那个时代最冷静的射手离开赛场。1963年,总决赛第六场,凯尔特人112比109领先湖人,拉鲁索、韦斯特、贝勒们满场追袭,库西俯下身体,用他令世界称羡的姿态,用奈史密斯规定过的合法运球动作,不断拍打着皮球,在硬木地板上穿梭,逃脱无数抢断的魔爪,让凯尔特人取下他们连续第5个总冠军。在这些人来人往的浪潮中,唯一不变的是奥尔巴赫的怒吼、对裁判的絮叨,以及那每逢胜利便点燃的雪茄——那几乎成为了他的一种仪式。 凯尔特人像一发不可收拾的机器,像闯进瓷器店的野牛,像蓬勃生长无法抑制的食人植物,像刹车失灵的火车。波士顿花园常年空着5000座位,而在座的8000人,则观看到了不可思议到了荒诞地步的一切。奥尔巴赫带着他的队员们坐着火车满美国的奔驰去追逐胜利,每年夏天就像守纪的学生一样准时出现在总决赛赛场,然后以令人厌倦的程序击败对手。“有一次,我们差点把那该死的雪茄掐灭了。”湖人队的某位主教练说。“我恨不能把那雪茄烟塞进那家伙的嗓子眼里。”另一位失败的教练说。“我愿意用我所有的得分来换取这最后一投。” 1962年总决赛第七场错失最后制胜球的湖人队员塞维说。这样的语录你可以列三天三夜。在NBA的其他人眼里,奥尔巴赫是魔鬼,是邪恶的化身。他就像一个科学怪人一样复制着胜利和冠军。从1959年夏天开始,连续8年。 波士顿人甚至没有理解他们身旁经历的奇迹,凯尔特人队寂寞的征服着一切。奥尔巴赫不讲情面、不讲道理、几近贪婪的吞噬着他的对手们。拉塞尔、琼斯、海因索恩们像机器的零件,各司其职年复一年的蹂躏着对手们。他们传递、协作、防守、投射、控制篮板、投中关键球,夺冠,倒香槟。他们除了胜利外什么都不想。他们人人都成为了奥尔巴赫。 我知道以下的记录会让你感觉腻味——但还是看一看吧。因为NBA的球员们在这样单调的过程中,度过了8年——8年,甚至是许多球员的整个职业生涯。 1959年,凯尔特人4比0复仇,击败鹰队夺冠。1960年,又是鹰队。拉塞尔在总决赛第七场独得22分35个篮板,蝉联总冠军。1961年,凯尔特人和鹰队连续第五次会面总决赛,4比1解决战斗。1962年,对手换了。湖人队站到了凯尔特人的对面,并在总决赛一度3比2领先。但凯尔特人单调的继续着胜利,第七场通过加时赛110比107击败湖人夺冠。1963年,凯尔特人4比2解决湖人,连续第5个冠军后,奥尔巴赫已经成为全美国的公敌,招致了所有对手以及球迷的仇恨。然而,1964年,他继续扼杀着悬念,4比1解决了鹰队,连续第6冠。以至于人们开始讨论凯尔特人队是否将永远夺冠下去。1965年,凯尔特人险些败北。东部决赛对费城的比赛中,史上最伟大中锋拉塞尔对上张伯伦。第七场最后5秒钟,凯尔特人以110比109领先,而张伯伦趁拉塞尔失误截获皮球。此时,年轻的替补白人后卫哈夫利切克闪电般出手断球,保证了凯尔特人的胜利,这一断也成为史上独一无二的经典断球。稍后的总决赛,奥尔巴赫没有让意外发生,4比1解决了湖人。1966年,凯尔特人队开始疲倦。奥尔巴赫在季后赛来临之前宣布,他在本季结束后将辞去主教练职务,专心球队管理,而继任者拉塞尔会成为美国各大体育联盟里第一个黑人主教练。士气昂扬的凯尔特人队在总决赛再逢湖人队。不知道是第几次了——第七场,凯尔特人队以95比93险胜,连续第八个冠军。 枯燥的数字背后是令人瞠目结舌的八座冠军奖杯,以及无数的第七场生死战。对于凯尔特人而言,在那八年时间里,失败这两个字是不存在的。奥尔巴赫痛苦的撕扯头发,或者大声的吼叫,驱动着凯尔特人惯性般不断夺冠。波士顿花园像被魔咒封印过,完全没有失败的可能。对其他队而言仿佛走钢丝一般的第七场,对凯尔特人来说就像胜利的普通过场一般容易。奥尔巴赫戴上他十年内第九个冠军戒指,那时他还不满50岁。 八连冠的王朝之师是一支怎样的球队?翻开记录本,我们能看到许多匪夷所思的数字。60年代是一个怎样的年代?埃尔金·贝勒在1962年总决赛里一场拿到61分,张伯伦在1962年3月2日对纽约时拿到100分,在那个赛季平均每场得50.4分。奥斯卡·罗伯逊在同一季场均30.8分12.5个篮板以及11.4个助攻的赛季三双记录。埃尔金·贝勒和杰瑞·韦斯特每个赛季的每场合力为湖人贡献平均接近60的得分。而凯尔特人队,甚至都很少有场均得分达到25的人。奥尔巴赫不允许他的队伍里有自私的现象,不允许任何独断专行——他自己除外。 时至今日,人们会回想起凯尔特人王朝的那些冠军成员——善于打板投篮的萨姆·琼斯,力扛联盟里任何一个前锋的汤姆·海因索恩,8届助攻王鲍勃·库西,神射手比尔·沙曼,5届联盟MVP比尔·拉塞尔,史上最佳的第六人哈夫利切克。这些人都已踏入名人堂,并在NBA 50周年之际被选入NBA最伟大的50名球员之列。有人说是他们成就了奥尔巴赫。但实际上,这些球员并非天资卓绝。奥尔巴赫的眼光精准独到,绝不会偏漏。他选择球员的标准并非这个人能得多少分,能做多少漂亮的动作。奥尔巴赫需要渴望胜利、愿意为了胜利牺牲一切的人。然后,他就让他选择的这些球员身陷地狱。即使是比尔·拉塞尔这样的巨星,一旦需要也会遭到这个矮老头毫不留情的斥责。就是在奥尔巴赫近于神经质的捏合和淬炼之中,凯尔特人队低调而乏味的年复一年摘取冠军。 约翰·哈夫利切克回忆起他第一次去到凯尔特人队的球馆训练时,紧张得说不出话来。而当时已经满手戒指的比尔·拉塞尔,NBA史上最伟大的中锋之一,走过来拍着他这个新人的肩与他交谈,并且约定训练结束后陪他一起去买辆汽车。在经历那次神鬼莫测的断球后,哈夫利切克作为凯尔特人的第六人为人们所知。这被一些人称颂,认为哈夫利切克是第一个也是最好的第六人。他是奥尔巴赫第六人战术的第一个完成品。但在另一些历史资料里,人们则被告知:奥尔巴赫没有发明第六人的打法。他仅仅是不知疲倦的向媒体记者——那些只知道鼓吹库西、沙曼这类白人球星的家伙们——宣传拉塞尔这样的黑人巨星,宣传拉姆西这样的第六人,宣传凯尔特人队所有的球员。久而久之,凯尔特人队的任何一个人都没有感觉到冷落和偏颇。他们意识到自己是团队的一部分,并且深深为自己的冠军成员身份而骄傲。 而在其他人眼里,奥尔巴赫就不是那么可亲可敬了。一个有趣的事实,至高无上的他,只在1965年当选过一次NBA的年度教练。论他与NBA官方的唇枪舌剑,利用媒体推波助澜打心理战的能力,现在的小牛老板库班与他一比简直就是小学生。在教导一些新入行的教练时,他又直言不讳的训诫说,要尽量的站得靠近技术台,要尽量大声的对裁判发出不满的声音,最大程度的影响裁判。由于他的胜利、顽固、粗暴和桀骜不逊,所有败在他脚下的人都渴望着击败他。然而,一年过去,两年过去,三年过去,八年过去。波士顿花园的冠军旗帜一面连着一面高高挂起。每当有人来到花园比赛,抬起头就能看到那些冠军的象征——那是至高无上、屡屡征服世界的战利品,也是所有那个时代的强者们灰溜溜败北的刺眼伤疤。 1966年夏天,奥尔巴赫在8连冠的典礼上信守诺言,将主教练的位置让给了比尔·拉塞尔,而他自己改任凯尔特人队的总经理,开始退居幕后。从50年代中期覆盖NBA的巨大阴影转过身来,悄然离开。就像一个老去的帝王交出了权杖,而俯跪的人们,只听到他的足音,孤独的响遍甬道,通向黑暗的幕后。 教父 奥尔巴赫离开的那一年,继任者拉塞尔并没有能够延续王朝的光荣。曾经多次败在奥尔巴赫手下的前鹰队主教练汉纳姆去到了费城,执教张伯伦、康宁汉和格利尔们。张伯伦做出了巨大的牺牲,之前可以赛季场均得50分的他在1966-67季场均得分只有24分。但在张伯伦向拉塞尔转型的这一年,76人队打出68胜的空前战绩,并最终在东部决赛里击败了那十年来不可一世的魔兽,总决赛击败勇士后问鼎冠军。60年代的第7年,冠军终于不是凯尔特人队了。 “他们打的正是过去十年我们打的那种篮球。”凯尔特人队的KC琼斯如是说。 奥尔巴赫的离开与凯尔特人的失败似乎有着某种必然,而被奥尔巴赫的铁腕统治了十年的NBA各队感觉阴霾散去,那笼罩着他们的凯尔特人巨树似乎枝散叶落。1967年秋天开始,在美国的各个球馆里,球迷们对着拉塞尔和偶尔随队出征的奥尔巴赫——那曾令他们恨不能食其肉寝其皮的家伙——高唱:“波士顿完啦,波士顿完啦,王朝已被灭亡。” 然而,1968年的春天,整个美国发现他们空欢喜了一场。帝王的远去不过是假象。那个老头隐身在黑暗之中,垂帘听政,继续操纵着那支由他一手打造的怪兽球队,面无表情而又不可阻挡的逼近王座。 整个NBA在1967年的心情,就像经历一次漫长的洪灾之后看到了晴天。然而,在1968年,他们发现黑云重新布满了天空。凯尔特人队用12年内第10个总冠军告诉人们76人的奇迹不过是意外。然后,1969年,老迈的凯尔特人队,被仇恨的凯尔特人队,奥尔巴赫的阴影覆盖的凯尔特人队,用一种最典型的奥尔巴赫方式——总决赛,对湖人,第七场,108比106,解决。13年内第11个总冠军,结束了60年代。 1969年,横贯王朝历程的拉塞尔在夺冠后退役,而奥尔巴赫则在总经理的位置上,继续吞吐他的雪茄,并且用他敏锐的目光发现球员、编织球队。在混乱的70年代,没有哪支队伍卫冕的70年代,凯尔特人队依靠着奥尔巴赫提拔的考文斯和长期培养的哈夫利切克,又拿到了两个总冠军。 当然,仅仅如此便不是奥尔巴赫的手笔了。 1979年,63岁的老头找到了他需要的王子,以继承他当初一手创制的光荣。他,奥尔巴赫,NBA史上第一个用全黑人首发的反种族歧视者,在1979年的选秀大会上,以第6位选了一个在印第安纳大学打了4年球的,既跑不快又跳不高的白人。根据他自己的说法,他只看过这家伙的一场球。 这个叫做拉里·伯德的白人在他退役时被认为是NBA史上最伟大的前锋,而奥尔巴赫的慧眼则令1979年手握2、3、4、5位选秀权的球队们追悔莫及——唯一的例外,那年状元是湖人队选中的魔术师——在他入队第一年他就成为了当季的第一阵容成员。再次出现这种事是在17年后,马刺的蒂姆·邓肯上演了类似的例子。与邓肯一样,伯德在入行的第二年就带领球队获得了总冠军。 1980年6月9日,奥尔巴赫又一次——三十多年里他已经做了多少次类似的狡猾勾当——做了一桩可怕的交易,这甚至为他赢得了一个“强盗”的美名。他用该赛季的第1和第13号选秀权从金州勇士换来第3号选秀权和罗伯特·帕里什,而后在第3顺位点中明尼苏达大学的前锋凯文·麦克海尔。从这一刻开始,凯尔特人80年代的三驾马车就聚在了一起。奥尔巴赫在一笔交易和一次选秀中,就决定了凯尔特人此后十年的辉煌,以及湖人队、76人队、活塞队煎熬的命运。 不测 在雨果《悲惨世界》的《滑铁卢》卷里,拿破仑的骑兵冲向圣约翰山的英国人。当时威灵顿与拿破仑都已经接近灯尽油枯,而优势在法国人那里。然而,骑兵们的面前出现了一条深沟,措手不及的法国骑兵集体掉入沟壑。这使拿破仑的攻击受挫。而就在此不久之后,普鲁士人的援军出现在地平线上。 许多时候,扭转战局和情势的不是风头转向的那一刻。一匹骏马在受伤后持续奔跑,最后无法支撑的倒下。命运早在他受伤时即已注定。某一个不测,某一个厄运的出现,会成为命途不为人知的转捩点。 1986年,奥尔巴赫企图为伯德领衔的凯尔特人队继续添砖加瓦。他巧妙的取到了一个榜眼选秀机会,并选到了——我们必须相信他的眼光——一个天才球员,比阿斯。就在中选的几小时后,这个天才,这个被幻想为未来天王巨星的孩子,这个本应为凯尔特人未来王朝博取荣誉的人物,死于可卡因中毒。 没有什么比这种事更打击一个年近古稀老人的心绪了。 伯德和麦克海尔在90年代初退役,帕里什辗转各队,1997年43岁时在新的王朝公牛结束职业生涯。而年过70的奥尔巴赫在比阿斯死后,终于开始像一个老人了。1993年,另一个厄运到来,凯尔特人队的队长刘易斯在训练中猝死。 接着,就是波士顿花园的搬迁,以及凯尔特人队的沦落——那时,奥尔巴赫已经离开。 “我没有工作的动力了。”他说。 桃李 1997年,80岁的奥尔巴赫参加了NBA50周年活动,NBA50周年50大伟大球员里,有8个是凯尔特人队的——理所当然是他的弟子。但那远不是全部。 1961年总决赛,沙曼对上湖人队的韦斯特。十年后,沙曼成为了湖人队主教练,并且带领张伯伦、韦斯特这些凯尔特人队的手下败将,打出了69胜的成绩,使湖人队取得搬到洛杉矶以后第一个总冠军——听上去有些讽刺,带领湖人夺冠的居然是一个屡次击败他们的人。 1969年总决赛第七场,凯尔特人队依靠后卫唐·尼尔森的一个中投击败湖人,夺下13年内第11个总冠军。而唐·尼尔森如今已经是NBA史上最伟大的教练之一。和奥尔巴赫一样,这个老头激进、昂扬、好胜,永不停布。 1993年与公牛决战于总决赛的太阳队主教练韦斯特法尔是凯尔特人队出身;1995年身为狼队总经理第5位选中加内特使狼队腾飞的总经理麦克海尔是凯尔特人队80年代功勋前锋;1996-97季带领黄蜂队打出队史最好成绩差点当了年度教练的戴夫·考文斯是奥尔巴赫钦点来代替拉塞尔的70年代凯尔特人栋梁;4度问鼎总冠军的教练KC琼斯是奥尔巴赫的第一代弟子;拉里·伯德1997-98季首度当主教练便拿下了当年最佳教练头衔…… 奥尔巴赫的影子布满了联盟。在他退出NBA这个舞台十多年后,你依然可以感觉到他的存在。从东海岸到西海岸,他的弟子效仿着他,效仿着某些凯尔特人精神。某些顽固的不被岁月改变的东西,在无声无息的流传。 红衣主教 直到他离开了那个王座,他带来的荣耀和声名依然悬挂在波士顿球迷的上空。波士顿的主场如今比奥尔巴赫当年夺冠要热闹得多,但球迷们却永远不会满意——这是自然的,因为奥尔巴赫手制的奇迹已经空前,而且完全可能绝后。他们朝如今的凯尔特人队,朝皮尔斯、戈麦斯们喊叫着,企图指正他们的打球方式。他们只有一种审美方式,那就是奥尔巴赫式的风格。那是根植入凯尔特人历史的,阴魂不散的精神。 凯尔特人这个词,源起于那些古代生活在民族,如今,高傲、倔强、崇尚绿色的爱尔兰人、苏格兰人,依然在讲凯尔特语。名如其队。奥尔巴赫贯穿了凯尔特人队的历史,他将高傲、倔强、执拗,以及硬木一般坚实的力度灌进了每一个凯尔特人的骨髓。从50年代开始,他对篮球的理解就先于所有人: 挑选有求胜欲望的球员;像拼图和下棋一样配置队伍;让队伍——不仅在场上,而且在生活中——成为一个牢不可破的整体;防守、速度、技巧和智慧至上;无私。 于是,有整整40年的时间,凯尔特人队在绿色的波士顿花园跳着节奏鲜明、质朴坚韧而又高贵的集体舞。 长虹经天般优美的投射弧线。寒带森林一般密集坚硬的防守体系。哲学家般精密的思索。预言家般睿智的判断。浑然一体仿佛骑阵般迅速又紧密的团队阵型。等式推论一样严格执行的战术配合。以及更衣室里那性格各异,却又严丝合缝的十二个人。 岁月流转,波士顿花园那古旧而典雅的穹顶上,不断挂起新的冠军旗帜,那代表着当你抬起头来,便能看到凯尔特人那比星辰更耀眼的历史。奥尔巴赫在教练席上,或者在包厢里,或者在技术台旁,或者在更衣室里——四十年前,他常被驱逐出场——然而无论他在哪里,你都能够感觉到他的存在。 在漫长的岁月里,篮球战术变化不断历经变化。而奥尔巴赫在幕后看着这颗篮球和它的操控者们的变化。事实已经证明,他的战术,他的思路并不如大卫·斯特恩宣传的那些内容华丽与具有视觉效果。在他的一生中,他的战术和他的要求都不怎么具有观赏性——然而,他就是可以不断的夺取胜利,来作为自己生涯的注脚。 就像一个不断戳破彩色纸片的木锥。 我们现在都叫他红衣主教——那是因为他的名字叫做RED。在欧洲历史上,有过许多红衣主教。但中国人最为熟悉的,永远是17世纪的法国红衣主教阿尔芒·让·杜普莱西·德·黎塞留。这个出现在大仲马小说《三剑客》里的法国首相,控制法国近三十年的枭雄,无疑是一个令人爱不上又恨不起来的复杂人物。奥尔巴赫——这个大权独揽、铁腕治军的独裁者,这个动辄暴跳如雷,让联盟所有人畏若蛇蝎的小个子老头。大多数时候,他就是反派角色。 有许多故事暗示了这个人的可怕。拉塞尔,凯尔特人的支柱,一个极其好胜又容易紧张的大个子,传闻他每场比赛前都要因为胃痉挛而呕吐。而在某一次他泰然自若的站在更衣室里,显示出他毫无呕吐之意时,红衣主教朝他怒吼:“去吐!” 凯尔特人队员霍威尔讲过另一个故事。当某场比赛他连续投失球后,主教大人叫了个暂停,然后告诉他,忘记那些投丢的球,不要再去挂念它们。“但你记住,”主教大人严肃的说,“如果你继续投丢,你就得回到板凳上来,坐在我身边。”然后,霍威尔开始连投连中。 他也曾经在波士顿花园的地板上做过手脚,让对方队员运球失误;他也曾经调整更衣室的空调,让湖人队集体苦不堪言;他对裁判进行恐吓、辱骂、抗议,并且在情势紧张时亲自上阵,不管自己是四十壮年还是年过花甲,不管自己是菜鸟教练还是功成名就,不管自己只有175公分高而对面是多可怕的一条巨汉,他总是不惮和对方吵、打、骂、扯。即使是打架,他也从来不会认输。范甘迪似的劝驾?在他的字典里没这回事。 犹太人的精明,俄罗斯移民式的冲动,1943年入伍1946年退伍的军旅生涯——如果他去了二战战场,天知道他会做出什么来——这一切熔铸了红衣主教的灵魂。一个不择手段的实利主义者,一个老年愤青,一个曹操,一个刘邦,一个你无法形容的怪家伙。 红衣主教不害怕甚至热爱被人们仇恨和畏惧。他悠然自得的在球馆里点燃他那著名的胜利雪茄,甚至把这也作为心理战的一种方式。他无时不刻不在思考着战斗和争胜,无论用哪种方式。他不教导什么是善良,什么是优雅,他只是站在黑暗中间并伸出手,使黑暗继续向周围延伸。 他拥有强悍、邪恶的力量,这一切来自于他的战斗精神,他的好胜心,他的精于计算和狡猾。 现在我们也许可以找到一个模版了。在NBA漫长的60年历史中,他使凯尔特人队保持了40年辉煌,夺下了16个总冠军和无数光辉头衔。他将一种朴素、坚韧、高贵而又顽固的精神发扬光大,而他自己一生都是一个枭雄。他就像马龙·白兰度扮演的教父。那个在黑暗之中聆听着要求,用自己的能力来左右大局的人。在他老去之前,他不负责给出绚丽的样本——他不像马拉维奇、J博士、乔丹那样风格绚丽。恰恰相反,他是优雅风格的扼杀者,他残忍无情的吞噬一切。红衣主教一生所在做的便是将温柔、烂漫、华丽、奔放的一切扼杀,然后将自己那坚韧、简约、精密的风格,加诸于一切荣誉之上。在红衣主教的历史里,世界是黑暗的。而我们无时不刻的必须与之做斗争。 拉拉队 直到2006年的春天,当大屏幕电视、全世界转播、爆米花、吉祥物和拉拉队充斥NBA赛场的时候,凯尔特人队依然保持着一项古老而又庄严的传统——他们没有跳大腿舞的女郎组成的拉拉队。因为,红衣主教说,“想要拉拉队女郎?那就先从我的尸体上迈过去!” 凯尔特人队凋零的90年代,公牛队、NIKE和ADIDAS的球鞋、可口可乐、乔丹飞翔的影子、NBA华丽的剪辑、街舞海报、黑人说唱乐:这一切流行于整个世界。而NBA已经不复往昔的灰暗与沉肃,这个联盟越来越像一个大的娱乐机构。球馆仿佛梦剧场,你买票,进场,然后你极尽声色之娱。 而那时,红衣主教在16面冠军旗帜下,看着那些技术不成熟的孩子们玩弄花式动作,上演飞天扣篮。 这也许是这个老头最后的顽固。凯尔特人式的、犹太人式的、俄罗斯式的顽固,对篮球这项运动的虔诚,对简约、精密和朴素的一贯爱好。曾经冒天下之大不韪引进全黑人首发的红衣主教,逆时代潮流的拒绝拉拉队女郎。 然后,2006年10月,他去世了。库西说,“表面粗暴,其实他内心温柔得像只猫。”这个一生都像老虎一样咆哮的老家伙下葬在华盛顿,他开始教练生涯的地方。他没入了黑暗,在他89岁的时候。然后,2006年11月2日,凯尔特人队的主场第一次出现了美女拉拉队员。凯尔特人队全场落后,最后败北给了黄蜂。 当你观看凯尔特人队的球衣时,你会产生一种迷离的幻觉。那绿色的球服之外,似乎有一个灵魂在飘荡。16面冠军旗帜,以及这个他征服得都已发腻的世界。你难以相信他已经离开了,你难以相信,历史的某一页悄然翻了过去,而这个老人的履历表,划上了一个句号。 这个NBA史上最为可怕的教父,争议最大的公敌,如今已经安然离去。他掐灭了雪茄烟,在波士顿花园那黑暗的地板上踏着步。曾经的争战之声在某些时刻响起,而16面冠军旗帜是过去岁月的缩影,正在风里簌簌做声。在花园之外是另一个歌舞升平的世界,是已经被他征服过的,对他又恨又爱的世界。而他终于停止了战斗,停止了和他的对手们、和他的心脏病、和他衰迈的身体那旷日持久、长达89年的战斗。他回到了本属于他的黑暗,而且在人们的记忆中,永远的成为了黑暗中的帝王。 November 14 使用C#的Assembly反射机制时遇到的问题——实在感谢网上雷锋的帮助!今天搞了一天的Facade模式, 以及利用Assembly处理反射来调用DAL层的工作,最后总是碰到一个异常:
没有找到文件或者依赖项——换尔言之,就是在Assembly.Load(String path)的时候系统找不到相应的类,这个着实困扰我好久,不过终于还是找到了一位雷锋的文章中有提到这个问题的解决方式,其实很简单:(
通过这次的经验,觉得一味的研究PetStore4.0的旅程依旧是那么有趣和充满了挑战性,太多太多的新的模式,技术,以及.NetFramework2.0种的新特性在这个小项目中得到了采用,感觉受益匪浅:)如果可能,希望自己能在读懂这个框架的基础上能对原来的框架进行修改,毕竟,读到现在,PetStore4.0还是有一些值得商榷的地方是有待消化和改善的。
转载那位雷锋的文章如下:(再次表达我诚挚的谢意!)
项目DALFactory是采用工厂模式设计的,设计模式的书我也曾看过java的设计模式,理解也不太深刻,但对工厂模式还是较为熟悉,使用它可以根据需求返回不同的实例对象,在DALFactory项目中使用反射机制来实现依赖注入,当然,它的实现还是没有java中的spring那样灵活,强大,部分代码如下:
由这一个类,就可以获取需要用的数据访问层的实例,可是,我在使用过程中却总是抛出异常,[System.IO.FileNotFoundException] = {"未能加载文件或程序集“SmsSystem.SQLServerDAL”或它的某一个依赖项。系统找不到指定的文件。":"SmsSystem.SQLServerDAL"} ,说实话,对于C#这排错和调试我还手生,我百思不得其解,为什么会一用反射就异常呢,整个上去我去看反射的IPA,感觉我的用法没错误啊,况且,我看PetShop的例子就是这样差不多的写法,它为什么能用,下午调试了好久还是在出错,我发狠心去和petShop去对比,后来终于发现,它的dll的名字有些怪,和我的不同,它的都是如PetShop.SQLServerDAL.dll这样的名字,而我的就是个SQLServerDAL.dll,我感觉极有可能是这里有问题,因为在wb.config里我配置过
这样一个程序集,搞了好久,请教别人,结果弄清楚,是要项目的属性里设置程序集的名称,就可以生成SmsSystem.SQLServerDAL.dll这样的dll文件
设置,重新生成 ,又出了一点问题, 类型“SmsSystem.BLL.CustEmployee”同时存在于“c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files \smssystem\3358d7f2\16ba9bb7\assembly\dl3\7296d5df\40ded961_96d8c601\BLL.DLL” 和“c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\smssystem\3358d7f2 \16ba9bb7\assembly\dl3\644d894c\4cf8840a_9ad8c601\SmsSystem.BLL.DLL” 中 G:\ASP.NET\SmsSystem\Default.aspx.cs 22 我仔细一看,原来在web项目的bin下面,原来的SQLServerDAL.dll还在,又多了个SmsSystem.SQLServerDAL.dll,哈哈,vs2005又一个没有自动删除掉的多余文件,昨天是一个项目文件AssemblyInfo.cs删除掉后,在相应的删除文件竟然没删除,不过,我把它手工删除掉,OK,一切正常,还是感谢告诉我怎么样改项目的Assembly name的朋友,不然我竟然找好久也不晓得怎么生成带上命名空间的dll。 November 12 The Beautiful Ones Lyrics, by Marriah CareyThe Beautiful Ones, which is one of the fine album----Butterfly with Marriah Carey, who's my favourite female singer, has been played many times coz the loud and melodious singing of Mariah arouse me of many memories to the end of my life. It's hard for me to judge from those singers , who's better, who's the best. I take the job by myself and sometimes I'll rely on the effect of a song by the singer, which means if i had comfort, spritly in this song, that's good and I'd like to reenjoy it for a long time until it's time to change to the other. As traditional, I'm not a man with many favourites, that's those singers who can be counted by my fingers, will take up a certain space in my memory and I'll not forget them and their great music works for me.
It's really by chance that I chosed to listen this old song when i was reading about those dull codes and programmes, and I'd be a little over-emotional for this song. OK, just some catharsis:)
PS, I've my back muscle pull when i played basketball yesterday on the court, and difficult to move about quickly right now, just like an old man, whoooooo! wish i can recover soon:) Maybe it's another version of <broken back> :)
Here's the lyrics of <The Beautiful Ones> , please check it out:)
Mariah Carey - Butterfly When you love someone so deeply They become your life It's easy to succumb overwhelming fears inside Blindly I imagined I could Keep you under glass Now I understand to hold you I must open up my hand And watch you rise Spread your wings and prepare to fly For you have become a butterfly Fly abandonly into the sun If you should return to me We truly were meant to be So spread your wings and fly Butterfly I have learned that beauty Has to flourish in the light Wild horses ride unbridled Or their spirit dies You have given me the courage To be all that I can And I truly feel your heart will Lead you back to me when you're Ready to land Spread your wings and prepare to fly For you have become a butterfly Fly abandonly into the sun If you should return to me We truly were meant to be So spread your wings and fly Butterfly I can't pretend these tears Aren't overflowing steadily I can't prevent this hurt from Almost overtaking me But I will stand and say goodbye For you'll never be mine Until you know the way it feels to fly Spread your wings and prepare to fly For you have become a butterfly Fly abandonly into the sun If you should return to me We truly were meant to be So spread your wings and fly Butterfly Spread your wings and prepare to fly For you have become a butterfly Fly abandonly into the sun If you should return to me We truly were meant to be So spread your wings and fly Butterfly So flutter through the sky Butterfly Spread your wings and fly Butterfly November 08 午夜阳光——转别人的剧评,感觉不错:)午夜阳光
宁静漆黑的暗夜中,怎么会有温暖的阳光
这不是心灵的遐想
而是……
在美国最北面有一个小镇叫巴罗,
她在北极圈以北五百三十公里的北冰洋岸以北 , 在那里大街上可以看得到北极熊 , 每年的五月十一日到八月一日这八十三天里 , 这个地方的太阳都不会落到地平线下面 , 所以人们叫她午夜阳光...... 有幸先后看了两部关于阳光的电视剧,《一米阳光》和《午夜阳光》,同样都是迷人的景色,悲伤的收尾,至死不渝的爱情,以及弥漫在空气中的潮湿的味道,不,应该是湿润最为贴切,让人沐浴在这样的情、景、事中,享受令人心驰神往的阳光美景,最重要的是片子中所有的丰富颜色都是自然的颜色,我甚至闻到了阳光的干燥、海洋的咸味、雨后的清新、清幽的花香以及绿草的味道…整部片子色彩明快、干净,没有模糊的布景朦胧的色调,一切简简单单。 后来才知道,原来这是海润阳光三部曲其中的两部,其实剧情并不新颖,无非是爱情、亲情、友情的是是非非,但亮点就在于阳光、美景与剧情的绝美融合,在这里景色不仅仅是景色,她表达了不同的生活方式、不同的心情写照。赋予了景色以生命,是我爱上她的不二理由。 《一米阳光》是一部没有结局的剧目,我甚至觉得它是一部悬疑剧,以商战为背景,不多的人物,看似清晰,但有着纷乱的关系,似乎还有违伦理,可背后又另有隐情。最重要的是这部剧带给了我一个天堂,就是丽江,自此之后,我就疯狂的爱上了这里,但我明白,我们只是丽江的过客,因为,我们不可能用一辈子去感受去体味她。 《午夜阳光》一开始就把重点放在爱情上,他讲述了一个童话,一个每个女孩在有梦的年纪都编织过的爱情童话,一个在真实生活中每天都在上演,却结局大有不同的童话。高中,一个单纯而倔强的女孩,一个同样单纯而坚定的男孩,一个五年之约。女孩为了这个五年之约等了十年,而当初的那个男孩现在的这个男人,在说出“I do”后缓缓的向后倒去……一切似乎结束了,而我的心怎么也不能平静,任眼泪横流,思绪乱飞,想会不会有奇迹出现,力挽狂澜,而一切,已平静的结束了,我听到了百合花瓣飘落的声音…… 午夜阳光,最终没有出现…… 但那份坚定的爱情,早已永铸心间…… 他们,是得到了,对吗? 特蕾莎修女特蕾莎修女
特蕾莎修女,(Mother Teresa of Calcutta,1910年8月27日—1997年9月5日,又称做德兰修女、泰瑞莎修女),是世界敬重的天主教慈善工作者,主要替印度加尔各答的穷人服务。于1979年得到诺贝尔和平奖。并被教皇约翰·保罗二世在2003年10月列入了天主教宣福名单Beatification。目前德蕾莎修女的名称也变为真福德雷莎修女(Blessed Teresa)。 早期的生活
特蕾莎修女的本名是艾格尼斯·刚察·博加丘(Agnes Gonxha Bojaxhiu),她是一个出生于奥斯曼帝国科索沃省的斯科普里﹙前南斯拉夫联邦马其顿共和国的首都﹚的阿尔巴尼亚裔人, 父亲尼格拉(Nikolla Bojaxhiu)是成功的地方杂货承包商,母亲是Dranafila Bojaxhiu,她是么女,上有哥哥和姐姐﹙姐姐后来也成为修女﹚。家中说阿尔巴尼亚语,是天主教家庭,在她所居住的镇上多为穆斯林和基督徒,仅有少数的天主教徒。
德蕾莎修女很少提到她的童年生活,但她曾说,在12岁加入一个天主教的儿童慈善会时,她就感觉自己未来的职业是要帮助贫寒,15岁时,她和姐姐决定到印度接受传教士训练工作,18岁时,她进了爱尔兰罗雷托修会,并在都柏林及印度大吉岭接受传教士训练工作,三学期后,德蕾莎修女正式到了印度的加尔各答,在圣玛莉罗雷托修会中学担任教职,主要是教地理。1931年,德蕾莎正式成为修女,1937年5月更决定成为终身职的修女,并依法国19世纪最著名的修女‘圣女德莉莎’ (St. Theresa)的名字和精神,改名为德蕾莎修女。1940年代初期,德蕾莎修女在圣玛莉罗雷托修会中学担任校长一职,但当时印度贫富差距非常大,校内一片安宁,但校外却满街都是无助的麻疯患者、乞丐、流浪孩童。1946年9月10日,德蕾莎修女到印度大吉岭的修院休息了一年,并强烈的感受到自己要为穷人服务的心,返回加尔各答后,她向当地的总主教请求离开学校和修会,但一直得不到许可。
仁爱传教修女会
1947年东巴基斯坦脱离印度独立,加尔各答涌入了数以万计的难民,大多数都是怕被回教徒迫害的印度教徒,传染病如霍乱和麻疯病没有受到控制,在街头巷尾爆发开来,于是加尔各答的街头,学校的高墙外越来越像是地狱,折磨着德蕾莎修女的心,在不断向总主教以及梵蒂冈请求下,1948年,教皇庇护十二世终于给德蕾莎修女以自由修女身分行善的许可。并拨给她一个社区和居住所让她去帮助有需要的穷人。德蕾莎修女马上去接受医疗训练,并寻找帮手,1950年10月,德蕾莎修女与其他12位修女,成立了仁爱传教修女会﹙Missionaries of Charity;又称博济会﹚,并将教会的修女服改为印度妇女传统的沙龙,以白布镶上朴素的蓝边,成为博济会修女的制服。
小故事 有一天,德蕾莎要到巴丹医院商量工作,在靠近车站的广场旁发现了一位老妇人,倒在路上,像是死了一般。德蕾莎蹲下来仔细一看:破布裹著脚,爬满了蚂蚁, 头上好像被老鼠咬了一个洞,残留著血迹,伤口周围满是苍蝇和蛆虫。她赶紧替老妇人测量呼吸及脉搏,似乎还有一口气,她为好赶走苍蝇,驱走蚂蚁,擦去血迹和蛆虫。德蕾莎心想,如果任她躺在那里,必死无疑。于是她暂时放弃了去巴丹的行动,请人帮忙把老妇人送到附近的医院。医院开始时对这个没有家属的老妇人不予理会,但医师在德蕾莎的再三恳求下,便替老妇人医理,然后对德蕾莎说:‘必须暂时住院,等脱离危险期后,再需找个地方静养。’德蕾莎把病人托给医院后,立即到市公所保健课,希望能提供一个让贫困病人休养的埸所。市公所保健所的所长是位热心的人他仔细听完德蕾莎的请求后,便带她来到加尔各答一座有名的卡里寺院,答应将寺庙后面信徒朝拜后的一处地方免费提供给他使用。他们一开始受到印度教区婆罗门的强烈反对,理由是德蕾莎修女不是印度人,然而德蕾莎修女不畏反对,依然在街头抢救许多临危的病患到收容所来替他们清洗,给他们休息的地方,其中也包括印度教的僧侣,此举感动了许多的印度人,于是反对声浪就渐渐的平息了。
自从找到这个落脚点后,不到一天的时间,修女们就将三十多个最贫困痛苦的人安顿了下来。其中有个老人,在搬来的那天傍晚即断了气,临死前,他拉着德蕾莎的手,用孟加拉语低声地说:‘我一生活得像条狗,而我现在死得像个人,谢谢了。’
光靠德蕾莎及修女们的工作,要救助全加尔各答我垂死者是不可能的.,但德蕾莎她有自己独特的看法,她认为人类的不幸并不存在于贫困、生病或饥饿,真正的不幸是当人们生病或贫困时没有人伸出援手,即使死去,临终前也应有个归宿,这就是德蕾莎向垂死者传播了主的爱。
成立
这所名符其实的贫病、垂死者收容院终于在1952年八月正在成立,当时在入口处挂着一块牌子,上面写着‘尼尔玛.刮德’, 按孟加拉语的意思,就是‘清心之家’。
七年后,德蕾莎的‘仁爱传教会’分别又在印度首都新德里和兰奇设立了两座这样我垂死者收容院。
纪录片与知名度
1960年代,德蕾莎修女的收容所在加尔各答成为知名的地方,在街头生病、需要帮助的患者都知道这个能够让他们安息的地方,收容所开始急速成长,因人手不足,开始招募世界各地的义工,透过义工的口耳相传,也打开了世界的知名度。1969年,英国记者马科尔·蒙格瑞奇拍摄了一部以德蕾莎修女为主的纪录片《Something Beautiful for God》,片中拍出收容所和印度街头惊人的贫穷和无助,以及德蕾莎修女决定终身侍奉最贫穷的人的精神,让许多人相当感动,也让德蕾莎修女变成了世界名人。
获奖
1971年,教皇庇护十二世颁给德蕾莎修女“Pope John XXIII”和平奖;同年的肯尼迪奖也颁发给她,此外还有如1975年Albert Schweitzer国际奖也颁发给她,1985年美国总统自由勋章;1994年美国国会金牌;1996年11月16日美国名誉公民,和许多大学的名誉学位;1979年的最重要的诺贝尔和平奖,也颁发给她。当时她拒绝了颁奖宴会和奖金。媒体问及她:“我们可能做什么促进世界和平?”。她回答:“回家和爱您的家庭。”
健康恶化与过世
1983年,德蕾莎修女到罗马拜访教皇保罗二世时,心脏病第一次发作。1989年心脏病第二次发作时,她接受了人工心脏的安装,1991年从墨西哥拜访回来之后,得了肺炎,健康状况日趋恶化。于是她向博济会提出辞职,理由是她已无法像其他修女一样全天照顾病患,在修会的秘密投票下,其他修女和修士都投票希望德蕾莎修女要留在博济会领导她们。
1997年4月,德蕾莎修女跌倒并伤到锁骨。8月时接受了心脏移植手术,但健康并没有日渐好转, 1997年3月13日,她退出了博济会,同年9月,87岁时逝世。德蕾莎修女留下了4,000 个修会的修女,超过10万以上的义工,还有在123个国家中的610个慈善工作。印度替她举行了国葬。讽刺的是,同年8月31日,英国的戴安娜王妃车祸身亡,媒体花了整整一个月报导戴安娜王妃车祸和后续消息,而德蕾莎修女的过世则变成报端的小角。
评论
奇迹和宣福
德蕾莎修女过世之后,被尊敬她的印度人神化,由于天主教进行宣福仪式前,必须要有奇迹的见证记录,德蕾莎修女的奇迹见证纪录来自于一位印度妇女,Monica Besra,她声称自己是德蕾莎修女神迹的见证人,她将德蕾莎修女的照片,放在腹部,癌症肿瘤就消失,但她的丈夫却对媒体说,这事实上是她接受医院手术治疗的结果,他们之所以如此做是受到天主教教会要替德蕾莎修女进行宣福的压力,根据时代杂志的报导,治疗她的医生也受到天主教教会的压力,必须对外声称这是一个奇迹,此罗生门最后没有定案,Monica Besra的丈夫后来也改变说词,将癌症肿瘤的治愈称为德蕾莎修女的奇迹。目前天主教教会在等待第二个奇迹以将德蕾莎修女进行到册封为圣徒的程序中。
给垂死者以天主教洗礼 收容所里的垂死者多数为印度教徒和穆斯林,但德蕾莎修女总是敦促工作者们给他们施以天主教洗礼。这个做法引发很多争议。
慈善行为的动机
克里斯多弗·息金斯(Christopher Hitchens)认为,德蕾莎修女的组织的目的是以信仰的方式倡导受苦,而不是帮助有需求的人。在1981年的一次新闻发布会上,有记者问:“您是否在教导穷人应该忍受苦难?”德蕾莎修女回答道:“我认为,穷人接受自己的命运、与受难的基督分享痛苦是非常美好的。我认为,穷人受苦会对这个世界更有帮助。”
查特基(Chatterjee)说,德蕾莎修女以“穷人的帮助者”的形像出现,误导了公众。在她最大的收容所里,也仅有二、三百人。加尔各答的另一清教慈善组织,上帝的集会,每日发放18,000份免费餐,远远多于德蕾莎修女全部收容所发放数量的总和。
查特基说,德蕾莎修女的许多机构只传教而不做任何慈善活动。如,在巴布亚新几内亚,八所设施未收容任何人,全部经费都用于传教。
医疗护理的质量
1991年,英国著名医学杂志《柳叶刀》的编辑罗宾·福克斯博士访问了加尔各答的“垂死者的家”发现,许多服务的修女和志愿者没有任何医学知识,但却要常常做医疗决定。他们也不区分“可医治”与“不可医治”的病人,而前者可能处于由于感染而死去的危险中。另外,他们严重缺乏麻醉剂,使病人不得不忍受剧痛。他们用过的针头只在温水中洗一下。
与此形成对照的是,德蕾莎修女自己有医疗需要时,她会去美国、欧洲、印度的有名望的医院获得医治。
捐款的去向
德蕾莎修女的前雇员们、及前修女苏珊·希尔兹(Susan Shields)称,德蕾莎修女不允许她们买医疗器械,而是将捐款转入梵蒂冈银行作为一般用途,即使捐赠者特别注明将捐款用于慈善行为。
除了法律要求的有关部门,德蕾莎修女从不向公众提供她的组织的财政状况。
德蕾莎修女祷文
最亲爱的主:让我在今天以及每一天,从你的病人身上看见;并在照顾他们的同时服侍。
纵然你将自己隐藏那些急躁、斤斤计较、蛮不讲理的人背后,让我仍然看得出是;并且欣然地说:‘服侍你是何等的甜蜜。’
主啊!赐我这种洞悉的信心,我的工作便永远不致沈闷,每次鼓励、开解那些可怜的受苦者,我必寻得无尽的喜乐。
啊!亲爱的病者,你于我是何等的可贵,因你代表了基督,能够服侍你是何等的权利。
主啊!让我觉悟这高尚召唤的尊严及其责任,不要容许我因冷漠、麻木或不耐烦而令这职份蒙羞。
神啊!当降卑成为耶稣,我的病,恳求也容许我的诸般错误,只看我内心的动机,就是在每一个病人身上爱及服侍。
主啊!增添我的信心,在此刻及以后,赐福我的努力及工作,诚心所愿。 |
|
|