[转载]汇编开发环境搭建

mikel阅读(700)

引子

由于这些日子一直都在研究底层的技术,从 Windows 驱动程序,到 Windows 内核等等技术的学习,

让我对底层的技术越发有兴趣了,而刚好,在研究 WRK 时,

对内存管理,寄存器,地址总线,数据总线,控制总线等的理解不够透彻,

所以越发的想学习汇编程序设计来提升功力,

而由于近来在公司里一直都有项目压着,所以在公司里也实在不好拿本汇编程序设计看,

所以只好晚上回来学习了, 汇编看了几个晚上,也算是蛮有感觉的。

今天就先来搭个开发环境再说吧。

开发环境搭配

我介绍四种开发汇编程序的方式:

第一种:直接在 Dos 环境下使用 Edit 命令调出源码编辑框,

生成源码后,可以使用由微软提供的 masm 汇编编译器来对源码进行编译,

编译完后再使用 Linker 连接器即可得到可执行文件,

这种方式现在几乎被灭绝了(当然使用 masm 汇编编译器还是很普遍的),

除非你真要在 DOS 环境下运行汇编程序;

第二种:通过简化第一种方式而来;

第三种:直接使用 Masm for Windows 集成实验环境,这个开发环境呢,非常适合汇编语言的初学者,

因为这个 IDE 本身就是由一些从事汇编程序教学的大学老师开发的出来用于汇编初学者进行学习和实验的,

所以使用简单,方便,这里可以对这个 IDE 稍加推荐;

第四种:则是通过 Visual  Studio 这个强大的 IDE 来实现汇编程序的编译,运行和调试,

至于 Visual  Studio 就不多做介绍了,.Net 用了这么多年,这东西强大到什么程度那是总所周知的;

第一种方式:使用 Edit + MASM 5.0 编译器 + Linker 连接器

其实这种方式是很简单的,只是很麻烦,因为简单而且麻烦,

所以我采用尽可能的将截图传上来,然后稍加注解的方式进行介绍,

软件准备:

需要 MASM 5.0 或者以上的汇编编译器

首先,是要编辑汇编源代码:

其实对于源码的编辑根本不需要向如下这么麻烦,直接拿个记事本就 OK 了

运行 cmd 命令

image

输入 Edit 命令从而弹出汇编源码编辑框

image

image

在源码输入框中输入汇编源码

image

将编辑好的汇编源码保存到 xx.asm 文件中

image

image

image

然后就是要编译编辑好的汇编源代码

在 Dos 环境下进入到  MASM 5.0  汇编编译器所在的目录

image

然后运行 masm.exe

image

image

可以从上面的截图中看到  [. ASM]  的标记,这个标记代表的是需要在这里输入要编译的源程序文件名,

这里有一点特别的是,由于默认的文件扩展名为 .asm ,所以在编译 .asm 的汇编源程序时可以不用指定源程序所在文件的扩展名。

我们将一开始编辑好的汇编源程序所在的文件输入以进行编译

image

指定文件所在路径后按  Enter  键

image

此时可以看到编译器提示需要输入要编译出的目标文件的名称,由于在一开始已经指定了 BoyXiao. asm ,

所以编译器自动指定了目标文件的名称为 BoyXiao. obj 的名称,如果在这里不做修改的话,

则编译器会以默认目标文件名称 BoyXiao. obj 进行输出,在这里我并不改变名称,所以直接按 Enter 键即可

image

此时又提示需要输入列表文件的名称,其实是完全可以不要让编译器生成这个 LST 文件的,所以也不需要进行输入,

直接按 Enter 键即可

image

此时又提示需要输入交叉引用文件的名称,这里也完全可以不要让编译器生成这个 CRF 文件,

所以也不需要进行输入,直接按 Enter 键即可

image

至此,汇编源程序编译成功,

编译得到的结果就是在我的 E:\Tools\MASM\MASM 5.0 目录下生成了一个 BoyXiao.obj 文件

image

下面就是要实现对目标文件的连接

经过编译操作后,我们得到了一个 .obj 的目标文件,但很显然,这还并不是一个可执行文件,

下面就需要对目标文件进行连接,从而得到一个可执行文件。

一般来说,需要准备一个连接器,这里我使用的是微软提供的 Linker 连接器,即 LINK.EXE ,

image

进入 LINK.EXE 文件所在目录,直接运行 LINK.EXE

image

image

此时提示需要输入被连接的目标文件的名称,这里也就是  BoyXiao.obj  ,

由于我的 BoyXiao.obj 和 Link.exe 在同一目录下,所以不需要指定路径,直接给出 .obj 的名称即可,

image

按  Enter  键

image

这里提示需要输入要生成的可执行文件的名称,此时如果想要将可执行文件输入到指定目录下,

则需要指定目录,否则只需要指定名称即可,并且可以看到名称已有默认值:BOYXIAO.EXE

在这里我选择默认值,所以直接按 Enter 键即可

image

按  Enter  键

image

又继续提示需要输入映像文件的名称,在这里,不需要生成这个文件,所以直接按 Enter 键即可

image

此时又提示需要输入库文件的名称,由于我们的这个程序中没有使用任何的子程序,

也就是根本没有调用什么库文件,所以这里也可以直接按 Enter  键处理

image

至此,整个目标文件的连接工作结束,得到的结果是一个 EXE 文件

image

执行汇编程序

image

其实执行起来是看不到什么结果的,因为上面的汇编代码没有输出任何内容,而只是改变了几个寄存器的值而已,

自然也就看不到任何的输出了。

第二种方式:使用 Edit + MASM 5.0 编译器 + Linker 连接器 (简化版)

这种方式其实和第一种方式说不上有什么区别,只不过在编译和连接过程中使用了很多编译器和连接器的默认设置而已

软件准备:

和第一种方式一样

编辑汇编源代码:

和第一种方式一样,也可以是直接使用文本编辑器编辑即可

编译编辑好的汇编源代码

直接到 MASM.EXE 文件目录,然后直接使用 masm 编译指定路径的文件即可

特别注意的是,需要在目录的后面加上 “;”

image

image

同样在 E:\Tools\MASM\MASM 5.0 目录下生成了  BoyXiao.obj 目标文件

image

实现目标文件的连接

同样,直接下到连接器 LINK.EXE 文件所在的目录,然后直接使用 LINK 连接指定的目标文件即可

同样需要注意在目录或文件名的后面加上 “;”

image

image

可以看到连接成功了,从而生成了可执行文件,当然这个可执行文件运行的效果和第一种方式中一样,

即看不到任何输出

image

第三种方式:MASM For Windows 集成开发环境

上面的两种方式都显得非常麻烦,编译了还要连接,谁有那么多时间去浪费啊,

所以,下面介绍的这个 MASM For Windows 集成开发环境就显得非常有优势了,

软件准备:

MASM For Windows 集成开发环境,我这里使用的是 2010 版本,大小 15.5 MB

实现 HelloWorld

直接打开 MASM For Windows 集成开发环境,然后找到范例程序,然后直接运行即可

image

image

可以看出,使用这个东东确实会方便很多很多

第四种方式:使用 Visual  Studio 来实现开发汇编程序

软件准备:

既然是使用  Visual  Studio  来开发了,自然就需要  Visual  Studio  IDE 了,

在这里呢,我使用的是  Visual  Studio  2010 ,当然 2008 和 2005 都是可以的,

只不过在一些设置上有些许区别而已,在这里,我也不做区分,大家感兴趣的可以去网上淘一大把,

然后就是<<Intel  汇编语言程序设计>>中的 Irvine 包,这个在网上也有一大把

VS 2010 设置:

在  VC++  中新建一个空项目,取名为  Test

image

定制  VC++  工程构建规则

image

image

设置完  VC++  生成自定义项文件后,再添加一个  C++  文件,并注意取名时后缀名记为  .asm

image

设置  VC++  工程的项目属性

image

需要添加库路径,这里的库路径指的是 <<Intel  汇编语言程序设计>> 中的 Irvine 库

image

设置包含路径

image

设置依赖库文件,添加 Irvine32.lib

image

设置项目输出

image

设置生成汇编代码列表,添加  $(ProjectName).lst  属性

image

Hello World 程序:

image

直接运行即可

image

结束语

花了这么多的截图来介绍这四种汇编程序开发方式,也算是良苦用心了,事实上呢,这四种方式,

我们并没有必要全部掌握,我们只需找到适合自己的方式即可,

比如,初学的话,我觉得  MASM  For  Windows  IDE  就非常不错,

而至于系统性的开发,尤其是对于 Win32  汇编程序的开发,则选择  Visual  Studio  是个不错的选择。

2010 年 11 月 05 日

[转载]浅谈C# 中的lock 方法与Monitor 类的关系_以及同步与互斥

mikel阅读(811)

[转载]浅谈C# 中的lock 方法与Monitor 类的关系_以及同步与互斥 – xugang – 博客园.

这是一个旧瓶新装的话题。只是将我今日的所见所思予以实践和整理,以备往后所用。同时也提供给大家,希望能有所帮助。

A  从单例模式说起

代码如下:

class Program
{
 static void Main(string[] args)
 {
 Singleton demo1 = Singleton.Init();
 Singleton demo2 = Singleton.Init();
 }
}

public class Singleton
{
 private Singleton() { }

 private static Singleton instance = null;
 private static readonly object singleObj = new object();

 public static Singleton Init()
 {
 if (null == instance)
 {
 lock (singleObj) //singleObj 不能使用instance 代替
 {
 if (null == instance)
 {
 instance = new Singleton();
 }
 }
 }
 return instance;
 }
}

关于单例模式,大家可以参考:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html

B  关于lock 方法

在以上单列模式的代码中:

如果将: private static readonly object singleObj = new object();
修改为: private static readonly object singleObj = null;

将在lock( ) 方法处,抛出未处理的异常:System.ArgumentNullException: 值不能为空!

●  lock 关键字将语句块标记为临界区

lock( obj ) 方法中的obj 对象为:获取排他锁的指定对象

obj 对象为null 将导致 ArgumentNullException 异常。

lock 方法在MSIL 中会被编译成 Monitor.Enter( ) 和 Monitor.Exit( ) 。例如:

public static void MyLock()
{
 lock (typeof(Program))
 {
 }
}

以上代码通过lock 语句使MyLock 同步,这个方法被编译成MSIL 后,代码如下图所示:

image

从上图被标注的区域可以看到:一条lock 语句被编译成了调用Monitor 的Enter 和Exit 的方法。
lock 的功能就相当于直接调用Monitor 的Entry 方法,并在结束后会自动调用Monitor 的Exit 方法解除锁定。

C  关于Monitor 类

Monitor 类属于System.Threading 命名空间;

Monitor 类提供同步对对象的访问的机制;

使用 Monitor 锁定对象(即引用类型)而不是值类型;

Monitor 类型对于多线程操作是安全的;

Monitor 类的示例一:

class Program2
{
 static void Main(string[] args)
 {
 MyMonitor1 mon_1 = new MyMonitor1();
 mon_1.Test();
 }
}

class MyMonitor1
{
 private object obj = new object();

 public void Test()
 {
 //开始锁定
 System.Threading.Monitor.Enter(obj);
 try
 {
 //lock 的区域
 }
 catch (Exception e)
 {
 // 异常处理代码
 }
 finally
 {
 //解除锁定
 System.Threading.Monitor.Exit(obj);
 }
 }
}

Monitor 类的示例二:

class Program3
{
 static void Main(string[] args)
 {
 //多个线程调用Test方法
 Thread t1 = new Thread(MyMonitor2.Test);
 Thread t2 = new Thread(MyMonitor2.Test);
 t1.Start();
 t2.Start();
 }
}
class MyMonitor2
{
 private static object obj = new object();

 public static void Test()
 {
 //使用TryEntry方法设置一个锁定超时
 if (Monitor.TryEnter(obj, 2000))
 {
 try
 {
 Console.WriteLine("等待4秒开始");
 Thread.Sleep(4000);
 Console.WriteLine("等待4秒结束");
 }
 finally
 {
 //解除锁定
 Monitor.Exit(obj);
 }
 }
 else 
 {
 Console.WriteLine("已超时2秒!");
 }

 }
}

D  关于同步与互斥

关于同步的问题,可以使用Monitor 类来解决。

在使用Monitor 类的时候,建议将Monitor.Enter( ) 方法替换成Monitor.TryEnter( ) 方法。

使用Monitor.Enter( ) 方法时,代码如下:

Monitor.Entry(lockObj);
try
{
 // lockObj的同步区
}
catch(Exception e)
{
 // 异常处理代码
}
finally
{
 Monitor.Exit(lockObj); // 解除锁定
}

注意:如果直接在C#源程序中使用Monitor类,就必须调用Exit方法来显式地解除锁定。

使用Monitor.TryEnter( ) 方法时,代码如下:

if(Monitor.TryEntry(lockObj, 1000))
{
 try
 {
 }
 finally
 {
 Monitor.Exit(lockObj);
 }
}
else
{
 // 超时后的处理代码
}

注意:使用TryEntry方法设置一个锁定超时,单位是毫秒。

上面的代码设置了锁定超时时间为1秒。

如果在1秒钟之内,lockObj 还未被解锁,TryEntry 方法就会返回 false;

如果在1秒钟之内,lockObj 被解锁,TryEntry 方法就会返回 true。

这样,可以使用TryEntry 方法来避免死锁。

同步与互斥 示例一:

class Program4
{
 static void Main(string[] args)
 {
 Thread A = new Thread(TestClass1.GetA);
 A.Name = "Thread_A ";
 Thread B = new Thread(TestClass1.GetB);
 B.Name = "Thread_B ";
 A.Start();
 B.Start();
 }
}

class TestClass1
{
 private static object resource_A = new object();
 private static object resource_B = new object();

 public static void GetA()
 {
 MyWrite("in GetA()");
 if (Monitor.TryEnter(resource_A, 2000))
 {
 MyWrite("get resource_A");
 GetB();
 Thread.Sleep(2000);
 Monitor.Exit(resource_A);
 MyWrite("exit resource_A");
 }
 else
 {
 MyWrite("no has resource_A");
 }
 }

 public static void GetB()
 {
 MyWrite("in GetB()");
 if (Monitor.TryEnter(resource_B, 1000))
 {
 MyWrite("get resource_B");
 GetA();
 Thread.Sleep(1000);
 Monitor.Exit(resource_B);
 MyWrite("exit resource_B");
 }
 else
 {
 MyWrite("no has resource_B");
 }
 }

 //自定义打印方法
 private static void MyWrite(string str)
 {
 Console.WriteLine(Thread.CurrentThread.Name + str);
 }
}

结果如下:

TryEnter1

同步与互斥 示例二:

class Program5
{
 static void Main(string[] args)
 {
 Thread A = new Thread(TestClass2.GetA);
 A.Name = "Thread_A ";
 Thread B = new Thread(TestClass2.GetB);
 B.Name = "Thread_B ";
 A.Start();
 B.Start();
 }
}

class TestClass2
{
 //排他锁的对象 A
 private static object resource_A = new object();
 //排他锁的对象 B
 private static object resource_B = new object();

 public static void GetA()
 {
 MyWrite("in GetA()");
 if (Monitor.TryEnter(resource_A, 1000))
 {
 MyWrite("get resource_A");
 Thread.Sleep(1000);
 //GetB();
 if (Monitor.TryEnter(resource_B, 2000))
 {
 Monitor.Exit(resource_B);
 }
 Monitor.Exit(resource_A);
 MyWrite("exit resource_A");
 }
 else
 {
 MyWrite("no has resource_A");
 }
 }

 public static void GetB()
 {
 MyWrite("in GetB()");
 if (Monitor.TryEnter(resource_B, 1000))
 {
 MyWrite("get resource_B");
 Thread.Sleep(1000);
 //GetA();
 if (Monitor.TryEnter(resource_A, 2000))
 {
 Monitor.Exit(resource_A);
 }
 Monitor.Exit(resource_B);
 MyWrite("exit resource_B");
 }
 else
 {
 MyWrite("no has resource_B");
 }
 }

 //自定义打印方法
 private static void MyWrite(string str)
 {
 Console.WriteLine(Thread.CurrentThread.Name + str);
 }
}

结果如下:

TryEnter2

参考文章:

浅谈c#中使用lock的是与非 作者:Jeff Wong

同步技术之Monitor 作者:银河使者

示例下载

[转载]LogParser的IIS网站分析技巧

mikel阅读(1186)

[转载]LogParser的IIS网站分析技巧 – 虹桥路3号 – 博客园.

LogParser的IIS网站分析技巧

LogParser介绍

LogParser是微软的一个免费的日志分析工具,它支持许多格式的文件类型。主要有如下几类:

· IIS 文件格式

Ø IISW3C: IIS产生的W3C扩展格式

Ø IIS: IIS专有格式.

Ø BIN: IIS的BIN格式.

Ø IISODBC: IIS可以把日志存储在数据库中。LogParser可以分析存储在数据库中的IIS日志.

Ø HTTPERR: Http.sys日志格式.

Ø URLSCAN: URLScan 日志格式.

· 通用文本格式

Ø CSV: 逗号分隔符文件.

Ø TSV: 以空格或者以制表符分隔的文件.

Ø XML: XML格式.

Ø W3C: W3C格式.

Ø NCSA: NCSA格式.

Ø TEXTLINE: 普通文件文件. LogParser可以按行返回内容

Ø TEXTWORD: LogParser可以把按字返回内容.

· 系统信息

EVT: 事件日志文件.

FS: 文件目录.

REG: 注册表格式.

ADS: AD信息.

另外还有一些其它格式,如NetMon, ETW等,在此不详述了。

LogParser原理

LogParser架构如下图所示:

clip_image001

注:图片引自http://e-mojo.net/wp-content/uploads/2009/11/logparser_architecture.gif

LogParser的核心为类SQL引擎,主要用于LogParser的SQL解析。使用LogParser我们可以把日志文件转换为很多格式,然后,我们可以用自己顺手的工具对其进行分析。

需要注意的是,如果我们要输出图形格式,必须安装Office Web组件。

IIS高级日志分析

本文主要介绍一些高级IIS日志分析功能,基本的分析功能请参考这些BLOG:

http://hi.baidu.com/tpxc/blog/item/b6e4561060f2ecf9c2ce7931.html

http://www.cnblogs.com/yonglun/archive/2007/02/20/652929.html

每天用户访问数

logparser “SELECT To_Date(TO_LOCALTIME(TO_TIMESTAMP(date, time))) AS [Date1], c-ip AS CIP INTO IISHC_DistinctClientIPPerDay.csv FROM *.log GROUP BY [Date1], CIP” -i:IISW3C -o:CSV -recurse:-1

我们按日期进行汇总,主要是利用Group by 实现。由于IIS日志中时间为UTC格式,因此,我们需要使用To_Date(TO_LOCALTIME(TO_TIMESTAMP(date, time)))把其转换为本地时间。

recurse:-1参数使LogParser对子目录下所有文件进行统计。

本例中产生一个CSV文件,我们可以使用Excel进行处理,得出每天用户数曲线(当然,我们也可以直接用LogParser产生图形)。如下是一个例子:

clip_image003

每小时用户访问数

logparser “SELECT TO_LOCALTIME(QUANTIZE(TO_TIMESTAMP(date, time),3600)) AS Hours, COUNT(*) AS Hits INTO IISHC_RequestsPerHour.csv FROM *.log where To_Date(TO_LOCALTIME(TO_TIMESTAMP(date, time)))=TIMESTAMP(’10/08/2010′,’MM/dd/yyyy’ ) GROUP BY Hours ORDER BY Hours” -i:IISW3C -o:CSV -recurse:-1

主要用法与上例类似。不过我们需要指定日期。指定日期在where To_Date(TO_LOCALTIME(TO_TIMESTAMP(date, time)))=TIMESTAMP(’10/08/2010′,’MM/dd/yyyy’ )中实现。

clip_image005

拆分文件

缺省情况下,IIS每天产生一个日志文件。对于一些特别繁忙的网站来说,IIS日志文件可能会非常大。我曾经有一个客户,每个日志文件有2个G之多。这么大的文件用LogParser进行分析时会非常慢,同时也很容易报错。

解决办法是把日志文件进行拆分成许多小文件分别进行分析。如下命令可以把一个IIS日志按小时分成24个文件:

logparser “SELECT REPLACE_CHR(REPLACE_CHR(TO_STRING(TO_LOCALTIME(QUANTIZE(TO_TIMESTAMP(date, time), 3600)), ‘yyyy-MM-dd hh:mm:ss’), ‘:’, ‘_’), ‘ ‘, ‘_’), date, time, c-ip, cs-uri-stem, cs-uri-query, sc-status, sc-substatus, sc-win32-status, sc-bytes, cs-bytes, time-taken FROM ex080114.log TO ex080114_*.log” -i:IISW3C -o:W3C

这里边的技巧请大家自己去理解J 怎么样?

附录

1. LogParser下载地址

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&displaylang=en

2. Office 2003 Web Component

http://www.microsoft.com/downloads/en/details.aspx?FamilyId=7287252C-402E-4F72-97A5-E0FD290D4B76&displaylang=en

3. Security Update for Microsoft Office Web Components

http://www.microsoft.com/downloads/en/details.aspx?familyid=95c94c9a-6aca-42fb-9679-3234f06c72f7&displaylang=en

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(2)

mikel阅读(1034)

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(2) – 刘铭.net-OPS.cc – 博客园.

webHandler执行类的方法,

但在多数情况下,我们会将WebHandler封装进一个单独的动态链接库,我们需要将引用WebHandler DLL的程序集或程序集中的任意一个类的Type做为参数传递给WebHandler,

这样就可以在WebHandler中利用反射调用引用WebHandler类库的程序集中的代码!

实现代码如下:

/* *
 * name     : ExecuteHandler.cs 
 * author   : newmin
 * date     : 09/29 2010
 * note     : 用来处理请求,请求的URI参数如:Exc.ashx?cmd=IP,GetIP,127.0.0.1
 * 
 * 要执行操作的类必需要程序集名称命名空间下:
 * 如要执行AtNet.Security下的User类,则User类的命名空间为:HuiShi.Security.User
 * 调用方式**.ashx?cmd=User,GetScore,newmin
 * 
 * */
namespace AtNet.Web
{
    using System;
    using System.Web;
    using System.Reflection;
    using System.Collections.Generic;

    public abstract class ExecuteHandler : IHttpHandler
    {
        //绑定类型用于获取程序集,只能在子类的静态构造函数中赋值
        protected static Type _type;
        #region IHttpHandler 成员
        public bool IsReusable{ get; set; }
        
        public void ProcessRequest(HttpContext context)
        {
            string cmd=context.Request["cmd"].Replace("+"," ");         //将空格做为+号替换

            string[] args = cmd.Split(',');
            if (args.Length > 2)
            {
                //获取执行当前代码的程序集并创建实例
               Assembly ass = Assembly.GetAssembly(_type);
                object obj = ass.CreateInstance(_type.Namespace+"."+args[0], true);

                //获取实例类型
                Type type=obj.GetType();

                //未添加WebExecuteAttribute特性的类将不被执行
                object[] attrs= type.GetCustomAttributes(typeof(WebExecuteAttribute), false);
                WebExecuteAttribute attr =attrs.Length>0?attrs[0] as WebExecuteAttribute:null;
                if (attr == null) { context.Response.Write("此模块不允许被执行!"); return; }

                //获取方法并执行
                MethodInfo method =type.GetMethod(args[1],BindingFlags.Instance|BindingFlags.Public|BindingFlags.IgnoreCase);
                object returnObj=method.GetParameters() != null?method.Invoke(obj,cmd.Substring(args[0].Length + args[1].Length + 2).Split(','))
                        :method.Invoke(obj, null);

                //如国返回String类型或值类型则输出到页面
                if (method.ReturnType == typeof(string) ||obj is ValueType)
                    context.Response.Write(returnObj.ToString());
            }
        }

        #endregion
    }
}

我们需在继承ExecuteHandler的类的静态构造函数中对_type赋值:

namespace AtNet.Web.Tools
{
    using System;
    using System.Reflection;

    public class WebHandler:AtNet.Web.ExecuteHandler
    {
        static WebHandler()
        {
           _type = typeof(WebHandler);
       }
    }
}

这样我们就能在将ExecuteHandler分离出来,被别的项目所引用

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(1)

mikel阅读(1030)

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(1) – 刘铭.net-OPS.cc – 博客园.

一般处理程序(.ashx)比Web窗体文件(.aspx)性能更好,再不涉及到html的场景中经常用到!

通过VS创建的ashx文件包括代码后置文件,而实际上在ashx文件中定义只需要声明Web Handler并添加class

如: <%@ WebHandler Class=”Web.Handler” %>

我们可以在项目里面创建一个实现IHttpHandler接口的类,然后将ashx文件class设为该类的名称,这样维护起来是不是更方便?

大多数的同学可能就直接在IHttpHandler的ProccessRequest(HttpContext context)方法中添加自己的代码了,但如果网站包含50个ashx文件的话又会怎么样呢?下面我来阐述一个思路

我们是否可以将要请求的代码包含在一个个的类里,然后在ProccessRequest方法里利用反射技术执行代码就好了呢?

反射,程序员的快乐!

下面我们一步一步开始实现我们的想法:

首先我们需要为被执行代码添加授权,表明他能通过WebHandler执行,要不然就能通过WebHandler执行类库里的任何类!

1 代码:WebExecuteAttribute.cs
2 namespace HuiShi.Web
3 {
4 using System;
5 [AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=true)]
6 public class WebExecuteAttribute : Attribute{}
7 }
8
9 }
东方网新,为您提供专业的网站建设,软件开发,网络营销SEO,网络推广服务,代理国外主机空间,域名注册,服务热线:(+86)18608275575,电子邮件:master#atnet.cc;欢迎您访问东方网新网站:www.atnet.cc

下面该是反射技术大展神手的时候了!先说明一下我们请求的URI格式如下:

http://localhost:11080/exc.ashx?cmd=IPQuery,GetNameByAddress,127.0.0.1

参数以”,”格开,IPQuery为类,GetNameByAddress为IPQuery的方法,GetNameByAddress后的为方法的参数

实际上执行的代码为:

01 namespace HuiShi.Web
02 {
03 using System;
04 using System.Web;
05
06 [WebExecute]
07 public class IPQuery
08 {
09 public string GetNameByAddress(string address)
10 {
11 return “newmin’s website www.atnet.cc“;
12 }
13 }
14 }

在代码中通过”,”来将参数传给方法,并判断方法的返回值是否可以输出到页面,可以的话就输出到页面!

01 代码:ExecuteHandler.cs
02
03 namespace HuiShi.Web
04 {
05 using System;
06 using System.Web;
07 using System.Reflection;
08 using System.Collections.Generic;
09
10 public class ExecuteHandler : IHttpHandler
11 {
12
13 #region IHttpHandler 成员
14 public bool IsReusable{ get; set; }
15 public void ProcessRequest(HttpContext context)
16 {
17 string cmd=context.Request["cmd"].Replace(“+”,” “); //将空格做为+号替换
18
19 string[] args = cmd.Split(‘,’);
20 if (args.Length > 2)
21 {
22 //获取执行当前代码的程序集并创建实例
23 Assembly ass = Assembly.GetAssembly(this.GetType());
24 object obj = ass.CreateInstance(this.GetType().Namespace+”.”+args[0], true);
25
26 //获取实例类型
27 Type type=obj.GetType();
28
29 //未添加WebExecuteAttribute特性的类将不被执行
30 object[] attrs= type.GetCustomAttributes(typeof(WebExecuteAttribute), false);
31 WebExecuteAttribute attr =attrs.Length>0?attrs[0] as WebExecuteAttribute:null;
32 if (attr == null) { context.Response.Write(“此模块不允许被执行!”); return; }
33
34 //获取方法并执行
35 MethodInfo method =type.GetMethod(args[1],BindingFlags.Instance|BindingFlags.Public|BindingFlags.IgnoreCase);
36 object returnObj=method.GetParameters() != null?method.Invoke(obj,cmd.Substring(args[0].Length + args[1].Length + 2).Split(‘,’))
37 :method.Invoke(obj, null);
38
39 //如国返回String类型或值类型则输出到页面
40 if (method.ReturnType == typeof(string) ||obj is ValueType)
41 context.Response.Write(returnObj.ToString());
42 }
43 }
44
45 #endregion
46 }
47 }
东方网新,为您提供专业的网站建设,软件开发,网络营销SEO,网络推广服务,代理国外主机空间,域名注册,服务热线:(+86)18608275575,电子邮件:master#atnet.cc;欢迎您访问东方网新网站:www.atnet.cc

然后我们创建1个WebHandler将其Class设为”HuiShi.Web.ExecuteHandler”,再在 ExecuteHandler命名空间下创建几个类,并用[WebExecute]特性修饰,这样我们只需要加代码而不用加文件就可以完成操作了!是不是 省了很多功夫,将使用WebHandler请求的类放到1个文件中集中管理,不是方便了代码组织管理吗?

想想上面的实现,没什么错误,但如果我们要将WebHandler封装成一个动态链接库,引用到其他项目的话呢?

具体实现请浏览:更灵活,更易维护的WebHandler之通用webHandler编码方案(2)

[转载]asp.net中的HttpHandler解决方案:OPS.ExecuteHandler组件

mikel阅读(837)

[转载]asp.net中的HttpHandler解决方案 – OPS.ExecuteHandler组件 – SkyBOOB – 博客园.

请看介绍这个解决方案的两篇文章

更灵活,更易维护的WebHandler之通用webHandler编码方案(1)

更灵活,更易维护的WebHandler之通用webHandler编码方案(2)

此次在原有基础上进行大规模的改进和升级:

添加 IWebExecute 接口。用于对执行类和类的方法时候进行更多控制!

内置:PostAttributeGetAttribute 均实现了IWebExecute接口!

使用方法如下:

一:引用OPS.Lib.dll到项目中

二:向ExecuteHandler注册

01 namespace OPS.HandlerDemo
02 {
03 using OPS.Web; //引用命名空间
04
05 public class WebHandler:ExecuteHandler
06 {
07 static WebHandler()
08 {
09 _type=typeof(Login);
10 }
11 }
12 }

三:注册Handler载体 — 一般程序处理程序(.ashx后缀的文件)

添加ops.ashx文件,代码如下:

1 <%@ WebHandler Class="OPS.HandlerDemo.WebHandler" %>

我们使用ops.ashx来执行类和调用类的方法

ops.ashx参数说明:

ops.ashx?task=类名,方法名,参数(多个参数用”,”隔开)

例:ops.ashx?task=login,enter,ops,ops

(执行login类的enter方法,两个ops为enter方法的两个参数)

四:创建可被ExecuteHandler执行的类

如果需要被ExecuteHandler执行,则需要为类型添加 WebExecuteable 特性

01 namespace OPS.HandlerDemo.Login
02 {
03 [WebExecuteable] //必须添加此特性类型的方法才能被调用
04 public class Login
05 {
06 public string Enter(string username, string password)
07 {
08 return "成功";
09 }
10 }
11 }

运行ops.ashx?task=login,enter,ops,ops,你将会看见成功字样!

五:使用内置的Post和Get特性

1.为方法添加Post特性将可以阻止用户发送GET请求,如:

01 namespace OPS.HandlerDemo.Login
02 {
03 [WebExecuteable] //必须添加此特性类型的方法才能被调用
04 public class Login
05 {
06 [Post]
07 public string Enter(string username, string password)
08 {
09 return "成功";
10 }
11 }
12 }

在浏览器中直接输入地址将出现结果如图:

2.Get特性,跟Post同理

3.阻止短时间内的多次反复请求

只需要为Get或Post特性的AllowRefreshMillliSecond属性赋值就可以简单实现!如:

1 //1秒种之内只允许请求一次,否则提示服务不可用
2 [Get(AllowRefreshMillliSecond=1000)]
3 public string Enter(string username, string password)
4 {
5 return "成功";
6 }

六:为ExecuteHandler创建自定义特性

我们将通过实例创建一个NotLoginAttribute让已经登陆的用户不能再次登陆

01 using OPS.Web;
02
03 [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple=false,Inherited=false)]
04 public class NotLoginAttribute:Attribute,IWebExecute
05 {
06 #region IWebExecute 成员
07 //实现IWebExecute的方法
08 public void PreExecuting()
09 {
10 HttpContext.Current.Response.Write("已经登陆");
11 HttpContext.Current.Response.End();
12 }
13 #endregion
14 }

并在Login类的Enter方法上应用此特性

01 namespace OPS.HandlerDemo.Login
02 {
03 using OPS.Web;
04 [WebExecuteable] //必须添加此特性类型的方法才能被调用
05 public class Login
06 {
07 [Get]
08 [NotLogin]
09 public string Enter(string username, string password)
10 {
11 return "成功";
12 }
13 }
14 }

再次打开浏览器请求ops.ashx?task=login,enter,ops,ops

结果如下:

该组件在创建Ajax应用时候能简化很多工作,使用该组件可以称的上是在写类型,而不是写页面

点击这里下载ExecuteHandler的代码文件:

本地下载地址:http://files.cnblogs.com/newmin/ops.lib.rar

官方主页下载:http://www.ops.cc/lib/

[转载]InfoQ: WCF的未来是RESTful

mikel阅读(1038)

[转载]InfoQ: WCF的未来是RESTful.

Windows通信基础(WCF)的产品经理,Glenn Block在主题为“WCF,Evolving for the Web”的在线研讨会上表示,微软面向服务应用的构建框架将进行根本性的重构,新的架构将以HTTP为中心。

在这次在线会议的开始,Block总结了业界的当前趋势:

  • 向基于云的计算转变
  • SOAP逐渐淡出
  • 浏览器运行于各类设备之上日渐盛行
  • REST采纳的增长
  • 类似OAuth、WebSocket这样标准的出现

他表示,WCF的当前架构在很大程度上是基于SOAP的,如下图示:

image

WCF的一个关键特性是,在相同编程模型下支持多种传输协议(HTTP、TCP、命名管道)。遗憾的是,一旦触及HTTP,它的大量好处(伸缩性、 内容协商)就消失了,原因在于WCF只是把它当作一种传输手段。因此,Block期望将支持HTTP的WCF视为一种具备简单灵活编程模型的一流应用协 议。如下图示:

image

HTTP是在.NET 3.5中引进的,这让创建通过HTTP访问的服务成为可能,但是“没有办法访问所有HTTP必须提供的东西,它是一种非常扁平的模型,面向RPC,但 Web不是这样的。在Block看来,Web是一种非常丰富的资源集”。与其将当前的WCF改造成可以在HTTP之上正常工作,Block认为WCF应该 “以HTTP的思想,使用RESTful方式”重新构架。

WCF将包含助手API,完成预处理HTTP请求或响应、解析和操纵所有参数、将HTTP信息封装到对象中以供未来处理之用。只要愿意,用户就可以 利用它将自己从直接处理HTTP内部细节的痛苦中解脱出来。这个特性还将提供一种插件功能,主要针对像JSON, Atom, OData等这样的数据格式的媒体类型格式化器。WCF将内置部分格式的支持,但是用户能够加入自己的格式化器。

新的WCF已经正在构建当中,Block演示了使用它的样例代码,但他表示这个特性集和WCF将来的样子尚未最终定案。他们不久将在CodePlex上发布框架的初始版本,让社区能够进行测试和反馈,让WCF的未来逐渐成型。更多的细节将在PDC 2010大会期间得到公开。

更新

我们向Glenn Block问起了其他协议,尤其是SOAP,的未来状况。他的答复是,WCF将完全支持现有的技术栈,当前的发展旨在将WCF演变成完全支持HTTP,而又不宣布放弃WCF目前已经取得的成果。

现在,WCF社区站点搭建完成,所有对WCF演变感兴趣的人们可以通过它了解WCF的近况。

在PDC 2010大会上,Glenn Block在WCF未来和它与微软在SOA技术中的当前投资之间的关系里给出了更多细节。

查看英文原文: The Future of WCF Is RESTful [Updated]

[转载]Android 为你的应用程序添加快捷方式

mikel阅读(1088)

[转载]Android 为你的应用程序添加快捷方式【优先级高的快捷方式】 – Terry_龙 – 博客园.

有人会说,快捷方式,不是安装完应用程序后,长按应用程序的ICON然后将它拖到桌面上不就行了吗?没错,这样是一种方法,但这种方法有一个缺点,看图吧:

如上图,如果我们长按桌面点击快捷方式,将会跳到如下界面,如果单从这个界面选择的话,我们就必须进入Applications 目录,然后再在Applications 里面选择我们对应的应用程序,这样的话用户可能得麻烦的去找咯。但我们同时会发现,在Applications 的下面有很多另外的ICON比如 上图的BookMark ,Contact 等,这些也是应用,那么这些是怎么做到不用进去Applications 而在第一页就出现供用户选择呢?今天我们就针对这点来讲讲吧。

要做这一功能首先我们先来了解一下manifest 里面的这一标签:

<activity-alias>

syntax:语法:
<activity-alias android:enabled=["true" | "false"]
                android:exported=["true" | "false"]
                android:icon="drawable resource"
                android:label="string resource"
                android:name="string"
                android:permission="string"
                android:targetActivity="string" >
    . . .
</activity-alias>
contained in:隶属于:
<application>
can contain:可以包含:
<intent-filter>
<meta-data>
description:说明:
An alias for an activity, named by the targetActivity attribute. The target must be in the same application as the alias and it must be declared before the alias in the manifest.
activity的一个别名,用targetActivity属性命名。目标activity必须与别名在同一应用程序的manifest里,并且在别名之前声明。
The alias presents the target activity as a independent entity. It can have its own set of intent filters, and they, rather than the intent filters on the target activity itself, determine which intents can activate the target through the alias and how the system treats the alias. For example, the intent filters on the alias may specify the “Android.intent.action.MAIN” and “Android.intent.category.LAUNCHER” flags, causing it to be represented in the application launcher, even though none of the filters on the target activity itself set these flags.
别名作为一个独立的实体代表目标activity。它可以有它自己的一套intent filter,它们,而不是目标activity自己的intent filter,决定哪个intent能够活性化目标通过别名以及系统如何处理别名。例如,别名的intent filter可以指定”Android.intent.action.MAIN“和”android.intent.category.LAUNCHER“标签,使之显示在应用程序启动器上,即使目标activity自己没有设置这些标签。

With the exception of targetActivity, <activity-alias> attributes are a subset of <activity> attributes. For attributes in the subset, none of the values set for the target carry over to the alias. However, for attributes not in the subset, the values set for the target activity also apply to the alias.
targetActivity的例外,<activity-alias>属性是<activity>属性的一个子集。对于该子集中的属性,目标activity中设置的值不会覆盖别名的值。然而,对于那些子集中没有设置的属性,设置给目标activity的值同样适用于别名。

上面给出的解释我们来配置一下manifest,配置为如下:

<activity android:name=”.shortcut”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
</intent-filter>
</activity>

<activity-alias android:name=”.CreateShortcuts”
android:targetActivity
=”.shortcut” android:label=”@string/shortcut”>

<intent-filter>
<action android:name=”android.intent.action.CREATE_SHORTCUT” />
<category android:name=”android.intent.category.DEFAULT” />
</intent-filter>

</activity-alias>

Activity:

.shortcut 是我们快捷方式需要的Activity

activity-alias:

对应的targetActivity是指向应用创建快捷方式使用的Activity

android:label对应的创建快捷方式列表显示的文字,而该应用对应的快捷方式的图标则默认使用我们给定的application的图标。如图:

好了,这是第一步步骤,下面进入代码阶段,先看代码:

package com.terry.attrs;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.LinearLayout;
import android.widget.TextView;

public class shortcut extends Activity {
private static final String SHORT_CUT_EXTRAS = com.terry.extra.short;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
final Intent intent
= getIntent();
final String action
= intent.getAction();
if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
createShortCut();
finish();
return;
}

String extra = intent.getStringExtra(SHORT_CUT_EXTRAS);
LinearLayout layout
= new LinearLayout(getApplicationContext());
TextView tv
= new TextView(getApplicationContext());

if (extra != null)
tv.setText(extra);
layout.addView(tv);
setContentView(layout);
}

void createShortCut() {
Intent shortcutIntent
= new Intent(Intent.ACTION_MAIN);
shortcutIntent.setClass(
this, this.getClass());
shortcutIntent.putExtra(SHORT_CUT_EXTRAS,
测试的快捷方式);

Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME,
这里随便指定);
Parcelable shortIcon
= Intent.ShortcutIconResource.fromContext(
this, com.terry.attrs.R.drawable.icon);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortIcon);
setResult(RESULT_OK, intent);
}
}

代码解释:

onCreate方法,首先获取intent 的action如果接收到的action为创建快捷方式的请求,则执行创建快捷方式的代码,否则则通过得到的extra 为textView 赋值。

createShortCut方法,首先设置快捷方式点击后要跳转的intent 和要带入的参数,然后设置桌面快捷方式的名称,图标和对应的intent(即上面带入数据和跳转的界面的 class的Intent)最后将结果传入。

最近运行的结果:

跳击后到达的界面:

TIP:这里可以是任何ACTIVITY界面。

最后给大家分享下源码吧:

快捷方式

就到这里,希望我的一篇废话能对你有所帮助。

[转载]条形码(barcode)系列(1)

mikel阅读(1028)

[转载]条形码(barcode)系列(1) – 专注实用,代码真实可用 – 博客园.

条形码(barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符。常见的条形码是由反射率相 差很大的黑条(简称条)和白条(简称空)排成的平行线图案。条形码可以标出物品的生产国、制造厂家、商品名称、生产日期、图书分类号、邮件起止地点、类 别、日期等许多信息,因而在商品流通、图书管理、邮政管理、银行系统等许多领域都得到了广泛的应用。

条形码的识别原理

要将按照一定规则编译出来的条形码转换成有意义的信息,需要经历扫描和译码两个过程。物体的颜色是由其反射光的类型决定的,白色物体能反射各种 波长的可见光,黑色物体则吸收各种波长的可见光,所以当条形码扫描器光源发出的光在条形码上反射后,反射光照射到条码扫描器内部的光电转换器上,光电转换 器根据强弱不同的反射光信号,转换成相应的电信号。根据原理的差异,扫描器可以分为光笔、CCD、激光三种。电信号输出到条码扫描器的放大电路增强信号之 后,再送到整形电路将模拟信号转换成数字信号。白条、黑条的宽度不同,相应的电信号持续时间长短也不同。 然后译码器通过测量脉冲数字电信号0,1的数目来判别条和空的数目。通过测量0,1信号持续的时间来判别条和空的宽度。此时所得到的数据仍然是杂乱无章 的,要知道条形码所包含的信息,则需根据对应的编码规则(例如:EAN-8码),将条形符号换成相应的数字、字符信息。最后,由计算机系统进行数据处理与 管理,物品的详细信息便被识别了。

条形码的优越性

可靠性强、效率高、成本低、易于制作、构造简单、灵活实用

条形码的扫描

条形码的扫描需要扫描器,扫描器利用自身光源照射条形码,再利用光电转换器接受反射的光线,将反射光线的明暗转换成数字信号。不论是采取何种规则印制的条形码,都由静区、起始字符、数据字符与终止字符组成。有些条码在数据字符与终止字符之间还有校验字符。

▲静区:静区也叫空白区,分为左空白区和右空白区,左空白区是让扫描设备做好扫描准备,右空白区是保证扫描设备正确识别条码的结束标记。   为了防止左右空白区(静区)在印刷排版时被无意中占用,可在空白区加印一个符号(左侧没有数字时印<号,右侧没有数字时加印>号)这个符 号就叫静区标记。主要作用就是防止静区宽度不足。只要静区宽度能保证,有没有这个符号都不影响条码的识别。

▲起始字符:第一位字符,具有特殊结构,当扫描器读取到该字符时,便开始正式读取代码了。

▲数据字符:条形码的主要内容。

▲校验字符:检验读取到的数据是否正确。不同编码规则可能会有不同的校验规则。

▲终止字符:最后一位字符,一样具有特殊结构,用于告知代码扫描完毕,同时还起到只是进行校验计算的作用。   为了方便双向扫描,起止字符具有不对称结构。因此扫描器扫描时可以自动对条码信息重新排列。 条码扫描器有光笔、CCD、激光三种

▲光笔:最原始的扫描方式,需要手动移动光笔,并且还要与条形码接触。

▲CCD:以CCD作为光电转换器,LED作为发光光源的扫描器。在一定范围内,可以实现自动扫描。并且可以阅读各种材料、不平表面上的条码,成本也较为低廉。但是与激光式相比,扫描距离较短。

▲激光:以激光作为发光源的扫描器。又可分为线型、全角度等几种。   线型:多用于手持式扫描器,范围远,准确性高。   全角度:多为卧式,自动化程度高,在各种方向上都可以自动读取条码。

常用条码类型

1) UPC码

1973年,美国率先在国内的商业系统中应用于UPC码之后加拿大也在商业系统中采用UPC码。UPC码是一种长度固定的连续型数字式码制,其 字符集为数字0~9。它采用四种元素宽度,每个条或空是1、2、3或4倍单位元素宽度。IPC码有两种类型,即UPC-A码和UPC-E码。

2) EAN码

1977年,欧洲经济共同体各国按照UPC码的标准制定了欧洲物品编码EAN码,与UPC码兼容,而且两者具有相同的符号体系。EAN码的字符 编号结构与UPC码相同,也是长度固定的、连续型的数字式码制,其字符集是数字0~9。它采用四种元素宽度,每个条或空是1、2、3或4倍单位元素宽度。 EAN码有两种类型,即EAN-13码和EAN-8码。

3)交叉25码

交叉25码是一种长度可变的连续型自校验数字式码制,其字符集为数字0~9。采用两种元素宽度,每个条和空是宽或窄元素。编码字符个数为偶数, 所有奇数位置上的数据以条编码,偶数位置上的数据以空编码。如果为奇数个数据编码,则在数据前补一位0,以使数据为偶数个数位。

4)39码

39码是第一个字母数字式码制。1974年由Intermec公司推出。它是长度可比的离散型自校险字母数字式码制。其字符集为数字0— 9,26个大写字母和7特殊字符(-、。、Space、/、%、¥),共43个字符。每个字符由9个元素组成,其中有5个条(2个宽条,3个窄条)和4个 空(1个宽空,3个窄空),是一种离散码。

5)库德巴码

库德巴码(Code Bar)出现于1972年,是一种长度可变的连续型自校验数字式码制。其字符集为数字0—9和6个特殊字符(-、:、/、。、+、¥),共16个字符。常用于仓库、血库和航空快递包裹中。

6)128码

128码出现于1981年,是一种长度可变的连续型自校验数字式码制。它采用四种元素宽度,每个字符由3个条和3个空,共11个单元元素宽度, 又称(11,3)码。它由106个不,同条形码字符,每个条形码字符有三种含义不同的字符集,分别为A、B、C。它使用这3个交替的字符集可将128个 ASCII码编码。

7)93码

93码是一种长度可变的连续型字母数字式码制。其字符集成为数字。0-9,26个大写字母和7个特殊字符(-、。、Space、/、+、%、¥)以及4个控制字符。每个字符由3个条和3个罕,共9个元素宽度。

8)49码

49码是一种多行的连续型、长度可变的字母数字式码制。出现于1987年,主要用于小物品标签上的符号。采用多种元素宽度。其字符集为数字 0-9,26个大写字母和7个特殊字符(-、。、Space、%、/、+、%、¥)、3个功能键(F1、 陀、F3)和3个变换字符,共49个字符。

9)其他码制

除上述码外,还有其他的码制,例如25码出现于1977年,主要用于电子元器件标签;矩阵25码是11码的变形;Nixdorf码已被EAN码所取代Plessey码出现于1971年5月主要用于图书馆等。

2、按维数分类

1) 普通的一维条码

普通的一维条码自本问世以来,很快得到了普及并广泛应用。但是由于一维条码的信息容量很小,如商品上的条码仅能容13位的阿拉伯数字,更多的描 述商品的信息只能依赖数据库的支持,离开了预先建立的数据库,这种条码就变成了无源之水,无本之木,因而条码的应用范围受到了一定的限制。

2) 二维条码

除具有普通条码的优点外,二维条码还具有信息容量大、可靠性高、保密防伪性强、易于制作、成本低等优点。<BR>美国Symbol 公司于1991年正式推出名为PDF417的二维条码,简称为PDF417条码,即“便携式数据文件”。FDF417条码是一种高密度、高信息含量的便携 式数据文件,是实现证件及卡片等大容量、高可靠性信息自动存储、携带并可用机器自动识读的理想手段。

3) 多维条码

进入20世纪80年代以来,人们围绕如何提高条形码符号的信息密度,进行了研究工作。多维条形码和集装箱条形码成为研究、以展与应用的方 向。<BR>信息密度是描述条形码符号的一个重要参数据,即单位长度中可能编写的字母个数,通常记作:字母个数/cm。影响信息密度的主要因 素是条、空结构和窄元系的宽度。<BR>128码和93码就是人们为提高密度而进行的成功的尝试。128码城1981年被推荐应用;而93码 于1982年投入使用。这两种码的符号密度均比39码高将近30%。<BR>随着条形码技术的发展和条形码三制的种类不断增加,条形码的标准 化显得愈来愈重要。为此,曾先后制定了军用标准1189;交叉25码、39码和Coda Bar码ANSI标准MH10.8M等。同时,一些行业也开始建立行业标准,以适应发展的需要。此后,戴维·阿利尔又研制出49码。这是一种非传统的条形 码符号,它比以往的条形码符号具有更高的密度。特德·威廉姆斯(Ted Williams)GFI988推出16K码,该码的结构类似于49码,是一种比较新型的码制,适用于激光系统。

以上内容来源于网络,整理而成。就写到这里吧,下一节以128码为例 语言C#

[转载]使用linq的ToArray() ToList() ToDictionary()

mikel阅读(1793)

[转载]Linq 中的琐碎东西 – 天涯走狗 – 博客园.

使用linq的ToArray() ToList() ToDictionary()

当我们对某个Ienumerable<T>对象下达where等条件式时,所取得的结果会是一个实现了 Ienumerable<T>接口的对象,此时所有指定的条件式都尚未执行比对的操作,而只是的到了一个WhereIterator对象,拿 到了由编译器对linq expression 进行分析之后所建立的delegate 和string。当通过此Ienumerable<T>对象获得Enumerator对象,并调用MoveNext函数时(foreach会 触发该函数),where Iterator开始起作用,该对象才会一笔一笔地对元素进行条件比对。这一模式不仅用于LINQ TO Objects, 同时也用于LINQ To XML, LINQ ToDataSet 乃至LINQ To SQL, LINQ TO Entities。

但ToArray()等函数会以foreach一一巡览Ieunmerable<T>对象中的所有元素并进行比较,然后将符合条件的元素方放在Array中返回。

那么,操作这样一个比较过的Array 或者 List 对象,显然比直接操作必须在取得元素前进行比对条件的对象集来的有效率

LINQ Expression无法完全取代函数调用。以Where为例。当使用函数时,我们可以写下很复杂的Lambda Exression

Var pq = new[]{"ybwang", "dingmeng", "yhzhou"}
Var p5 = p1.Where(
	x=>{
		Bool result = false;
		sqlConnection conn = new SqlConnection("…...");
		Conn.Open();
		Return result;
	}
)

这是无法以单纯的LINQ Expression 办到的,如果硬要以LINQ Expression 来完成,就必须使用静态函数或者是Extension Method 才行。所以学会如何调用Extension Method 以及运用 Lambda Expression, 是活用Linq to Object 的不二法门。

C#3.0只是单纯地把LINQ Expression 转成object.Select(),

如果你自己打造了一个类Persons<T>,

Public class Persons<T>{
	Private List<T> _list = new List<t>();
	Public T this[int index]
	{
		Get{
			Return _list[index];
		}
	}

	Public void add[T item]{
		_list.Add(item);
	}
}

你用from o in Persons1 select o 的时候,由于这个类没有实现Ienumerable<T>接口,则它将该Lambda表达式转换为Select()方法之后,会因为找不到这 个方法而报错。于是你得自己写个Extension方法,示例如下

public static class PersonsExtension{
	public static Persons<TResult> Select<TSource, TResult>(this Persons<TSource>, Func<TSource, TResult> selector){
		//select elements using the Fucn
		//return result;        
	}
}

可见,选择过程的控制权在我们手上

Linq to SQL 查询返回的那个东西,代表这一组sql语句,也就是说你写下var result = from …..的时候并没有去数据库进行查询,当你真正用到数据时,比如对result进行foreach时,才会用result里头的sql语句去数据库进行查 询,查询过程 默认使用的是连接模式,即用sqlDataReader来读数据。

示例一

aDataContext c = new aDataContext();

var result1 = from c1 in c.Customers select c1;
var result2 = from c2 in c.Customers select c2;

foreach(var item in result1){
	foreach(var item2 in result2){
		//do something
	}
}

这是可以的,由于result1和result2属于同一个context,当result2开始去尝试连接数据库时,result1会把它要的数据全部提取出来,缓存到一个DataTable中,然后绑定到该DataTable,好让result2绑定到数据库

实例二

aDataContext c1 = new aDataContext();
aDataContext c2 = new aDataContext();

var result1 = from c1 in c1.Customers select c1;
var result2 = from c2 in c2.Customers select c2;

foreach(var item in result1){
	foreach(var item2 in result2){
		//do something
	}
}

就不行了,因为这种缓存机制之适应于同一个dataContext的不同result

有些适用于Linq to Object 的语法,并不适用于Linq to SQL

示例

static void main(string [] args){
	var list = new [] {"A", "B", "C"};
	var result = from s1 in list where CheckMe(s1) select s1;
	
	foreach(var item in result){}
}	

static bool CheckMe(string item){
	return true;
}


这是可以的,但在Linq to SQL中

static void main(string [] args){
	aDataContext context = new aDataContext();	
	var result = from s1 in context.Customers where CheckMe(s1) select s1;

	foreach(var item in result){}	
}

static bool CheckMe(string item){
	return true;
}

这是不行的,因为linq不知道该如何将CheckMe函数转化成sql语句。

这种情况,你可已先调用ToArray或者ToList函数,使得取回的对象变为一般的Collection,于是就进入了Linq to Object 的范围,可以用Linq to Object 来操作它了。

在LINQ TO SQL 默认模式中,调用submitChanges函数更新数据之前会激活一个Transaction,若期间发生任何错误时会抛出一个异常,终止更新操作并调用Transcation的RollBack函数来恢复事务前的状态。

Linq to sql 为Entity Class的每个属性提供了Delay Load 属性,当该属性的Delay Load被设置为True时,Linq to SQL于撷取时便不会撷取该字段,而是等到该属性第一次被访问时才下达一个SQL指令由数据库撷取该字段数据。往往将一些二进制data的 Delay Load设置成true

在lts(Linq To SQL)中使用select new 时,所select 出来的对象是只读的。这些对象和数据库里边的行并没有什么联系,不像是直接选出来的那些Entity Object, 你修改他们再调用context.Submit(),就会将修改提交到数据库

class Program{
	static void Main(string[] args){
		test();
	}

	static test(){
		aDataContext context = new aDataConetxt();
		var result = context.ExecuteQuery<OrdersWithTotal>("select orderId, sum(UnitPrice * Quantity) as Totla from [Order Details] group by orderId");

		foreach(var item in result){
			Console.WriteLine("Order Id: {0} Total : {1}", item.OrderId, item.Total);
		}
	}
}

public class OrdersWithTotal{
	public int OrderId{get; set}
	public Decimal Total{get; set}
}

当 Linq to Sql 无法满足要求时,可以用ExecuteQuery函数来直接执行SQL指令。它需要一个类型参数,该函数为每一行创建指定类型的对象,此处就是 OrderWithTotal.然后将相同名字的字段值填入同名的属性。这也是为何查询语句里会出现as Total 的缘故。as Total ,则生成的OrdersWithTotal对象的Total属性会是空的。

DataContext有一个Translate<T>(IDataReader)函数,用于从实现了IDataReader的对象中获取实体对象

相比于ExecuteQuery(), Translate()是架构与IDataReader之上,所以我们可以通过ODBC、OLEDB、Oracle等ADO.Net Provider将取得的IDataReader对象转成Entity Objects,对于转文件、汇入等功能来说,Translate函数相当好用。

但它有个限制,就是只能对返回对象做一次foreach,不过我们仍然可以通过ToList来跨越此限制

另外,该函数执行之后,所取得的Entity Object 会被加入到DataContext中,受dataContext所管辖,因此你可以对这些对象做修改,然后调用dataContext.Submit将改后的数据写回数据库