[转载]C#开发Android应用的必备——Mono for Android V1.0 发布

mikel阅读(782)

[转载]C#开发Android应用的必备——Mono for Android V1.0 发布_IT新闻_博客园.

Mono for Android V1.0 正式发布啦!

Mono for Android就是原先的MonoDroid,由于商标问题(名称中含有Droid),现在改名为Mono for Android

Mono for Android提供了一个基于Android的Mono虚拟机,让开发者可以用C#开发Android应用程序。另外,Dalvik API已经被绑定至C#,你可以用C#方便地调用Android内置的很多类库。OpenTK类库也被移值过来,你可以在Windows, Linux与iPhone三个不同的平台上共享同样的OpenGL代码。

当前版本只支持C#语言,但理论上应该支持其他语言的编译器。通过针对Mono for Android的Visual Studio 2010 add-on,你可以在熟悉的VS2010开发环境中开发Android应用。

如果你是.NET程序员,如果你想开发移动应用程序,如果你不想学习和编写Java代 码,如果你目前不看好Windows Phone 7,那就用Mono for Android吧!而且,如果哪天Windows Phone发达了,你想开发WP应用程序了,那你现在写的很多代码还可以用于WP应用开发!另外,如果你考虑用MonoTouch开发iPhone应用程 序,那就更幸福了,为Android应用写的C#代码,也可以用于iPhone应用开发。一次写代码,却可以用于三大移动平台,世上难道还有比.NET程 序员更幸福的程序员吗!.NET程序员们,欢呼吧!

但是欢呼的同时,我们也要面对现实,使用Mono for Android有一些限制。比如,不能使用C# 4.0的dynamic特性。另外,一些专门针对Android的类库(比如针对Android特有的硬件,针对由Android本地类库和TK实现的 UI),在其他平台的.NET实现中可能得不到支持。这就意味着,如果Android应用与Windows Phone应用要共享代码,只能共享核心代码。Mono for Android提供的只是让你可以用C#代码编写Android应用,但是开发一个真正的Android应用,你还需要学习很多东西,比 如:Activities, Intents,通过XML创建UI。

Mono for Android提供了一个可以免费下载的版本,但只能在模拟器中使用。要想在真实环境中使用,需要购买商业许可。专业版$399/年,企业版$999/年。 i-programmer上的报道有误,经过在Mono for Android官网上查证,专业版授权费$399,企业版授权费$999,学生版授权费$99(无时间限制)。

博客园/编译

英文原文:Mono for Android V1.0 now shipping

[转载]分享18个非常棒的 jQuery 表格插件

mikel阅读(770)

[转载]分享18个非常棒的 jQuery 表格插件 – 梦想天空 – 博客园.

我们一般都是用HTML表格来显示结构化数据,如今有很多的 JQuery 表格插件可以帮助我们更好的组织和控制表格数据,增强表格的功能和操作。今天要与大家分享的是18个非常优秀的 JQuery 表格插件,有用到朋友可以参考一下。

1.DataTables

jQuery Table

在线例子

2.tablesorter

jQuery Table

在线例子

3.uiTableFilter

1

在线例子

4.columnHover

jQuery Table

在线例子

5.Scrollable HTML

1

在线例子

6.columnManager

1

在线例子

7.Flexigrid

1

在线例子

8.Table Drag and Drop

1

在线例子

9.HeatColor

1

在线例子

10.JQTreeTable

1

在线例子

11.FireScope Grid

1

在线例子

12.Ingrid

1

在线例子

13.Animated Sortable Data Table – jTPS

1

在线例子

14.PicNet Table Filter

jQuery Table

在线例子

15.TableSort

1

在线例子

16.Fixed Header Table

1

在线例子

17.Expand table rows with jQuery – jExpand plugin

1

在线例子

18.TableEditor

1

在线例子

(编译来源:梦想天空 原文来自:15+ Best jQuery Table

[转载]ASV2011之SWF去壳之解密实战一

mikel阅读(1128)

[转载]ASV2011之SWF去壳之解密实战一 – ASV2011 – 博客园.

近几年,国内Flash Web Game发展趋势突飞猛进,有利益就得有保护,SWF格式本身是开源的,许多人也在寻找各种各样的保护措施,防止源码被盗取。针对加密SWF格式的 Flash文件反编译,众所周知,首推ASV(Action Script Viewer)软件。不过现在加密手段和方法也是不断的摸索前进中,比较常见的一种就是对SWF加壳。可是作为一个Flash爱好者,并不一定只是要搞破 坏,如果你只想学习学习源代码的时候,就遇到了困难,ASV2010对真实的源码无法提取出来,怎么办呢?还好,ASV2011来了,其插件SWF Revealer主要功能就是针对AS3加壳的SWF文件提取。

今天就具体实验下它的效果如何!

首先,在网络上发现了一个加壳的SWF文件,大家可以自己下载试研究下,下载地址:http://u.115.com/file/f588b76b6

首先我们试着用ASV2011打开这个文件看看效果:

一开始弹出了个错误日志对话框,点击关闭即可。

接下来进入主界面:

注意:接下来我们要看一些特征了。

例如class的名是乱码样的字符。

然后点开库中看到的二进制数据,和脚本也会发现类似情况如下:

这些特征是加过壳的SWF文件特有的,当然,也许其他情况也很多,但都大同小异。

现在看到的代码肯定就不是这个SWF真身的源码了,下面我们就请出SWF Revelaer看看吧。

先关掉刚才那个文件后,点击菜单中的工具->SWF Revelaer。界面如下:

点击选项卡后勾选捕获到第一个文件时立即切换到数据选项卡:

接下来,把刚才的SWF文件拖入这个窗口中后,进度条走了一会后,自动跳转了选项卡。

如图中,看到两个文件,根据文件大小,那么后者就应该是这个文件的真身了,根据提示,先把它保存出来,点中第二个文件不松,然后拖拽出来,我先拖动到自己的文件夹里吧。

得到了一个test002.swf文件,大小1170KB,比源文件小了3KB,看起来壳应该是脱掉了。

继续把它拖回ASV2011看看吧,源码现身了。

下面可以好好学习学习代码了。不过,有时候,SWF并不一定只加一次壳,所以可能会多几次将 SWF文件拖入SWF Revealer去壳的操作!而有的SWF真身可能进行了某些锁定操作,使得真身并没释放出来,那么就要用到另一个工具SWF Seeker了,下一篇日 志再介绍了。Enjoy it!

本文由网友若迪投稿,版权归原作者所有,转载请联系软件一品堂(http://www.softypt.com/)

[转载]SWF Seeker 2011之SWF去壳解密反编译实战二

mikel阅读(1080)

[转载]SWF Seeker 2011之SWF去壳解密反编译实战二 – ASV2011 – 博客园.

前一篇,我们使用ASV2011的 插件SWF Revealer来将一个AS3加壳的SWF文件去壳。但不是所有情况都能搞定,例如一个加密的EXE电子杂志文件,看得到Flash在播放,却抓不到, 或是一个网页中进行域名锁定的小游戏,虽然能下载下来,却由于域名锁定的关系,源文件真身没有被释放出来,这个时候该怎么办呢?SWF Seeker 2011内存提取工具就是来帮助我们抓取SWF真身的软件,所见即所得,只要看得见Flash在运行,那么就能抓得到!
废话不多说,直接动手实验。我们就以本地的电子杂志为例。
首先,开启ASV2011,将一个加密过的电子杂志文件拖入,弹出了“SWF文件智能检测”窗口,ASV需要进行扫描找到嵌入其中的SWF文件,点击开始,等待扫描过程。

扫描结束后,找到了4个文件,挨个选中,并预览后,很遗憾,没有我们需要的文件。

接下来,轮到SWF Seeker 2011上场了,先看看运行界面。

界面很简洁,点开了目标下拉列表,就明白其用途了,列表中是现在正在运行的所有进程,那么只要保证电子杂志的进程正在运行中,然后选中,点下扫描按钮,等待一会即可。

稍等片刻后,抓取的内容列表更新了。我们看到004号文件,大小容量41.1MB,帧数367。(部分信息显示未全,是试用版的原因)那么它就是我们要的文件了,选中004,用文件菜单中的保存,或点击右键保存即可。

我们把这个文件拖入ASV2011看看,所有的素材一目了然。

最后,SWF Seeker 2011还提供了一个功能,用于检测一个SWF中是否还有隐藏并嵌入的SWF真身,操作很简单,只需要把SWF文件拖入其窗口即可,检测完毕后会自动弹出一个提示窗口。利用收藏夹功能也可方便选中常用的目标进程。


Enjoy it!
本文由网友若迪投稿,版权归原作者所有,转载请联系软件一品堂http://www.softypt.com

[转载]Android学习系列(1)--为App签名(为apk签名)

mikel阅读(757)

[转载]Android学习系列(1)–为App签名(为apk签名) – 谦虚的天下 – 博客园.

写博客是一种快乐,前提是你有所写,与人分享,是另一种快乐,前提是你有舞台展示,博客园就是这样的舞台。
这篇文章是Android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用。

1.签名的意义
为了保证每个应用程序开发商合法ID,防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序,我们需要对我们发布的APK文件进行唯一签名,保证我们每次发布的版本的一致性(如自动更新不会因为版本不一致而无法安装)。

2.签名的步骤
a.创建key
b.使用步骤a中产生的key对apk签名

3.具体操作

方法一: 命令行下对apk签名(原理)
创建key,需要用到 keytool.exe (位于jdk1.6.0_24\jre\bin目录下),使用产生的key对apk签名用到的是jarsigner.exe (位于jdk1.6.0_24\bin目录下),把上两个软件所在的目录添加到环境变量path后,打开cmd输入

D:\>keytool -genkey -alias demo.keystore -keyalg RSA -validity 40000 -keystore demo.keystore
/*说明:-genkey 产生密钥
-alias demo.keystore 别名 demo.keystore
-keyalg RSA 使用RSA算法对签名加密
-validity 40000 有效期限4000天
-keystore demo.keystore */
D:\>jarsigner -verbose -keystore demo.keystore -signedjar demo_signed.apk demo.apk demo.keystore
/*说明:-verbose 输出签名的详细信息
-keystore  demo.keystore 密钥库位置
-signedjar demor_signed.apk demo.apk demo.keystore 正式签名,三个参数中依次为签名后产生的文件demo_signed,要签名的文件demo.apk和密钥库demo.keystore.*/

注意事项:Android工程的bin目录下的demo.apk默认是已经使用Debug用户签名的,所以不能使用上述步骤对此文件再次签名。正确步骤应该是:在工程点击右键->Anroid Tools-Export Unsigned Application Package导出的apk采用上述步骤签名。

方法二:使用Eclipse导出带签名的apk
Eclipse直接能导出带签名的最终apk,非常方便,推荐使用,步骤如下:
第一步:导出。

第二步:创建密钥库keystore,输入密钥库导出位置和密码,记住密码,下次Use existing keystore会用到。

第三步:填写密钥库信息,填写一些apk文件的密码,使用期限和组织单位的信息。

第四步:生成带签名的apk文件,到此就结束了。

第五步:如果下次发布版本的时候,使用前面生成的keystore再签名。


第六步:Next,Next,结束!

方法三:使用IntelliJ IDEA导出带签名的apk
方法步骤基本和Eclipse相同,大概操作路径是:菜单Tools->Andrdoid->Export signed apk。

4.签名之后,用zipalign(压缩对齐)优化你的APK文件。
未签名的apk不能使用,也不能优化。签名之后的apk谷歌推荐使用zipalign.exe(位于android-sdk-windows\tools目录下)工具对其优化:

D:\>zipalign -v 4 demo_signed.apk final.apk

如上,zipalign能够使apk文件中未压缩的数据在4个字节边界上对齐(4个字节是一个性能很好的值),这样android系统就可以使用mmap()(请自行查阅这个函数的用途)函数读取文件,可以在读取资源上获得较高的性能,
PS:在4个字节边界上对齐的意思就是,一般来说,是指编译器吧4个字节作为一个单位来进行读取的结果,这样的话,CPU能够对变量进行高效、快速的访问(较之前不对齐)。

5.签名对你的App的影响。
你不可能只做一个APP,你可能有一个宏伟的战略工程,想要在生活,服务,游戏,系统各个领域都想插足的话,你不可能只做一个APP,谷歌建议你把你所有的APP都使用同一个签名证书。
使用你自己的同一个签名证书,就没有人能够覆盖你的应用程序,即使包名相同,所以影响有:
1) App升级。 使用相同签名的升级软件可以正常覆盖老版本的软件,否则系统比较发现新版本的签名证书和老版本的签名证书不一致,不会允许新版本安装成功的。
2) App模块化。android系统允许具有相同的App运行在同一个进程中,如果运行在同一个进程中,则他们相当于同一个App,但是你可以单独对他们升级更新,这是一种App级别的模块化思路。
3) 允许代码和数据共享。android中提供了一个基于签名的Permission标签。通过允许的设置,我们可以实现对不同App之间的访问和共享,如下:

AndroidManifest.xml:<permission android:protectionLevel="normal" />

其中protectionLevel标签有4种值:normal(缺省 值),dangerous, signature,signatureOrSystem。简单来说,normal是低风险的,所有的App不能访问和共享 此App。dangerous是高风险的,所有的App都能访问和共享此App。signature是指具有相同签名的App可以访问和共享此App。 signatureOrSystem是指系统image中App和具有相同签名的App可以访问和共享此App,谷歌建议不要使用这个选项,因为签名就足 够了,一般这个许可会被用在在一个image中需要共享一些特定的功能的情况下。
最后,请一定要记得保管好你的签名证书的两个密码,两个密码都不要告诉任何人,也不要把你的密钥库拷贝给别人,包括我!

[转载]利用FlexPaper实现Word、PPT、PDF在线浏览

mikel阅读(1247)

[转载]利用FlexPaper实现Word、PPT、PDF在线浏览 – php mysql 足迹 – 博客园.

今天在百度文库看文件时想着有没有可以在线看电子书的插件或源码呢?到网上搜索下发现了FlexPaper,下载下来,找了一些资料,折腾一番,出的效果还不错,就是将中文文档转换成swf文件时卡住了,先作个记录,以后有空再研究了。

FlexPaper是 一个开源轻量级的在浏览器上显示各种文档的组件,被设计用来与PDF2SWF一起使用, 使在Flex中显示PDF成为可能,而这个过程并无需PDF软件环境的支持。它可以被当做Flex的库来使用.另外也可以通过将一些例如Word、PPT 等文档转成PDF,然后实现在线浏览。

目前FlexPaper最新版是1.4.1,可以到官网Google Project下载

解压后有一个FlexPaperViewer.html demo文件,和一个Debug文件FlexPaperViewer_Debug.html,这两个文件很好的展示了FlexPaper的用法,以下搜集了FlexPaper的一些参数和函数供大家参考,结合这些参数和函数很容易就可以应用FlexPaper

参数列表

参数名称

参数值及说明

CursorToolsVisible

(True/False)

FitPageOnLoad

(True/False)

FitWidthOnLoad

(True/False)

FullScreenAsMaxWindow

(True/False)

FullScreenVisible

(True/False)

NavToolsVisible

(True/False)

PrintEnabled

(True/False)

PrintToolsVisible

(True/False)

ProgressiveLoading

(True/False)

Scale

SearchToolsVisible

(True/False)

StartAtPage

SwfFile

ViewModeToolsVisible

(True/False)

ZoomInterval

ZoomTime

ZoomToolsVisible

(True/False)

ZoomTransition

事件与函数

函数名称

函数说明

gotoPage (Number pageNumber)

跳转到指定页

fitWidth()

设置为宽度模式视图

fitHeight()

设置为高度模式视图

loadSwf (String swffile)

加载一个新的swf文件到浏览器中

getCurrPage()

获取当前页码

nextPage()

跳转到下一页

prevPage ()

跳转到上一页

Zoom (Number factor)

按系数缩放

searchText (String text)

搜索文字

switchMode (String mode)

变换视图模式;参数值可为(“Portrait”, “Two Page”, “Tile”)

printPaper ()

打印加载的文档

事件名称

事件说明

onDocumentLoaded ()

文档加载完成后触发

onDocumentLoadedError (String errorMessage)

加载文档出错时候触发

onProgress (Number bytesloaded, Number bytestotal)

文档正在加载的时候触发

onCurrentPageChanged (Number pagenumber)

页面改变时触发

onExternalLinkClicked (String link)

当用户点击外部链接的时候触发

将各种文档转换成swf文件是关键,从官网和其它资料都是介绍用SwfTools工具将pdf文件换成swf文件,在windows下可以使用以下命令行

C:\SWFTools\pdf2swf.exe Paper.pdf -o Paper.swf -T 9 -f

Paper.pdf转换成Paper.swf,当然也可以用它的UI工具

但问题就来了,转换英文文档是可以的,但是中文就不行了会出现乱码,后来在网上找了一些方法,但折腾了一番没成功,以后有时间再研究,大家有兴趣可以参考以下的资料来研究下:使用xpdf来处理中文PDF文档

[转载]存储过程 vs ORM 性能大比拼

mikel阅读(1050)

[转载]存储过程 vs ORM 性能大比拼 – fish-li – 博客园.

其实早就准备好这个测试项目了,一直还忘记了写出来。今天又完善了一下测试用例,打算把它贴出来。

我是一个比较喜欢使用存储过程的人,自然经常会写很多存储过程。 但现在连MS也在关注ORM了,而且还做了二个了,所以也不得不了解一下了。 同时也为了检验一下自己写的通用数据访问层的性能,所以就写了个性能测试程序来将存储过程与ORM的性能做个比较, 当然了,也把我的通用数据访问层与原生的Ado.net的性能做了一番比较。

点击此处下载完整源代码

要测试比较的数据访问方式

这个测试程序提供了5种数据访问的方式来做进行测试。

1. FishWebLib-自动加载实体。(使用我的通用数据访问层,加载实体时,使用反射)

2. FishWebLib-手工加载实体。(使用我的通用数据访问层,加载实体时,无反射)

3. Ado.net直接调用存储过程

4. LINQ-TO-SQL

5. Entity Framework

说明一下,
第一种方式,我想有些人一看到反射就会想到性能差。这里我只想补充一句,反射的性能差不差,要看你如何去写,性能差不差要看结果。
另外,前三种方式全都采用调用存储过程的方式来进行测试。
后二者嘛,都属于ORM工具,就直接使用它们所提供的动态生成SQL语句的方式来进行测试。

停一下,为什么没有采用直接发出SQL语句的方式来进行测试??
好吧,我来解释一下:的确可能有些人喜欢在C#中使用SQL语句的方式来操作数据库,这里就又可以为了二种方式了:
1. 采用SQL语句,并且采用参数的方式。我种做法本身是没有问题的,只是我不喜欢在C#代码中混着一堆SQL语句,看起来代码不清爽。 而且SQL语句放在C#中也没有语法着色的提示,写错了也不知道,并且不方便在数据库的一些工具中测试运行, 如果后期想优化语句,还得重新编译程序,再部署,太麻烦了。所以我不喜欢。
2. 拼接SQL语句。这种方式嘛,我真的不想评价它。

以上二种采用SQL语句的方式,不管如何,肯定快不过存储过程!,所以这里就不提供这种方式了。

比较哪些操作?

一般说来,数据库类的应用程序,操作数据库也就那么几种方式,增,删,改,查询分页列表,获取单个对象。 所以本次测试也就测试这5个方面。我想应该是很有代表性的。

再来看看实体类的定义吧(表结构与实体类对应,就不贴图了)

public class Customer
{
    public int CustomerID { get; set; }
    public string CustomerName { get; set; }
    public string ContactName { get; set; }
    public string Address { get; set; }
    public string PostalCode { get; set; }
    public string Tel { get; set; }
}

分页的搜索参数

class QueryParam
{
    public string SearchWord = "上";
    public int PageIndex = 1;
    public int PageSize = 20;
    public int TotalRecords;
}

至于C#的测试代码嘛,我就挑2种出来,其它的完整代码及存储过程,您可以下载压缩包,打开项目来看。

1. FishWebLib-自动加载实体 的测试代码


// 为了避免打开关闭连接的额外的时间,这里的所有操作全部放在一个连接中。

using( FishDbContext db = new FishDbContext(false) ) {
    Customer customer = new Customer();
    customer.CustomerName = Guid.NewGuid().ToString();
    customer.ContactName = "ccccccccccc";
    customer.PostalCode = "123456";
    customer.Address = "aaaaaaaaaaaaaaaaaaaaaaaa";
    customer.Tel = "12345678";

    // Add
    FishBLLHelper.CallSpExecuteNonQuery(db, "InsertCustomer", customer);

    customer.ContactName = Guid.NewGuid().ToString();
    customer.PostalCode = "430076";
    customer.Address = "湖北武汉";
    customer.Tel = "87654321";

    // Update
    FishBLLHelper.CallSpExecuteNonQuery(db, "UpdateCustomer", customer);

    // Get One
    Customer ccc = FishBLLHelper.CallSpGetDataItem<Customer>(db, "GetCustomerById", null, customer.CustomerID);

    if( ccc == null || ccc.Tel != customer.Tel )    // 检验查询结果
        throw new Exception("call GetCustomerById failed.");

    // Delete
    FishBLLHelper.CallSpExecuteNonQuery(db, "DeleteCustomer", null, customer.CustomerID);

    // 分页查询:要求不仅取到列表,还要知道符合条件的记录数。
    QueryParam param = new QueryParam();
    List<Customer> list = FishBLLHelper.CallSpGetDataItemList<Customer>(db, "GetCustomerList", param);
    int recCount = param.TotalRecords;
}

4. LINQ-TO-SQL 的测试代码

using( MyNorthwindDataContext db = new MyNorthwindDataContext() ) {
    db.Connection.Open();

    Customer customer = new Customer();
    customer.CustomerName = Guid.NewGuid().ToString();
    customer.ContactName = "ccccccccccc";
    customer.PostalCode = "123456";
    customer.Address = "aaaaaaaaaaaaaaaaaaaaaaaa";
    customer.Tel = "12345678";

    // Add
    db.Customer.InsertOnSubmit(customer);
    db.SubmitChanges();

    customer.ContactName = Guid.NewGuid().ToString();
    customer.PostalCode = "430076";
    customer.Address = "湖北武汉";
    customer.Tel = "87654321";

    // Update
    db.SubmitChanges();

    // Get One
    Customer ccc = db.Customer.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();

    if( ccc == null || ccc.Tel != customer.Tel )    // 检验查询结果
        throw new Exception("call Get One failed.");

    // Delete
    db.Customer.DeleteOnSubmit(ccc);
    db.SubmitChanges();

    // 分页查询:要求不仅取到列表,还要知道符合条件的记录数。
    MyDataItem.QueryParam parm = new MyDataItem.QueryParam();
    var query = from cust in db.Customer
                where cust.CustomerName.Contains(parm.SearchWord)
                select cust;

    int recCount = query.Count();
    List<Customer> list = query.Skip(parm.PageIndex * parm.PageSize).Take(parm.PageSize).ToList();
}

测试环境及结果

我的测试机器配置(ThinkPad SL510):Core2 T6670 2.2GHz, 4G内存
操作系统:Wiondow server 2003 SP2
数据库:Sql Server 2005 Express SP4

由于以前听说MSDE有并发限制,我想现在的2005 Express版应该也会有限制,所以只开了2个线程。而且由于不想在测试时等太久,所以测试次数也就选了1000次, 有点少,如果您有兴趣自己来试试,可以下载压缩包,里面有完整的代码。

一般说来,应用程序在第一次连接数据库时会慢一些,由于听说.net中有所谓的连接池的概念, 所以本测试程序在运行测试前,会根据线程的数量创建相应数量的连接,然后关闭它们,就算是给连接池做好了准备。
而且每次的测试结果只取程序启动后第一次的运行结果。

贴测试结果:

让人意外的是:Entity Framework比IINQ-TO-SQL慢了不少。比“Ado.net直接调用存储过程”就差更远了。

存储过程还是没让我失望,仍然是我最信赖的技术。所以呢,如果您想让程序有更好的性能,还是建议使用存储过程, 我想这也是为什么即使那些ORM工具一方面可以动态生成SQL,却仍然要支持调用存储过程的原因,在性能面前没有任何技术能取代存储过程!

当然了,如果某些小的项目,或者不经常执行的逻辑中,或者准确的说:对性能要求不高的地方,使用ORM也行吧。
我想有些人在性能面前又会扯到缓存,的确缓存可以在某些时候改善性能,因此,可能会说:我有缓存,存储过程不需要也很好啊。 但是,我也想说:我用存储过程,再加上缓存,会不会更快呢?

说到存储过程,让我想到一件难忘记的事: 今年早些时候去汉庭面试时,最后遇到一位“牛人”,当时我刚提到存储过程,没想到就听到对方的一堆对于存储过程的批评, 最后还说出一句很雷人的话:“存储过程只适合做点小项目!”, 哎,我当时真想说:“你去看看Sharepoint,TFS,看看人家微软用了多少存储过程!”

我知道,在这个世上的确存在一些存储过程的反对者。但是,我上家公司所有做开发的同事,全是支持存储过程的,当然了,他们也都会写存储过程, 问他们存储过程好不好,他们可以说出一大堆存储过程的优点。那些反对者所谓的缺点,在他们看来,并不认为是缺点,这里也就不想列举了。

我呢,只想说二句话:
1. 不会存储过程的人,建议去学学存储过程,学习肯定是有代价的,尤其是不同的数据库的存储过程语法不一样。
2. 会存储过程的人,可以去看看ORM,不用太投入,了解一下它们就好。

在这个测试程序项目中,还有一个问题未能解决,Entity Framework支持POCO的方式来使用(放在目录EFPOCO),我也写了相应的代码, 但项目中同时存在使用Entity Framework设计器生成的代码(放在目录EF), 当运行Entity Framework POCO的代码时,会出现异常“找不到“WinFormApp.EF.Customer”的概念模型类型”。 这二种方式单独运行时(在项目中排除另一个目录),是没有任何问题的,总之就是不能混用这二种方式。
如果谁知道原因,请帮我修改一下。 只要把目录EFPOCO加入到项目中,然后取消注释TestFactory.cs中的一些代码就可以重现异常了。在此先谢谢了。

点击此处下载完整源代码

[转载]存储过程 vs ORM 性能大比拼

mikel阅读(1480)

[转载]存储过程 vs ORM 性能大比拼 – fish-li – 博客园.

其实早就准备好这个测试项目了,一直还忘记了写出来。今天又完善了一下测试用例,打算把它贴出来。

我是一个比较喜欢使用存储过程的人,自然经常会写很多存储过程。 但现在连MS也在关注ORM了,而且还做了二个了,所以也不得不了解一下了。 同时也为了检验一下自己写的通用数据访问层的性能,所以就写了个性能测试程序来将存储过程与ORM的性能做个比较, 当然了,也把我的通用数据访问层与原生的Ado.net的性能做了一番比较。

点击此处下载完整源代码

要测试比较的数据访问方式

这个测试程序提供了5种数据访问的方式来做进行测试。

1. FishWebLib-自动加载实体。(使用我的通用数据访问层,加载实体时,使用反射)

2. FishWebLib-手工加载实体。(使用我的通用数据访问层,加载实体时,无反射)

3. Ado.net直接调用存储过程

4. LINQ-TO-SQL

5. Entity Framework

说明一下,
第一种方式,我想有些人一看到反射就会想到性能差。这里我只想补充一句,反射的性能差不差,要看你如何去写,性能差不差要看结果。
另外,前三种方式全都采用调用存储过程的方式来进行测试。
后二者嘛,都属于ORM工具,就直接使用它们所提供的动态生成SQL语句的方式来进行测试。

停一下,为什么没有采用直接发出SQL语句的方式来进行测试??
好吧,我来解释一下:的确可能有些人喜欢在C#中使用SQL语句的方式来操作数据库,这里就又可以为了二种方式了:
1. 采用SQL语句,并且采用参数的方式。我种做法本身是没有问题的,只是我不喜欢在C#代码中混着一堆SQL语句,看起来代码不清爽。 而且SQL语句放在C#中也没有语法着色的提示,写错了也不知道,并且不方便在数据库的一些工具中测试运行, 如果后期想优化语句,还得重新编译程序,再部署,太麻烦了。所以我不喜欢。
2. 拼接SQL语句。这种方式嘛,我真的不想评价它。

以上二种采用SQL语句的方式,不管如何,肯定快不过存储过程!,所以这里就不提供这种方式了。

比较哪些操作?

一般说来,数据库类的应用程序,操作数据库也就那么几种方式,增,删,改,查询分页列表,获取单个对象。 所以本次测试也就测试这5个方面。我想应该是很有代表性的。

再来看看实体类的定义吧(表结构与实体类对应,就不贴图了)

public class Customer
{
    public int CustomerID { get; set; }
    public string CustomerName { get; set; }
    public string ContactName { get; set; }
    public string Address { get; set; }
    public string PostalCode { get; set; }
    public string Tel { get; set; }
}

分页的搜索参数

class QueryParam
{
    public string SearchWord = "上";
    public int PageIndex = 1;
    public int PageSize = 20;
    public int TotalRecords;
}

至于C#的测试代码嘛,我就挑2种出来,其它的完整代码及存储过程,您可以下载压缩包,打开项目来看。

1. FishWebLib-自动加载实体 的测试代码


// 为了避免打开关闭连接的额外的时间,这里的所有操作全部放在一个连接中。

using( FishDbContext db = new FishDbContext(false) ) {
    Customer customer = new Customer();
    customer.CustomerName = Guid.NewGuid().ToString();
    customer.ContactName = "ccccccccccc";
    customer.PostalCode = "123456";
    customer.Address = "aaaaaaaaaaaaaaaaaaaaaaaa";
    customer.Tel = "12345678";

    // Add
    FishBLLHelper.CallSpExecuteNonQuery(db, "InsertCustomer", customer);

    customer.ContactName = Guid.NewGuid().ToString();
    customer.PostalCode = "430076";
    customer.Address = "湖北武汉";
    customer.Tel = "87654321";

    // Update
    FishBLLHelper.CallSpExecuteNonQuery(db, "UpdateCustomer", customer);

    // Get One
    Customer ccc = FishBLLHelper.CallSpGetDataItem<Customer>(db, "GetCustomerById", null, customer.CustomerID);

    if( ccc == null || ccc.Tel != customer.Tel )    // 检验查询结果
        throw new Exception("call GetCustomerById failed.");

    // Delete
    FishBLLHelper.CallSpExecuteNonQuery(db, "DeleteCustomer", null, customer.CustomerID);

    // 分页查询:要求不仅取到列表,还要知道符合条件的记录数。
    QueryParam param = new QueryParam();
    List<Customer> list = FishBLLHelper.CallSpGetDataItemList<Customer>(db, "GetCustomerList", param);
    int recCount = param.TotalRecords;
}

4. LINQ-TO-SQL 的测试代码

using( MyNorthwindDataContext db = new MyNorthwindDataContext() ) {
    db.Connection.Open();

    Customer customer = new Customer();
    customer.CustomerName = Guid.NewGuid().ToString();
    customer.ContactName = "ccccccccccc";
    customer.PostalCode = "123456";
    customer.Address = "aaaaaaaaaaaaaaaaaaaaaaaa";
    customer.Tel = "12345678";

    // Add
    db.Customer.InsertOnSubmit(customer);
    db.SubmitChanges();

    customer.ContactName = Guid.NewGuid().ToString();
    customer.PostalCode = "430076";
    customer.Address = "湖北武汉";
    customer.Tel = "87654321";

    // Update
    db.SubmitChanges();

    // Get One
    Customer ccc = db.Customer.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();

    if( ccc == null || ccc.Tel != customer.Tel )    // 检验查询结果
        throw new Exception("call Get One failed.");

    // Delete
    db.Customer.DeleteOnSubmit(ccc);
    db.SubmitChanges();

    // 分页查询:要求不仅取到列表,还要知道符合条件的记录数。
    MyDataItem.QueryParam parm = new MyDataItem.QueryParam();
    var query = from cust in db.Customer
                where cust.CustomerName.Contains(parm.SearchWord)
                select cust;

    int recCount = query.Count();
    List<Customer> list = query.Skip(parm.PageIndex * parm.PageSize).Take(parm.PageSize).ToList();
}

测试环境及结果

我的测试机器配置(ThinkPad SL510):Core2 T6670 2.2GHz, 4G内存
操作系统:Wiondow server 2003 SP2
数据库:Sql Server 2005 Express SP4

由于以前听说MSDE有并发限制,我想现在的2005 Express版应该也会有限制,所以只开了2个线程。而且由于不想在测试时等太久,所以测试次数也就选了1000次, 有点少,如果您有兴趣自己来试试,可以下载压缩包,里面有完整的代码。

一般说来,应用程序在第一次连接数据库时会慢一些,由于听说.net中有所谓的连接池的概念, 所以本测试程序在运行测试前,会根据线程的数量创建相应数量的连接,然后关闭它们,就算是给连接池做好了准备。
而且每次的测试结果只取程序启动后第一次的运行结果。

贴测试结果:

让人意外的是:Entity Framework比IINQ-TO-SQL慢了不少。比“Ado.net直接调用存储过程”就差更远了。

存储过程还是没让我失望,仍然是我最信赖的技术。所以呢,如果您想让程序有更好的性能,还是建议使用存储过程, 我想这也是为什么即使那些ORM工具一方面可以动态生成SQL,却仍然要支持调用存储过程的原因,在性能面前没有任何技术能取代存储过程!

当然了,如果某些小的项目,或者不经常执行的逻辑中,或者准确的说:对性能要求不高的地方,使用ORM也行吧。
我想有些人在性能面前又会扯到缓存,的确缓存可以在某些时候改善性能,因此,可能会说:我有缓存,存储过程不需要也很好啊。 但是,我也想说:我用存储过程,再加上缓存,会不会更快呢?

说到存储过程,让我想到一件难忘记的事: 今年早些时候去汉庭面试时,最后遇到一位“牛人”,当时我刚提到存储过程,没想到就听到对方的一堆对于存储过程的批评, 最后还说出一句很雷人的话:“存储过程只适合做点小项目!”, 哎,我当时真想说:“你去看看Sharepoint,TFS,看看人家微软用了多少存储过程!”

我知道,在这个世上的确存在一些存储过程的反对者。但是,我上家公司所有做开发的同事,全是支持存储过程的,当然了,他们也都会写存储过程, 问他们存储过程好不好,他们可以说出一大堆存储过程的优点。那些反对者所谓的缺点,在他们看来,并不认为是缺点,这里也就不想列举了。

我呢,只想说二句话:
1. 不会存储过程的人,建议去学学存储过程,学习肯定是有代价的,尤其是不同的数据库的存储过程语法不一样。
2. 会存储过程的人,可以去看看ORM,不用太投入,了解一下它们就好。

在这个测试程序项目中,还有一个问题未能解决,Entity Framework支持POCO的方式来使用(放在目录EFPOCO),我也写了相应的代码, 但项目中同时存在使用Entity Framework设计器生成的代码(放在目录EF), 当运行Entity Framework POCO的代码时,会出现异常“找不到“WinFormApp.EF.Customer”的概念模型类型”。 这二种方式单独运行时(在项目中排除另一个目录),是没有任何问题的,总之就是不能混用这二种方式。
如果谁知道原因,请帮我修改一下。 只要把目录EFPOCO加入到项目中,然后取消注释TestFactory.cs中的一些代码就可以重现异常了。在此先谢谢了。

点击此处下载完整源代码

[转载]android源代码下载目录(包含十五个开源项目)

mikel阅读(990)

[转载]android源代码下载目录(包含十五个开源项目) – qixiinghaitang – 博客园.

数量 目录
1 android源代码下载:一个图片浏览器的源码
2 android源码下载:天气预报源码
3 Android版通讯录(ExpandableListView)
4 android源代码: 开源音乐播放器
5 3D 正方体,触摸旋转,照片贴图,ANDROID的源代码
6 冒险游戏——胜利大逃亡源码另附ppt详解
7 Android学习代码,并附上豆瓣网for android项目工程
8 android Toast大全(五种情形)建立属于你自己的Toast
9 Android股票软件源代码下载
10 人人网 Android 客户端的源代码
11 facebook 客户端 Android源码下载
12 一个gallery写的类似UC桌面的menubar
13 Android源代码(国外的一个开源项目 在线音频文件播放)
14 一个游戏的源代码—netscramble
15 Android 游戏源代码下载:棋牌游戏——中国象棋人机对弈

[转载]我们的故事墙--一切为了可视化

mikel阅读(1153)

[转载]我们的故事墙–一切为了可视化 – 横刀天笑的技术空间 – 博客园.

几乎所有讲敏捷的书或者说使用了敏捷软件开发的团队都会拿出一个用户故事墙来说事。我们也有一面墙,如下所示:

20110408021

用手机拍的,不是很清晰。不过能大致看出分栏。

可能有人要说,现在都二十几世纪了,还用这么落后的手段管理,累不累啊。Project干啥吃的,Excel,Word和PowerPoint都哪儿去了,比这好用多了吧。

其实不然,且听我细细道来。

墙的可见性

这么一面墙就放到团队低头不见抬头见的地儿,所以可见性非常高。你早晨来上班的时候从墙面前经过,可能会引起你驻足一会儿,你编写代码的时候抬起头,你又看到了这面墙,或许你会发现什么问题。下班了,猛一回头,还是那面墙默默的注视着你。

比 起传统的计划管理工具,墙的可视化程度要高得多了。使用PPT制作出精美的项目计划,使用Project做出精确到小时的资源安排,但那又怎样,几乎是在 项目开始的时候项目经理将这些文件发给大家的时候大家才会看看,或者项目中开会的时候项目经理将这些文件往投影仪上一投感觉倍儿有气派,最后看这些文件的 人聊聊无几,真的我没有欺骗你。而且大家都喜欢将自己的硬盘填得满满的,到最后要找到这几个文件甚至要动用全盘搜索,那么谁还去看这些文件?只留下项目经 理在那儿意淫而已。

我们要的就是不断地在你面前晃,晃到你都记得下来为止。

更好操作

有人说软件更好用,我可真的不信。现在Office套件一个个大得惊人,打开一个大文档慢的有点受不了(可能是我的电脑不好吧),然后操作也是麻烦的要死,经常找不着自己要的东东在哪儿。

对于这面墙呢,我们只需要把卡片从左移到右,就这么简单,下至三岁小孩,上至80岁的老太太都可以完成。轻松而快捷,就像过家家一样。

分栏里可有小窍门

别看这个分栏,里面可隐藏着一些小窍门的。看看上面那张图,第二行分为7栏:

准备开发->正在开发->准备测试->正在测试->测试人员已确认->已经秀给客户看->客户已接受

这七个分栏表示一个用户故事的生命周期,从左到右。

每一栏的大小也不是随便画画的,每个故事卡片都占有一定的空间,当一个分栏里卡片过满或者很不满的时候都是一些有用的信号。比如,这里如果准备开发的卡片太少了,那就表示业务分析人员要加把劲了,我们可以做的东西不多了,你再慢了我们可要去玩了啊。

而准备测试的那一栏很满的时候责表示:测试人员受不了了,你们开发的能不能慢点啊,或者派两个人过来帮我测试吧。等等这些都是非常有用的信息,而且一看就明了的事儿。

准备开发栏卡片在墙上从上到下的排列也不是瞎来的,每个卡片都有一个优先级。优先级高的表示客户最希望赶紧完成的,所以开发人员从这一栏拿卡去做的时候可不是随便拿的哦,你得按从上往下的顺序拿卡(要是想拿下面那张容易点的,你就等等吧,呵呵)。

看 到墙的最上端没?一个大红的Blocked标记在右侧。有的卡片因为某些事儿,比如正在开发的时候发现有的地方需求不明白,需要用户确认啊;或者正在测试 的时候发现了居然有地方没完成呢,这个就像线程被某些东西阻塞了一样,我们就把卡从对应的栏移动到它对应的上方。项目经理这个时候的作用就出现了,他将重 点关注这些被阻塞的卡,为嘛被阻塞了,他都要过来“管管闲事儿”。而且用这种方式还能很好的发现我这个卡是在哪个环节被拦住的,这也有利于跟踪。

卡片上也暗藏玄机

别看那一张小小的故事卡片,上面包含的信息可多了。

左上角是一个故事编号,一般项目应该有一个项目管理系统,里面记录着故事的详细信息,用什么到系统里去索引?就靠这个小编号。而且在向版本控制系统里提交代码时写注释也可以加上这个小编号,对日后查找有用的信息那可比文字搜索派用场多了。

右上角是一个故事点数,参见前一篇文章。

中间是用一句简单的话描述这个故事。为啥用一句话呢,还用那么大的笔写。嗯,用大字写就是为了写的内容少。一句话很容易记住,所以交流的时候也能更好的沟通。

左 下角画了很多正字,那是干啥的?那个表明这个卡片从准备开发移动到正在开发栏的时刻到现在已经过去了多少天了,一直记录到该卡片从正在开发栏移动到准备测 试栏。这个数据对于用来发现开发中的时间浪费是很有用的。比如估计的一个点的故事,咋现在开发了四天了呢?别人一看就会产生这么一个疑问,这样你就要跳起 来解释一下:靠,那个地方,部署太麻烦了,太消耗时间了。这样就有可能有人自告奋勇的来改善这个部署流程(我们就是在这么一步一步的改善中成长起来的)。

注意到没有,有的卡片右下角也有正字呢。呵呵,那是测试人员画的,作用同上。

唔,有的卡片上面还贴了小纸条,那是干啥的?小纸条上一般记录着这个故事划分了多少个任务(参见前一篇文章),在完成一个任务后开发人员会在任务后面画勾勾。

哎呀,我们的大头贴都上墙了。对,那个卡片上贴的照片就是正在这个故事上工作的开发人员,这样别人一走过去就知道某某某在干啥事儿,如果有啥问题可以找他去。而且这大头贴还能生出很多很多有意思的事情,对团队的融洽也很有帮助~~

一切为了可视化

好 了,小小的一面墙,甚至是小小的一个卡片记录的东西是不是真的很多?唔,还有很多东西这篇文章里还没记录呢。因为墙上画画很容易修改,你可以按照你的团队 需要来改进这面墙。总之就是要做到更好的可视化,反映出团队中的问题,能用一些明确的信号来表示出来,这真的比项目经理做的那个精美的PPT要高兴得多, 不信你也试试。