[转载]ASP.NET MVC中对Model进行多步验证的解决方法

mikel阅读(924)

[转载]ASP.NET MVC中对Model进行多步验证的解决方法 – 海纳百川 – 博客园.

在我之前的博文:ASP.NET MVC2.0结合WF4.0实现用户多步注册流程中 将一个用户的注册分成了四步,而这四个步骤都是对一个Model操作的。当时我加上ModelState.IsValid这句验证代码的时候,根本没法通 过验证,因为在注册的前面三步,注册用户的Model信息都没填写完整。当时很纠结,因为刚接触ASP.NET MVC,故没有找到解决方案。我想现在给出解决的办法也为时不晚。看下面需要验证的Model的代码如下:

代码

public class UserViewModel { [DisplayName("step")] [Required(ErrorMessage = "You must select a step .")] public int Step { get; set; } //个人信息 [Required(ErrorMessage = "姓名不能为空")] [StringLength(20, ErrorMessage = "姓名长度不能超过20个字符")] public string Name { get; set; } [RegularExpression(@"120|((1[0-1]|\d)?\d)", ErrorMessage = "年龄格式不对")] public int? Age { get; set; } //职位信息 [Required(ErrorMessage = "职位不能为空")] public string Post { get; set; } public int? Salary { get; set; } //学历信息 [Required(ErrorMessage = "毕业院校不能为空")] public string University { get; set; } public int? GraduationYear { get; set; } //联系信息 [Required(ErrorMessage = "邮件不能为空")] [RegularExpression(@"^[a-z][a-z|0-9|]*([_][a-z|0-9]+)*([.][a-z|" + @"0-9]+([_][a-z|0-9]+)*)?@[a-z][a-z|0-9|]*\.([a-z]" + @"[a-z|0-9]*(\.[a-z][a-z|0-9]*)?)$", ErrorMessage= "邮件格式不正确")] public string Email { get; set; } public int? Mobile { get; set; } public IEnumerable<SelectListItem> StepList { get; set; } public UserViewModel() { var list = new List<SelectListItem>() { new SelectListItem { Text = "(Select)" }, new SelectListItem { Value = "1", Text = "Step1" }, new SelectListItem { Value = "2", Text = "Step2" }, new SelectListItem { Value = "3", Text = "Step3" }, new SelectListItem { Value = "4", Text = "Step4" } }; this.StepList = new SelectList(list, "Value", "Text"); } }

实现:

这篇文章这种情况服务端和客户端的验证都会讲到。为了简化起见,这里我除去的WF的流程功能,直接用下拉框表示,当下拉框选择step1表示填写第一步注 册的信息,当下拉框选择step2表示填写第二步注册的信息,当下拉框选择step3表示填写第三步注册的信息,当下拉框选择step4表示填写第四步注 册的信息。这个很容易实现,我使用JQuery来显示和隐藏下拉框对应的step,JQuery代码如下:

代码

<script type="text/javascript"> $(function () { $.fn.enable = function () { return this.show().removeAttr("disabled"); } $.fn.disable = function () { return this.hide().attr("disabled", "disabled"); } var dllStep = $("#Step"); var step1 = $("#Step1,#Step1 input"); var step2 = $("#Step2,#Step2 input"); var step3 = $("#Step3,#Step3 input"); var step4 = $("#Step4,#Step4 input"); setControls(); dllStep.change(function () { setControls(); }); function setControls() { switch (dllStep.val()) { case "1": step1.enable(); step2.disable(); step3.disable(); step4.disable(); break; case "2": step1.disable(); step2.enable(); step3.disable(); step4.disable(); break; case "3": step1.disable(); step2.disable(); step3.enable(); step4.disable(); break; case "4": step1.disable(); step2.disable(); step3.disable(); step4.enable(); break; case "": step1.disable(); step2.disable(); step3.disable(); step4.disable(); break; } } }); </script>

如下图:

第一步:填写姓名和年龄。

第二步:填写职位和薪水

第三步填写:毕业院校和毕业时间

第四步填写:邮箱和电话

为了实现这样的验证,我们可以将验证的错误信息中移除不在当前步骤填写的字段的错误信息,写一个类InputValidationModelBinder 继承DefaultModelBinder并重载OnModelUpdated方法,将不必要的错误信息清除,代码如下:

public class InputValidationModelBinder : DefaultModelBinder { protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) { var modelState = controllerContext.Controller.ViewData.ModelState; var valueProvider = controllerContext.Controller.ValueProvider; var keysWithNoIncomingValue = modelState.Keys.Where(x => !valueProvider.ContainsPrefix(x)); foreach (var key in keysWithNoIncomingValue) modelState[key].Errors.Clear(); } }

上面是服务端的代码,对于客户端,我们都知道ASP.NET MVC客户端验证时通过MicrosoftMvcValidation.js去实现的。看下面代码。

1 validate: function Sys_Mvc_FormContext$validate(eventName) { 2 var fields = this.fields; 3 var errors = []; 4 for (var i = 0; i < fields.length; i++) { 5 var field = fields[i]; 6 if (!field.elements[0].disabled) { 7 var thisErrors = field.validate(eventName); 8 if (thisErrors) { 9 Array.addRange(errors, thisErrors); 10 } 11 } 12 } 13 if (this.replaceValidationSummary) { 14 this.clearErrors(); 15 this.addErrors(errors); 16 } 17 return errors; 18 } 19 }

在第6行代码加入了一句判断:当页面的元素没有被disabled的时候才验证。

好了这样就实现了一次只对Model中的几个属性字段进行验证。

运行:

ASP.NET MVC的验证机制只对model中当前页面的属性进行验证:

填写正确通过验证:

总结:

[转载]在ActionScript 3中动态加载类

mikel阅读(1033)

[转载]在ActionScript 3中动态加载类 — Windows Live.

在ActionScript 3中动态加载类

Loading classes dynamically in ActionScript 3 is easy, but there are a couple of tricks to keep in mind.

ActionScript 3动态加载类很容易。有一些窍门便于使用。

First of all, to load a class dynamically, use the flash.utils.getDefinitionByName function. Be sure to pass in the fully qualified class name, like this:

首先,加载一个动态类可以使用flash.utils.getDefinitionByName 方法。确保使用的是完整的类名,例如:

var MyClass:Class = getDefinitionByName(“com.mydomain.package.MyClass”) as Class;

var myInstance:MyClass = new MyClass();

Easy enough. But there’s something to watch out for. Class definitions only get compiled into your SWF if they’re declared somewhere in your code. In other words, if MyClass was never declared, the class definition wouldn’t be included in your SWF, and you would get a runtime error when trying to load it dynamically. (Note that this is not the case for classes native to the runtime — only your own custom classes.) Even importing the class isn’t enough to get it included — it must actually be declared.

很容易做到。但是有一些需要注意。如果他们使用在代码的某个地方,类的声明只编译到您的SWF中。换句话说,当它试图动态加载时,如果MyClass从未引用,类定义将不包括在您的SWF,你会得到一个运行时错误。 (请注意,这不是对原生类(即FLASH PLAYER自带的)情况只有你自己的自定义类。)即使引入类是不够的,得将它包含进去它实际上必须调用。

There are two ways to work around this issue:

有两种方法解决这个问题:

1. Declare the class somewhere in the code.在代码中的某个位置声明这个类

2. Use a command line argument to force the class definition to be included.Below is an example of declaring the class before loading it dynamically:使用命令行参数来强制类定义应包括在内。

下面是一个动态加载它之前宣布的类的例子:

MyClass;

// or

var mc:MyClass;

var MyClass:Class = getDefinitionByName(“com.mydomain.package.MyClass”) as Class;

var myInstance:MyClass = new MyClass();

This works fine, but in my opinion, it may defeat the purpose of loading a class dynamically. Usually you want to load classes dynamically because you’re not sure until runtime which class you’re going to want. If you knew which classes you wanted before you loaded them dynamically, you could just instantiate them directly.

The other option is to use the mxmlc -includes compiler argument like this:

这个工作得很好,但在我看来,它可以达到动态加载一个类的目的。通常你要动态加载的类,因为不是在你当前的代码中,直到运行时你会想知道。如果你想知道哪些类,然后再加载它们的动态,你可以只直接实例。
另一种选择是使用mxmlc –includes 编译器这样:

-includes=com.mydomain.package.MyClass

Now, the class definition will be compiled into your SWF, and you can load it dynamically anytime you want without ever having to declare it.

现在定义的类被编译到你的SWF中,你可以在任何没有声明他的情况下,随时动态加载它。

To specify compiler arguments in Flash Builder, follow these steps:

具体在Flash Builder中的编译参数,遵循下列步骤:

1. Right-click on your project. 右键你的项目

2. Choose “Properties”.选择“属性”

3. Select “Flex Compiler”.选择“Flex 编译”

4. Enter your arguments in the “Additional compiler arguments” section.输入你的参数在“Additional compiler arguments”选项中

As an aside, you can use the flash.utils.getQualifiedClassName andflash.utils.getQualifiedSuperclassName functions to get the fully qualified class name of an object instance.

同时你可以使用

flash.utils.getQualifiedClassName flash.utils.getQualifiedSuperclassName 方法获得完整的类名和对象实例。

[转载]七大.NET著名开源项目

mikel阅读(1065)

[转载]百万开发者拥戴!七大.NET著名开源项目 – CSDN.NET – CSDN软件研发频道.

尽管过了相当长的时间,花费了不少资源,微软和.NET社区还是在最近几年加入到了开源运动的阵营中来了,这令人相当惊讶,因为两大阵营一直都是经 常对立的。然而,事实是依靠开源,微软社区中的开源开发工具日益发展壮大。本文将深入了解.NET领域的开源项目,介绍七个在全球受到数百万.NET开发 者拥戴和欢迎的开源项目。

AJAX 控件工具包

仅仅五年时间,自从AJAX的概念提出来以后,使用JavaScript,XML和异步通信去提升用户的在线体验已经从新颖的想法变为实在的需要。 因为AJAX驱动的要求已经变得很普通,不久开发者们都投入到开发AJAX框架中去,这使得像日历和客户端表单验证这样的功能变得很容易实现。

.NET开发者在处理AJAX方面有ASP.NET AJAX Control Toolkit工具包这个很好的解决方案。它由微软公司和开发者社区联合开发,提供了多种功能强大的控件,如评分控件,模态弹出窗口,密码强度验证器,可拖拉的面板。

可以查看ASP.NET主页上该项目的主页,上面有控件示例的清单和例子,除此之外,还有大量的导学文章,能指导如何充分利用工具包的很多特性。

ASP.NET MVC

MVC的架构在现在的Web开发中起着重要的作用,象Ruby on Rails,Zend Framwork等框架都是使用MVC框架进行开发的。多亏有了ASP.NET MVC框架,.NET开发者也能够拥有一个功能强大的MVC框架了。ASP.NET MVC框架提供了MVC的良好分层,测试驱动以及“约定优先”的最佳实践,为.NET开发者构建复杂的网页提供了强大的解决方案。因为是基于.NET构建 的,开发者能充分利用ASP.NET的诸如数据缓存和表单验证等功能。你还可以发现不少其他项目也是基于ASP.NET MVC构建,并且提升了其功能,象MvcContrib,它扩展了ASP.NET MVC的功能,还包括象UI helper和模型绑定器等功能。

ASP.NET MVC框架的网站提供给新手一系列学习资源,包括了视频系列导学,它们通过示范搭建应用程序的方法去指导读者学习。

CruiseControl

现在软件的复杂性使得软件开发团队不得不重新考虑软件开发的过程,这要引入既能缩短开发时间又能提高软件质量的方法。这使得出现了大量的软件开发最 佳实践,它们越来越广泛应用在企业中,象测试驱动和持续集成。其中持续集成在整个软件开发过程中,通过有计划和严格地整合工程的组件,并能尽可能减少在这 方面付出的时间和精力。这使得开发者能尽早发现和解决在整合过程中的问题,而不是等问题变得越来越复杂再去解决。

更准确来说,持续集成包含了软件开发过程中的自动化过程,包括定期运行测试,在每次开发者向工程代码库提交代码时,重新编译构建项目。因为这个自动 化的阶段包含了大量的象文件移动等操作,近年来,很多能完成自动持续化集成的解决方案出现了,其中包括开源项目 CruiseControl,CruiseControl提供了自动化构建的工具,可以查看构建的结果,并且生成报告。CruiseControl现在已 变成一个十分流行的持续集成解决方案。在众多的第三方持续集成工具中,可以找到象JCCTray这样的工具,它是一个桌面运行的应用程序,可以直接了解你 的构建服务器的状态,并且BigVisibleCruise这个工具,使用可视化的提示显示构建服务器上所有受管理的工程的状态。

DotNetNuke

随着越来越多的公司正把它们的商务活动迁移到在网上,这需要功能强大的网站内容管理系统,而不仅是简单更新一下网页内容。实际上,现在的网站不仅是 卖商品,同样也管理销售机会和其他合同等,也要维护文档和提供如图片和视频等多媒体服务。最有效去管理这些大量的内容的是采用集中的内容管理系统。其中最 著名的解决方案是DotNetNuke,它是一个功能强大的基于 .NET的内容管理系统,已在全球500强中很多企业和众多开发者中被采用。

DotNetNuke虽然已经有了多个版本,但开源的社区版本提供了数百个特性,如它们能让公司去管理通告,实现论坛交互,而这些都不需要有任何的编程知识。如果公司需要自定义一些新功能的话也能按它们的需要去扩展。

Mono

2002年,.NET 1.0的出现是软件开发领域中的一个分水岭,在众多特性中,它可以让开发者使用任何支持.NET公共运行时的语言去开发应用。当然,微软将WINDOWS 平台作为.NET运行的主要平台,这对象LINUX等其他系统来说是个噩梦。然而因为.NET是基于一系列公开的标准的,一些企业组织的开发者开发了 Mono项目,能让.NET可以运行在非微软平台上。

现在由于Novell公司的大力支持,Mono项目这些年发展得相当迅速,它不但能让.NET跑在非微软的平台上,也支持在LINUX上运行Sliverlight技术(目前代号为Monnlight),甚至开始研究在使用C#语言去编写iPhone上的应用。

可以到Mono的主页上去查看更多的相关信息,除此之外还可以去下载Mono专门为Visual Studio开发的插件工具。

NAnt

无论是JAVA还是.NET的开发者对代码的编译部署过程都是十分熟悉的,这个过程随着工程项目变得越来越复杂,从而也会耗费不少时间。为了应对这 一问题,开发者James Davidson编写了ANT这一自动构建工具,它在JAVA开发者社区阵营中开始应用得越来越普遍,不久,NET阵营中的NANT项目也随之诞生。使用 NANT,你可以建立构建脚本,不论是执行单元测试还是创建文档等其他.NET的构建周期,都可以自动执行这些脚本。

NHibernate

尽管在软件开发中,关系数据库的应用是很普遍了,但开发者和数据库之间还是存在一些壁垒。问题关键在于如何高效地在应用和数据库之间以各自支持的格 式转换数据。开发者尽了很大的努力创造了很多方便转换的工具,其中最著名的是象Hibernate这样的对象关系映射框架(ORM)

.NET开发者在处理ORM方面有NHibernate这样的工具,自从2005年它出现后,广为受到开发者的欢迎。NHibernate能完 成.NET开发者面对的大量枯燥的数据日常操作,不仅在映射应用的模型到数据表上很有作用,而且能根据预先定义好的数据模型去产生表的模型定义。

NHibernate的网站上提供了大量的有用的资源,能帮助你去了解这个强大的ORM解决方案框架。

小结

如果你是.NET开发者而且还没开始进入庞大并且日益发展的开源阵营的话,那么你应该去看看了。花点时间去研究本文提到的几个开源项目,我保证你会 马上看到生产效率的提高的,有可能这还会引领你去向开源社区贡献你自己的开源项目呢,如果你使用了本文没提到的开源项目工具,可以在评论中告诉我。

原文链接:Introducing Seven Popular Open Source Projects for .NET Developers

译文链接:http://tech.it168.com/a2010/0906/1099/000001099775_all.shtml

[转载]以Model为核心的表单设计器的思路

mikel阅读(1047)

[转载]以Model为核心的表单设计器的思路 – 海纳百川 – 博客园.

在之前的文章中介绍过一些表单设计器的思路和想法。在上一篇文章:零代码平台实现中说到我要实现一个功能强大的表单设计工具。经过几天思考,觉得以Model为核心去实现表单设计器思路既简单也很清楚。这篇文章我将谈谈如何以Model为核心去实现表单设计器。

设计思路:

之所以会我想到以Model为核心,主要借鉴ASP.NET MVC框架。ASP.NET MVC中控制器向View提供Model。View将Model渲染成表单。有一点不好的是生成的View中夹杂了HTML和C#代码,没有了 ASP.NET Web Form的用户控件,所以就不能去可视化拖拽了,看下面ASP.NET MVC生成表单的两张图。

简单的List页面:

Detail页面:

从上图中可以看出不存在控件,那就不能可视化的拖拽。

我做这个设计器的目的之一就是解决这个不能拖拽的问题,先对比一下asp.net表单生成机制和我的表单设计器的机制:

从上图可以看出两种机制是差不多的。

mvc中有ModeL和ViewModel两个概念。Model是一般都固定不变的,编译之后就会存在dll,所以通过下面代码使用反射来生成表单。

1 System.Windows.Forms.OpenFileDialog dlg = new System.Windows.Forms.OpenFileDialog(); 2 dlg.AutoUpgradeEnabled = false; 3 if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) 4 { 5 string fileName = dlg.FileName; 6 txtPath.Text = fileName; 7 System.Reflection.Assembly ass; 8 Type[] types; 9 ass = System.Reflection.Assembly.LoadFile(fileName);//要绝对路径 10 //获取所以的实体类 11   types = ass.GetTypes(); 12 foreach(Type type in types) 13 { 14 ListBoxItem li = new ListBoxItem(); 15 li.Content = type.Namespace+"."+type.Name; 16 lbxModel.Items.Add(li); 17 18 } 19 20 21 22 }

对于ViewModel,我计划先使用SQL语句生成ViewModel的结构和代码,然后生表单。

Model方式界面:

ViewModel方式界面:

简单示例:

看个例子,实体类代码如下:

1 public class Person 2 { 3 public string Name 4 { 5 get; 6 set; 7 } 8 9 public int Age 10 { 11 get; 12 set; 13 } 14 15 public string Sex 16 { 17 get; 18 set; 19 } 20 }

在List页面,我生成一个固定的Grid和以下常用的工具栏按钮如:新增、修改、删除…,如下如。

对于修改页面、详情页面等,我生成label+textbox组合方式的表单。

下面我们就可以自由调整界面了:

调整之后的一级界面

调整之后的二级界面

最后通过代码生成机制生成aspx代码。

总结:这个是我思考出的一个表单设计器的解决方案,感觉比较简单而且比较通用,故写这篇文章做为一个分享。考虑不周的地方期待大家多多指正。

[转载]Visual Studio一款免费生成流程图的插件

mikel阅读(2573)

[转载]一款免费生成流程图的插件 – eaglet – 博客园.

最近写文档,要贴流程图,自己画太烦,就到网上去找自动生成流程图的软件,结果知道了这个叫 Microsoft Visual Studio Learning Pack 的插件,用它来生成函数的流程图,感觉很方便。

下载地址

http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=0ce3cbbd-7fc7-410b-8c2c-e18d1c60a6cd

下载后安装,安装完以后打开VS ,在代码中相应函数的函数名处点右键选 Generate Flow Chart 就可以生成这个函数的流程图了,非常方便

image

image

是不是很方便,介绍给大家,对写文档或者学习代码会有些帮助。

[转载]JavaScript 设计模式 :安全沙箱模式

mikel阅读(958)

[转载]JavaScript 设计模式 :安全沙箱模式 – Stand Alone – 博客园.

沙箱模式常见于YUI3 core,它是一种采用同一构造器(Constructor)生成彼此独立且互不干扰(self-contained)的实例对象,而从避免污染全局对象的方法。

命名空间


JavaScript本身中没有提供命名空间机制,所以为了避免不同函数、对象以及变量名对全局空间的污染,通常的做法是为你的应用程序或者库创建一个唯一的全局对象,然后将所有方法与属性添加到这个对象上。

1 /* BEFORE: 5 globals */ 2  // constructors 3  function Parent() {} 4  function Child() {} 5  // a variable 6  var some_var = 1; 7  // some objects 8  var module1 = {}; 9 module1.data = {a: 1, b: 2}; 10  var module2 = {}; 11  /* AFTER: 1 global */ 12  // global object 13  var MYAPP = {}; 14  // constructors 15  MYAPP.Parent = function() {}; 16 MYAPP.Child = function() {}; 17  // a variable 18  MYAPP.some_var = 1; 19  // an object 20  MYAPP.modules = {}; 21  // nested objects 22  MYAPP.modules.module1 = {}; 23 MYAPP.modules.module1.data = {a: 1, b: 2}; 24 MYAPP.modules.module2 = {};

代码清单1 : 传统命名空间模式

在这段代码中,你创建了一个全局对象MYAPP,并将其他所有对象、函数作为属性附加到MYAPP上.

通常这是一种较好的避免命名冲突的方法,它被应用在很多项目中,但这种方法有一些缺点。

1.需要给所有需要添加的函数、变量加上前缀。

2.因为只有一个全局对象,这意味着一部分代码可以肆意地修改全局对象而导致其余代码的被动更新。

全局构造器

你可以用一个全局构造器,而不是一个全局对象,我们给这个构造器起名为Sandbox(),你可以用这个构造器创建对象,你还可以为构造器传递一个回调函数作为参数,这个回调函数就是你存放代码的独立沙箱环境。

1 new Sandbox(function(box){ 2    // your code here... 3  });


代码清单2:沙箱的使用


让我们给沙箱添加点别的特性


1.创建沙箱时可以不使用’new’操作符

2.Sandbox()构造器接受一些额外的配置参数,这些参数定义了生成对象所需模块的名称,我们希望代码更加模块化。


拥有了以上特性后,让我们看看怎样初始化一个对象。


代码清单3显示了你可以在不需要‘new’操作符的情况下,创建一个调用了’ajax’和’event’模块的对象.


1 Sandbox(['ajax', 'event'], function(box){ 2    // console.log(box); 3  });

代码清单3:以数组的形式传递模块名

1 Sandbox('ajax', 'dom', function(box){ 2    // console.log(box); 3  });

代码清单4:以独立的参数形式传递模块名

代码清单5显示了你可以把通配符’*’作为参数传递给构造器,这意味着调用所有可用的模块,为了方便起见,如果没有向构造器传递任何模块名作为参数,构造器会把’*’作为缺省参数传入.

1 Sandbox('*', function(box){ 2    // console.log(box); 3  }); 4 Sandbox(function(box){ 5    // console.log(box); 6  });

代码清单5:调用所用可用模块

代码清单6显示你可以初始化沙箱对象多次,甚至你可以嵌套它们,而不用担心彼此间会产生任何冲突.

1 Sandbox('dom', 'event', function(box){ 2  // work with dom and event 3    Sandbox('ajax', function(box) { 4    // another sandboxed "box" object 5   // this "box" is not the same as 6   // the "box" outside this function 7   //... 8   // done with Ajax 9    }); 10  // no trace of Ajax module here 11  });

代码清单6:嵌套的沙箱实例

从上面这些示例可以看出,使用沙箱模式,通过把所有代码逻辑包裹在一个回调函数中,你根据所需模块的不同生成不同的实例,而这些实例彼此互不干扰独立的工作着,从而保护了全局命名空间。

现在让我们看看怎样实现这个Sandbox()构造器.

添加模块

在实现主构造器之前,让我们看看如何向Sandbox()构造器中添加模块。

因为Sandbox()构造器函数也是对象,所以你可以给它添加一个名为’modules’的属性,这个属性将是一个包含一组键值对的对象,其 中每对键值对中Key是需要注册的模块名,而Value则是该模块的入口函数,当构造器初始化时当前实例会作为第一个参数传递给入口函数,这样入口函数就 能为该实例添加额外的属性与方法。

在代码清单7中,我们添加了’dom’,’event’,’ajax’模块。

1 Sandbox.modules = {}; 2 Sandbox.modules.dom = function(box) { 3   box.getElement = function() {}; 4   box.getStyle = function() {}; 5   box.foo = "bar"; 6 }; 7 Sandbox.modules.event = function(box) { 8  // access to the Sandbox prototype if needed: 9 // box.constructor.prototype.m = "mmm"; 10    box.attachEvent = function(){}; 11   box.dettachEvent = function(){}; 12 }; 13 Sandbox.modules.ajax = function(box) { 14   box.makeRequest = function() {}; 15   box.getResponse = function() {}; 16 };

代码清单7:注册模块

实现构造器

代码清单8描述了实现构造器的方法,其中关键的几个要点:

1.我们检查this是否为Sandbox的实例,若不是,证明Sandbox没有被new操作符调用,我们将以构造器方式重新调用它。

2.你可以在构造器内部为this添加属性,同样你也可以为构造器的原型添加属性。

3.模块名称会以数组、独立参数、通配符‘*’等多种形式传递给构造器。

4.请注意在这个例子中我们不需要从外部文件中加载模块,但在诸如YUI3中,你可以仅仅加载基础模块(通常被称作种子(seed)),而其他的所有模块则会从外部文件中加载。

5.一旦我们知道了所需的模块,并初始化他们,这意味着调用了每个模块的入口函数。

6.回调函数作为参数被最后传入构造器,它将使用最新生成的实例并在最后执行。

1 function Sandbox() { 2    // turning arguments into an array 3    var args = Array.prototype.slice.call(arguments), 4    // the last argument is the callback 5      callback = args.pop(), 6    // modules can be passed as an array or as individual parameters 7      modules = (args[0] && typeof args[0] === "string") ? 8     args : args[0], 9     i; 10      // make sure the function is called 11     // as a constructor 12    if (!(this instanceof Sandbox)) { 13      return new Sandbox(modules, callback); 14   } 15   // add properties to 'this' as needed: 16   this.a = 1; 17   this.b = 2; 18   // now add modules to the core 'this' object 19   // no modules or "*" both mean "use all modules" 20   if (!modules || modules === '*') { 21     modules = []; 22     for (i in Sandbox.modules) { 23       if (Sandbox.modules.hasOwnProperty(i)) { 24         modules.push(i); 25       } 26      } 27    } 28   // init the required modules 29   for (i = 0; i < modules.length; i++) { 30     Sandbox.modules[modules[i]](this); 31   } 32   // call the callback 33   callback(this); 34 } 35 // any prototype properties as needed 36 Sandbox.prototype = { 37   name: "My Application", 38   version: "1.0", 39   getName: function() { 40     return this.name; 41   } 42 };

代码清单8:实现Sandbox构造器

原文来自:Stoyan Stefanov – JavaScript Patterns Part 7:The Sandbox Pattern

更多资料:www.infoq.com/cn/articles/sandboxOnB

[转载]在 ASP.NET MVC 中创建自定义 HtmlHelper

mikel阅读(903)

[转载]在 ASP.NET MVC 中创建自定义 HtmlHelper – 雪的梦幻 – 博客园.

ASP.NET MVC应用程序的开发中,我们常碰到类似Html.Label或Html.TextBox这样的代码,它将在网页上产生一个label或input标记。 这些HtmlHelper的扩展方法有些像WebForm中的控件,只需传入一些参数即可生成相应的HTML代码。本文将介绍创建HtmlHelper的 方法。

Html.Textbox方法的返回值是MvcHtmlString,它生成了一些HTML代码。创建HtmlHelper,就像在生成HTML代 码。下面以一个带有简要描述功能的链接HtmlHelper为例介绍创建自定义HtmlHelper的方法。它将显示一个链接并在下方简要介绍该与该链接 内容有关的信息。在某些带有简要描述的项列表页上可能会需要类似的功能。最后的结果预览如下图。


上面使用了3次自定义的HtmlHelper,每次生成的代码如下

1 <div>
2 <p class=”LinkTitle”><a href=”#”>链接标题</a></p>
3 <p class=”LinkDescription”>链接描述</p>
4 </div>

可能稍微有点复杂,因为有了标签的嵌套。

做好准备工作以后,新建一个静态类LinkWithDescriptionExtensions,添加静态方法LinkWithDescription,代码如下

代码

1 /// <summary>
2 /// 带描述的链接扩展方法
3 /// </summary>
4 /// <param name=”htmlHelper”>要扩展的HtmlHelper类</param>
5 /// <param name=”title”>标题</param>
6 /// <param name=”url”>链接地址</param>
7 /// <param name=”description”>描述</param>
8 /// <returns>HTML代码</returns>
9 public static MvcHtmlString LinkWithDescription(this HtmlHelper htmlHelper, string title, string url, string description)
10 {
11 // 生成与标题链接有关的HTML代码
12 TagBuilder titleContainer = new TagBuilder(“p”);    // 标题链接容器p
13 TagBuilder titleLink = new TagBuilder(“a”);    // 标题中的文字要有链接,所以包含在a标签内
14 titleLink.MergeAttribute(“href”, url);    // 为a添加href属性并指定链接地址
15 titleLink.SetInnerText(title);    // 标题文字
16 titleContainer.InnerHtml = titleLink.ToString();    // 将a放到p中
17 titleContainer.AddCssClass(“LinkTitle”);    // 为标题添加样式
18
19 // 生成与链接描述有关的HTML代码
20 TagBuilder descriptionContainer = new TagBuilder(“p”);    // 连接描述容器p
21 descriptionContainer.InnerHtml = description;    // 描述文字
22 descriptionContainer.AddCssClass(“LinkDescription”);    // 为描述添加样式
23
24 // 将上述元素放入一个DIV中
25 TagBuilder div = new TagBuilder(“div”);
26 div.InnerHtml = string.Format(“{0}{1}”, titleContainer.ToString(), descriptionContainer.ToString());
27
28 // 返回生成的HTML代码
29 return MvcHtmlString.Create(div.ToString());
30 }

先理清结构再使用TagBuilder生成HTML代码是比较方便的。这里也可以使用拼接字符串的方式来生成HTML代码,只要最后得到所需的 HTML代码就可以,但是我个人不建议使用拼接字符串的方式,这样不仅思维容易混乱而且容易出错。使用TagBuilder既结构清晰,又不容易出错。

在ASPX页中,可以使用

1 <%:Html.LinkWithDescription(测试链接1, #, 这是测试链接1的描述)%>
2 <%:Html.LinkWithDescription(测试链接2, #, 这是测试链接2的描述)%>
3 <%:Html.LinkWithDescription(测试链接3, #, 这是测试链接3的描述)%>

来调用上面的扩展方法,这里的链接标题、链接地址和描述等信息可以通过ViewData等方式传入。在Action中写

代码

1 /// <summary>
2 /// Demo
3 /// </summary>
4 /// <returns>Demo视图</returns>
5 public ActionResult Demo()
6 {
7 // 创建链接信息列表
8 List<LinkInfo> links = new List<LinkInfo>();
9 links.Add(new LinkInfo { Description = 这是测试链接1的描述, Title = 测试链接1, Url = # });
10 links.Add(new LinkInfo { Description = 这是测试链接2的描述, Title = 测试链接2, Url = # });
11 links.Add(new LinkInfo { Description = 这是测试链接3的描述, Title = 测试链接3, Url = # });
12
13
14 ViewData[Links] = links;
15
16 return View();
17 }

在ASPX页中写

1 <%List<LinkInfo> links=ViewData[Links] as List<LinkInfo>;
2 foreach (var link in links)
3 { %>
4 <%:Html.LinkWithDescription(link.Title, link.Url, link.Description)%>
5 <%} %>

示例下载

本文适用于  ASP.NET MVC 2

[转载]获取网络MP3真实地址

mikel阅读(1045)

[转载]获取网络MP3真实地址 – Java综合 – Java – JavaEye论坛.

MP3网站的歌曲链接都采用了不同的加密方法,直接从页面的源文件中是找 不到其MP3的网址的。以下有两个public class都可独立运行,只要将其构造方法更名为main方法就可以了,同时还需要在给出的JAVA源代码中找到“//播放或下载代码…”这一行,将 其改为“Thread.sleep(200)”延时,否则同一IP频繁的连接请求会遭服务器拒绝或引发服务器的防恶意搜索保护。

1.获取百度新歌MP3真实地址

百度新歌的网址是http://xinge.baidu.com/index.html,打开该页面后用查看源文件,搜索“{sid:”,会看到这样的文本:

http://xinge.baidu.com/index.html的源文件片断
{sid:’468aecfeaabbd9467fb939a2e80da58a.mp3′,al:’今 生无缘’,ti:’一天爱一点’,si:’易欣 孙莺’,cp:’华友金信子 ‘,da:’2010-08-03′,cv:’38d9e957d5bdfb788989f1eb12239d8f.jpg’,lrc:’b118977f14893a70ab4652031dd1633d.txt’,dl:’511′,tl:’281394′,ico:0}

其中:“sid:”后面是歌曲连接、“al:”后是唱片集、“ti:”后面是歌曲标题、“si:”后面是歌手。

  • 读取“sid:”后面用一对单引号括起来的字符串,在前面加上 http://xinge.baidu.com/wgns/url/构成歌曲的链接,例如:http://xinge.baidu.com/wgns /url/468aecfeaabbd9467fb939a2e80da58a.mp3,这个链接是用于打开试听窗口的。
  • 试听窗口查看不到源文件,那就编程打开这个歌曲链接的网址并解析其源文件。接收到的源文件只有一行,在这一行字符串前面加上http://xinge.baidu.com就是MP3的真实网址了,这个网址可用于播放或下载MP3。

源代码如下:

Java代码
  1. /*
  2. * XingeBaidu.java – 获取’百度新歌’的MP3真实网址
  3. */
  4. package jmp123.player;
  5. import java.io.BufferedReader;
  6. import java.io.InputStream;
  7. import java.io.InputStreamReader;
  8. import java.net.URL;
  9. import java.net.HttpURLConnection;
  10. public class XingeBaidu {
  11. public XingeBaidu() {
  12. String strLine;
  13. int beginIndex, endIndex, idx;
  14. System.out.println(“连接到百度新歌\n”);
  15. try {
  16. URL url = new URL(“http://xinge.baidu.com/”);
  17. HttpURLConnection objHttp = (HttpURLConnection) url.openConnection();
  18. objHttp.setRequestProperty(“Connection”, “Keep-Alive”);
  19. InputStream objIS = objHttp.getInputStream();
  20. BufferedReader objReader = new BufferedReader(new InputStreamReader(objIS));
  21. while ((strLine = objReader.readLine()) != null) {
  22. if ((beginIndex = strLine.indexOf(“{sid:”)) != –1) {
  23. if ((idx = strLine.indexOf(“al:”)) != –1
  24. && (endIndex = strLine.indexOf(“‘,ti”)) != –1
  25. && idx + 4 < endIndex)
  26. System.out.printf(“[唱片集:%s]  “,strLine.substring(idx+4,endIndex));
  27. if ((idx = strLine.indexOf(“ti:”)) != –1
  28. && (endIndex = strLine.indexOf(“‘,si”)) != –1
  29. && idx + 4 < endIndex)
  30. System.out.printf(“%s”, strLine.substring(idx + 4,endIndex));
  31. if ((idx = strLine.indexOf(“si:”)) != –1
  32. && (endIndex = strLine.indexOf(“‘,cp”)) != –1
  33. && idx + 4 < endIndex)
  34. System.out.printf(”  [歌手:%s]”,strLine.substring(idx+4,endIndex));
  35. System.out.printf(“\n”);
  36. if ((endIndex = strLine.indexOf(“.mp3”)) != –1) {
  37. strLine = strLine.substring(beginIndex + 6, endIndex + 4);
  38. getMP3URL(“http://xinge.baidu.com/wgns/url/” + strLine);
  39. }
  40. }
  41. }
  42. catch (Exception e) {
  43. // e.printStackTrace();
  44. }
  45. }
  46. private void getMP3URL(String surl) throws Exception {
  47. String strLine;
  48. URL url = new URL(surl);
  49. HttpURLConnection objHttp = (HttpURLConnection) url.openConnection();
  50. InputStream objIS = objHttp.getInputStream();
  51. BufferedReader objReader = new BufferedReader(new InputStreamReader(objIS));
  52. if ((strLine = objReader.readLine()) != null) {
  53. strLine = “http://xinge.baidu.com” + strLine;
  54. System.out.println(strLine); //打印查找到的MP3的真实网址
  55. //播放或下载的代码…
  56. }
  57. objHttp.disconnect();
  58. objHttp = null;
  59. objReader.close();
  60. objReader = null;
  61. url = null;
  62. }
  63. }

2.获取搜狗MP3真实网址

用上面的方法不能获取搜狗新歌100等的MP3真实网址,原因可能是其服 务器有更严格的限制,防止用上面的方法去恶意搜索。前两天调试代码时连接上去,接收到的页面源文件中提示输入验证码,所以就不能用程序去解析其MP3网址 了,晕,接连两天都不行,不知道是前两天调试程序连接的太频繁了还是别的什么原因,触发了网站的防恶意搜索保护。

http://music.sogou.com/song/newtop_1.html源文件片断
<td width=”25″><a onclick=”window.open(‘http://mp3.sogou.com/down.so?t=%C0%F1%CE%EF&s=%BD%AD%D3%B3%C8%D8&w=02210600′,”,’width=428,height=394,scrollbars=no’);uigsPB(‘consume=phb_down’);return false;” href=”JavaScript:void(0);” target=”_blank” class=”link” title=”链接”></a></td>

源代码如下,自己对比一下,就能琢磨出与第一种方法有什么不同了。总的步骤是一样的,仍是两步:

  • 连接到http://music.sogou.com/song/newtop_1.html从接收到的数据流中查找到歌曲链接。打开这个页面的源文件,查找到window.open(,它后面用一对单引号括起来的内容就是歌曲的链接,这个链接是用于打开试听窗口的。
  • 用程序连接到这个歌曲链接,从接收到的数据流中查找以http://开头、以.mp3结尾的字符串,这个字符串就是MP3的真实网址。
Java代码
  1. /*
  2. * SogouNewTop.java – 获取’搜狗音乐新歌TOP100’的MP3真实网址
  3. */
  4. package jmp123.player;
  5. import java.io.IOException;
  6. import java.io.PrintWriter;
  7. import java.io.BufferedReader;
  8. import java.io.InputStreamReader;
  9. import java.net.Socket;
  10. /**
  11. * 创建、发送HTTP请求头
  12. */
  13. class MySocket {
  14. private String strReferer;
  15. private Socket socket;
  16. private PrintWriter pwOut;
  17. BufferedReader brIn;
  18. public MySocket(String strReferer) {
  19. this.strReferer = strReferer;
  20. }
  21. public void create(String surl) {
  22. int beginIndex, endIndex, iPort = 80;
  23. String strHost = surl.substring(7);
  24. endIndex = strHost.indexOf(“/”);
  25. String strPath = strHost.substring(endIndex);
  26. strHost = strHost.substring(0, endIndex);
  27. if( (beginIndex = strHost.indexOf(“:”)) != –1) {
  28. if(endIndex – beginIndex > 1)
  29. iPort = Integer.parseInt(strHost.substring(beginIndex+1, endIndex));
  30. strHost = strHost.substring(0, beginIndex);
  31. }
  32. try {
  33. socket = new Socket(strHost, iPort);
  34. pwOut = new PrintWriter(socket.getOutputStream(), true);
  35. // 构建HTTP请求头
  36. pwOut.println(“GET “ + strPath + ” HTTP/1.1″);
  37. pwOut.println(“Host:” + strHost);
  38. pwOut.println(“Referer:” + strReferer);
  39. pwOut.println(“Accept:*/*”);
  40. pwOut.println(“User-Agent:Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)”);
  41. pwOut.println(“Connection: Keep-Alive”);
  42. pwOut.println();
  43. // 调用socket.getInputStream方法时才发送HTTP请求头
  44. brIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  45. catch (IOException e) {
  46. System.out.println(“创建套接字/输入流错误。”);
  47. System.exit(1);
  48. }
  49. }
  50. public BufferedReader getBufferedReader() {
  51. return brIn;
  52. }
  53. public void close() {
  54. try {
  55. brIn.close();
  56. pwOut.close();
  57. socket.close();
  58. catch (IOException e) {
  59. System.out.println(“关闭套接字错误。”);
  60. System.exit(1);
  61. }
  62. }
  63. }
  64. /**
  65. * 解析搜狗音乐新歌TOP100页面获取MP3真实网址。
  66. */
  67. public class SogouNewTop {
  68. private static final String strReferer = “http://music.sogou.com/song/newtop_1.html”;
  69. private MySocket htmlSocket = new MySocket(strReferer);
  70. private MySocket urlSocket = new MySocket(strReferer);
  71. /*
  72. * 查找页面的歌曲链接
  73. */
  74. public SogouNewTop() throws Exception {
  75. System.out.println(“连接到搜狗音乐新歌TOP100\n”);
  76. String strline = “”;
  77. htmlSocket.create(strReferer);
  78. BufferedReader brIn = htmlSocket.getBufferedReader();
  79. int beginIndex, endIndex;
  80. while ((strline = brIn.readLine()) != null) {
  81. // 1.查找歌曲名(可省略)
  82. if ((beginIndex = strline.indexOf(“consume=phb_song”)) != –1 ) {
  83. strline = strline.substring(beginIndex);
  84. if ((beginIndex = strline.indexOf(“>”)) != –1
  85. && (endIndex = strline.indexOf(“<“)) != –1) {
  86. strline = strline.substring(beginIndex+1, endIndex);
  87. System.out.println(“[歌曲名] “ + strline);
  88. }
  89. continue;
  90. }
  91. // 2.查找歌曲链接
  92. if ((beginIndex = strline.indexOf(“onclick=\”window.open(“)) != –1
  93. && (beginIndex = strline.indexOf(“http://mp3.sogou.com/down.so”)) != –1
  94. && (endIndex = strline.indexOf(“‘,”)) != –1) {
  95. strline = strline.substring(beginIndex, endIndex);
  96. getMP3URL(strline);
  97. }
  98. }
  99. htmlSocket.close();
  100. }
  101. /**
  102. * 分析歌曲链接找到其真实网址
  103. */
  104. private void getMP3URL(String surl) throws Exception {
  105. String strline = “”;
  106. urlSocket.create(surl);
  107. BufferedReader brIn = urlSocket.getBufferedReader();
  108. int beginIndex, endIndex;
  109. while ((strline = brIn.readLine()) != null) {
  110. if ((beginIndex = strline.indexOf(“http://”)) != –1
  111. && (endIndex = strline.indexOf(“.mp3”)) != –1) {
  112. strline = strline.substring(beginIndex, endIndex + 4);
  113. System.out.println(strline);    //打印MP3的真实地址
  114. //播放或下载的代码放这……;
  115. break;
  116. }
  117. }
  118. urlSocket.close();
  119. }
  120. }

另外,http://mp3.sogou.com/的:

  • 歌曲TOP100 http://music.sogou.com/song/topsong.html
  • 单曲抢先听 http://music.sogou.com/song/newnew_1.html
  • 劲爆dj音乐榜 http://music.sogou.com/song/newdj_1
  • 欧美流行榜 http://music.sogou.com/song/enpop_1.html

等页面的搜索方法跟上面的是一样的,并不建议你写代码到 http://music.sogou.com/song/目录下搜索*.html并用上述方法解析(就是实现传说中的网络蜘蛛的一部分功能),这样一顿海搜不礼貌哈,别人藏着掖着的就是不想让你查找到其MP3的网址的嘛。 这些页面上的歌曲经常更新,固定查找某一页面的MP3也可以听到新歌,不错了。一边干活一边听听歌,挺不错的哦~~


MP3网站的加密方法经常变更,到目前为止这种方法可用,不能保证一直可用。应用示例到我的主页http://jmp123.sf.net/ 下载最新的MP3播放程序,程序(jar包)用法见其中的readme.txt。

[转载]以.NET MF为依托,打造物联网时代轻量级嵌入式组态系统

mikel阅读(1042)

[转载]以.NET MF为依托,打造物联网时代轻量级嵌入式组态系统 – 叶帆工作室 – 博客园.

1 前言

在工控领域,组态软件司空见惯,国外的iFixInTouchWinCC,国内的组态王、力控、MSCG等等。组态软件的出现彻底解决了软件重复开发的问题,实现模块级复用,好处不仅仅是提高了开发效率,降低了开发周期,更大的优势的是成熟模块的复用,大大提高了系统稳定性和可靠性。

所谓组态(Configuration),就是模块化任意组合(类似积木玩具)。组态软件的主要特点有:

1)、延展性。所谓延展性,就是系统的延续和易于扩展性,用组态软件开发的系统,当现场或用户需求发生改变时(包括硬件设备或系统结构的改变),用户无需做很多修改,就可以很方便地完成系统的升级和改造;

2)、易用性。组态软件对底层功能都进行了模块级封装,对于用户,只需掌握简单的编程语言(内嵌的脚本语言,类Basic或类C语言),甚至不需要编程技术,就能很好地,通过组态配置的方式完成一个复杂系统的开发和集成;

3)、通用性。不同用户根据系统的不同,利用组态软件提供的I/O驱动(如PLC、仪表、板卡、智能模块、变频器等等驱动)、数据库和图元,就能完成一个具有动画、实时数据处理、历史数据和图表并存,且具有多媒体功能和网络功能的系统工程,不受领域或行业限制。

但是无论是基于PC平台的组态软件还是基于ARM系统的嵌入式组态软件,其组态粒度都显过大,大部分通过串口、网口、CAN等通道把个系统模块连接在一起,在一定程度上增加了系统构建的成本和代价。

而以.NET MF为依托构建的轻量级嵌入式组态软件(TinyIOs)就很好的解决了上述问题,除支持常规的串口、网口、CAN外,还支持USBWifiZigBeeSPII2C等通道,SPII2C片级总线的支持加上强大的托管代码(C#)开发能力,使嵌入式硬件系统真正的组态化、模块化成为可能,这项技术的推出,无疑为快速打造形态各异,功能不同的产品提供了最有力的支撑,完全符合新时代科技、绿色、环保的发展理念。

2 TinyIOs简介

TinyIOs,就是Tiny I/O Server的简称,在物联网、云计算时代,一切以数据为中心,不同的传感器通过不同的方式联入网络,通过云计算的方式为不同的终端用户提供服务。为了适应这种新形势的发展,加速和降低各种传感器、智能模块的入网代价,以微软成熟的.NET Micro Framework系统为基础,打造出物联网时代的轻量级嵌入式组态系统 —— TinyIOs

2.1 .NET Micro Framework简介(略)

2.2 TinyIOs系统架构

TinyIOs由三大部分构成,一是TinyIOs运行时,包含IODBIOBC、驱动引擎和策略引擎四部分;二是应用模块,包含驱动、策略和IO数据三部分;三是TinyIOs IDE环境,该工具和Microsoft Visual Studio开发工具一起共同完成驱动、策略的开发、配置及部署工作。

系统架构图(如下图所示):

TinyIOs.NET MF关系图(如下图所示)

2.3 IODB(略)

2.4 IOBC(略)

2.5驱动开发

一个驱动程序可对应一种设备,也可以对应一类设备,关键在于设备支持的协议是私有的,还是公开的,一般公开的协议,如Modbus,不同厂家的智能设备都有不同程度的支持,凡支持该协议的设备,都可以通过共同的设备驱动进行访问,唯一不同的就是访问的数据类型,起始地址,数据长度等参变量的不同而已。

2.5.1 驱动接口类

public interface IDriver

{

DeviceInfo GetDriverInfo();

int OnStart(Device device, IDeviceOperate operate);

int OnScan(Device device, IDeviceOperate operate);

int OnEnd(Device device, IDeviceOperate operate);

}

2.5.2 通信方式

public enum DeviceConnMode

{

SerialPort = 0,

Ethernet,

CAN,

USB,

SPI,

I2C,

SDIO,

Zigbee,

AD,

DA,

I,

Q,

PWM,

Other,

}

2.5.3 驱动配置信息类

public class DeviceInfo

{

public string Name;                         //32byte,驱动名称(要保证唯一)

public string Ver;                          //16byte,版本信息

public string Explain;                      //64byte,说明

public string Developer;                    //16byte,开发者

public string Date;                         //16byte,日期

public int AutoFlag;                        //自动化标志 0 – 系统为你初始化通信接口

1 – 由驱动程序本身完成通信接口初始化

public DeviceConnMode ConnMode;             //通信方式

public string Manufacturer;                 //64byte,设备制造商

public string DeviceType;                   //32byte,设备类型

//设备参数

public string PortAddrExplain;              //硬件端口名称 空为无效项

public string PortAddrValue;                //硬件端口默认值 项选择(如果有的话)用”|”

分隔开,默认项为第一个

public string PortConfigExplain;            //端口参数名称 空为无效项

public string PortConfigValue;              //端口参数默认值 项选择(如果有的话)用”|”

分隔开,默认项为第一个

public string DeviceAddrExplain;            //设备地址名称 空为无效项

public string DeviceAddrValue;              //设备地址默认值 项选择(如果有的话)用”|”

分隔开,默认项为第一个

public string DeviceConfigExplain;         //设备参数名称 空为无效项

public string DeviceConfigValue;            //设备参数默认值 项选择(如果有的话)用”|”

分隔开,默认项为第一个

//项参数

public string[] ItemExplain;                //8*32 byte,连接项名称

public string[] ItemValue;                  //8*4 byte 默认值 项选择(如果有的话)用

“|” 分隔开,默认项为第一个

}

2.5.4 驱动的执行

驱动除了按设定的扫描时间周期执行外,还可以把扫描时间设置为0,表示不会自动运行。设置为该模式的驱动,一般被策略程序直接调用而得以执行。

2.6 策略开发

可以把TinyIOs运行时想象成一个支持多任务的操作系统,这样每个策略的OnRun接口,都可以当成一个进程的Main函数,唯一不同的是,这个Main函数被调用的机制多种多样(参见策略执行模式)。

策略就是一段代码,一段标准的.NET Micro Framework程序,可以根据项目的需求充分访问.NET Micro Framework已有的开发资源(如各类库函数),编写实现任意功能的代码模块。

2.6.1 策略接口类

public interface IStrategy

{

string GetStrategyName();

int OnRun(IDeviceOperate operate, int parameter);

}

2.6.2 策略执行模式

public enum StrategyRunMode

{

None = 0,      //无动作

Loop,          //循环执行

System_Loop,   //系统循环执行

//事件驱动

Event_System_Start_Before,

Event_System_Start_After,

Event_System_End_Before,

Event_System_End_After,

Event_System_Error_Process,

Event_Driver_Scan_Before,

Event_Driver_Scan_After,

Event_Driver_Start_Before,

Event_Driver_Start_After,

Event_Driver_End_Before,

Event_Driver_End_After,

}

2.6.3 策略另类功能

策略除了按策略执行模式执行外,策略之间还可以互相调用,并且还可以直接调用指定名称的驱动程序的执行。

2.7 TinyIOs项目存储(略)

3 TinyIOs IDE简介

详情请观看视频:http://video.sina.com.cn/v/b/38583321-1804832611.html

4 TinyIOs应用实例(远程医疗系统)

5相关资源

1、官方网址

http://www.microsoft.com/netmf/default.mspx

2、官方博客

http://blogs.msdn.com/netmfteam/

3、中文博客

http://blog.csdn.net/yefanqiu

http://www.cnblogs.com/yefanqiu

4、中文论坛

http://space.cnblogs.com/group/MFSoft

http://social.msdn.microsoft.com/Forums/zh-CN/microframeworkzhchs/threads

5V4.0 SDK下载

http://www.microsoft.com/downloads/details.aspx?FamilyId=77dbfc46-14a1-4dcf-a809-eda7ccfe376b&displaylang=en

6V4.0 PortingKit(源码)下载

http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=16fa5d31-a583-4c0d-af74-f4d5e235d5bc

7.NET Micro Framework低价开发板

http://item.taobao.com/item.htm?id=7117999726

[转载]UCenter 与 Asp.net 通讯

mikel阅读(1018)

[转载]UCenter 与 Asp.net 通讯 – Dozer .NET 技术博客 – 博客园.

UCenter 与 Asp.net 通讯

前言

学生在线下面有多个子站,其中包括一个Discuz论坛

那当然要充分利用强大的UCenter来实现多点登陆

UCenter和别的网站跨域通讯,那用的肯定是WebService

PHP官方封装好了,所以很容易就搞定了,但是.Net…

网上找不到任何核心的通讯手册,除非去扣那个PHP的开发手册

Google后:

UCenter 接口开发手册:这个就是官方封装过的版本,其实这个根本不能叫接口开发手册,里面介绍的都是已经封装过的PHP函数,对核心只字不提

一个项目文件:刚看到这个我很兴奋,但是按照它说的调整好后,却不能用!一开始还不懂为什么,懂得原理后才知道,它其实是个空壳

一个DLL文件:这个DLL很强大,可惜,没有例程、没有手册、没有注释,还有BUG…

但是相对来说,最后的那个DLL是最接近的,所以决定反编译之,开始研究

最后就有了Dozer编辑版~ 成功实现通讯!

来源:dozer.cnblogs.com 作者:Dozer

UCenter通讯原理

原理网上很多,我也只是知道一个皮毛,在这里就以同步登陆为例子,来讲解一下这个类库的用法

login

以上就是同步登陆的步骤,如果你已经配置好,那么只需要这3行代码

01 namespace WebApplication1
02 {
03 public partial class Default : System.Web.UI.Page
04 {
05 protected void Page_Load(object sender, EventArgs e)
06 {
07 var uc = new UCClient();
08 var user = uc.UC_User_Login("user", "password").User;
09 Response.Write(uc.UC_User_Synlogin(user.Uid));
10 }
11 }
12 }

总之,在你的网站程序中需要有2个部分

一个是UCAPI部分,需要给UCenter调用

另外一部分就是UClient部分,用于调用UCenter

这样才能在最后实现双向通讯

来源:dozer.cnblogs.com 作者:Dozer

UCenter端配置过程

按照惯例,登陆UCenter后台,然后添加应用程序

别的地方和PHP网站一样,只有一个地方,就是“应用接口文件名称”的地方

需要填写uc.ashx

这个和此类库的原理有关,后面详解

1

提交…可惜,显示通讯不成功,因为我的网站还没配置呢~

提交后再次编辑,会得到一段PHP的配置信息

01 define('UC_CONNECT', 'mySQL');
02 define('UC_DBHOST', localhost');
03 define('UC_DBUSER', 'root');
04 define('UC_DBPW', 'mySQL');
05 define('UC_DBNAME', 'uc_discuz');
06 define('UC_DBCHARSET', 'utf8');
07 define('UC_DBTABLEPRE', '`uc_discuz`.uc_');
08 define('UC_DBCONNECT', '0');
09 define('UC_KEY', 'qwertyui');
10 define('UC_API', 'http://localhost/ucenter');
11 define('UC_CHARSET', 'utf-8');
12 define('UC_IP', '127.0.0.1');
13 define('UC_APPID', '19');
14 define('UC_PPP', '20');

先留着,后面会用到~

来源:dozer.cnblogs.com 作者:Dozer

WebApplication端配置过程

第一步当然是Web.config文件

新建一个网站应用程序,并且引用这个类库

上面的配置信息是PHP用的,我们把它转换到Web.config文件中去

01 <appSettings>
02 <add key="UC_CONNECT" value="mysql"/>
03 <add key="UC_DBHOST" value="localhost"/>
04 <add key="UC_DBUSER" value="root"/>
05 <add key="UC_DBPW" value="mysql"/>
06 <add key="UC_DBNAME" value="uc_discuz"/>
07 <add key="UC_DBCHARSET" value="utf8"/>
08 <add key="UC_APPIDUC_DBTABLEPRE" value="`uc_discuz`.uc_"/>
09 <add key="UC_DBCONNECT" value="0"/>
10 <add key="UC_KEY" value="qwertyui"/>
11 <add key="UC_API" value="http://localhost/ucenter"/>
12 <add key="UC_CHARSET" value="utf-8"/>
13 <add key="UC_IP" value="127.0.0.1"/>
14 <add key="UC_APPID" value="19"/>
15 <add key="UC_PPP" value="20"/>
16 </appSettings>

来源:dozer.cnblogs.com 作者:Dozer

第二步是建立UCAPI,供UCenter调用(这步完成后UCenter中会显示通讯正常)

1、新建一个叫API的文件

2、在里面建立一个新文件uc.ashx(不要建立.aspx)

3、打开这个uc.ashx文件,本来它继承于IHttpHandler,我们把它修改一下,让它继承于FS.API.UCenter.UCAPI.UCAPIBase

4、实现一下这个抽象类的函数(利用VS的代码自动完成功能)

5、接下来你就可以在这里写一些逻辑代码了

比如,当有人在别的站同步登陆后,会通知你的站点

然后会调用 Synlogin 函数,这时候,你就需要在这个函数里写一些代码

例如:写cookie之类的

Q:UCenter为什么不直接写Cookie,子站读Cookie?

A:UCenter实现的是跨域登陆,所以每个子站的Cookie是分开的,需要自己实现!

好了,完成这步后打开UCenter,你会发现:通讯成功!

UCenter测试通讯成功仅仅是调用了一个test函数,只要上述配置没写错,那就会显示通讯成功!但是它还不能实现任何功能,需要把上面的那些函数完善~

来源:dozer.cnblogs.com 作者:Dozer

第三步是在网站中调用UCenter的接口了

这个超级简单,其实“UCenter通讯原理”那部分代码

为什么要Respon.Write这段东西?

这和UCenter同步登陆原理有关,向UCenter传递信息,告诉它要同步登陆后,它不会自己通知别的子站,而是返回一段JS,需要你的网站调用这段JS,然后通知各个子站

OK了~所有配置完成~

来源:dozer.cnblogs.com 作者:Dozer

我对原来的那个DLL做了什么?

1、原来的DLL编码部分有几个严重的问题,导致编码错误,无法提交表单

2、原来的DLL估计是很久以前写的,里面序列化和反序列化的时候,规则和现在UCenter的规则不同,我根据现在的规则,修改了一下

3、修复别的一些小BUG

来源:dozer.cnblogs.com 作者:Dozer

类库下载&示例代码

代码的原始作者找不到了,遵循开源精神

另外不保证目前代码全部正确,我只是测试了几个函数

直接公布源代码:源代码