[转载]REST风格的应用程序实现

mikel阅读(1115)

[转载]REST风格的应用程序实现 – 小狼的世界 – 博客园.

莫笑我老土,因为我确实是最近才听说REST风格的,以前就是觉得 /category/product/pid

这样的地址非常 的漂亮,但是那只是表象罢了,了解深入以后,发现必须有一个客户端的Ajax Engine和Server端的服务配合,才能实现一个REST风格的应用,下面就是我的实验。

问题?

要对外提供哪些服务。服务器端的服务可能会被众多的浏览器请求,也可能被第三方应用程序所调用,所以需要从总体上来考虑这个对外的“应用程序接 口”(API),尽量保持接口的稳定性。REST是一种风格,并且形成了自己的规则,构建这样的应用,应尽量遵循REST的原则。

以一个足球服务为例,众多的观众会要求观看比赛的记录,上传新比赛记录,更新比赛记录,更正现有的比赛或者删除比赛等等。像这样描述的话,我们 需要提供众多不同的服务,并且最终会倒在维护一致性的工作上。那么应该怎么做呢,考虑一下客户可能的请求方式:

GET方式请求一个新建比赛服务:

http://example.com/newMatch?id=995&bluebaggers=150&redlegs=60

POST或PUT方式请求一个新建比赛服务:

http://example.com/newMatch

附加的XML为:

<match id=”995″>

<score team=”bluebaggers”>150</score>

<score team=”redlegs”>60</score>

</match>

CGI 风格的POST或PUT请求:

http://example.com/newMatch

请求体:

id=995&bluebaggers=150&redlegs=60

或 者一个维护服务的GET请求:

http://example.com/matchMaintenance/command=newMatch&id=995&bluebaggers=150&redlegs=60

或者POST请求

http://example.com/matchMaintenance/command=newMatch

<match id=”995″><score team=”bluebaggers”>150</score><score team=”redlegs”>60</score></match>

以此类推,可以有很多这样的功能。有些人觉得这并不是什么问题,对越来越多的请求,我们只要建立服务,然后给出 相应的说明就可以了。但是,他还是存在缺点的。

也许我们会假设访问 只是来自脚本,那么这种情况可能会简单一点。但实际上,还有很多的因素会涉及到,例如网页浏览器(会存在后撤和刷新按钮的问题)、Web服务器(可能会有 缓存和编译问题)、网络路由和缓存问题、应对爬虫的骚扰、一些个人站点对网站内容的抓取。如果我们考虑这些不同的请求,我们的程序就可以表现的更健壮。

理想的情况下,一个服务应该有自我说明的能力。如果一个服务建立在一种约定俗成的条件下, 那么大家就很容易适应并且进行后续的开发。

REST就是考虑了这些 因素,可以使用RESTful API来实现上面的服务。

RESTful 原则介绍

REST 的主要原则有:

用URL表示资源。资源就像商业实体一样,是我们希望作为API实体呈现的一部分。 通常是一个名词,每个资源都用一个独一无二的URL来表示。

HTTP方法表示操作。REST充分利 用了HTTP的方法,特别是GET、POST、PUT和DELETE。注意XMLHttpRequest对象实现了全部的方法,具体可以参看W3C HTTP 1.1 Specification

也就是说,客户端的任何请求都包含一个URL和一个HTTP方法。回到上面的例子中,比 赛显然是一个实体,那么对于一个特定比赛的请求就表示为:

 http://example.com/matches/995

这种方式是清晰明了的,也许和精确命名的方式有所区别,但是只要遵循这种形式,我们就能很快的进行GET、DELETE、UPDATE和新建操作。

RESTful的原则:

1、URL表示资源

2、HTTP方法表示操作

3、GET只是用来请求操作,GET操作永远都不应该修改服务器的状态。但是这个也要具体情况进行分析,例如一个页面中的计数器,每次访问的时候确 实引起了服务器数据的改变,但是在商业上来说,这并不是一个很重要的改变,所以仍然可以接收使用GET的方式来修改数据。

一个案例,使用GET方式修改数据遭受损失的案例

Witness the the debacle caused by the Google Accelerator interacting with non-RESTful services in mid-2005. The accelerator jumps ahead of the user and prefetches each link in case they should click on it (a non-Ajaxian example of Predictive Fetch). The problem came when users logged into non-RESTful applications likeBackpack. Because Backpack deletes items using GET calls, the accelerator – in its eagerness to activate each GET query – ended up deleting personal data. This could happen with regular search engine crawlers too, though the issue doesn’t tend to come up because they don’t have access to personal accounts.

4、服务应该是无状态的

在有状态的会话中,服务器可以记录之前的信息。而RESTful风格中是不应该让服务器记录状态的,只有这样服务器才具备可扩展性。当然,我们可以 在客户端使用cookie,而且只能用在客户端向服务器发送请求的时候。

5、服务应当是“幂等”的

“幂等”表示可以发送消息给服务,然后可以再次毫不费力的发送同样的消息给服务。例如,发送一个“删除第995场比赛”的消息,可以发送一次,也可 以连续发送十次,最后的结果都会保持一致。当然,RESTful的GET请求通常是幂等的,因为基本上不会改变服务器的状态。注意:POST 请求不能被定义为“幂等”,特别是在创建新资源的时候,一次请求创建一个资源,多次请求会创建多个资源。

6、拥抱超链接

7、服务应当自我说明

例如 http://example.com/match/995 请求了一个具体的比赛,但是 http://example.com/match 并没有对任何实体进行请求,因此,应当返回一些介绍信息。

8、服务约束数据格式。数据必须符合要求的格式

在PHP的程序中,想要实现这种REST风格的URL,仅仅依靠程序是不行的,还需要在服务器端配置rewrite规则,例如,对于一个REST风 格的资源请求:

http://www.api.com/product/113

一般实现的脚本为

http://www.api.com/product.php?id=113

这个是基于QueryString的,也可以做一个统一的 index.php 入口,然后通过处理URI的方式实现,例如:

http://www.api.com/index.php/product/113

这样的URL,都可以通过rewrite来实现rest风格。总之,REST是一种程序设计的风格,为我们整理自己的应用设计提供了一个原则,在利 用这些原则带来的遍历的同时,可以根据实际情况进行灵活的处理。

参考资料:

1、RESTful Service

2、RPC Service

3、HTTP Methods

4、verbs Can also be nouns

[转载]为ASP.NET MVC 2.0添加Razor模板引擎 (on .NET4)

mikel阅读(999)

[转载]为ASP.NET MVC 2.0添加Razor模板引擎 (on .NET4) – 重典的博客 – 博客园.

根据ScottGu的博客记述(http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx), 在未来不久将会发布一个ASP.NET MVC 3.0的Preview版本,在这个版本中可以使用多个内置的模板引擎,以它发布出来的截图来看,其中包括NHaml,Spark以及微软刚刚发布的 ASP.NET Web Pages(Razor)。 ASP.NET Web Pages包含在Web Matrix中,提供了一种新的模板模式,其扩展名为 .vbhtml/.cshtml,可以使用类似以下语法来做视图显示:

@{
	var i = 11;
}

@(i+1)
<br>

@if (i%2==1){
	<p>true</p>
}else{
	<p>false</p>
}

输出结果为:

12
<br>
 
<p>true</p>

在不久之后Ms还会对此提供Visual Studio 高亮及智能感知支持。

这种模板如此简捷,如果能用在现有的ASP.NET MVC 2.0上做为一个模板引擎是不错的。

首先我们要安装ASP.NET Web Pages,下载地址:http://bbs.eice.com.cn/showtopic-409.aspx ,当然直接安装WebMatrix也是可以。

安装之后在IIS中就会添加对cshtml及vbhtml的支持。

安装后程序集文件会被复制到Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies目录下。

其中包括

Microsoft.Data.dll
Microsoft.Web.Infrastructure.dll
Microsoft.Webpages.Compilation.dll
Microsoft.Webpages.Configuration.dll
Microsoft.Webpages.dll
Microsoft.Webpages.Helpers.dll
Microsoft.Webpages.Helpers.Toolkit.dll

下面我们就动手对ASP.NET MVC程序添加一个Razor的模板引擎:

首先建立一个ASP.NET MVC的项目,然后对其中的Web.Config的system.web/compilation/assemblies节点上添加内容:

<add assembly="Microsoft.WebPages.Compilation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="Microsoft.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="Microsoft.WebPages.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="Microsoft.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

并对system.web/compilation/buildProviders添加内容:

<add extension=".cshtml" type="Microsoft.WebPages.Compilation.InlinePageBuildProvider" />

并引用相应的

Microsoft.Data.dll 
Microsoft.Webpages.dll 
Microsoft.Webpages.Helpers.dll 
Microsoft.Webpages.Compilation.dll

几个文件

准备工作做好了,下面就来实现相应的模板引擎,我们先来实现一个IView对象:

public class WebPageView : IView
    {
        public WebPageView(string viewPath)
            : this(viewPath, null)
        {
        }

        public WebPageView(string viewPath, string masterPath)
        {
            if (string.IsNullOrEmpty(viewPath))
            {
                throw new ArgumentException("viewPath can't null", "viewPath");
            }
            this.ViewPath = viewPath;
            this.MasterPath = masterPath ?? string.Empty;
        }

        public virtual void Render(ViewContext viewContext, TextWriter writer)
        {
            if (viewContext == null)
            {
                throw new ArgumentNullException("viewContext");
            }
            WebPage page = WebPage.CreateInstanceFromVirtualPath(this.ViewPath);//load cshtml file
            if (page == null)
            {
                throw new InvalidOperationException("cshtml file not exists");
            }
            else
            {
                this.RenderViewPage(viewContext, page);
            }
        }

        private void RenderViewPage(ViewContext context, WebPage page)
        {
            if (!string.IsNullOrEmpty(this.MasterPath))
            {
                page.LayoutPage = this.MasterPath;
            }
            page.VirtualPath = this.ViewPath;
            page.ExecutePageHierarchy(CreatePageContext(context)
                , context.HttpContext.Response.Output, null);
            //execute cshtml file
        }

        internal static WebPageContext CreatePageContext(ViewContext content)
        {
            var pc = new WebPageContext();
            var t = pc.GetType();
            t.InvokeMember("HttpContext", BindingFlags.SetProperty | BindingFlags.NonPublic | BindingFlags.Instance
                , null, pc, new[] { content.HttpContext });
            t.InvokeMember("ViewContext", BindingFlags.SetProperty
                | BindingFlags.NonPublic | BindingFlags.Instance
                , null, pc, new[] { content });
            return pc;
        }

        /// <summary>Gets or sets the master path.</summary>
        /// <returns>The master path.</returns>
        public string MasterPath { get; private set; }

        /// <summary>Gets or sets the view path.</summary>
        /// <returns>The view path.</returns>
        public string ViewPath { get; private set; }
    }

然后我们再来实现一个IViewEngine对象:

    /// <summary>
    /// WebPage View Engine
    /// </summary>
    class WebPageEngine : VirtualPathProviderViewEngine
    {
       
        public WebPageEngine()
        {
            // how to find the template path
            base.MasterLocationFormats = new string[] { 
                "~/Views/{1}/{0}.cshtml", 
                "~/Views/Shared/{0}.cshtml" 
            };
            base.AreaMasterLocationFormats = new string[] { 
                "~/Areas/{2}/Views/{1}/{0}.cshtml", 
                "~/Areas/{2}/Views/Shared/{0}.cshtml"
            };
            base.ViewLocationFormats = new string[] { 
                "~/Views/{1}/{0}.cshtml", 
               "~/Views/Shared/{0}.cshtml"
            };
            base.AreaViewLocationFormats = new string[] { 
                "~/Areas/{2}/Views/{1}/{0}.cshtml", 
                "~/Areas/{2}/Views/Shared/{0}.cshtml" 
            };
            base.PartialViewLocationFormats = base.ViewLocationFormats;
            base.AreaPartialViewLocationFormats = base.AreaViewLocationFormats;
        }

        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            return new WebPageView(partialPath, null);
        }

        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            return new WebPageView(viewPath, masterPath);
        }

    }

这样我们就实现了Razor的模板引擎了,我们只要在Global.asax中将模板引擎添加进去:

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new WebPageEngine());
        }

并且将Global的基类改为WebPageHttpApplication:

public class MvcApplication : WebPageHttpApplication
{
//...
}

这样整个程序就可以工作了

我们在Views/Home下添加一个Index.cshtml:

@Html.ActionLink("Home","index","User")
<br>
@ViewData["Message"]

这样在我们访问/Home/Index的时候就可以得到ASP.NET MVC默认工程的HomeController.Index所生成的页面了:

<a href=”/User”>Home</a>
<br>
欢迎使用 ASP.NET MVC!

可见在这个模板引擎中,先天对ASP.NET MVC有良好的支持,本身已经集成了Helper、ViewData等诸多ASP.NET MVC的特性。

让我们期待ASP.NET MVC 3.0及Razor对VS的支持吧

8189E6B8-FBE4-4F01-8F9F-5687C0EA9F59

[转载]蛙蛙推荐:使用ASP.NET开发WAP2.0(XHTML MP)页面

mikel阅读(1039)

[转载]蛙蛙推荐:使用ASP.NET开发WAP2.0(XHTML MP)页面 – 蛙蛙池塘 – 博客园.

摘要:目前大多数手机已经不仅仅支持WAP1.0(WML),而是支持WAP2.0(XHTML MP)了,甚至有些手机不久就要支持HTML5了。本文演示如何用ASP.NET 开发WAP2.0页面,查阅了一些资料,整理分享给大家,希望大家能以后能少走弯路。手机浏览器作为一个人机交互界面,而且手机又有随时随地能使用的优 势,我们在这方面是可以大有作为的。

XHTML MP简介

WAP2.0有一套规范,XHTML MP是其中用于浏览器显示的规范,底层可以使用HTTP传输,它也是XHTML的一个子集,详细参考如下链接:

XHTML Mobile Profile

DOCTYPE设置

XHTML MP有自己的DOCTYPE,如下

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.1//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile11.dtd">

可以把它在Master文件里设置,以便在所有内容页里自动使用,而不是每个页面重复的设置。

配置浏览器文件

ASP.NET 项目里右键添加App_Browsers文件夹,再在里面添加一个mobile.browser文件,如下

代码

<browsers> <browser id="NewBrowser" parentID="Default"> <identification> <header name="Accept" match="application/xhtml\+xml; profile|application/vnd\.wap\.xhtml\+xml" /> </identification> <capabilities> <capability name="preferredRenderingMime" value="application/vnd.wap.xhtml+xml" /> <capability name="preferredRenderingType" value="xhtml-mp" /> </capabilities> <controlAdapters markupTextWriterType="System.Web.UI.XhtmlTextWriter" /> </browser> </browsers>

这个浏览器配置文件的意思,如果HTTP请求的Accept头里包含xhtml mp的MIME类型,则在给客户端返回Response的时候使用application/vnd.wap.xhtml+xml的 ContentType,且RenderType使用XHTML-MP类型,Render的时候强制使用XhtmlTextWriter。

浏览器配置文件是ASP.NET 2.0新增的机制,代替以前在WebConfig里配置的BrowserCaps节点。

WebConfig配置

因为我们开发的网页是面向手机的,手机的功能比较弱,有的甚至不支持Cookie等,而且只支持简单的控件,所以我们把Cookie和 ViewState等禁掉,如下

代码

<?xml version="1.0"?> <configuration> <system.web> <compilation debug="false" /> <authentication mode="None" /> <xhtmlConformance mode="Strict" /> <pages enableViewState="false" /> <sessionState cookieless="true"/> </system.web> </configuration>

启用页面压缩来减少流量传输

有些手机浏览器支持Gzip等页面压缩算法,我们应该检测出来这种情况,并让这种手机节省流量。可以在Global.asax里写一段代码支持,该 方法来源于网络,引用如下,原始链接参考文末的参考链接

代码

void Application_PreRequestHandlerExecute(object sender, EventArgs e) { HttpApplication app = sender as HttpApplication; string acceptEncoding = app.Request.Headers["Accept-Encoding"]; Stream prevUncompressedStream = app.Response.Filter; if (!(app.Context.CurrentHandler is Page || app.Context.CurrentHandler.GetType().Name == "SyncSessionlessHandler") || app.Request["HTTP_X_MICROSOFTAJAX"] != null) return; if (acceptEncoding == null || acceptEncoding.Length == 0) return; acceptEncoding = acceptEncoding.ToLower(); if (acceptEncoding.Contains("deflate") || acceptEncoding == "*") { // defalte app.Response.Filter = new DeflateStream(prevUncompressedStream, CompressionMode.Compress); app.Response.AppendHeader("Content-Encoding", "deflate"); } else if (acceptEncoding.Contains("gzip")) { // gzip app.Response.Filter = new GZipStream(prevUncompressedStream, CompressionMode.Compress); app.Response.AppendHeader("Content-Encoding", "gzip"); } }

在没有启用压缩和配置浏览器文件之前,手机访问页面抓包如下

代码

GET /mobileoaweb/?t=25345 HTTP/1.1 Host: 114.249.124.57 Accept: text/html, application/xhtml+xml, application/vnd.wap.xhtml+xml, application/vnd.wap.wmlc, application/vnd.wap.wmlscriptc, text/vnd.wap.wml, text/vnd.sun.j2me.app-descriptor, */*, text/x-vcard, text/x-vcalendar, image/gif, image/vnd.wap.wbmp Accept-Charset: ISO-8859-1,UTF-8,US-ASCII,UTF-16BE,windows-1252,UTF-16LE,GB2312,windows-1250 Accept-Language: zh-CN,zh;q=0.5 Accept-Encoding: gzip,deflate Content-length: 0 Via: WTP/1.1 BJBJ-PS-WAP2-GW07.bj2.monternet.com (Nokia WAP Gateway 4.1 CD1/ECD13_D/4.1.04) X-Forwarded-For: 10.140.248.32 X-Source-ID: BJGGSN06BMT-CSK X-Nokia-CONNECTION_MODE: TCP X-Up-Bear-Type: GPRS/EDGE X-Nokia-gateway-id: NWG/4.1/Build4.1.04 Connection: close HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Date: Sat, 10 Jul 2010 12:26:43 GMT X-Powered-By: ASP.NET Connection: close X-AspNet-Version: 2.0.50727 Cache-Control: private Content-Type: text/html; charset=utf-8 Content-Length: 2180

可以看到这时候给客户端返回的Content-Type是text/html,而且Content-Length很长,是2180,而配置浏览器文 件以及启用压缩之后,则如下

代码

GET /mobileoaweb/?t=25345&t=36045&t=26421 HTTP/1.1 Host: 114.249.124.57 Accept: text/html, application/xhtml+xml, application/vnd.wap.xhtml+xml, application/vnd.wap.wmlc, application/vnd.wap.wmlscriptc, text/vnd.wap.wml, text/vnd.sun.j2me.app-descriptor, */*, text/x-vcard, text/x-vcalendar, image/gif, image/vnd.wap.wbmp Accept-Charset: ISO-8859-1,UTF-8,US-ASCII,UTF-16BE,windows-1252,UTF-16LE,GB2312,windows-1250 Accept-Language: zh-CN,zh;q=0.5 Accept-Encoding: gzip,deflate Cookie: jid=M4GKS9T0hh!-849429530 Content-length: 0 Via: WTP/1.1 BJBJ-PS-WAP2-GW18.bj2.monternet.com (Nokia WAP Gateway 4.1 CD1/ECD13_D/4.1.04) X-Forwarded-For: 10.140.83.123 X-Source-ID: BJGGSN06BMT-CSK X-Nokia-CONNECTION_MODE: TCP X-Up-Bear-Type: GPRS/EDGE X-Nokia-gateway-id: NWG/4.1/Build4.1.04 Connection: close HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Date: Sat, 10 Jul 2010 14:33:48 GMT X-Powered-By: ASP.NET Connection: close X-AspNet-Version: 2.0.50727 Content-Encoding: deflate Cache-Control: private Content-Type: application/vnd.wap.xhtml+xml; charset=utf-8 Content-Length: 1295

看到变化了吧。

样式的考虑

WAP2.0里规定了WAP CSS规范,和普通的HTML 的CSS差不多,支持支持的属性少一些,但像font-weight,background-color,color这些都是支持的,而margin这些 经我测试在黑莓8310浏览器上是不支持的。我们开发的页面是给手机用的,所以也就不要用花里胡哨的样式以及很复杂的布局了,样式上一般就用加粗和颜色来 区分不同重要程度就行了,布局上一般就是单纵栏的布局,css文件最好使用独立的文件,这样手机浏览器第一次访问后可以缓存起来,另外样式表定义的话死后 尽量用伪类,不要用ID,这样可以少定义一些样式,减少网络流量,而且伪类的名字尽量短一些,以减少HTML页面的尺寸。

控件的使用

尽量使用简单的控件,如链接,图片,输入框,按钮等基本的控件,如果要显示数据列表,最好自己用Repeter控件自己控制输出,可以防止生成不必 要的代码。表格也尽量少用,尤其是嵌套表格,虽然支持,但会影响客户端解析速度。不建议用<p>来实现段落,<p>默认 margin不为0,而且css样式无法把它设为0,所以在设计页面的时候就尽量用<br />和<hr />吧。

参考链接

Enabling Gzip and Deflate HTTP Compression in ASP.NET pages
XHTML MP MIME 类型与文件扩展
Visual Studio 和 ASP.NET 中的 XHTML 标准
ASP.NET 2.0 / XHTML-MP Examples
XHTML Mobile Profile

[转载]C#.NET发EMAIL的几种方法 MailMessage/SmtpClient/CDO.Message

mikel阅读(889)

[转载]C#.NET发EMAIL的几种方法 MailMessage/SmtpClient/CDO.Message – 熊哥 – 博客园.

C#.NET发EMAIL的几种方法 MailMessage/SmtpClient/CDO.Message

源代码如下:

using System; using System.Collections.Generic; using System.Text; using System.Web; using System.Net.Mail; using System.Net; namespace Pub.Class { /// <summary> /// 发送Email类 /// </summary> public class Email { #region 私有成员 private static object lockHelper = new object(); private string _From; private string _FromEmail; private string _Subject; private string _Body; private string _SmtpServer; private string _SmtpPort = "25"; private string _SmtpUserName; private string _SmtpPassword; private System.Web.Mail.MailFormat _Format = System.Web.Mail.MailFormat.Html; private System.Text.Encoding _Encoding = System.Text.Encoding.Default; #endregion #region 属性 /// <summary> /// 正文内容类型 /// </summary> public System.Web.Mail.MailFormat Format { set { _Format = value; } } /// <summary> /// 正文内容编码 /// </summary> public System.Text.Encoding Encoding { set { _Encoding = value; } } /// <summary> /// FromEmail 发送方地址(如test@163.com) /// </summary> public string FromEmail { set { _FromEmail = value; } } /// <summary> /// From /// </summary> public string From { set { _From = value; } } /// <summary> /// 主题 /// </summary> public string Subject { set { _Subject = value; } } /// <summary> /// 内容 /// </summary> public string Body { set { _Body = value; } } /// <summary> /// SmtpServer /// </summary> public string SmtpServer { set { _SmtpServer = value; } } /// <summary> /// SmtpPort /// </summary> public string SmtpPort { set { _SmtpPort = value; } } /// <summary> /// SmtpUserName /// </summary> public string SmtpUserName { set { _SmtpUserName = value; } } /// <summary> /// SmtpPassword /// </summary> public string SmtpPassword { set { _SmtpPassword = value; } } #endregion #region 构造器 /// <summary> /// 构造器 /// </summary> public Email() { } #endregion #region Send /// <summary> /// 发送EMAIL /// </summary> /// <example> /// <code> /// Email _Email = new Email(); /// _Email.FromEmail = "test@163.com"; /// _Email.Subject = "&lt;div>aaaa&lt;/div>"; /// _Email.Body = "aaaaaaaaaaaaa"; /// _Email.SmtpServer = "smtp.163.com"; /// _Email.SmtpUserName = "aaa"; /// _Email.SmtpPassword = "aaa"; /// _Email.Send("test@163.com"); /// </code> /// </example> /// <param name="toEmail">收信人 接收方地址</param> /// <returns>成功否</returns> public bool SmtpMailSend(string toEmail) { lock (lockHelper) { System.Web.Mail.MailMessage msg = new System.Web.Mail.MailMessage(); try { msg.From = _FromEmail;//发送方地址(如test@163.com) msg.To = toEmail;//接收方地址 msg.BodyFormat = _Format;//正文内容类型 msg.BodyEncoding = _Encoding;//正文内容编码 msg.Subject = _Subject;//主题 msg.Body = _Body;//内容 msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1");//设置为需要用户验证 if (!_SmtpPort.Equals("25")) msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserverport", _SmtpPort);//设置端口 msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", _SmtpUserName);//设置验证用户名 msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", _SmtpPassword);//设置验证密码 System.Web.Mail.SmtpMail.SmtpServer = _SmtpServer;//邮件服务器地址(如smtp.163.com) System.Web.Mail.SmtpMail.Send(msg);//发送 return true; } catch { } finally { } } return false; } /// <summary> /// 发送EMAIL /// </summary> /// <param name="toEmail">Email</param> /// <returns>是否成功</returns> public bool CDOMessageSend(string toEmail) { lock (lockHelper) { CDO.Message objMail = new CDO.Message(); try { objMail.To = toEmail; objMail.From = _FromEmail; objMail.Subject = _Subject; if (_Format.Equals(System.Web.Mail.MailFormat.Html)) objMail.HTMLBody = _Body; else objMail.TextBody = _Body; //if (!_SmtpPort.Equals("25")) objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserverport"].Value = _SmtpPort; //设置端口 objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserver"].Value = _SmtpServer; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"].Value = 1; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout"].Value = 10; objMail.Configuration.Fields.Update(); objMail.Send(); return true; } catch {} finally{ } System.Runtime.InteropServices.Marshal.ReleaseComObject(objMail); objMail = null; } return false; } /// <summary> /// CDOMessageSend /// </summary> /// <param name="toEmail"></param> /// <param name="sendusing"></param> /// <returns></returns> public bool CDOMessageSend(string toEmail,int sendusing) { lock (lockHelper) { CDO.Message objMail = new CDO.Message(); try { objMail.To = toEmail; objMail.From = _FromEmail; objMail.Subject = _Subject; if (_Format.Equals(System.Web.Mail.MailFormat.Html)) objMail.HTMLBody = _Body; else objMail.TextBody = _Body; if (!_SmtpPort.Equals("25")) objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserverport"].Value = _SmtpPort; //设置端口 objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpserver"].Value = _SmtpServer; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"].Value = sendusing; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/sendemailaddress"].Value = _FromEmail; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpuserreplyemailaddress"].Value = _FromEmail; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpaccountname"].Value = _SmtpUserName; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/sendusername"].Value = _SmtpUserName; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/sendpassword"].Value = _SmtpPassword; objMail.Configuration.Fields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"].Value=1; objMail.Configuration.Fields.Update(); objMail.Send(); return true; } catch { } finally{ } System.Runtime.InteropServices.Marshal.ReleaseComObject(objMail); objMail = null; } return false; } /// <summary> /// SmtpClientSend /// </summary> /// <param name="toEmail"></param> /// <returns></returns> public bool SmtpClientSend(string toEmail) { lock (lockHelper) { System.Net.Mail.MailMessage message = new MailMessage(_FromEmail, toEmail, _Subject, _Body); message.SubjectEncoding = _Encoding; message.BodyEncoding = _Encoding; message.IsBodyHtml = true; message.Priority = MailPriority.High; SmtpClient client = new SmtpClient(_SmtpServer); client.UseDefaultCredentials = false; client.Credentials = new NetworkCredential(_SmtpUserName, _SmtpPassword); client.DeliveryMethod = SmtpDeliveryMethod.Network; client.Port = Str.ToInt(_SmtpPort, 587); client.EnableSsl = true; try { client.Send(message); } catch { return false; } return true; } } #endregion } }

多线程服务调用:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration.Install; using System.ServiceProcess; using System.Collections; using System.Threading; using System.Xml; using System.IO; using System.Net.Mail; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting; using Pub.Class; using System.Diagnostics; namespace MailService { [RunInstaller(true)] public partial class MService : ServiceBase { public static bool isRun = false; public Queue emailQueue = new Queue(); private Thread readEmailThread; private Thread[] sendEmailThread; private string[] strList = new string[] { "MailService 启动成功!", "MailService 停止!", "{2} {1} - [{0}] - 发送失败!", "{2} {1} - [{0}] - 发送成功!", "LiveRemotingService 已启动,服务端口6669。", "LiveRemotingService 停止!" }; private struct Config { public string Conn; public string LogFile; public string SmtpServer; public string UserName; public string Password; public string FromAddress; public int AmountThread; public int RecordCount; public int TimeInterval; } private Config config = new Config(); public MService() { System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false; InitializeComponent(); if (!System.Diagnostics.EventLog.SourceExists("MailSource")) System.Diagnostics.EventLog.CreateEventSource("MailSource", "MailServiceLog"); this.eventLog1.Source = "MailSource"; this.eventLog1.Log = "MailServiceLog"; this.eventLog2.Source = "LiveRemotingSource"; this.eventLog2.Log = "MailServiceLog"; } protected override void OnStart(string[] args) { try { InitConfig(); this.eventLog1.WriteEntry(strList[0], System.Diagnostics.EventLogEntryType.SuccessAudit); this.timer1.Interval = config.TimeInterval * 1000; this.timer1.Enabled = true; sendEmailThread = new Thread[config.AmountThread]; } catch (Exception e) { this.eventLog1.WriteEntry(e.ToString(), System.Diagnostics.EventLogEntryType.Error); } } protected override void OnStop() { this.eventLog1.WriteEntry(strList[1], System.Diagnostics.EventLogEntryType.SuccessAudit); GC.Collect(); this.timer1.Enabled = false; } private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (isRun) return; timer1.Enabled = false; readEmailThread = new Thread(new ThreadStart(ReadEmailQuque)); readEmailThread.IsBackground = true; readEmailThread.Start(); } private void InitConfig(){ config.Conn = Pub.Class.WebConfig.GetApp("ConnString"); config.LogFile = Pub.Class.WebConfig.GetApp("logFile"); config.SmtpServer = Pub.Class.WebConfig.GetApp("SmtpServer"); config.UserName = Pub.Class.WebConfig.GetApp("UserName"); config.Password = Pub.Class.WebConfig.GetApp("Password"); config.FromAddress = Pub.Class.WebConfig.GetApp("FromAddress"); string amountThread = Pub.Class.WebConfig.GetApp("AmountThread"); config.AmountThread = amountThread.Equals("") ? 1 : Convert.ToInt32(amountThread); config.AmountThread = config.AmountThread < 1 ? 1 : config.AmountThread; string recordCount = Pub.Class.WebConfig.GetApp("RecordCount"); config.RecordCount = recordCount.Equals("") ? 1000 : Convert.ToInt32(recordCount); config.RecordCount = config.RecordCount < 1000 ? 1000 : config.RecordCount; string timeInterval = Pub.Class.WebConfig.GetApp("TimeInterval"); config.TimeInterval = timeInterval.Equals("") ? 1000 : Convert.ToInt32(timeInterval); config.TimeInterval = config.TimeInterval < 2 ? 2 : config.TimeInterval; } private void ReadEmailQuque(){ timer1.Enabled = true; IList<EC_EmailList> list = EC_EmailListFactory.Instance().SelectListByTop(config.RecordCount); if (list.Count == 0) return; isRun = true; for (int i = 0; i < list.Count; i++) { emailQueue.Enqueue(list[i]); } for (int i = 0; i < config.AmountThread; i++) { sendEmailThread[i] = new Thread(new ThreadStart(DoSendEmail)); sendEmailThread[i].Name = "Thread" + (i+1).ToString(); sendEmailThread[i].Start(); } list = null; } private void DoSendEmail(){ while (true) { EC_EmailList objMail; lock(this){ if (emailQueue.Count>0) { objMail = (EC_EmailList)emailQueue.Dequeue(); } else { isRun = false; return; } } int mailID = (int)objMail.EmailID; string strTo = objMail.To; string strSubject = objMail.Subject; string strBody = objMail.Body; string strFrom = objMail.From; string smtpServer = objMail.SmtpServer; string userName = objMail.UserName; string password = objMail.Password; bool isTrue = SendMail(strTo, strSubject, strBody, strFrom, smtpServer, userName, password, ""); EC_EmailListFactory.Instance().DeleteByID(mailID); } } public bool SendMail(string strTo, string strSubject, string strBody, string strFrom, string smtpServer, string userName, string password, string attachments) { Email email = new Email(); string strSmtpServer = smtpServer.Length > 0 ? smtpServer : config.SmtpServer.Trim(); email.SmtpServer = strSmtpServer; email.SmtpUserName = userName.Length > 0 ? userName : config.UserName.Trim(); email.SmtpPassword = password.Length > 0 ? password : config.Password.Trim(); email.SmtpPort = strSmtpServer.ToLower().Contains("gmail") ? "587" : "25"; email.EnableSsl = strSmtpServer.ToLower().Contains("gmail") ? true : false; email.FromEmail = strFrom.Length > 0 ? strFrom : config.FromAddress.Trim(); email.Subject = strSubject; email.Body = strBody; email.Encoding = System.Text.Encoding.UTF8; bool isSuccess = email.SmtpClientSend(strTo); return isSuccess; } public void ErrorLog(string strMessage) { lock(this){ StreamWriter sw = new StreamWriter(config.LogFile + "MailLog.txt", true); sw.WriteLine(strMessage); sw.Flush(); sw.Close(); } } } }

曾经运行在MSN的MCLUB的服务器上跑发EMAIL的服务。应该是安全无死锁调用。

[转载]Asp.net MVC2使用第三方控件

mikel阅读(1065)

[转载]Asp.net MVC2使用第三方控件 – 海纳百川 – 博客园.

ASP.NET MVC框架提供了大量的HTML渲染的方法和控件,但是使用起来有诸多的不便。对于有经验的设计者使用HTML helpers可以构建一个简单的用户界面,然后加上一些HTML和css就能构建出非常漂亮的界面。但是,对开发人员来说使用一些第三方的控件,界面可 能更加方便,开发效率会更高,也使开发人员不用花大量的时间在UI界面上。

这篇文章将介绍两个非常有用的,可以在ASP.NET mvc 2中使用的第三方的控件:MvcContrib GridSlickUpload。文章将以 例子的形式进行说明。

MvcContrib Grid

Gird在现在的应用系统中随处可见。MvcContrib Grid是一个开源的控件,可以构建很整洁的HTML的表格。一般在ASP.NET mvc开发中,你可以使用下面代码产生一个表格。

<table>
<tr>
<th>Username</th>
<th>First name</th>
<th>Last name</th>
<th>Email</th>
<th>&nbsp;</th>
</tr>
<% foreach (var profile in Model) { %>
<tr>
<td>
<%= Html.Encode(profile.Username) %>
</td>
<td>
<%= Html.Encode(profile.FirstName) %>
</td>
<td>
<%= Html.Encode(profile.LastName) %>
</td>
<td>
<%= Html.Encode(profile.Email) %>
</td>
<td>
<%= Html.ActionLink("View", "Show",
new{username = profile.Username}) %>
</td>
</tr>
<% } %>
</table>

从上面的代码可以看出,写MVC的View和写Asp代码一样,一行一行的输出,非常的麻烦。使用MvcContrib Grid,只需一行代码,如下:

<%= Html.Grid(Model).AutoGenerateColumns() %>

这行代码将会把实体类所以的属性列出来。但是有些字段是不需要显示的,我们可以通过下面代码来指定输出列以及输出地格式:

    <h2>产品列表</h2>
   <%= Html.Grid(Model).Columns(column => {
    column.For(x => x.ProductID).Named("Product ID");
column.For(x => x.ProductName);
column.For(x => x.QuantityPerUnit);
column.For(x => x.UnitPrice).Format("{0:N2}");
column.For(x => Html.ActionLink("View Product", "Detail", new { id = x.ProductID })).DoNotEncode();
}) %>

这个例子的数据库是NorthWind,效果如下图:

显示数据库中所有产品分类的名称:

qq1

显示指定分类的所有产品,这块使用了MvcContrib Grid

tty

显示某个产品的详细信息:

qq3

上面的代码就指定输出列。格式化金额字段。更多关于此控件的用法可以查看:http://www.jeremyskinner.co.uk.。

SlickUpload

下面介绍一下在ASP.NET MVC中使用SlickUploadSlickUpload,估计很多童 鞋都有使用过。它有下面这些好处:

1、ASP.NET中上传文件的时候会把上传的文件全部加载到服务器内存中,而SlickUpload直接把上传文件流写入硬盘或数据库。
2、 上传进度条能够实时显示文件上传的进度状态。
3、SlickUpload高度的可自定义性,可以允许我们在上传过程中加入其它的业务逻辑
4、 支持web farm和web garden

ASP.NET MVC中使用SlickUpload和 asp.net中类似。

1、在ASP.NET MVC2项目中添加Krystalware.SlickUpload引用。

2、配置web.config:

在configuration节点中添加下面配置:

    <configSections>
        <sectionGroup name="slickUpload" type="Krystalware.SlickUpload.Configuration.NameValueConfigurationSectionHandler, Krystalware.SlickUpload">
            <section name="uploadParser" type="Krystalware.SlickUpload.Configuration.NameValueConfigurationSectionHandler, Krystalware.SlickUpload"/>
            <section name="uploadStreamProvider" type="Krystalware.SlickUpload.Configuration.NameValueConfigurationSectionHandler,Krystalware.SlickUpload"/>
            <section name="statusManager" type="Krystalware.SlickUpload.Configuration.StatusManagerConfigurationSectionHandler,Krystalware.SlickUpload"/>
        </sectionGroup>
    </configSections>

    <location path="">
        <slickUpload>
            <uploadParser handleRequests="true" />
            <uploadStreamProvider provider="File" location="~/Files/"  existingAction="Overwrite" />

        </slickUpload>
        <system.web>
            <httpRuntime maxRequestLength="1048576"
            executionTimeout="300"/>
        </system.web>
        <system.webServer>
            <security>
                <requestFiltering>
                    <requestLimits maxAllowedContentLength="2072576000"/>
                </requestFiltering>
            </security>
        </system.webServer>
    </location>

在system.web中添加下面配置

      <httpHandlers>
          <add path="SlickUpload.axd" verb="GET,HEAD,POST,DEBUG" type="Krystalware.SlickUpload.SlickUploadHandler,Krystalware.SlickUpload" />
      </httpHandlers>

      <httpModules>
          <add name="HttpUploadModule" type="Krystalware.SlickUpload.HttpUploadModule,Krystalware.SlickUpload"/>
      </httpModules>

3、在试图中引入此控件和其命名空间:

<%@ Import Namespace="Krystalware.SlickUpload"%>
<%@ Register Assembly="Krystalware.SlickUpload" Namespace="Krystalware.SlickUpload.Controls" TagPrefix="kw" %>

4、这个例子的控制器代码如下:

public class UploadController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult UploadResult()
    {
        UploadStatus status = UploadConnector.GetUploadStatus();
        return View(status.GetUploadedFiles());
    }
}

4、使用Html.BeginForm创建一个表单,在此表单上使用此控件,代码如下:

<% using (Html.BeginForm(
"UploadResult",
"Upload",
FormMethod.Post,
new {
id = "uploadForm",
enctype = "multipart/form-data"
})) { 
 %>
<kw:slickupload ID="SlickUpload1" runat="server" UploadFormId="uploadForm" MaxFiles="1" ShowDuringUploadElements="cancelButton" HideDuringUploadElements="uploadButton" >
<DownlevelSelectorTemplate>
<input type="file" />
</DownlevelSelectorTemplate>
<UplevelSelectorTemplate>
<input type="button" value="Add File" />
</UplevelSelectorTemplate>
<FileTemplate>
<kw:FileListRemoveLink ID="FileListRemoveLink1" runat="server">
[x] remove</kw:FileListRemoveLink>
<kw:FileListFileName ID="FileListFileName1" runat="server" />
<kw:FileListValidationMessage ID="FileListValidationMessage1" runat="server" ForeColor="Red" />
</FileTemplate>
<ProgressTemplate>
<table width="99%"><tr><td>
<p>Upload Progress:</p>
<div class="progressBorder">
<kw:UploadProgressBarElement ID="UploadProgressBarElement1" runat="server"
CssClass="progressBar"/>
<div class="progressValue">
<kw:UploadProgressElement ID="UploadProgressElement1" runat="server"
Element="PercentCompleteText">
(calculating)
</kw:UploadProgressElement>
</div>
</div>
</td></tr></table>
</ProgressTemplate>
</kw:slickupload>
<hr />
<p>
<input type="submit" value="Upload"
id="uploadButton" />
</p>
<% } %>

用UploadResult的View显示结果,使用MvcContrib Grid来显示:

   <%= Html.Grid(Model).Columns(column => {
    column.For(x => x.ClientName);
    column.For(x => x.ContentType);
    column.For(x => x.ContentLength);
}) %>

上传页面:

hhh

选择上传文件:

vvv

上传结果:

ggg

总结:这篇文章介绍了两个第三方控件在ASP.net MVC2中的使用。

参考Asp.net  mvc2 in action

代码:http://cid-aef1e64945224a20.office.live.com/browse.aspx/.Public?uc=1

作者:朱祁林
出处:http://zhuqil.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[转载]C# string 和 stringbuilder的区别

mikel阅读(883)

[转载]C# string 和 stringbuilder的区别 – ※森林小居※ – 博客园.

String 对象是不可改变的。每次使用 String 类中的方法之一或进行运算时(如赋值、拼接等)时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。而 StringBuilder 则不会,在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 System.Text.StringBuilder 类;例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。

1、设置容量与长度

StringBuilder   MyStringBuilder   =   new   StringBuilder(“Hello   World!”,   25);   方式1
MyStringBuilder.Capacity   =   25;  方式2
EnsureCapacity   方法可用来检查当前   StringBuilder   的容量。如果容量大于传递的值,则不进行任何更改;但是,如果容量小于传递的值,则会更改当前的容量以使其与传递的值匹配。

也可以查看或设置   Length   属性。如果将   Length   属性设置为大于   Capacity   属性的值,则自动将   Capacity   属性更改为与   Length   属性相同的值。如果将   Length   属性设置为小于当前   StringBuilder   对象内的字符串长度的值,则会缩短该字符串。

2、 修改   StringBuilder   字符串

方法名                                    使用
StringBuilder.Append                将信息追加到当前 StringBuilder 的结尾
StringBuilder.AppendFormat      用带格式文本替换字符串中传递的格式说明符
StringBuilder.Insert                   将字符串或对象插入到当前 StringBuilder 对象的指定索引处
StringBuilder.Remove                从当前 StringBuilder 对象中移除指定数量的字符
StringBuilder.Replace                 替换指定索引处的指定字符

Append
Append 方法可用来将文本或对象的字符串表示形式添加到由当前 StringBuilder 对象表示的字符串的结尾处。下面的示例将一个 StringBuilder 对象初始化为“Hello World”,然后将一些文本追加到该对象的结尾处。将根据需要自动分配空间。

C# ]
StringBuilder MyStringBuilder = new StringBuilder(“Hello World!”);
MyStringBuilder.Append(” What a beautiful day.”);
Console.WriteLine(MyStringBuilder);

此 示例将 Hello World! What a beautiful day. 显示到控制台。

AppendFormat
AppendFormat 方法将文本添加到 StringBuilder 的末尾,而且实现了 IFormattable 接口,因此可接受格式化部分中描述的标准格式字符串。可以使用此方法来自定义变量的格式并将这些值追加到 StringBuilder 的后面。下面的示例使用 AppendFormat 方法,将一个设置为货币值格式的整数值放到 StringBuilder 的末尾。

C# ]
int MyInt = 25;
StringBuilder MyStringBuilder = new StringBuilder(“Your total is “);
MyStringBuilder.AppendFormat(“{0:C} “, MyInt);
Console.WriteLine(MyStringBuilder);

此示例将 Your total is $25.00 显示到控制台。

Insert
Insert 方法将字符串或对象添加到当前 StringBuilder 中的指定位置。下面的示例使用此方法将一个单词插入到 StringBuilder 的第六个位置。

C# ]
StringBuilder MyStringBuilder = new StringBuilder(“Hello World!”);
MyStringBuilder.Insert(6,”Beautiful “);
Console.WriteLine(MyStringBuilder);

此 示例将 Hello Beautiful World! 显示到控制台。

Remove
可以使用 Remove 方法从当前 StringBuilder 中移除指定数量的字符,移除过程从指定的从零开始的索引处开始。下面的示例使用 Remove 方法缩短 StringBuilder。

[  C# ]
StringBuilder MyStringBuilder = new StringBuilder(“Hello World!”);
MyStringBuilder.Remove(5,7);
Console.WriteLine(MyStringBuilder);

此示例将 Hello 显示到控制台。

Replace使用 Replace 方法,可以用另一个指定的字符来替换 StringBuilder 对象内的字符。下面的示例使用 Replace 方法来搜索 StringBuilder 对象,查找所有的感叹号字符 (!),并用问号字符 (?) 来替换它们。

[  C# ]
StringBuilder MyStringBuilder = new StringBuilder(“Hello World!”);
MyStringBuilder.Replace(‘!’, ‘?’);
Console.WriteLine(MyStringBuilder);

此示例将 Hello World? 显示到控制台。

3、将Stringbuilder串转换为string形式

string = StringBuilder.toString();

[转载]轻松简单搭建Linux下的C#开发环境

mikel阅读(1193)

[转载]轻松简单搭建Linux下的C#开发环境 – 河马流星拳 – 博客园.

先看看本篇文章最终效果:在 Ubuntu 里跑的开 发环境 MonoDevelop


[图 片:MonoDevelop1.png]

如 果平时主要开发控制台类、组件、后端服务等程序,可以尝试在Linux类操作系统下搭建C#.Net开发环境,好处是在Linux环境里你不用担心朋友或 同事拿你的电脑来玩魔兽世界或者一不小心被装了一大堆流氓软件 😉

1、Linux发行版的选择

在Linuxux操作系统里只要安装Mono环 境就可以开发C#程序,Linux的众多发行版RedHat/CentOS/Fedora、OpenSuse、Debian、Ubuntu都可以安装 Mono。
鉴于 目前 Ubuntu 容易安装、界面漂亮而且比较多人用作桌面环境,所以这里推荐使用 Ubuntu 10.04 。官方网站是:http://www.ubuntu.com/
在官方网站下载回来的是一个光盘映像文件 (ISO格式),这里需要注意的是 Ubuntu 共有4个不同版本的ISO文件:Desktop版、Alternative版、Netbook版、 Server版。一般下载Desktop就可以了。如果你想通过网络启动安装程序或者使用硬盘安装则需要下载Alternative版。
如果你的电脑硬件配置比较低(内存少于等于 512MB),还可以下载一个轻量级的衍生版:Xubuntu(http://www.xubuntu.org/),如果你的电脑只有256MB内存,那还可以 下载另一个衍生版Lubuntu(http://lubuntu.net/),这个更加轻量级,平时系统启动后只占用 70~100MB内存。

2、安装Ubuntu

安装Ubuntu 的方法非常简单,跟装 WinXP差不多,只需点5,6次“下一步”过10来分钟就可以完成。因为关于安装Ubuntu的过程已经有大量的文章介绍,这里就不再赘述了,下面主要 列举一下安装方式,大家可以根据自己的具体情况选择合适的:

(1)虚拟机安装
如果你的电脑速度飞快,内存比较大,用这种方式 安装最快,虚拟机软件推荐使用免费 的 VirtualBox。先装好虚拟机软件,然后创建一个新的虚拟机,把下载回来的 ISO文件挂靠到虚拟机,启动之后就可以安装了。

(2)尝试性安装
如果你仅仅想尝试一下在Linux环境开发C# 的感觉,并不打算长期使用,则可以使用这种安装模式。这种安装模式不需要调整硬盘分区(因为整个Linux将安装到一个“虚拟硬盘”文件里头)、不会弄坏 你的现有的系统和软件,只是性能会稍微减低一些。
首先你的系统必须是WinXP/Vista /Win7,然后把ISO文件和一个 Wubi Installer (http://wubi-installer.org/) 的软件放在同一个目录,运行 Wubi installer,选择Ubuntu的安装位置,然后就开始复制文件了,重启计算机会多出一项启动项“Ubuntu install”,选择 它就开始真正的安装过程了。

下 面的安装方式需要先在硬盘腾出一块空白的空间(最好准备至少10GB),主分区以外的自由空间或者扩展分区的自由空间都可以,你可以用 PQMagic软件慢慢 调整自己硬盘的分区大小。在安装过程中程序会询问你将Ubuntu安装在何处,选择使用“最大连续空间”即可。

(3)光盘安装
这种安装方式最简单,将下载回来的ISO文件刻 录成光盘,设置从光盘启动并重启计算机。

(4) 硬盘安装
要下载Alternative版的ISO文件, 放到C盘根目录,然后下载“UNetbootin
”(http://unetbootin.sourceforge.net/)软件,也放在C盘根目录,运 行 UNetbootin,在发行版类型项选择Ubuntu和MediaHD即开始复制文件,重启电脑开始安装。

(5)用U盘安装/安装到U盘
先使用安装光盘启动计算机,选择“试用”进入 LiveCD模式的Ubuntu,然后在“系统”->“系统管理”点击“制作启动盘”,准备一个1GB以上的U盘,启动盘制作程序会把Ubuntu 的所有文件复制到U盘,然后就可以使用这个U盘启动其他电脑并安装系统了。也可以直接从这个U盘启动进入系统。

(6)通过网络安装
如果你的电脑没有光驱也不支持U盘启动,而带有 从网卡启动(PXE)功能。或者有一批电脑需要批量安装,则可以使用这种安装模式,具体的请见:http://kalashnicov.javaeye.com/blog/663337

3、安装开发环境 MonoDevelop

安装好Ubuntu 10.04之后会发现系统已经自带Mono运行和编译环境,而且还有部分Ubuntu系统自带的软件是C#写的,比如tomboy便利帖、IQ测试游戏 gbrainy、照片查看和管理程序F-Spot

[图片:F-spot.png]

如果你已经习惯了Win7的任 务栏,推荐另外一 个任务栏软件“Docky”,它也是C#写的

[图片:Docky.png]

MacOS的同学请淡定。
记住在Ubuntu里安装软件是不需要去什么软 件下载网站的,所有需要的软件都可以在“Ubuntu软件中心”找到、安装、卸载。

运行“Ubuntu软件中心”,输入需要安装的 软件名称,比如 “MonoDevelop”,然后点击“安装”,程序会自动上网下载并安装。

好了,现在就已经搭建好C#开发环境了,试试写 一个HelloWorld吧(效果图 片见文章开头处)

4、其他

MonoDevelop除了能 写C#程序之外, 还能写C,C++,Java等程序,只要安装相应的插件和编译器即可,

[图片:MonoDevelop2.png]

附录:

mono项目主页: http://mono-project.com

控制台、窗口、Web的HelloWorld演示程序:http://mono-project.com/Mono_Basics

mono 与 ms.net 的兼容性列表: http://mono-project.com/Compatibility

[转载]使用XML及XSL生成简单HTML

mikel阅读(939)

[转载]使用XML及XSL生成简单HTML – 专注ASP.NET & RIA以及SQLServer BI&GIS – 博客园.

某些时候需要生成HTML展现数据,考虑过XML加XSL方法吗?比如,以html邮件的方式发送一些数据。

本文通过两个已经存在的文件,xml文件和xsl文件演示如何将其转换成HTML。

首先,准备XML文件,这里为了演示,随便定义了一组数据。这些定义好的数据用于后面套入到对应的xsl模板中。

<ROOT>

<ASPNETX Username=dudu City=Shanghai Cool=70 />

<ASPNETX Username=Bill City=Meiguo Cool=100 />

<ASPNETX Username=Gates City=Meiguo Cool=100 />

<ASPNETX Username=Aobama City=Meiguo Cool=80 />

<ASPNETX Username=aspnetx City=Beijing Cool=60 />

<ASPNETX Username=Geo City=USA.East Cool=20 />

<ASPNETX Username=Mike City=USA.West Cool=30 />

<ASPNETX Username=Jim City=Jilin Cool=90 />

<ASPNETX Username=Tim City=Hebei Cool=10 />

<ASPNETX Username=Ada City=Big Apple Cool=10 />

<ASPNETX Username=Jill City=unknown Cool=50 />

</ROOT>

XML数据文件可以自己组织格式,因为在xsl模板中是支持x-path查询的。

然后,准备XSL文件:

<xsl:stylesheet version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform xmlns:msxsl=urn:schemas-microsoft-com:xslt exclude-result-prefixes=msxsl>

<xsl:output method=html indent=yes/>

<xsl:template match=/>

<table align=left cellpadding=2 cellspacing=5>

<tr>

<td style=font-family: Verdana; font-size: 15px; font-weight: bold;>User in cnblogs:</td>

</tr>

<tr>

<td style=font-family: Verdana; font-size: 10px;>

<table width=500px align=left cellpadding=2 cellspacing=0 style=font-family: Verdana; font-size: 10px;>

<tr>

<td bgcolor=#808080>

<font color=#FFFFFF>

<b>User name</b>

</font>

</td>

<td bgcolor=#808080>

<font color=#FFFFFF>

<b>City</b>

</font>

</td>

<td bgcolor=#808080>

<font color=#FFFFFF>

<b>Cool</b>

</font>

</td>

</tr>

<xsl:for-each select=ROOT/ASPNETX>

<tr>

<td style=border: 1px solid #808080>

<xsl:value-of select=@Username/>

</td>

<td style=border: 1px solid #808080>

<xsl:value-of select=@City/>

</td>

<td style=border: 1px solid #808080>

<xsl:value-of select=@Cool/>

</td>

</tr>

</xsl:for-each>

</table>

</td>

</tr>

</table>

</xsl:template>

</xsl:stylesheet>

在模板文件之中,xsl:template之间就是要展现的html模板的内容。

xsl:value-of对应数据区域,select后跟x-path查询。

Xsl:for-each枚举得到的集合。

通过以上两个标签的占位,xml的数据就会根据其定义出现在对应的位置。

Xml和xsl都准备好,最后,准备C#代码,下面的代码将把模板xsl和数据xml加载进来,然后把html内容输出成一个string字符串:

static void TestXls()

{

//数据文件

XmlReader _xmlxml = XmlReader.Create(“xmldata.xml”);

//模板文件

XmlReader _xmlxsl = XmlReader.Create(“xsldata.xml”);

//实例化转换对象

XslCompiledTransform xslct = new XslCompiledTransform();

xslct.Load(_xmlxsl);

MemoryStream ms = new MemoryStream();

XmlTextWriter xmltxtWr = new XmlTextWriter(ms, null);

//开始转换,并且将结果保存到writer中。

xslct.Transform(_xmlxml, xmltxtWr);

//读取结果

StreamReader st = new StreamReader(ms);

ms.Seek(0, SeekOrigin.Begin);

string TransformedHTML = st.ReadToEnd();

Console.WriteLine(TransformedHTML);

}

在.net下提供了现成的转换对象,XslCompiledTransform。通过Load方法加载xsl文件后,就可以调用Transform 方法对xml进行转换了。

Xmldata.xml和xsldata.xml文件如果在项目中,记得设置其copy to output directory。默认这两个文件是不输出到bin目录的,所以如果不设置会导致程序无法加载到相应的xml和xsl文件。

实际操作的时候,需要自己先组织好html部分的内容,尽量不要用网页设计工具,因为这样会生成很多的垃圾标签,所以最好自己手写。然后在适当的位 置加上<xsl:xxx />标签,最后放到xsl文件中。

做好xsl模板后,建议先自己调试一下看看能否搭配xml正常的输出数据,偶尔有一些不符合规范的地方程序会报错。

Xml的数据最常用的来源就是SQL语句加for xml auto了,此时需要注意模板里的x-path查询也要根据xml结果做相应的变化。

由于visual studio在调试的时候,查看字符串变量支持文本模式和html模式,所以在实际开发的时候调试起来会方便的很多。

需要注意:

模板中不能出现&这样的字符,所以&nbsp;这样的要处理掉。

XML做x-path查询是区分大小写的,比如Root和root是无法匹配上的。

示例项目下载

环境:Visual Studio 2010

[转载]命令模式-1

mikel阅读(930)

[转载]命令模式-1 – 云飞龙行 – 博客园.

命令模式也是开发中常见的一个模式,也不是太难,比较简单,下面来详细的写一下命令模式。

命令模式(Command)

1  场景问题

1.1  如何开机

估计有些朋友看到这个标题会非常奇怪,电脑装配好了,如何开机?不就是按下启动按钮就可以了吗?难道还有什么玄机不成。
对于使用电脑的客户——就是我们来说,开机确实很简单,按下启动按钮,然后耐心等待就可以了。但是当我们按下启动按钮过后呢?谁来处理?如何处理?都经历 了怎样的过程,才让电脑真正的启动起来,供我们使用。
先一起来简单的认识一下电脑的启动过程,了解一下即可。

  • 当我们按下启动按钮,电源开始向主板和其它设备供电
  • 主板的系统BIOS(基本输入输出系统)开始加电后自检
  • 主板的BIOS会依次去寻找显卡等其它设备的BIOS,并让它们自检或者初始化
  • 开始检测CPU、内存、硬盘、光驱、串口、并口、软驱、即插即用设备等等
  • BIOS更新ESCD(扩展系统配置数据),ESCD是BIOS和操作系统交换硬件配置数据的一种手段
  • 等前面的事情都完成后,BIOS才按照用户的配置进行系统引导,进入操作系统里面,等到操作系统装载并初始化完毕,就出现我们熟悉的系统登录界面 了。

1.2  与我何干

讲了一通电脑启动的过程,有些朋友会想,这与我何干呢?
没错,看起来这些硬件知识跟你没有什么大的关系,但是,如果现在提出一个要求:请你用软件把上面的过程表现出来,你该如何实现?
首先把上面的过程总结一下,主要就这么几个步骤:首先加载电源,然后是设备检查,再然后是装载系统,最后电脑就正常启动了。可是谁来完成这些过程?如何完 成?
不能让使用电脑的客户——就是我们来做这些工作吧,真正完成这些工作的是主板,那么客户和主板如何发生联系呢?现实中,是用连接线把按钮连接到主板上的, 这样当客户按下按钮的时候,就相当于发命令给主板,让主板去完成后续的工作。
另外,从客户的角度来看,开机就是按下按钮,不管什么样的主板都是一样的,也就是说,客户只管发出命令,谁接收命令,谁实现命令,如何实现,客户是不关心 的。

1.3  有何问题

把上面的问题抽象描述一下:客户端只是想要发出命令或者请求,不关心请求的真正接收者是谁,也不关心具体如何实现,而且同一个请求的动作可以有不同的请求 内容,当然具体的处理功能也不一样,请问该怎么实现?

2  解决方案

2.1  命令模式来解决

用来解决上述问题的一个合理的解决方案就是命令模式。那么什么是命令模式呢?
(1)命令模式定义
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

(2)应用命令模式来解决的思路
首先来看看实际电脑的解决方案
先画个图来描述一下,看看实际的电脑是如何处理上面描述的这个问题的,如图1所示:

图 1  电脑操作示意图

当客户按下按钮的时候,按钮本身并不知道如何处理,于是通过连接线来请求主板,让主板去完成真正启动机器的功能。
这里为了描述它们之间的关系,把主板画到了机箱的外面。如果连接线连接到不同的主板,那么真正执行按钮请求的主板也就不同了,而客户是不知道这些变化的。
通过引入按钮和连接线,来让发出命令的客户和命令的真正实现者——主板完全解耦,客户操作的始终是按钮,按钮后面的事情客户就统统不管了。
要用程序来解决上面提出的问题,一种自然的方案就是来模拟上述解决思路。
在命令模式中,会定义一个命令的接口,用来约束所有的命令对象,然后提供具体的命令实现,每个命令实现对象是对客户端某个请求的封装,对应于机箱上的按 钮,一个机箱上可以有很多按钮,也就相当于会有多个具体的命令实现对象。
在命令模式中,命令对象并不知道如何处理命令,会有相应的接收者对象来真正执行命令。就像电脑的例子,机箱上的按钮并不知道如何处理功能,而是把这个请求 转发给主板,由主板来执行真正的功能,这个主板就相当于命令模式的接收者。
在命令模式中,命令对象和接收者对象的关系,并不是与 生俱来的,需要有一个装配的过程,命令模式中的Client对象就来实现这样的功能。这就相当于在电脑的例子中,有了机箱上的按钮,也有了主板,还需要有 一个连接线把这个按钮连接到主板上才行。
命令模式还会提供一个Invoker对象来持有命令对象,就像电脑的例子,机箱上会有多个按钮,这个机箱就相当于命令模式的Invoker对象。这样一 来,命令模式的客户端就可以通过Invoker来触发并要求执行相应的命令了,这也相当于真正的客户是按下机箱上的按钮来操作电脑一样。

2.2  模式结构和说明

命令模式的结构如图2所示:


图2  命令模式结构图
Command:
定义命令的接口,声明执行的方法。
ConcreteCommand:
命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
Receiver:
接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
Invoker:
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对 象的入口。
Client:
创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者 会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。

2.3  命令模式示例代码

(1)先来看看命令接口的定义,示例代码如下:

/**

* 命令接口,声明执行的操作

*/

public interface Command {

/**

* 执行命令对应的操作

*/

public void execute();

}

 (2)再来看看具体的命令实现对象,示例代码如下:
/**  * 具体的命令实现对象  */ public class ConcreteCommand implements Command {     /**      * 持有相应的接收者对象      */     private Receiver receiver = null;     /**      * 示意,命令对象可以有自己的状态      */     private String state;     /**      * 构造方法,传入相应的接收者对象      * @param receiver 相应的接收者对象      */     public ConcreteCommand(Receiver receiver){        this.receiver = receiver;     }       public void execute() {        //通常会转调接收者对象的相应方法,让接收者来真正执行功能        receiver.action();     } }

(3)再来看看接收者对象的实现示意,示例代码如下:

/**

* 接收者对象

*/

public class Receiver {

/**

* 示意方法,真正执行命令相应的操作

*/

public void action(){

//真正执行命令操作的功能代码

}

}

(4)接下来看看Invoker对象,示例代码如下:

/**

* 调用者

*/

public class Invoker {

/**

* 持有命令对象

*/

private Command command = null;

/**

* 设置调用者持有的命令对象

* @param command 命令对象

*/

public void setCommand(Command command) {

this.command = command;

}

/**

* 示意方法,要求命令执行请求

*/

public void runCommand() {

//调用命令对象的执行方法

command.execute();

}

}

(5)再来看看Client的实现,注意这个不是我们通常意义上的测试客户端,主要功能是要创建命令对象并设定它的接收者,因此这 里并没有调用执行的代码,示例代码如下:

public class Client {

/**

* 示意,负责创建命令对象,并设定它的接收者

*/

public void assemble(){

//创建接收者

Receiver receiver = new Receiver();

//创建命令对象,设定它的接收者

Command command = new ConcreteCommand(receiver);

//创建Invoker,把命令对象设置进去

Invoker invoker = new Invoker();

invoker.setCommand(command);

}

}

2.4  使用命令模式来实现示例

要使用命令模式来实现示例,需要先把命令模式中所涉及的各个部分,在实际的示例中对应出来,然后才能按照命令模式的结构来设计和实现 程序。根据前面描述的解决思路,大致对应如下:

  • 机箱上的按钮就相当于是命令对象
  • 机箱相当于是Invoker
  • 主板相当于接收者对象
  • 命令对象持有一个接收者对象,就相当于是给机箱的按钮连上了一根连接线
  • 当机箱上的按钮被按下的时候,机箱就把这个命令通过连接线发送出去。

主板类才是真正实现开机功能的地方,是真正执行命令的地方,也就是“接收者”。命令的实现对象,其实是个“虚”的实现,就如同那根连接线,它哪知道如何实 现啊,还不就是把命令传递给连接线连到的主板。
使用命令模式来实现示例的结构如图3所示:


图3  使用命令模式来实现示例的结构示意图
还是来看看示例代码,会比较清楚。
(1)定义主板
根据前面的描述,我们会发现,真正执行客户命令或请求的是主板,也只有主板才知道如何去实现客户的命令,因此先来抽象主板,把它用对象描述出来。
先来定义主板的接口,最起码主板会有一个能开机的方法,示例代码如下:

/**

* 主板的接口

*/

public interface MainBoardApi {

/**

* 主板具有能开机的功能

*/

public void open();

}

定义了接口,那就接着定义实现类吧,定义两个主板的实现类,一个是技嘉主板,一个是微星主板,现在的实现是一样的,但是不同的主板对同一个命令的操作可以 是不同的,这点大家要注意。由于两个实现基本一样,就示例一个,示例代码如下:

/**

* 技嘉主板类,开机命令的真正实现者,在Command模式中充当Receiver

*/

public class GigaMainBoard implements MainBoardApi{

/**

* 真正的开机命令的实现

*/

public void open(){

System.out.println(“技嘉主板现在正在开机,请等候”);

System.out.println(“接通电源……”);

System.out.println(“设备检查……”);

System.out.println(“装载系统……”);

System.out.println(“机器正常运转起来……”);

System.out.println(“机器已经正常打开,请操作”);

}

}

微星主板的实现和这个完全一样,只是把技嘉改名成微星了。
(2)定义命令接口和命令的实现
对于客户来说,开机就是按下按钮,别的什么都不想做。把用户的这个动作抽象一下,就相当于客户发出了一个命令或者请求,其它的客户就不关心了。为描述客户 的命令,现定义出一个命令的接口,里面只有一个方法,那就是执行,示例代码如下:

/**

* 命令接口,声明执行的操作

*/

public interface Command {

/**

* 执行命令对应的操作

*/

public void execute();

}

有了命令的接口,再来定义一个具体的实现,其实就是模拟现实中机箱上按钮的功能,因为我们按下的是按钮,但是按钮本身是不知道如何启动电脑的,它需要把这 个命令转给主板,让主板去真正执行开机功能。示例代码如下:

/**

* 开机命令的实现,实现Command接口,

* 持有开机命令的真正实现,通过调用接收者的方法来实现命令

*/

public class OpenCommand implements Command{

/**

* 持有真正实现命令的接收者——主板对象

*/

private MainBoardApi mainBoard = null;

/**

* 构造方法,传入主板对象

* @param mainBoard 主板对象

*/

public OpenCommand(MainBoardApi mainBoard) {

this.mainBoard = mainBoard;

}

public void execute() {

//对于命令对象,根本不知道如何开机,会转调主板对象

//让主板去完成开机的功能

this.mainBoard.open();

}

}

由于客户不想直接和主板打交道,而且客户根本不知道具体的主板是什么,客户只是希望按下启动按钮,电脑就正常启动了,就这么简单。就 算换了主板,客户还是一样的按下启动按钮就可以了。
换句话说就是:客户想要和主板完全解耦,怎么办呢?
这就需要在客户和主板之间建立一个中间对象了,客户发出的命令传递给这个中间对象,然后由这个中间对象去找真正的执行者——主板,来完成工作。
很显然,这个中间对象就是上面的命令实现对象,请注意:这个实现其实是个虚的实现,真正的实现是主板完成的,在这个虚的实现里面,是通过转调主板的功能来 实现的,主板对象实例,是从外面传进来的。
(3)提供机箱
客户需要操作按钮,按钮是放置在机箱之上的,所以需要把机箱也定义出来,示例代码如下:

/**

* 机箱对象,本身有按钮,持有按钮对应的命令对象

*/

public class Box {

/**

* 开机命令对象

*/

private Command openCommand;

/**

* 设置开机命令对象

* @param command 开机命令对象

*/

public void setOpenCommand(Command command){

this.openCommand = command;

}

/**

* 提供给客户使用,接收并响应用户请求,相当于按钮被按下触发的方法

*/

public void openButtonPressed(){

//按下按钮,执行命令

openCommand.execute();

}

}

(4)客户使用按钮
抽象好了机箱和主板,命令对象也准备好了,客户想要使用按钮来完成开机的功能,在使用之前,客户的第一件事情就应该是把按钮和主板组装起来,形成一个完整 的机器。
在实际生活中,是由装机工程师来完成这部分工作,这里为了测试简单,直接写在客户端开头了。机器组装好过后,客户应该把与主板连接好的按钮对象放置到机箱 上,等待客户随时操作。把这个过程也用代码描述出来,示例代码如下:

public class Client {

public static void main(String[] args) {

//1:把命令和真正的实现组合起来,相当于在组装机器,

//把机箱上按钮的连接线插接到主板上。

MainBoardApi mainBoard = new GigaMainBoard();

OpenCommand openCommand = new OpenCommand(mainBoard);

//2:为机箱上的按钮设置对应的命令,让按钮知道该干什么

Box box = new Box();

box.setOpenCommand(openCommand);

//3:然后模拟按下机箱上的按钮

box.openButtonPressed();

}

}

运行一下,看看效果,输出如下:

技嘉主板现在正在开机,请等候

接通电源……

设备检查……

装载系统……

机器正常运转起来……

机器已经正常打开,请操作

你可以给命令对象组装不同的主板实现类,然后再次测试,看看效果。
事实上,你会发现,如果对象结构已经组装好了过后,对于真正的客户端,也就是真实的用户而言,任务就是面对机箱,按下机箱上的按钮,就可以执行开机的命令 了,实际生活中也是这样的。
(5)小结
如同前面的示例,把客户的开机请求封装成为一个OpenCommand对象,客户的开机操作就变成了执行OpenCommand对象的方法了?如果还有其 它的命令对象,比如让机器重启的ResetCommand对象;那么客户按下按钮的动作,就可以用这不同的命令对象去匹配,也就是对客户进行参数化。
用大白话描述就是:客户按下一个按钮,到底是开机还是重启,那要看参数化配置的是哪一个具体的按钮对象,如果参数化的是开机的命令对象,那就执行开机的功 能,如果参数化的是重启的命令对象,那就执行重启的功能。虽然按下的是同一个按钮,但是请求是不同的,对应执行的功能也就不同了。
在模式讲解的时候会给大家一个参数化配置的示例,这里就不多讲了。至于对请求排队或记录请求日志,以及支持可撤销的操作等功能,也放到模式讲解里面。

[转载]jquery :nth-child()选择器的简单应用

mikel阅读(1063)

[转载]jquery :nth-child()选择器的简单应用 – 我是一个不入流的Coder. – 博客园.

今天项目中遇到过一个这样的问题,就是希望读出来的文章列表能够每隔五个加一个分割条,而不是每个都加。

通过网上咨询使用这个选择器便很容易的解决。特此记录一下。

下面是主要的代码

js脚本:

<script type=”text/JavaScript”>
$(document).ready(
function () {
//每隔五行给li加一个样式
$(‘.article_li li:nth-child(5n)’).addClass(‘liborder’);
$(‘.article_li li:last’).addClass(‘liborder’);
}
);
</script>

html代码:

<ul class=”article_li”>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点物业 税:长沙暂不试点</a>
</li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
<li>
<label class=”datename”>
<span>2010-06-12 08:37:59 </span>
</label>
<a href=”/a/xinwenzixun/caishuidongtai/20100612/2323.html”>物业税:长沙暂不试点& lt;/a> </li>
</ul>

具体的用法这里就不写了,大家可以参考

http://www.cnblogs.com/Elgin/archive/2010/05/24/1742563.html

http://www.2ndvisual.com/xhtml/css/20616.html

效果图如下: