IE6,IE7,IE8,Firefox兼容的css hack

IE6,IE7,IE8,Firefox兼容的css hack
补充:
.color{
background-color: #CC00FF; /*所有浏览器都会显示为紫色*/
background-color: #FF0000\9; /*IE6、IE7、IE8会显示红色*/
*background-color: #0066FF; /*IE6、IE7会变为蓝色*/  
_background-color: #009933; /*IE6会变为绿色*/
}
好多css hack,最重要的是简单实用能解决问题就行了
总结:
\9: IE6 IE7 IE8
*: IE6 IE7
_: IE6
*+: IE7(经我测试没多大用)
----------------------------------------
IE6,IE7,Firefox兼容的css hack
第一种办法:
body
{
    background:red;
    *background:blue !imp

ortant;(经测试在IE里不使用)   
    *background: green;
}

第一排给Firefox以及其他浏览器看;
第二排给IE7,IE7既能识别*号,也能识别imp

ortant;
第三排给IE6也能识别*号;
第二种办法,使用_来区分IE6:
body
{
    background:red;
    *background:blue;  
    _background: green;
}

第一排给Firefox以及其他浏览器看;
第二排给IE7,IE7既能能识别*号;
第三排给IE6能识别下划线;
CSS对浏览器器的兼容性具有很高的价值,通常情况下IE和Firefox存在很大的解析差异,这里介绍一下兼容要点。

常见兼容问题:
  1.DOCTYPE 影响 CSS 处理(但这个声明对于WEB标准的验证是非常重要的)
  2.FF: div 设置 margin-left, margin-right 为 auto 时已经居中, IE 不行(已经过时)

  3.FF: body 设置 text-align 时, div 需要设置 margin: auto(主要是 margin-left,margin-right) 方可居中
  4.FF: 设置 padding 后, div 会增加 height 和 width, 但 IE 不会, 故需要用 !imp

ortant 多设一个 height 和 width(IE也会增加,没用!)

  5.FF: 支持 !imp

ortant, IE 则忽略, 可用 !imp
ortant 为 FF 特别设置样式(IE不会忽略!这谁写的没用的东西!)

  6.div 的垂直居中问题: vertical-align:middle; 将行距增加到和整个DIV一样高 line-height:200px; 然后插入文字,就垂直居中了。缺点是要控制内容不要换行
  7.cursor: pointer 可以同时在 IE FF 中显示游标手指状, hand 仅 IE 可以
  8.FF: 链接加边框和背景色,需设置 display: block, 同时设置 float: left 保证不换行。参照 menubar, 给 a 和 menubar 设置高度是为了避免底边显示错位, 若不设 height, 可以在 menubar 中插入一个空格。(这个没看懂!)

  9.在mozilla firefox和IE中的BOX模型解释不一致导致相差2px解决方法:
div{margin:30px!imp

ortant;margin:28px;}(这方法不使用!没用!用*、-多好!)

  注意这两个margin的顺序一定不能写反,据阿捷的说法!imp

ortant这个属性IE不能识别,但别的浏览器可以识别。所以在IE下其实解释成这样:
div{maring:30px;margin:28px}
  重复定义的话按照最后一个来执行,所以不可以只写margin:XXpx!imp

ortant;
  10.IE5 和IE6的BOX解释不一致
  IE5下
div{width:300px;margin:0 10px 0 10px;}
  div的宽度会被解释为300px-10px(右填充)-10px(左填充)最终div的宽度为280px,而在IE6和其他浏览器上宽度则是以300px+10px(右填充)+10px(左填充)=320px来计算的。这时我们可以做如下修改
div{width:300px!imp

ortant;width /**/:340px;margin:0 10px 0 10px}
  关于这个/**/是什么我也不太明白,只知道IE5和firefox都支持但IE6不支持,如果有人理解的话,请告诉我一声,谢了!:)
  11.ul标签在Mozilla中默认是有padding值的,而在IE中只有margin有值所以先定义
ul{margin:0;padding:0;}
  就能解决大部分问题(不只这一个吧!还有P,DL 等。。)

注意事项:
  1、float的div一定要闭合。

  例如:(其中floatA、floatB的属性已经设置为float:left;)
<#div id=”floatA” ></#div>
<#div id=”floatB” ></#div>
<#div id=”NOTfloatC” ></#div>
  这里的NOTfloatC并不希望继续平移,而是希望往下排。
  这段代码在IE中毫无问题,问题出在FF。原因是NOTfloatC并非float标签,必须将float标签闭合。
  在
<#div class=”floatB”></#div>
<#div class=”NOTfloatC”></#div>
  之间加上
<#div class=”clear”></#div>
  这个div一定要注意声明位置,一定要放在最恰当的地方,而且必须与两个具有float属性的div同级,之间不能存在嵌套关系,否则会产生异常。
  并且将clear这种样式定义为为如下即可:
.clear{clear:both;}
  此外,为了让高度能自动适应,要在wrapper里面加上overflow:hidden;
  当包含float的box的时候,高度自动适应在IE6下无效,这时候应该触发IE的layout私有属性(万恶的IE啊!)用zoom:1;可以做到,这样就达到了兼容。
  例如某一个wrapper如下定义:
.colwrapper{
overflow:hidden;
zoom:1;
margin:5px auto;}
  2、margin加倍的问题。

  设置为float的div在ie6下设置的margin会加倍。这是一个ie6都存在的bug。
  解决方案是在这个div里面加上display:inline;
例如:
<#div id=”imfloat”></#div>
  相应的css为
#IamFloat{
float:left;
margin:5px;/*IE6下理解为10px*/
display:inline;/*IE6下再理解为5px*/}
  3、关于容器的包涵关系

  很多时候,尤其是容器内有平行布局,例如两、三个float的div时,宽度很容易出现问题。在IE中,外层的宽度会被内层更宽的div挤破。一定要用Photoshop或者Firework量取像素级的精度。
  4、关于高度的问题

  如果是动态地添加内容,高度最好不要定义。浏览器可以自动伸缩,然而如果是静态的内容,高度最好定好。(似乎有时候不会自动往下撑开,不知道具体怎么回事)
  5、最狠的手段 - !imp


ortant;

  如果实在没有办法解决一些细节问题,可以用这个方法.FF对于”!imp

ortant”会自动优先解析,然而IE则会忽略.如下
.tabd1{
background:url(/res/images/up/tab1.gif) no-repeat 0px 0px !imp

ortant; /*Style for FF*/
background:url(/res/images/up/tab1.gif) no-repeat 1px 0px; /* Style for IE */}
  值得注意的是,一定要将xxxx !imp

ortant 这句放置在另一句之上,上面已经提过

 

 

IE浏览器都能识别“*” “\9”;标准浏览器(如FF)不能识别“*”;

IE6能识别“_” “+” “#” “@”, 同一属性有两个的只看后者 无论有没有 如果是两句它就能识别“!imp
ortant”;
IE7能识别“+” “#” “@” “!imp
ortant”,不能识别“_”;
FF能识别“!imp
ortant”,不能识别“_” “+” “#” “@”;

以上是我自己测试的结果,如有差错还请指出~!

注:不管是什么方法,书写的顺序都是firefox的写在前面,IE7的写在中间,IE6的写在最后面。

例如:select{
Color:blue;//所有浏览器
Color:yellow\9;//所有IE浏览器
*Color:red;//forIE7
_color:green;//forIE6
}

 

关注过IE8的css hack的人相信大家都在使用这个hack,就是“\9”的css hack:

发表在 article | 标签为 | 62条评论

VS2005 模板的制作方法

Visual Studio 2005 提供的模板功能非常不错,本文演示如何创建一个带有信息头的Class模板。

1. 创建一个如图所示的Class1.cs文件。有关模板参数请查看 MSDN 帮助文档。
ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_vssoln/html/1b567143-08c6-4d7a-b484-49f0671754fe.htm

uploads/200606/23_210046_snap1.gif

2. 使用文件菜单中的 "导出模板" 功能开始制作模板。

uploads/200606/23_210050_snap2.gif

3. 选择 "项模板" 。

uploads/200606/23_210055_snap3.gif

4. 选中我们刚才创建的 "Class1" 类文件。

uploads/200606/23_210059_snap4.gif

5. 输入模板信息。完成后会自动在 "我的文档\Visual Studio 2005\Templates" 和 "我的文档\Visual Studio 2005\My Exported Templates" 目录下创建模板文件 "Team Project Class.zip"。

uploads/200606/23_210103_snap5.gif

6. 好了,我们试试效果。使用模板创建一个新的类型。

uploads/200606/23_210108_snap7.gif

7. 下面的效果怎么样?当然您还可以创建更多更复杂的应用……

uploads/200606/23_210333_snap8.gif

以下内容是为了创建一个可分发(安装)的模板文件。
详细内容可参考 ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_vsintro/html/a5d7dc88-29a8-4a37-be6b-949e90ae2242.htm

8. 创建一个 "TeamClass.vscontent" 文件,内容如下:

<VSContent xmlns="http://schemas.microsoft.com/developer/vscontent/2005">
  <Content>
    <FileName>Team Project Class.zip</FileName>
    <DisplayName>Team Project Class Template</DisplayName>
    <Description>A class template example.</Description>
    <FileContentType>VSTemplate</FileContentType>
    <ContentVersion>1.0</ContentVersion>
    <Attributes>
      <Attribute name="ProjectType" value="Visual C#"/>
      <Attribute name="ProjectSubType" value=""/>
      <Attribute name="TemplateType" value="Item"/>
    </Attributes>
  </Content>
</VSContent>

9. 将 "TeamClass.vscontent" 文件和 "我的文档\Visual Studio 2005\My Exported Templates" 目录下我们刚才创建的模板文件 "Team Project Class.zip" 一起压缩到一个 Zip 包中,并将文件扩展名改为 ".vsi",如 "MyTemplate.vsi"。

10. 删除"我的文档\Visual Studio 2005\Templates" 和 "我的文档\Visual Studio 2005\My Exported Templates" 目录下IDE自动生成的模板文件,然后双击执行 "MyTemplate.vsi",看看出现了什么……

uploads/200606/23_211652_snap9.gif

当然,模板还有很多更高级的功能,具体可以参考 MSDN 中的说明。ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_vssoln/html/141fccaa-d68f-4155-822b-27f35dd94041.htm

模板除了可用于团队编码规范外,还可以创建一些半成品的 Application Framework/Project 等。非常值得一试!!!

发表在 .net | 标签为 , | VS2005 模板的制作方法已关闭评论

ASP.NET MVC 理解

一.摘要

一个Url请求经过了Routing处理后会调用Controller的Action方法. 中间的过程是怎样的? Action方法中返回ActionResult对象后,如何到达View的? 本文将讲解Controller的基本用法,  深入分析Controller的运行机制, 并且提供了创建所有类型Action的代码. 值得学习ASP.NET MVC时参考.

二.承上启下

在上一篇文章中, 我已经学会了如何使用Routing获取Controller和Action, 随后的程序会调用Controller中的Action方法.

每个Action方法都要返回一个ActionResult对象. 一个Action会将数据传递给View,如图:

image

三.Controller与Action的作用

1.职责

Controller负责将获取Model数据并将Model传递给View对象.通知View对象显示.

2.ASP.NET MVC中的Controller和Action

在ASP.NET MVC中, 一个Controller可以包含多个Action. 每一个Action都是一个方法, 返回一个ActionResult实例.

ActionResult类包括ExecuteResult方法, 当ActionResult对象返回后会执行此方法.

下面分层次的总结Controller 处理流程:

1. 页面处理流程

发送请求 –> UrlRoutingModule捕获请求 –> MvcRouteHandler.GetHttpHandler() –>
MvcHandler.ProcessRequest()

2.MvcHandler.ProcessRequest() 处理流程:

使用工厂方法获取具体的Controller –>
Controller.Execute()
–> 释放Controller对象

3.Controller.Execute() 处理流程

获取Action –> 调用Action方法获取返回的ActionResult –> 调用
ActionResult.ExecuteResult()
方法

4.ActionResult.ExecuteResult() 处理流程

获取IView对象-> 根据IView对象中的页面路径获取Page类-> 调用
IView.RenderView()
方法(内部调用Page.RenderView方法)

通过对MVC源代码的分析,我们了解到Controller对象的职责是传递数据,获取View对象(实现了IView接口的类),通知View对象显示.

View对象的作用是显示.虽然显示的方法RenderView()是由Controller调用的,但是Controller仅仅是一个"指挥官"的作用, 具体的显示逻辑仍然在View对象中.

需要注意IView接口与具体的ViewPage之间的联系.在Controller和View之间还存在着IView对象.对于ASP.NET程序提供了WebFormView对象实现了IView接口.WebFormView负责根据虚拟目录获取具体的Page类,然后调用Page.RenderView().

四.ActionResult解析

通过上面的流程,我们知道了ActionResult对象在整个流程中的作用.ActionResult是一个抽象类, 在Action中返回的都是其派生类.下面是我整理的ASP.NET MVC 1.0 版本中提供的ActionResult派生类:

 

类名 抽象类 父类 功能
ContentResult     根据内容的类型和编码,数据内容.
EmptyResult     空方法.
FileResult abstract   写入文件内容,具体的写入方式在派生类中.
FileContentResult   FileResult 通过 文件byte[] 写入文件.
FilePathResult   FileResult 通过 文件路径 写入文件.
FileStreamResult   FileResult 通过 文件Stream 写入文件.
HttpUnauthorizedResult     抛出401错误
JavaScriptResult     返回javascript文件
JsonResult     返回Json格式的数据
RedirectResult     使用Response.Redirect重定向页面
RedirectToRouteResult     根据Route规则重定向页面
ViewResultBase abstract   调用IView.Render()
PartialViewResult   ViewResultBase 调用父类ViewResultBase 的ExecuteResult方法.

重写了父类的FindView方法.

寻找用户控件.ascx文件
ViewResult   ViewResultBase 调用父类ViewResultBase 的ExecuteResult方法.

重写了父类的FindView方法.

寻找页面.aspx文件

目前ASP.NET MVC还没有提供官方的ActionResult列表.上面的列表是我在源代码中分析得出的.有些解释的可能不够清楚,请谅解.

下面我将列举各个ActionResult的实例.

五.实例应用

1.添加Controller

安装了ASP.NET MVC后, 在项目上点击右键会找到添加Controller项:

image

2.添加Action

下面这个类提供了返回各种类型的ActionResult的Action实例:

public
 class
 DemoController : Controller
    {

        
/// <summary>

        /// http://localhost:1847/Demo/ContentResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult ContentResultDemo()
        {
            
string
 contentString = 
"ContextResultDemo!"
;
            
return
 Content(contentString);
        }

        
/// <summary>

        /// http://localhost:1847/Demo/EmptyResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult EmptyResultDemo()
        {
            
return
  new
 EmptyResult();
        }

        
/// <summary>

        /// http://localhost:1847/Demo/FileContentResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult FileContentResultDemo()
        {
            FileStream fs = 
new
 FileStream(Server.MapPath(
@"/resource/Images/1.gif"
), FileMode.Open, FileAccess.Read);
            
byte
[] buffer = 
new
 byte
[Convert.ToInt32(fs.Length)];
            fs.Read(buffer, 0, Convert.ToInt32(fs.Length) );
            
return
 File(buffer, 
@"image/gif"
);
        }

        
/// <summary>

        /// http://localhost:1847/Demo/FilePathResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult FilePathResultDemo()
        {
            
//可以将一个jpg格式的图像输出为gif格式

            return
 File(Server.MapPath(
@"/resource/Images/2.jpg"
), 
@"image/gif"
);
        }

        
/// <summary>

        /// http://localhost:1847/Demo/FileStreamResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult FileStreamResultDemo()
        {            
            FileStream fs = 
new
 FileStream(Server.MapPath(
@"/resource/Images/1.gif"
), FileMode.Open, FileAccess.Read);
            
return
 File(fs, 
@"image/gif"
);
        }

        
/// <summary>

        /// http://localhost:1847/Demo/HttpUnauthorizedResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult HttpUnauthorizedResultDemo()
        {
            
return
 new
 HttpUnauthorizedResult();
        }

        
/// <summary>

        /// http://localhost:1847/Demo/JavaScriptResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult JavaScriptResultDemo()
        {
            
return
 JavaScript(
@"alert("
"Test JavaScriptResultDemo!"
")"
);
        }

        
/// <summary>

        /// http://localhost:1847/Demo/JsonResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult JsonResultDemo()
        {
            var tempObj = 
new
 { Controller = 
"DemoController"
, Action = 
"JsonResultDemo"
 };
            
return
 Json(tempObj);
        }

        
/// <summary>

        /// http://localhost:1847/Demo/RedirectResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult RedirectResultDemo()
        {
            
return
 Redirect(
@"http://localhost:1847/Demo/ContentResultDemo"
);
        }

        
/// <summary>

        /// http://localhost:1847/Demo/RedirectToRouteResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult RedirectToRouteResultDemo()
        {
            
return
 RedirectToAction(
@"FileStreamResultDemo"
);
        }

        
/// <summary>

        /// http://localhost:1847/Demo/PartialViewResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult PartialViewResultDemo()
        {
            
return
 PartialView();
        }

        
/// <summary>

        /// http://localhost:1847/Demo/RedirectToRouteResultDemo

        /// </summary>

        /// <returns></returns>

        public
 ActionResult ViewResultDemo()
        {
            
//如果没有传入View名称, 默认寻找与Action名称相同的View页面.

            return
 View();
        }

    }

在文章最后提供有完整实例代码下载.

六.Controller 深入分析

在研究Controller/Action的流程过程中, 发现了ASP.NET MVC一些问题.

1.Routing组件与MVC框架的结合

Routing组件和ASP.NET MVC并不是一个项目, 在ASP.NET MVC中仅仅是使用了Routing组件, 在源代码中是通过dll的方式引用的.Routing组件已经包含在.net framework 3.5 sp1中了.

那么ASP.NET MVC是如何应用Routing组件的呢?

Routing组件获取了Url中的数据后, 会将数据保存在一个 RouteData 对象中.并将请求传递给一个实现了IRouteHandler接口的对象. 在Asp.net MVC中提供的MvcRouteHandler类实现了此接口, Routing 将请求传递给MvcRouteHandler的GetHttpHandler方法.下面是源代码:

IRouteHandler接口:

    public
 interface
 IRouteHandler
    {
        IHttpHandler GetHttpHandler(RequestContext requestContext);
    }

 

MvcRouteHandler类:

    public
 class
 MvcRouteHandler : IRouteHandler {
        
protected
 virtual
 IHttpHandler GetHttpHandler(RequestContext requestContext) {
            
return
 new
 MvcHandler(requestContext);
        }

        
#region
 IRouteHandler Members
        IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {
            
return
 GetHttpHandler(requestContext);
        }
        
#endregion

    }

 

曾经我认为IRouteHandler是多余的, 用IHttpHandler就够了. 现在知道了为何要定义这个接口. 主要是为了传递RouteData对象.GetHttpHandler方法需要一个RequestContext 对象.RequestContext 是 System.Web.Routing程序集中的类, 里面除了处理请求需要的HttpContextBase对象,还包括了一个RouteData对象.

RequestContext类:

    public
 class
 RequestContext
    {
        
public
 RequestContext(HttpContextBase httpContext, RouteData routeData);
        
public
 HttpContextBase HttpContext { get; }
        
public
 RouteData RouteData { get; }
    }

Routing组件在Web.Config中注册了一个HttpModule: System.Web.Routing.UrlRoutingModule, 而不是HttpHandler:

<
add
 name
="UrlRoutingModule"
 type
="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
/>

 

可惜看不到这个类的源代码. 所有请求最后都是要传递给IHttpHandler对象处理, 主要的工作是编译页面, 所以我猜测这个Module将请求截获后通过IRouteHandler接口对象获取一个HttpHandler, 然后将处理移交给获取到的HttpHandler.

 

ASP.NET MVC 中实现了IHttpHandler接口的类是MvcHandler, MvcRouteHandler.GetHttpHandler方法就是返回一个MvcHandler对象. MvcHandler类的构造函数需要传入一个RequestContext对象. 实现的IHttpHandler接口方法处理过程中都需要依赖这个对象.

但是微软在这里的处理有一些不足. MvcHandler虽然实现了IHttpHandler接口但是不能被当作IHttpHandler接口使用. 因为IHttpHandler中没有定义RequestContext属性, 如果一个MvcHandler对象此属性没有赋值则会出错, 也没有将默认的无参数构造函数设置为private, 所以理论上可以很随意的实例化一个MvcHandler而不为其RequestContext属性赋值.

IRouteHandler想实现的语意是: 返回一个具有RequestContext属性的IHttpHandler对象.

但是最后的实现结果是: 提供"返回IHttpHandler对象"的方法,  此方法接收RequestContext对象参数.

还需要注意ControllerContext类. 在Controller的处理过程中使用此对象作为保存上下文数据的容器.下面是这几个类的包含关系:

image

可以看到在ControllerContext中包含了RequestContext对象,但是又将RequestContext对象中的两个属性提取到自己的类中.如果仅仅是为了使用方便而这么做, 个人认为不是一个好的设计.数据对象的存储职责也应该明确,使用ControllerContext.RequestContext.RouteData 的方式更容易被人理解.

PS:这种方式类似于方法内联.对于属性JIT为了效率会帮助我们做内联.而仅仅是为了使用方便.

2.IView 与 View对象的关系

所以从系统的角度上看, 实现了IView接口的对象才是View.

但是从实现效果上看, 具体的aspx或者ascx页面才是View.

当第一次看到IView接口时我认为它应该是"View角色"需要实现的接口. 但是结果并不是这样.

在我们的系统中View对象应该是aspx或者ascx文件. 而且并不是所有的ActionResult都需要找到aspx或者ascx文件, 事实上只有PartialViewResult 和 ViewResult 才会去寻找View对象.其他的ActionResult要么是返回文件, 要么是跳转等等.

那么两者的关系到底是怎样的? 其实其中的过程需要牵扯到这几个接口和类:

IViewEngine, ViewEngineResult, ViewEngineCollection

ViewEngine是View引擎, ViewEngineCollection是一个引擎集合,里面保存了各种寻找View的引擎.但是在目前的源代码中只有WebFormViewEngine : VirtualPathProviderViewEngine : IViewEngine

这一系列WebForm使用的引擎.引擎的作用有两个:

1.寻找Page/用户控件的路径

2.根据路径创建IView对象.也就是根据页面的物理文件创建IView接口对象.

而且目前实现了IView接口的对象也只有一个:

WebFormView

WebFormViewEngine 根据页面路径, 将一个页面地址转化为一个WebFormView对象,也就是一个IView接口对象.

至此IView接口和Page页面类仍然没有任何关系, IView对象只是保存了页面的物理路径.

接着在IView的Render事件中,根据物理路径创建了一个页面的object实例,注意看这一段代码:

            object
 viewInstance = BuildManager.CreateInstanceFromVirtualPath(ViewPath, 
typeof
(
object
));
            
if
 (viewInstance == 
null
) {
                
throw
 new
 InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentUICulture,
                        MvcResources.WebFormViewEngine_ViewCouldNotBeCreated,
                        ViewPath));
            }

            ViewPage viewPage = viewInstance 
as
 ViewPage;
            
if
 (viewPage != 
null
) {
                RenderViewPage(viewContext, viewPage);
                
return
;
            }

            ViewUserControl viewUserControl = viewInstance 
as
 ViewUserControl;
            
if
 (viewUserControl != 
null
) {
                RenderViewUserControl(viewContext, viewUserControl);
                
return
;
            }

 

viewInstance 就是通过物理路径创建的页面对象.但是他的类型是object, 而且程序尝试将其分别转化为ViewPage对象和ViewUserControl对象.

我想很多人都看到了这里的设计不足.现在我们只能"约定": 所有的MVC中的页面对象都必须继承自ViewPage或者ViewUserControl类, 否则程序就会出错.产生这种不足的原因就是IView接口和ViewPage没有任何的耦合性, 完全是硬编码进去的.

为什么不让页面直接实现IView接口? 然后尝试将页面转化为IView接口对象, 而不是ViewPage, 这样才是好的设计. 其实微软知道什么是好的设计, 我猜测他们遇到的困难是Page对象和IView接口的冲突. 因为两者都需要Render. 如果在IView中定义自己的Render名称, 那就意味着ASP.NET MVC开发小组要自己处理页面的显示逻辑, 而现在ASP.NET WebForm模式下面的页面显示引擎又不能复用, 重新开发自己的一套显示引擎成本又太大, 才出此下策.

以上只是猜测.这种设计的缺陷虽然可以接受, 但是真的是让我好几天陷入了看不懂代码的痛苦之中.还好, 现在可以解脱了.

 

七.如何在MVC项目中使用MVC源代码项目

另外在为了跟踪实现过程, 我将ASP.NET MVC的源代码项目添加到了实例项目中, 其中有一些需要注意的地方:

1. 将实例项目中的System.Web.Mvc引用删除, 改成项目引用.

2. 需要在Web.Config中注释掉程序集引用:

        <compilation debug=
"true"
>
            <assemblies>
                <add assembly=
"System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
/>
                <add assembly=
"System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
/>
                <add assembly=
"System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
/>
                <add assembly=
"System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
/>
                
<!-- <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
/>-->

                <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
/>
                <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
/>
                <add assembly="System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
/>
            </assemblies>
        </compilation>

 

注释掉的程序集存在于GAC中, 但是我们现在不希望使用GAC中的程序集, 而是引用项目.

3. 将View目录下的Web.Config中的所有System.Web.Mvc相关的 PublicKeyToken 都修改为 null:

    <pages
        validateRequest=
"false"

        pageParserFilterType=
"System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"

        pageBaseType=
"System.Web.Mvc.ViewPage, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"

        userControlBaseType=
"System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
>
      <controls>
        <add assembly=
"System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
 namespace
=
"System.Web.Mvc"
 tagPrefix=
"mvc"
 />
      </controls>
    </pages>
发表在 article | 标签为 , | 57条评论

性能监视工具的使用

一个产品需要进行压力测试,所以我决定使用Windows2003系统自带的Performance工具进行系统性能监视。

如果在测试环境中你有足够的权限,你可以方便地使用专门一台机器执行Performance工具,远程监视目标服务器,比起在目标服务器上执行监视工具,不会给目标服务器带来额外的资源负担。

当你执行"性能"工具,准备开始测试的时候,你会发现其监视当前系统状态的图表默认只记录小于二分钟的数据,而往往我们要监视的时间会长得多,那么怎么样使用该工具得到我们想要的监视数据呢?下面我将一步一步的介绍:

1. 右键"我的电脑",单击"计算机管理"。

2. 展开"系统工具"和"性能日志和警报"。

 

   点击查看原图

3. 右键单击"计数器日志"。

4. 选择"新的日志",在弹出的对话框中输入你希望的名字并单击"确定",将会出现如下窗口。

 点击查看原图

 

 

5. 单击"增加计数器"按钮。

   点击查看原图

 

   

6. 在弹出的窗口中,选择"从计算机上选择计数器"单选按钮。

7. 输入你要测试的计算机名字,例如:"\\MS-DAVIDCOMPUTE

",或是点击下拉列表进行选择。

8. 然后,点击"性能对象"的下拉列表。

此时要注意,如果你的Windows登录用户没有足够权限的话,该列表将不能正常展开,或是提示不能连接。你可以登录Windows时采用具有足够权限的账号,或是手动设置"性能日志与警报"服务的登录账号。

如果您要手动设置"性能日志与警报"服务的登录账号,你可以展开"服务与应用"选择"服务",在右侧列表中选择"性能日志与警报"。

   点击查看原图

 

   

9. 右键选择"属性",在弹出的属性窗口中选择"登录"标签,如下图,您可以手动修改该服务使用的登录账号。

   点击查看原图

 

   

10. 如果您确认有足够的权限,您将拥有如下界面。您选择"性能对象"后下面的列表将会列出相关的可监视的性能指标。

   点击查看原图

 

   

11. 选择列表中您要监视的性能指标,并单击"增加"按钮,然后单击"关闭"按钮。此时会如下图:

   点击查看原图

 

 

12. 如上图,您选择的监视指标会显示在"计数器"列表中,您还可以修改采样时间,默认为15秒。单击"进度表"标签您可以设定是手动起动或关闭日志还是定时起动或关闭日志,我们这里采用手动起动或关闭。

   点击查看原图

 

   

13. 单击"确定"按钮,将弹出提示您是否想要创建日志文件。

   点击查看原图

 

 

14. 单击"确定"按钮。

. 点击查看原图

 

   

15. 右键单击我们新建的日志"test",在弹出菜单中选择"开始",则其图标将变成绿色,如下图:

   点击查看原图

 

 

16. 经过一段时间,你可以停止该日志计数器,右键单击"test"选择"停止"即可。

17. 下面,我们就可以具体观察我们记录的日志了。点击"开始","控制面板",在"管理工具"中双击"性能"运行监视工具。

   点击查看原图

 

   

18. 在弹出的主窗体中,当前显示的默认数据是当前计算机的活动状态,我们需要把默认的个计数器删除,并重新添加我们上面记录的日志。选中列表中的项目,单击工具栏中的"删除"按钮,把所有的项全部删除。

   点击查看原图

 

   

19. 删除所有默认项后,如下图:

   点击查看原图

 

   

20. 右键单击空列表,在弹出菜单中选择"属性",如下图:

 点击查看原图

 

   

21. 选择"源"标签,"日志文件",这时"增加"按钮将会变成可用状态。

   点击查看原图

 

   

22. 单击"增加"按钮。

   点击查看原图

 

   

23. 在弹出的文件选择对话框中,选择您上次记录的日志文件,点击"打开"按钮。

   点击查看原图

 

   

24. 单击"时间范围"按钮,下边的时间带将会变成可用状态。

   点击查看原图

 

   

25. 拖动时间带上左右两个小方块,来改变你要观察的时间范围。点击"确定"按钮。

   点击查看原图

 

   

26. 右键单击空列表,选择"添加计数器"。

   点击查看原图

 

   

27. 在添加计数器窗口中,默认会显示你曾经记录日志的所有性能指标,你可以选中你想要观察的项目,单击"增加"按钮,然后单击"关闭"按钮。

   点击查看原图

 

   

28. 最后,你将看到你曾经记录的性能记录,其时间范围也是你指定的时间范围。

   

附注:整个过程中,很可能会遇到无法启动"计数器"的情况,其原因多半是其服务使用的账号权限不够,可以参考从第8步开始的介绍。

发表在 article | 标签为 , | 性能监视工具的使用已关闭评论

C#中用GDI+生成饼状图和柱状图

 

using System;
using System.IO;//用于文件存取


using System.Data;//用于数据访问


using System.Drawing;//提供画GDI+图形的基本功能
using System.Drawing.Text;//提供画GDI+图形的高级功能
using System.Drawing.Drawing2D;//提供画高级二维,矢量图形功能
using System.Drawing.Imaging;//提供画GDI+图形的高级功能
namespace lc.laili.Web.Code
{
/// <summary>
/// MyImage 的摘要说明。
/// </summary>
public class MyImage
{
public MyImage()
{
   //
   // TODO: 在此处添加构造函数逻辑
   //

}

 

/// <summary>
/// 数据源是PieChartValue对象的饼状图
/// </summary>
/// <param name="title">饼状图大标题</param>
/// <param name="subTitle">饼状图小标题</param>
/// <param name="width">图宽</param>
/// <param name="height">图高</param>
/// <param name="Mydata">PieChartValue对象</param>
/// <returns>饼状图路径</returns>
public string Render(string title, string subTitle, int width, int height, PieChartValue[] Mydata)
{
   const int SIDE_LENGTH = 400;
   const int PIE_DIAMETER = 200;
   //DataTable dt = DataTable;

   //通过输入参数,取得饼图中的总基数
   float sumData = 0;
   for (int i = 0; i < Mydata.Length; i++)
   {
    sumData += Convert.ToSingle(Mydata[i].MValue);
   }
   //产生一个image对象,并由此产生一个Graphics对象
   Bitmap bm = new Bitmap(width, height);
   Graphics g = Graphics.FromImage(bm);
   //设置对象g的属性
   g.ScaleTransform((Convert.ToSingle(width)) / SIDE_LENGTH, (Convert.ToSingle(height)) / SIDE_LENGTH);
   g.SmoothingMode = SmoothingMode.Default;
   g.TextRenderingHint = TextRenderingHint.AntiAlias;

   //画布和边的设定
   g.Clear(Color.White);
   g.DrawRectangle(Pens.Black, 0, 0, SIDE_LENGTH - 1, SIDE_LENGTH - 1);
   //画饼图标题
   g.DrawString(title, new Font("Tahoma", 14), Brushes.Black, new PointF(5, 5));
   //画饼图的图例
   g.DrawString(subTitle, new Font("Tahoma", 12), Brushes.Black, new PointF(7, 35));
   //画饼图
   float curAngle = 0;
   float totalAngle = 0;
   for (int j = 0; j < Mydata.Length; j++)
   {
    curAngle = Convert.ToSingle(Mydata[j].MValue) / sumData * 360;

    g.FillPie(new SolidBrush(ChartUtil.GetChartItemColor(j)), 100, 65, PIE_DIAMETER, PIE_DIAMETER, totalAngle, curAngle);
    g.DrawPie(Pens.Black, 100, 65, PIE_DIAMETER, PIE_DIAMETER, totalAngle, curAngle);
    totalAngle += curAngle;
   }
   //画图例框及其文字
   g.DrawRectangle(Pens.Black, 200, 300, 199, 99);
   g.DrawString("图表说明", new Font("Tahoma", 12, FontStyle.Bold), Brushes.Black, new PointF(200, 300));

   //画图例各项
   PointF boxOrigin = new PointF(210, 330);
   PointF textOrigin = new PointF(235, 326);
   float percent = 0;
   for (int k = 0; k < Mydata.Length; k++)
   {
    g.FillRectangle(new SolidBrush(ChartUtil.GetChartItemColor(k)), boxOrigin.X, boxOrigin.Y, 20, 10);
    g.DrawRectangle(Pens.Black, boxOrigin.X, boxOrigin.Y, 20, 10);
    percent = Convert.ToSingle(Mydata[k].MValue) / sumData * 100;
    g.DrawString(Mydata[k].MValue.ToString() + " - " + Mydata[k].Name.ToString() + " (" + percent.ToString("0") + "%)", new Font("Tahoma", 10), Brushes.Black, textOrigin);
    boxOrigin.Y += 15;
    textOrigin.Y += 15;
   }
   //回收资源
   g.Dispose();
//此处存储路径需要自己改

   System.Drawing.Image MyImage=(System.Drawing.Image)bm;
   string TruePath= System.Web.HttpContext.Current.Server.MapPath("~/images");
   string TrueName=DateTime.Now.ToString("yyyyMMddhhmmss")+DateTime.Now.Millisecond;
   MyImage.Save(TruePath+"\\"+TrueName+".jpg
", System.Drawing.Imaging.ImageFormat.Gif);
   return "~/images/"+TrueName+".jpg";
}

 

 

 

/// <summary>
/// 数据源是BarChartValue对象的柱状图
/// </summary>
/// <param name="title">大标题</param>
/// <param name="subTitle">小标题</param>
/// <param name="width">图宽</param>
/// <param name="height">图高</param>
/// <param name="Mydata">BarChartValue对象</param>
/// <returns>柱状图路径</returns>
public string Render(string title, string subTitle, int width, int height, BarChartValue[] Mydata)
{
   const int SIDE_LENGTH = 400;
   const int CHART_TOP = 75;
   const int CHART_HEIGHT = 200;
   const int CHART_LEFT = 50;
   const int CHART_WIDTH = 300;

   //计算最高的点
   float highPoint = 0;
   for (int i=0; i < Mydata.Length;i++ )
   {
    if (highPoint < Convert.ToSingle(Mydata[i].MValue))
    {
     highPoint = Convert.ToSingle(Mydata[i].MValue);
    }
   }
   //建立一个Graphics对象实例
   Bitmap bm = new Bitmap(width, height);

    Graphics g = Graphics.FromImage(bm);
    //设置条图图形和文字属性
    g.ScaleTransform((Convert.ToSingle(width)) / SIDE_LENGTH, (Convert.ToSingle(height)) / SIDE_LENGTH);
    g.SmoothingMode = SmoothingMode.Default;
    g.TextRenderingHint = TextRenderingHint.AntiAlias;

    //设定画布和边
    g.Clear(Color.White);
    g.DrawRectangle(Pens.Black, 0, 0, SIDE_LENGTH - 1, SIDE_LENGTH - 1);
    //画大标题
    g.DrawString(title, new Font("Tahoma", 14), Brushes.Black, new PointF(5, 5));
    //画小标题
    g.DrawString(subTitle, new Font("Tahoma", 12), Brushes.Black, new PointF(7, 35));
    //画条形图
    float barWidth = CHART_WIDTH / (Mydata.Length * 2);
    PointF barOrigin = new PointF(CHART_LEFT + (barWidth / 2), 0);
    float barHeight = Mydata.Length;
    for (int i = 0; i < Mydata.Length; i++)
    {
     barHeight = Convert.ToSingle(Mydata[i].MValue) * 200 / highPoint * 1;
     barOrigin.Y = CHART_TOP + CHART_HEIGHT - barHeight;
     g.FillRectangle(new SolidBrush(ChartUtil.GetChartItemColor(i)), barOrigin.X, barOrigin.Y, barWidth, barHeight);

     g.DrawString(Mydata[i].Name, new Font("Tahoma", 3), Brushes.Black, new PointF(barOrigin.X-3, 277));

 

     barOrigin.X = barOrigin.X + (barWidth * 2);
    }
    //设置边
    g.DrawLine(new Pen(Color.Black, 2), new Point(CHART_LEFT, CHART_TOP), new Point(CHART_LEFT, CHART_TOP + CHART_HEIGHT));
    g.DrawLine(new Pen(Color.Black, 2), new Point(CHART_LEFT, CHART_TOP + CHART_HEIGHT), new Point(CHART_LEFT + CHART_WIDTH, CHART_TOP + CHART_HEIGHT));
    //画图例框和文字

    //g.DrawRectangle(Pens.Black, 200, 300, 199, 99);
    //g.DrawString("图表说明", new Font("Tahoma", 12, FontStyle.Bold), Brushes.Black, new PointF(200, 300));

    g.DrawRectangle(new Pen(Color.Black, 1), 10, 290, 299, 110);
    g.DrawString("图表说明", new Font("Tahoma", 10, FontStyle.Bold), Brushes.Black, new PointF(11, 290));

    //画图例
    PointF boxOrigin = new PointF(10, 310);
    PointF textOrigin = new PointF(35, 306);
    for (int i = 0; i < Mydata.Length; i++)
    {
     g.FillRectangle(new SolidBrush(ChartUtil.GetChartItemColor(i)), boxOrigin.X, boxOrigin.Y, 20, 10);
     g.DrawRectangle(Pens.Black, boxOrigin.X, boxOrigin.Y, 2, 1);
     g.DrawString(Mydata[i].Name.ToString() + " - " + Mydata[i].MValue.ToString(), new Font("Tahoma", 10), Brushes.Black, textOrigin);
     if(i<5)
     {
      boxOrigin.Y += 15;
      textOrigin.Y += 15;
     }
     else if(i==5)
     {
      boxOrigin.X = 150;
      boxOrigin.Y = 310;
      textOrigin.X = 176;
      textOrigin.Y = 306;

     }
     else
     {
      boxOrigin.Y += 15;
      textOrigin.Y += 15;
     }

    }
    //输出图形
    g.Dispose();
//此处存储路径需要自己改

   System.Drawing.Image MyImage=(System.Drawing.Image)bm;
   string TruePath= System.Web.HttpContext.Current.Server.MapPath("~/images");
   string TrueName=DateTime.Now.ToString("yyyyMMddhhmmss")+DateTime.Now.Millisecond;
   MyImage.Save(TruePath+"\\"+TrueName+".jpg
", System.Drawing.Imaging.ImageFormat.Gif);
   return "~/images/"+TrueName+".jpg";

}
}

/// <summary>
/// 选择颜色
/// </summary>
public class ChartUtil
{
public ChartUtil()
{
}
public static Color GetChartItemColor(int itemIndex)
{
   Color selectedColor;
   switch (itemIndex)
   {
    case 0:
     selectedColor = Color.AliceBlue;
     break;
    case 1:
     selectedColor = Color.Red;
     break;
    case 2:
     selectedColor = Color.Yellow;
     break;
    case 3:
     selectedColor = Color.AntiqueWhite;
     break;
    case 4:
     selectedColor = Color.Aqua;
     break;
    case 5:
     selectedColor = Color.Aquamarine;
     break;
    case 6:
     selectedColor = Color.Azure;
     break;
    case 7:
     selectedColor = Color.Beige;
     break;
    case 8:
     selectedColor = Color.Black;
     break;
    case 9:
     selectedColor = Color.Brown;
     break;
    case 10:
     selectedColor = Color.Coral;
     break;
    case 11:
     selectedColor = Color.DarkCyan;
     break;
    case 12:
     selectedColor = Color.DarkOrange;
     break;
    default:
     selectedColor = Color.DarkViolet;
     break;
   }
   return selectedColor;
}
}

/// <summary>
/// 饼状图的数据对象
/// </summary>
public class PieChartValue
{
public PieChartValue()
{

}
public PieChartValue(string MyName, int Myvalue)
{
   Name = MyName;
   MValue = Myvalue;
}
private string name;
public string Name
{
   get
   {
    return name;
   }
   set
   {
    name = value;
   }
}

private int mvalue;
public int MValue
{
   get
   {
    return mvalue;
   }
   set
   {
    mvalue = value;
   }
}
}

/// <summary>
/// 柱状图的数据对象
/// </summary>
public class BarChartValue
{
public BarChartValue()
{

}
public BarChartValue(string MyName, int Myvalue)
{
   Name = MyName;
   MValue = Myvalue;
}
private string name;
public string Name
{
   get
   {
    return name;
   }
   set
   {
    name = value;
   }
}

private int mvalue;
public int MValue
{
   get
   {
    return mvalue;
   }
   set
   {
    mvalue = value;
   }
}
}
}

用法

   #region 生成柱状图

   MyImage MyMyImage = new MyImage();
   BarChartValue[] BarChartValue ={

          new BarChartValue("第1个月",5),
          new BarChartValue("第2个月",2),
          new BarChartValue("第3个月",3),
          new BarChartValue("第4个月",4),
          new BarChartValue("第5个月",5),
          new BarChartValue("第6个月",6),
          new BarChartValue("第7个月",7),
          new BarChartValue("第8个月",8),
          new BarChartValue("第9个月",9)

             };
   Image1.ImageUrl = MyMyImage.Render("全年统计", "98年", 1000, 1000, BarChartValue);
   #endregion

 

   #region 生成饼状图
   PieChartValue[] PieChartValue ={

              new PieChartValue("第一个仓库",1),
              new PieChartValue("第一个仓库",2)
             };

   Image2.ImageUrl = MyMyImage.Render("仓库统计饼状图", "小仓库", 500, 500, PieChartValue);
   #endregion

发表在 article | 标签为 , | 58条评论

c# GDI+简单绘图

最近对
GDI+
这个东西接触的比较多,也做了些简单的实例,比如绘图板,仿
QQ
截图等.

  最早接触这个类,是因为想做仿
QQ
截图的效果.巧的很,学会了如何做截图后,
.NET
课堂上老师也正巧要讲关于
c#
绘图方面的知识,并且我自己又在网上学习金老师的培训班,也是要用到这个类.在学习中有一些体会,所以准备把这些体会记下来,因为内容比较多,可能我会分几次写.

  废话不多说了,我们先来认识一下这个
GDI+
,看看它到底长什么样
.

GDI+

Graphics Device Interface Plus
也就是图形设备接口
,
提供了各种丰富的图形图像处理功能
;

C#.NET
中,使用
GDI+
处理二维(
2D
)的图形和图像,使用
DirectX
处理三维(
3D
)的图形图像
,
图形图像处理用到的主要命名空间是
System . Drawing
:提供了对
GDI+
基本图形功能的访问,主要有
Graphics
类、
Bitmap
类、从
Brush
类继承的类、
Font
类、
Icon
类、
Image
类、
Pen
类、
Color
类等
.

大概了解了什么是
GDI+

,
我们来看一下绘图要用到的主要工具
,
要画图
,
肯定要画板

,

C#
中画板可以通过
Graphics
这个类来创建
,
有了画板
,
总得弄个
什么之类的吧

,
不然怎么画呀
,
难不成我们用手指画
.
笔又可以分好多种类
,
比如铅笔
,
画刷等
.
它们的区别主要是铅笔可以用来画线条
,
而画刷呢
,
嘿嘿
,
自己考虑下
.

c#
中我们可以用
Pen,Brush
类来实现类似功能
.
颜料则自然是用
Color
类了
.

有了工具
,
我们就可以开始动手了
!(所需命名空间:using System.Drawing;
)

实现效果
:
在空白窗体中画基本图形

首先

准备一个画板
:

创建一个画板主要有
3
种方式
:
A:

在窗体或控件的
Paint
事件中直接引用
Graphics
对象

B:

利用窗体或某个控件的
CreateGraphics
方法

C:

从继承自图像的任何对象创建
Graphics
对象


这次我们就先以
A
为例说明问题
:

 
private
 
void
 Form1_Paint(
object
 sender, PaintEventArgs e)
        

 

{
            Graphics g 

=
 e.Graphics; 
//
创建画板,这里的画板是由Form提供的.
 

         }





然后

,
我们要只笔
:

private
 
void
 Form1_Paint(
object
 sender, PaintEventArgs e)
        

 

{
            Graphics g 

=
 e.Graphics; 
//
创建画板,这里的画板是由Form提供的.
 

             Pen p 
=
 
new
 Pen(Color.Blue, 
2
);
//
定义了一个蓝色,宽度为的画笔
 

         }


接下来

我们就可以来画画了
.

private
 
void
 Form1_Paint(
object
 sender, PaintEventArgs e)
        

 

{
            Graphics g 

=
 e.Graphics; 
//
创建画板,这里的画板是由Form提供的.
 

             Pen p 
=
 
new
 Pen(Color.Blue, 
2
);
//
定义了一个蓝色,宽度为的画笔
 

             g.DrawLine(p, 
10

10

100

100
);
//
在画板上画直线,起始坐标为(10,10),终点坐标为(100,100)
 

             g.DrawRectangle(p, 
10

10

100

100
);
//
在画板上画矩形,起始坐标为(10,10),宽为,高为
 

             g.DrawEllipse(p, 
10

10

100

100
);
//
在画板上画椭圆,起始坐标为(10,10),外接矩形的宽为,高为
 

         }



        

效果图如下

:

 点击查看原图

 

1.
首先我们来看下上一片中我们使用过的
Pen.

Pen的属性主要有
: Color(颜色
),DashCap(短划线终点形状
),DashStyle(虚线样式
),EndCap(线尾形状
), StartCap(线头形状
),Width(粗细
)
.

我们可以用
Pen 来画虚线
,带箭头的直线等

Pen  p 
=
 
new
  Pen(Color.Blue, 
5
);
//
设置笔的粗细为,颜色为蓝色


Graphics  g 
=
 
this
.CreateGraphics();


//
画虚线


p.DashStyle 
=
 DashStyle.Dot;
//
定义虚线的样式为点


g.DrawLine(p, 
10

10

200

10
);


//
自定义虚线


p.DashPattern 
=
 
new
  
float
[] 

2

1
 }

;
//
设置短划线和空白部分的数组


g.DrawLine(p, 
10

20

200

20
);


//
画箭头,只对不封闭曲线有用


p.DashStyle 
=
 DashStyle.Solid;
//
恢复实线


p.EndCap 
=
 LineCap.ArrowAnchor;
//
定义线尾的样式为箭头


g.DrawLine(p, 
10

30

200

30
);

g.Dispose();
p.Dispose();


 

以上代码运行结果:
点击查看原图

 

2.
接下来我们来看下
Brush

的使用


作用
:我们可以用画刷填充各种图形形状,如矩形、椭圆、扇形、多边形和封闭路径等
,主要有几种不同类型的画刷
:

        

SolidBrush:画刷最简单的形式,用纯色进行绘制

        

HatchBrush:类似于
SolidBrush,但是可以利用该类从大量预设的图案中选择绘制时要使用的图案,而不是纯色

        

TextureBrush:使用纹理(如图像)进行绘制

        

LinearGradientBrush:使用沿渐变混合的两种颜色进行绘制

        

PathGradientBrush :基于编程者定义的唯一路径,使用复杂的混合色渐变进行绘制

我们这里只是简单介绍使用其中的几种
:

Graphics g 
=
 
this
.CreateGraphics();
Rectangle rect 

=
 
new
 Rectangle(
10

10

50

50
);
//
定义矩形,参数为起点横纵坐标以及其长和宽


//
单色填充


SolidBrush b1 
=
 
new
 SolidBrush(Color.Blue);
//
定义单色画刷          


g.FillRectangle(b1, rect);
//
填充这个矩形


//
字符串


g.DrawString(
"
字符串
"

new
 Font(
"
宋体
"

10
), b1, 
new
 PointF(
90

10
));


//
用图片填充


TextureBrush b2 
=
 
new
 TextureBrush(Image.FromFile(
@"
e:\picture\1.jpg
"
));
rect.Location 

=
 
new
 Point(
10

70
);
//
更改这个矩形的起点坐标


rect.Width 
=
 
200
;
//
更改这个矩形的宽来


rect.Height 
=
 
200
;
//
更改这个矩形的高


g.FillRectangle(b2, rect);


//
用渐变色填充


rect.Location 
=
 
new
 Point(
10

290
);
LinearGradientBrush b3 

=
 
new
  LinearGradientBrush(rect, Color.Yellow , Color.Black , LinearGradientMode.Horizontal);
g.FillRectangle(b3, rect);



 

运行效果图
:


点击查看原图


3.
坐标轴变换



winform中的坐标轴和我们平时接触的平面直角坐标轴不同
,winform中的坐标轴方向完全相反
:窗体的左上角为原点
(0,0),水平向左则
X增大
,垂直下向则
Y增大


点击查看原图

 

 

  运行效果图:

4.
最后我们来看下
Graphics

这个画板上我们还可以画什么






其实我们上面用到的都是在画一些简单的图形
,直线
,矩形
,扇形
,圆孤等
,我们还可以用它来绘制图片
,这可以用它的
DrawImage方法
.


这里我不详细讲解
,大家有兴趣可以自己去
MSDN了解下
.


我们后面会讲到的截图就会用到这个方法







点击查看原图

 


接下来
,
我们来实际操作下
,
通过旋转坐标轴的方向来画出不同角度的图案
,
或通过更改坐标原点的位置来平衡坐标轴的位置


Graphics g 
=
 
this
.CreateGraphics();


//
单色填充

//
SolidBrush b1 = new SolidBrush(Color.Blue);
//
定义单色画刷          


Pen p 
=
 
new
 Pen(Color.Blue,
1
);


//
转变坐标轴角度


for
 (
int
 i 
=
 
0
; i 
<
 
90
; i
++
)


{
    g.RotateTransform(i);

//
每旋转一度就画一条线


    g.DrawLine(p, 
0

0

100

0
);
    g.ResetTransform();

//
恢复坐标轴坐标


}




//
平移坐标轴


g.TranslateTransform(
100

100
);
g.DrawLine(p, 

0

0

100

0
);
g.ResetTransform();


//
先平移到指定坐标,然后进行度旋转


g.TranslateTransform(
100
,
200
);

for
 (
int
 i 
=
 
0
; i 
<
 
8
; i
++
)

{
g.RotateTransform(

45
);
g.DrawLine(p, 

0

0

100

0
);
}




g.Dispose();

我们先来做一个简单的----仿QQ截图,关于这个的例子其实网上已经有这方面的资料了,但是为了文章的完整性,还是觉得有必要讲解.
  我们先来看一下效果:
                                                                                                                  (图1)点击查看原图
 
                                                      点击查看原图
 
                                                                                                                     (图2)

  接下来看看这是如何做到的. 
  思路:聊天窗体上有一个截图按钮,点击按钮后,程序将整个屏幕画在一个新的全屏窗体上,然后显示这个窗体.因为是全屏的窗体,并且隐藏了菜单栏、工具栏等,所以在我们看来就好像是一个桌面的截图,然后在这个新窗体上画矩形,最后保存矩形中的内容并显示在原来的聊天窗体中.
  步骤:
  A.新建一个窗体.命名为Catch.然后设置这个窗体的FormBorderStyle为None,WindowState为Maximized.
  B.我们对代码进行编辑:

  C.创建了Catch窗体后,我们在截图按钮(位于聊天窗体上)上加入以下事件:

        
private
 
void
 bCatch_Click(
object
 sender, EventArgs e)
        

{

            
if
 (bCatch_HideCurrent.Checked)
            


{
                

this
.Hide();
//
隐藏当前窗体


                Thread.Sleep(
50
);
//
让线程睡眠一段时间,窗体消失需要一点时间


                Catch CatchForm 
=
 
new
 Catch();
                Bitmap CatchBmp 

=
 
new
 Bitmap(Screen.AllScreens[
0
].Bounds.Width, Screen.AllScreens[
0
].Bounds.Height);
//
新建一个和屏幕大小相同的图片         


                Graphics g 
=
 Graphics.FromImage(CatchBmp);
                g.CopyFromScreen(

new
 Point(
0

0
), 
new
 Point(
0

0
), 
new
 Size(Screen.AllScreens[
0
].Bounds.Width, Screen.AllScreens[
0
].Bounds.Height));
//
保存全屏图片


                CatchForm.BackgroundImage 
=
 CatchBmp;
//
将Catch窗体的背景设为全屏时的图片


                
if
 (CatchForm.ShowDialog() 
==
 DialogResult.OK)
                


{
//
如果Catch窗体结束,就将剪贴板中的图片放到信息发送框中


                    IDataObject iData 
=
 Clipboard.GetDataObject();
                    DataFormats.Format myFormat 

=
 DataFormats.GetFormat(DataFormats.Bitmap);
                    

if
 (iData.GetDataPresent(DataFormats.Bitmap))
                    


{
                        richtextbox1.Paste(myFormat);
                        Clipboard.Clear();

//
清除剪贴板中的对象


                    }


                    

this
.Show();
//
重新显示窗体


                }

            }

        }

  这样我们的截图功能便完成了.
  我想对于初学者来说如何消去第一次绘制的图片是个比较困难的问题.如果没有采取措施,你会发现只要你鼠标移动,就会画一个矩形,这样便会出现N多的矩形,而我们只是要最后的那一个.
  一般解决这种问题的方法有两种:
  1.就是在绘制第二个图形时,我们先用与底色相同的颜色将上次绘制的图形重新绘制一下.但这往往需要底色为纯色时使用.
  2.我们并不直接将图形画在画板上,我们用一个图片A来保存原画板上的图片.然后再新建一个与图片A相同的图片B,将我们要绘制的图形画在该图片B上,然后再将该图片B画在画板上.这样图片A并没有被改变.于是第二次画的时候我们还是同样新建一个与图片A相同的图片进行绘制.那么上一次的图形就不会被保留下来.问题也就解决了.

  下一次,向大家介绍如何做一个仿windows画板的程序

 

 

 

个人认为如果想做一个功能强大的绘图工具,那么单纯掌握GDI还远远不够,我的目前也只能做一个比较简单的绘图工具了.不足之处,欢迎大家讨论!

  先来看一下最终效果吧:

点击查看原图

  
  主要实现功能:画直线,矩形,橡皮,圆形,切换颜色,打开图片,保存图片,清除图片,手动调节画布大小;软件刚启动时,为一张空白画布,我们可以直接在画布上绘画,也可以通过菜单中的“打开”,导入一张图片,然后我们就可以在这张图片上进行绘制。
  平台:VS2005 WINFORM

  由于代码过多,在这里只简要介绍下制作步骤,提供大家工程下载.
  1.对整个界面进行布局.
  2.实现绘图工具的功能
  3.实现颜色拾取的功能,这里我们直接拿上次写的自定义控件来用.
  4.实现菜单功能
  5.实现手动调节画布大小的功能
  6.测试 

  实现绘图工具的功能

  为了让代码藕合度小点,稍许用了些设计模式,因为不是很会,所以代码还是有点乱乱的,嘿嘿!关于绘图工具的这些功能块全部写在了DrawTools这个类里.那么在主窗体中,只需要调用这个类来完成绘制就行了,而不需要过多的涉及到具体的绘图代码。绘图工具这个类提供的主要工具就是:铅笔、橡皮、直线、矩形、圆形、实心矩形、实心圆形。关于这些功能块的代码,并不难,只要大家对认真看过前几篇内容,那应该都看得懂。
  这里要注意以下几点:
  1.如何防止记录不必要的绘图过程中的痕迹?
  这个问题在第三篇

中有提到过,大家不妨先去看看那一篇。为了让代码看起来可读性高点,我设置了两个Image变量,finishingImg用来保存绘图过程中的痕迹,orginalImg用来保存已完成的绘图过程和初始时的背景图片。
  2.这个类如何与主窗体进行通信?
  当然如果直接将这些功能块写在主窗体中自然没有这个问题。但是那样代码会显得很混杂,如果只是工具代码出现问题就需要改整个项目。我在这里通过定义方法和属性,让主窗体通过给属性赋值将画板画布以及颜色什么的信息传给这个工具类,然后通过调用相应的工具方法来使用这些工具。
  3.关键属性
  要想让这些工具能正常使用,必须传递给他以下几样东西:目标画板(也就是picturebox),绘图颜色,原始画布。

  实现菜单功能

  点击查看原图

  这里就需要我们对文件的操作有一点了解,大家可以去查一下相关资料。
  难点主要就是“打开”这个菜单项的实现
  我们要实现将打开后的图片在修改后重新保存就必须让文件在打开后就能关闭,否则就会因为文件打开而无法覆盖原文件。就会导致编译时弹出“GDI  一般性错误”。所以根据网上其它朋友的做法就是先将打开的图片通过GDI+将图片画到另一个画布上,然后及时关闭打开的图片和用来绘制该图片的画板。详见http://www.wanxin.org/redirect.php?tid=3&goto=lastpost



 
private
 
void
 openPic_Click(
object
 sender, EventArgs e)
        

{
            OpenFileDialog ofd 

=
 
new
 OpenFileDialog();
//
实例化文件打开对话框


            ofd.Filter 
=
 
"
JPG|*.jpg|Bmp|*.bmp|所有文件|*.*
"
;
//
设置对话框打开文件的括展名


            
if
 (ofd.ShowDialog() 
==
 DialogResult.OK)
            


{
                Bitmap bmpformfile 

=
 
new
 Bitmap(ofd.FileName);
//
获取打开的文件


                panel2.AutoScrollPosition 
=
 
new
 Point(
0
,
0
);
//
将滚动条复位


                pbImg.Size 
=
 bmpformfile.Size;
//
调整绘图区大小为图片大小



                reSize.Location 

=
 
new
 Point(bmpformfile.Width, bmpformfile.Height);
//
reSize为我用来实现手动调节画布大小用的
                

//
因为我们初始时的空白画布大小有限,"打开"操作可能引起画板大小改变,所以要将画板重新传入工具类


                dt.DrawTools_Graphics 
=
 pbImg.CreateGraphics();

                Bitmap bmp 
=
 
new
 Bitmap(pbImg.Width, pbImg.Height);
                Graphics g 

=
 Graphics.FromImage(bmp);
                g.FillRectangle(

new
 SolidBrush(pbImg.BackColor), 
new
 Rectangle(
0

0
, pbImg.Width, pbImg.Height));
//
不使用这句话,那么这个bmp的背景就是透明的


                g.DrawImage(bmpformfile, 
0

0
,bmpformfile.Width,bmpformfile.Height);
//
将图片画到画板上


                g.Dispose();
//
释放画板所占资源
                

//
不直接使用pbImg.Image = Image.FormFile(ofd.FileName)是因为这样会让图片一直处于打开状态,也就无法保存修改后的图片


                bmpformfile.Dispose();
//
释放图片所占资源


                g 
=
 pbImg.CreateGraphics();
                g.DrawImage(bmp, 

0

0
);
                g.Dispose();
                dt.OrginalImg 

=
 bmp;
                bmp.Dispose();
                sFileName 

=
 ofd.FileName;
//
储存打开的图片文件的详细路径,用来稍后能覆盖这个文件


                ofd.Dispose();

            }


        }

  清除图像其实就是用白色填充整个画布
  其它的都比较简单,这就不具体讲了。

  实现手动调节画布大小
  

网上有人说使用API,但是个人觉得还是使用其它控件帮忙比较简单,至少我们还看得懂。
  思路:放置一个picturebox1(尺寸为5*5),将它固定在主画板的右下角,然后改变鼠标进入时的Cursor为箭头形状,设置鼠标按下移动时的事件,让该picturebox1 跟随鼠标移动。当鼠标松开时,将主画板的右下角坐标调整为picturebox1的坐标。
  下面来看下代码:
  其中的reSize就是我们用来帮忙的picturebox控件 

        
private
 
bool
 bReSize 
=
 
false
;
//
是否改变画布大小


        
private
 
void
 reSize_MouseDown(
object
 sender, MouseEventArgs e)
        

{
            bReSize 

=
 
true
;
//
当鼠标按下时,说明要开始调节大小


        }



        

private
 
void
 reSize_MouseMove(
object
 sender, MouseEventArgs e)
        

{
            

if
 (bReSize)
            


{
                reSize.Location 

=
 
new
 Point(reSize.Location.X 
+
 e.X, reSize.Location.Y 
+
 e.Y);

            }


        }



        

private
 
void
 reSize_MouseUp(
object
 sender, MouseEventArgs e)
        

{
            bReSize 

=
 
false
;
//
大小改变结束
            

//
调节大小可能造成画板大小超过屏幕区域,所以事先要设置autoScroll为true.
            

//
但是滚动条的出现反而增加了我们的难度,因为滚动条上下移动并不会自动帮我们调整图片的坐标。
            

//
这是因为GDI绘图的坐标系不只一个,好像有三个,没有仔细了解,一个是屏幕坐标,一个是客户区坐标,还个是文档坐标。
            

//
滚动条的上下移动改变的是文档的坐标,但是客户区坐标不变,而location属性就属于客户区坐标,所以我们直接计算会出现错误
            

//
这时我们就需要知道文档坐标与客户区坐标的偏移量,这就是AutoScrollPostion可以提供的



            pbImg.Size 

=
 
new
 Size(reSize.Location.X 
-
 (
this
.panel2.AutoScrollPosition.X), reSize.Location.Y 
-
 (
this
.panel2.AutoScrollPosition.Y));
            dt.DrawTools_Graphics 

=
 pbImg.CreateGraphics();
//
因为画板的大小被改变所以必须重新赋值

            
//
另外画布也被改变所以也要重新赋值


           Bitmap bmp 
=
 
new
 Bitmap(pbImg.Width, pbImg.Height);
            Graphics g 

=
 Graphics.FromImage(bmp);
            g.FillRectangle(

new
 SolidBrush(Color.White), 
0

0
, pbImg.Width, pbImg.Height);
            g.DrawImage(dt.OrginalImg, 

0

0
);
            g.Dispose();
            g 

=
 pbImg.CreateGraphics();
            g.DrawImage(bmp, 

0

0
);
            g.Dispose();
            dt.OrginalImg 

=
 bmp;

            bmp.Dispose();
        }

  效果如下图(仔细看白色区域的右下角):
  点击查看原图

  此时就可以通过拖动那个小方块来调节图片大小了

发表在 article | 标签为 , | c# GDI+简单绘图已关闭评论

正则表达式--递归匹配、非贪婪匹配与分组替换

1. 表达式的递归匹配

有时候,我们需要用正则表达式来分析一个计算式中的括号配对情况。比如, 使用表达式 "\( [^)]* \)" 或者 "\( .*? \)" 可以匹配一对小括号。但是如果括号 内还嵌有一层括号的话 ,如 "( ( ) )",则这种写法将不能够匹配正确,得到的结果是 "( ( )" 。类似情况的还有 HTML 中支持嵌套的标签如 "<font> </font>" 等。本节将要讨论的是,想办法把有嵌套的的成对括号或者成对标签匹配出来。
匹配未知层次的嵌套:
有的正则表达式引擎,专门针对这种嵌套提供了支持。并且在栈空间允许的情况下,能够支持任意未知层次的嵌套:比如 Perl,PHP,GRETA 等。在 PHP 和 GRETA 中,表达式中使用 "(?R)" 来表示嵌套部分。
匹配嵌套了未知层次的 "小括号对" 的表达式写法如下:"\( ([^()] | (?R))* \)"。
[Perl 和 PHP 的示例代码]
匹配有限层次的嵌套:
对于不支持嵌套的正则表达式引擎,只能通过一定的办法来匹配有限层次的嵌套。思路如下:
第一步,写一个不能支持嵌套的表达式:"\( [^()]* \)","<font>((?!</?font>).)*</font>"。 这两个表达式在匹配有嵌套的文本时,只匹配最内层。
第二步,写一个可匹配嵌套一层的表达式:"\( ([^()] | \( [^()]* \))* \)"。这个表达式在匹配嵌套层数大于一时,只能匹配最里面的两层,同时,这个表达式也能匹配没有嵌套的文本或者嵌套的最里层。
匹 配嵌套一层的 "<font>" 标签,表达式为:"<font>((?!</?font>).|(<font>((?!</? font>).)*</font>))*</font>"。这个表达式在匹配 "<font>" 嵌套层数大于一的文本时,只匹配最里面的两层。
第三步,找到匹配嵌套(n)层的表达式 与 嵌套(n-1)层的表达式之间的关系。比如,能够匹配嵌套(n)层的表达式为:
[标记头] ( [匹配 [标记头] 和 [标记尾] 之外的表达式] | [匹配 n-1 层的表达式] )* [标记尾]
回头来看前面编写的“可匹配嵌套一层”的表达式:
\( ( [^()] | \(([^()])*\) )* \)
<font> ( (?!</?font>). | (<font>((?!</?font>).)*</font>) )* </font>

PHP 和 GRETA 的简便之处在于,匹配嵌套(n-1)层的表达式用 (?R) 表示:
\( ( [^()] | (?R) )* \)
第四步,依此类推,可以编写出匹配有限(n)层的表达式。这种方式写出来的表达式,虽然看上去很长,但是这种表达式经过编译后,匹配效率仍然是很高的。

 
 
2. 非贪婪匹配的效率
可能有不少的人和我一样,有过这样的经历:当我们要匹配类似 "<td>内容</td>" 或者 "[b]加粗[/b]" 这样的文本时,我们根据正向预搜索功能写出这样的表达式:"<td>([^<]|<(?!/td>))*< /td>" 或者 "<td>((?!</td>).)*</td>"。
当发现非贪婪匹配之时,恍然 大悟,同样功能的表达式可以写得如此简单:"<td>.*?</td>"。 顿时间如获至宝,凡是按边界匹配的地方,尽量使用简捷的非贪婪匹配 ".*?"。特别是对于复杂的表达式来说,采用非贪婪匹配 ".*?" 写出来的表达式的确是简练了许多。
然而,当一个表达式中,有多个非贪婪匹配时,或者多个未知匹配次数的表达式时,这个表达式将可能存在效率上的陷阱。有时候,匹配速度慢得莫名奇妙,甚至开始怀疑正则表达式是否实用。
效率陷阱的产生:
在本站基础文章里,对非贪婪匹配的描述中说到:“如果少匹配就会导致整个表达式匹配失败的时候,与贪婪模式类似,非贪婪模式会最小限度的再匹配一些,以使整个表达式匹配成功。”
具体的匹配过程是这样的:
"非贪婪部分" 先匹配最少次数,然后尝试匹配 "右侧的表达式"。
如果右侧的表达式匹配成功,则整个表达式匹配结束。如果右侧表达式匹配失败,则 "非贪婪部分" 将增加匹配一次,然后再尝试匹配 "右侧的表达式"。
如果右侧的表达式又匹配失败,则 "非贪婪部分" 将再增加匹配一次。再尝试匹配 "右侧的表达式"。
依此类推,最后得到的结果是 "非贪婪部分" 以尽可能少的匹配次数,使整个表达式匹配成功。或者最终仍然匹配失败。
当 一个表达式中有多个非贪婪匹配,以表达式 "d(\w+?)d(\w+?)z" 为例,对于第一个括号中的 "\w+?" 来说,右边的 "d(\w+?)z" 属于它的 "右侧的表达式",对于第二个括号中的 "\w+?" 来说,右边的 "z" 属于它的 "右侧的表达式"。
当 "z" 匹配失败时,第二个 "\w+?" 会 "增加匹配一次",再尝试匹配 "z"。如果第二个 "\w+?" 无论怎样 "增加匹配次数",直至整篇文本结束,"z" 都不能匹配,那么表示 "d(\w+?)z" 匹配失败,也就是说第一个 "\w+?" 的 "右侧" 匹配失败。此时,第一个 "\w+?" 会增加匹配一次,然后再进行 "d(\w+?)z" 的匹配。循环前面所讲的过程,直至第一个 "\w+?" 无论怎么 "增加匹配次数",后边的 "d(\w+?)z" 都不能匹配时,整个表达式才宣告匹配失败。
其实,为了使整个表达式匹配成功,贪婪匹 配也会适当的“让出”已经匹配的字符。因此贪婪匹配也有类似的情况。当一个表达式中有较多的未知匹配次数的表达式时,为了让整个表达式匹配成功,各个贪婪 或非贪婪的表达式都要进行尝试减少或增加匹配次数,由此容易形成一个大循环的尝试,造成了很长的匹配时间。本文之所以称之为“陷阱”,因为这种效率问题往 往不易察觉。
举例:"d(\w+?)d(\w+?)d(\w+?)z" 匹配 "ddddddddddd..." 时,将花费较长一段时间才能判断出匹配失败 。
效率陷阱的避免:
避免效率陷阱的原则是:避免“多重循环”的“尝试匹配”。并不是说非贪婪匹配就是不好的,只是在运用非贪婪匹配的时候,需要注意避免过多“循环尝试”的问题。
情 况一:对于只有一个非贪婪或者贪婪匹配的表达式来说,不存在效率陷阱。也就是说,要匹配类似 "<td> 内容 </td>" 这样的文本,表达式 "<td>([^<]|<(?!/td>))*</td>" 和 "<td>((?!</td>).)*</td>" 和 "<td>.*?</td>" 的效率是完全相同的。
情况二:如果一个表达式中有多个未知匹配次数的表达式,应防止进行不必要的尝试匹配。
比如,对表达式 "<script language='(.*?)'>(.*?)</script>" 来说, 如果前面部分表达式在遇到 "<script language='vbscript'>" 时匹配成功后,而后边的 "(.*?)</script>" 却匹配失败,将导致第一个 ".*?" 增加匹配次数再尝试。而对于表达式真正目的,让第一个 ".*?" 增加匹配成“vbscript'>”是不对的,因此这种尝试是不必要的尝试。
因此,对依靠边界来识别的表达式,不要让未知匹配次数的部分跨 过它的边界。前面的表达式中,第一个 ".*?" 应该改写成 "[^']*"。后边那个 ".*?" 的右边再没有未知匹配次数的表达式,因此这个非贪婪匹配没有效率陷阱。于是,这个匹配脚本块的表达式,应该写成:"<script language='([^']*)'>(.*?)</script>" 更好。
 
3.正则表达式-分组构造

分组构造使您可以捕获子表达式组并提高具有非捕获预测先行和回顾后发修饰符的正则表达式的效率。下表描述了正则表达式分组构造。
分组构造 说明
( ) 捕获匹配的子字符串(或非捕获组;有关详细信息,请参见正则表达式选项中的 ExplicitCapture 选项)。使用 () 的捕获根据左括号的顺序从 1 开始自动编号。捕获元素编号为零的第一个捕获是由整个正则表达式模式匹配的文本。
(?<name> ) 将匹配的子字符串捕获到一个组名称或编号名称中。用于 name 的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如 (?'name')。
(?<name1-name2> ) 平衡组定义。删除先前定义的 name2 组的定义并在 name1 组中存储先前定义的 name2 组和当前组之间的间隔。如果未定义 name2 组,则匹配将回溯。由于删除 name2 的最后一个定义会显示 name2 的先前定义,因此该构造允许将 name2 组的捕获堆栈用作计数器以跟踪嵌套构造(如括号)。在此构造中,name1 是可选的。可以使用单引号替代尖括号,例如 (?'name1-name2')。
(?: ) 非捕获组。
(?imnsx-imnsx: ) 应用或禁用子表达式中指定的选项。例如,(?i-s: ) 将打开不区分大小写并禁用单行模式。有关详细信息,请参见正则表达式选项。
(?= ) 零宽度正预测先行断言。仅当子表达式在此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。
(?! ) 零宽度负预测先行断言。仅当子表达式不在此位置的右侧匹配时才继续匹配。例如,\b(?!un)\w+\b 与不以 un 开头的单词匹配。
(?<= ) 零宽度正回顾后发断言。仅当子表达式在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。
(?<! ) 零宽度负回顾后发断言。仅当子表达式不在此位置的左侧匹配时才继续匹配。
(?> ) 非回溯子表达式(也称为“贪婪”子表达式)。该子表达式仅完全匹配一次,然后就不会逐段参与回溯了。(也就是说,该子表达式仅与可由该子表达式单独匹配的字符串匹配。)
命 名捕获根据左括号的从左到右的顺序按顺序编号(与非命名捕获类似),但在对所有非命名捕获进行计数之后才开始对命名捕获进行编号。例如,模式 ((?<One>abc)/d+)?(?<Two>xyz)(.*) 按编号和名称产生下列捕获组。(编号为 0 的第一个捕获总是指整个模式)。
编号 名称 模式
0 0(默认名称) ((?<One>abc)/d+)?(?<Two>xyz)(.*)
1 1(默认名称) ((?<One>abc)/d+)
2 2(默认名称) (.*)
3 1 (?<One>abc)
4 2 (?<Two>xyz)

 
4.正则表达式-替换和分组
替换使用 | 字符来允许在两个或多个替换选项之间进行选择。例如,可以扩展章节标题正则表达式,以返回比章标题范围更广的匹配项。但是,这并不象您可能认为的那样简 单。替换匹配 | 字符两边的尽可能最大的表达式。您可能认为,下面的表达式匹配出现在行首和行尾、后面跟一个或两个数字的 Chapter 或 Section:
/^Chapter|Section [1-9][0-9]{0,1}$/
很遗憾,上面的正则表达式要么匹配行首的单词 Chapter,要么匹配行尾的单词 Section 及跟在其后的任何数字。如果输入字符串是 Chapter 22,那么上面的表达式只匹配单词 Chapter。如果输入字符串是 Section 22,那么该表达式匹配 Section 22。
若要使正则表达式更易于控制,可以使用括号 来限制替换的范围,即,确保它只应用于两个单词 Chapter 和 Section。但是,括号也用于创建子表达式,并可能捕获它们以供以后使用,这一点在有关反向引用的那一节讲述。通过在上面的正则表达式的适当位置添加 括号,就可以使该正则表达式匹配 Chapter 1 或 Section 3。
下面的正则表达式使用括号来组合 Chapter 和 Section,以便表达式正确地起作用:
/^(Chapter|Section) [1-9][0-9]{0,1}$/
虽 然这些表达式正确发挥作用,但 Chapter| Section 两边的括号还会使得两个匹配单词中的任何一个被捕获以供将来使用。由于在上面的表达式中只有一组括号,因此,只有一个被捕获的“子匹配项”。可以通过使用 RegExp 对象的 $1-$9 属性来引用此子匹配项。
在上面的示例中,您只需要使用括号来组合单词 Chapter 和 Section 之间的选择。若要防止匹配被保存以备将来使用,请在括号内正则表达式模式之前放置 ?:。下面的修改提供相同的能力而不保存子匹配项:
/^(?:Chapter|Section) [1-9][0-9]{0,1}$/
除 ?: 元字符外,两个其他非捕获元字符创建被称为“预测先行”匹配的某些内容。正向预测先行使用 ?= 指定,它匹配处于括号中匹配正则表达式模式的起始点的搜索字符串。反向预测先行使用 ?! 指定,它匹配处于与正则表达式模式不匹配的字符串的起始点的搜索字符串。
例 如,假设您有一个文档,该文档包含指向 Windows 3.1、Windows 95、Windows 98 和 Windows NT 的引用。再进一步假设,您需要更新该文档,将指向 Windows 95、Windows 98 和 Windows NT 的所有引用更改为 Windows 2000。下面的正则表达式(这是一个正向预测先行的示例)匹配 Windows 95、Windows 98 和 Windows NT:
/Windows(?=95 |98 |NT )/
找到一处匹配后,紧接着就在匹配的文本(不包括预测先行中的字符)之后搜索下一处匹配。例如,如果上面的表达式匹配 Windows 98,将在 Windows 之后而不是在 98 之后继续搜索。
发表在 article | 标签为 | 正则表达式--递归匹配、非贪婪匹配与分组替换已关闭评论

SQL Server 2005 之 事物复制

SQL Server 2005相对于SQL Server 2000来说,无论是性能还是功能都有一个相当大的提高,甚至可以用“革命”来形容这一次升级。SQL Server 2005使 SQL Server 跻身于企业级数据库行列。在数据高可用性方面,SQL Server 2005为用户提供了数据镜像、复制、故障转移群集、日志传送功能。本文向读者简单介绍SQL Server 2005的复制功能。

    一、 “复制”简介

    复制是将数据或数据库对象从一个数据库复制和分发到另外一个数据库,并进行数据同步,从而使源数据库和目标数据库保持一致。使用复制,可以在局域网和广域网、拨号连接、无线连接和 Internet 上将数据分发到不同位置以及分发给远程或移动用户。

    一组SQL Server 2005复制有发布服务器、分发服务器、订阅服服务器(图1:复制服务器之间的关系图)组成,它们之间的关系类似于书报行业的报社或出版社、邮局或书店、读者之间的关系。

    以报纸发行为例说明,发布服务器类似于报社,报社提供报刊的内容并印刷,是数据源;分发服务器相当于邮局,它将各报社的报刊送(分发)到订户手中;订阅服 务器相当于订户,从邮局那里收到报刊。在实际的复制中,发布服务器是一种数据库实例,它通过复制向其他位置提供数据,分发服务器也是一种数据库实例,它起 着存储区的作用,用于复制与一个或多个发布服务器相关联的特定数据。每个发布服务器都与分发服务器上的单个数据库(称作“分发数据库”)相关联。分发数据 库存储复制状态数据和有关发布的元数据,并且在某些情况下为从发布服务器向订阅服务器移动的数据起着排队的作用。在很多情况下,一个数据库服务器实例充当 发布服务器和分发服务器两个角色,这称为“本地分发服务器”。订阅服务器是接收复制数据的数据库实例。一个订阅服务器可以从多个发布服务器和发布接收数 据。

点击查看原图

图1

    复制有三种类:事务复制、快照复制、合并复制。

  •  

    ? 事务复制:事务复制是将复制启用后的所有发布服务器上发布的内容在修改时传给订阅服务器,数据更改将按照其在发布服务器上发生的顺序和事务边界,应用于订阅服务器,在发布内部可以保证事务的一致性。

     

  •  

    ? 快照复制:快照复制将数据以特定时刻的瞬时状态分发,而不监视对数据的更新。发生同步时,将生成完整的快照并将其发送到订阅服务器。

     

  •  

    ? 合并复制:合并复制通常是从发布数据库对象和数据的快照开始,并且用触发器跟踪在发布服务器和订阅服务器上所做的后续数据更改和架构修改。订阅服务器在连接到网络时将与发布服务器进行同步,并交换自上次同步以来发布服务器和订阅服务器之间发生更改的所有行。

     

二、复制实例

 

    这里以配置一个事务复制来说明复制配置过程 。

    试验在同一台机器的二个实例间进行,实例名分别是SERVER01、SERVER02 。将SERVER01配置发布服务器和分发服务器(也就是前面提到的“本地分发服务器”),SERVER02配置为订阅服务器。在本例中将 SERVER01中一个DBCoper库中person表作为发布的数据,在发布前请确保person表有主键、SQL SERVER 代理自动启动、发布数据库是日志是完整模式。

    第一步:完全备份SERVER01 DBCopy数据库,在SERVER02上恢复DBCopy数据库(复制前的同步,使用发布的源和目标数据一致)。

       第二步: 在SERVER01上设置发布和分发。

    A、 在SERVER01的复制节点-->本地发布右键选择新建订阅(如图2)。

点击查看原图

图2

    B、 在新建发布向导中首先要求选择分发服务器,本例选择本机作为分发服务器,选择默认值(如图3)。

点击查看原图

图3

    C、 向导第三步要求选择快照的路径,一般情况下选择默认路径。

    D、 向导第四步选择发布的数据库(如图四),选择DBCopy。

点击查看原图

图4

    E、 接着选择发布的类型,这里选择事务复制(如图5)。

点击查看原图

图5

    F、 选择发布的内容(PERSON),这里不仅可以发表,还可以发布其他的数据库对象,比如函数。在选择某一个表之后还可以选择发布某一列或几列。在这个步骤下一个界面中可以选择要发布的行。

点击查看原图

图6

    G、 设置发布的内容之后设置 运行SQL代理的账号。设置如下:

点击查看原图

图7

    H、 设置上一步之后,给复制起个名字PersonCopy。到此为止,发布和分发已配置成功(如图8)。

点击查看原图

图8第三步:配置订阅

    订阅有两种方种,一种是由发布服务器向订阅服务器“推”数据,由订阅服务器去请求订阅数据。本例在SERVER02上设置请求订阅。

    A、 第一步在SERVER02复制节点右击订阅,新建订阅(图9)。

点击查看原图

图9

    B、 选择发布服务器,在下拉列表框中选择查找SQL SERVER 发布服务器,选择SERVER01,就可以看到刚才新建的发布PersonCopy(如图10)。

点击查看原图

图10

    C、 选择订阅方式(如图11), 这里选择请求订阅。

点击查看原图

图11

    D、 选择订阅的本地数据库(如图12)。

点击查看原图

图12

    E、 设置完本地数据库之后要求设置运行代理的安全性,设置成SQL 代理账号。完成以上设置后,订阅已设置完成。

    在SERVER01表中插入一条新记录后,在SERVER02中去检查是否同步过来。一般来说,几乎SERVER01执行完了,SERVER02就可以看到更新后的数据。

 

 

***************************

以上实在网上看到一个网友的文章的,图文并茂的 还不错

自己也在做数据库复制

不过是从sql server2000到 sql server2005

之前复制是成功了的,但是 不知干嘛现在又执行不了了

重做一下

实际验证一下这位仁兄的做法 再来评价一下

 

 

--------20090507

要把订阅服务器上那个新建的订阅的 快照文件夹地址 换成  “\\\\

发布服务器名称\\快找文件夹”

右键点击 订阅服务器的“本地订阅”下的订阅文件,进入“属性”

点击查看原图

属性界面如下,将“4.快照”下面的 “快照文件夹” 改成  “\\\\

发布服务器名称\\快找文件夹”

(我的,改成了\\\\mz02\\ReplData

,mz02是我的SQL Server 2000 发布服务器,ReplData是我在mz02的D盘上建立的快照文件夹,先前被我设置成共享文件夹了)

点击查看原图

发表在 article | 标签为 , | 36条评论

编写简单的脚本解释器

首先声明一下以下文章是跟据我用C#写的脚本解释器的经验之谈,如不认可也请不要找本人。

一般写个脚本解释器需要以下的步骤:

源程序-词法分析-语法分析-生成中间代码-解释中间代码

一、我写的脚本解释器就是跟据上面的过程写的,下面说明一下本脚本解释器的语法。

1、语法规则:

(1)script_begin代表语句开始

(2)script_end代表语句结束

(3)条件语句:if 表达式 语句 endif

(4)循环语句:while 表达式 语句 endwhile

(5)赋值语句:变量=表达式

(6)表达式:

(为方便我们这里使用产生式来说明)

expr->expr+term|expr-term|term|term>=term|term<=term|term==term|term!=term|term>term|term<term|term

term->term*factor|term/factor|factor

factor->(expr)|数字|变量|字符串|!变量

(注意:产生式中的->代表前面的值可以是后面中的任何一个值,|代表着或的意思)

(7)变量:本脚本只有全局变量,我们使用一个结构符号表(另外这个表还保存着关键字等)来保存变量名、类型(说明是变量、关键字等)和值。以下是此符号表的定义:

public struct Symtable

{

public string value;

public string valuestr;

public int toketype;

}

Symtable[] m_table=new Symtable[max_size];

max_size的大小说明了本脚本可以定义的变量数有多少。

2、词法分析:

在这个阶段解释器把读取的字符分为以下类型:

(1)、变量

(2)、数字

(3)、字符串

(4)、+、-、*、/等符号

(5)、if、while等关键字

以下是此过程的代码:

       private int lexan(StreamReader sr)

        {

            m_tmpvalue = "";

            char t;

            while (true)

            {

                t = (char)sr.Read();

                if (sr.EndOfStream)

                {

                    return -1;

                }

                if (t == ' ')

                {

                }

                else if (t == '\r')

                {

                    t = (char)sr.Read();

                    if (t == '\n')

                    {

                        error_line_num++;

                    }

                }

                else if (Char.IsDigit(t))

                {

                    while (Char.IsDigit(t))

                    {

                        m_tmpvalue += t;

                        t = (char)sr.Peek();

                        if (Char.IsDigit(t))

                        {

                            sr.Read();

                        }

                    }

                    return m_numtype;

                }

                else if (isStrword(t))

                {

                    while (isStrword(t))

                    {

                        m_tmpvalue += t;

                        t = (char)sr.Peek();

                        if (isStrword(t))

                        {

                            sr.Read();

                        }

                    }

                    int p = LookUp(m_tmpvalue);

                    if (p == -1)

                    {

                        p = InertTable(m_tmpvalue, m_idtype);

                    }

                    return m_symtable[p].toketype;

                }

                else if (isSingleword(t))

                {

                    return (int)t;

                }

                else if (isDoubleword(t))

                {

                    char tmpc = (char)sr.Peek();

                    if (tmpc == '=')

                    {

                        sr.Read();

                        if (t == '>')

                        {

                            return m_largede;

                        }

                        else if (t == '<')

                        {

                            return m_smallde;

                        }

                        else if (t == '!')

                        {

                            return m_bude;

                        }

                        else if (t == '=')

                        {

                            return m_dede;

                        }

                        else

                        {

                            CException.ScriptError("格式错误!");

                        }

                    }

                    return (int)t;

                }

                else if (t == '\"')

                {

                    t=(char)sr.Read();

                    while (t != '\"')

                    {

                        m_tmpvalue += t;

                        t = (char)sr.Read();

                    }

                    return m_strtype;

                }

                else

                {

                    CException.ScriptError("错误格式");

                    return -1;

                }

            }

      }

2、语法分析:

在这个过程中对读取的字符按产生式的进行分阶段处理;表达式从中缀变成后缀,中缀就像3+4+5的后缀就是34+5+并面在后缀中是不需要括号的。这个阶段还要生成中间代码。

代码如下:

        private void match(int t, StreamReader sr)
        {
            if (t == m_headtype)
            {
                m_headtype = lexan(sr);
            }
            else
            {
                CException.ScriptError("错误格式");
            }
        }
        private void WriteToMemory(string s)
        {
            m_zhongJingdaima += s;
        }
        public int stmtExplain(StreamReader sr)
        {
            if (m_headtype == m_begintype)
            {
                match(m_headtype, sr);
                int ret = stmtExplain(sr);
                while (ret != 0)
                {
                    ret = stmtExplain(sr);
                }
            }
            else if (m_headtype == m_endtype)
            {
                match(m_headtype, sr);
                return 0;
            }
            else if (m_headtype == m_iftype)
            {
                WriteToMemory("label:" + label_line + "\n");
                label_line++;
                match(m_headtype, sr);
                expr(sr);
                WriteToMemory("gofalse label:" + label_line + " \n");

                stmtExplain(sr);
                match(m_endif, sr);
                WriteToMemory("label:" + label_line + "\n");
                label_line++;
            }
            else if (m_headtype == m_whiletype)
            {
                int tmplabel=label_line;
                WriteToMemory("label:" + label_line + "\n");
                label_line++;
                match(m_headtype, sr);
                expr(sr);
                WriteToMemory("gofalse label:" + label_line + " \n");

                stmtExplain(sr);
                match(m_endwhile, sr);
                WriteToMemory("goto label:" + tmplabel + " \n");
                WriteToMemory("label:" + label_line + "\n");
                label_line++;
            }
            else if (m_headtype == m_funtiontype)
            {
                WriteToMemory("function ");
                WriteToMemory(m_tmpvalue);

                WriteToMemory("\n");
                match(m_headtype, sr);
            }
            else if (m_headtype == m_idtype)
            {

                int index = LookUp(m_tmpvalue);
                WriteToMemory("lvalue " + m_tmpvalue + "\n");
                match(m_headtype, sr);
                match('=', sr);
                expr(sr);
                WriteToMemory(":=\n");
            }
            return 1;
        }
        private void expr(StreamReader sr)
        {
            term(sr);
            while (true)
            {
                switch (m_headtype)
                {
                    case '+':
                        {
                            match(m_headtype, sr);
                            term(sr);
                            WriteToMemory("+\n");
                            continue;
                        }
                    case '-':
                        {
                            match(m_headtype, sr);
                            term(sr);
                            WriteToMemory("-\n");
                            continue;
                        }
                    case m_largede:
                        {
                            match(m_headtype, sr);
                            term(sr);
                            WriteToMemory(">=\n");
                            continue;
                        }

                    case m_smallde:
                        {
                            match(m_headtype, sr);
                            term(sr);
                            WriteToMemory("<=\n");
                            continue;
                        }
                    case m_bude:
                        {
                            match(m_headtype, sr);
                            term(sr);
                            WriteToMemory("!=\n");
                            continue;
                        }
                    case m_dede:
                        {
                            match(m_headtype, sr);
                            term(sr);
                            WriteToMemory("==\n");
                            continue;
                        }
                    case '>':
                        {
                            match(m_headtype, sr);
                            term(sr);
                            WriteToMemory(">\n");
                            continue;
                        }
                    case '<':
                        {
                            match(m_headtype, sr);
                            term(sr);
                            WriteToMemory("<\n");
                            continue;
                        }
                    default:
                        return;
                }
            }
        }
        private void term(StreamReader sr)
        {
            factor(sr);
            while (true)
            {
                switch (m_headtype)
                {
                    case '*':
                        {
                            match(m_headtype, sr);
                            factor(sr);
                            WriteToMemory("*\n");
                            continue;
                        }
                    case '/':
                        {
                            match(m_headtype, sr);
                            factor(sr);
                            WriteToMemory("/\n");
                            continue;
                        }
                    default:
                        return;
                }
            }
        }
        private void factor(StreamReader sr)
        {
           
            switch (m_headtype)
            {
                case '(':
                    {
                        match('(', sr);
                        expr(sr);
                        match(')', sr);
                        break;
                    }
                case m_numtype:
                    {
                        WriteToMemory("push " + m_tmpvalue + "\n");
                        match(m_numtype, sr);
                        break;
                    }
                case m_idtype:
                    {
                        WriteToMemory("rvalue "+m_tmpvalue+"\n");
                        match(m_idtype, sr);
                        break;
                    }
                case m_strtype:
                    {
                        WriteToMemory("push " + m_tmpvalue + "\n");
                        match(m_headtype, sr);
                        break;
                    }
                case '!':
                    {   
                        match(m_headtype, sr);
                        match(m_headtype, sr);
                        WriteToMemory("oppvalue "+m_tmpvalue+"\n");
                        break;
                    }
                case m_funtiontype:
                    {
                        WriteToMemory("function ");
                        WriteToMemory(m_tmpvalue);

                        WriteToMemory("\n");
                        match(m_headtype, sr);
                        break;
                    }
                default:
                    CException.ScriptError("错误格式!");
                    break;
            }
        }
        private string ReadStrLine(string s)
        {
            int tmpindex = s.IndexOf("\n",m_excuteline_index);
            string tmpstr;
            if (tmpindex != -1)
            {
                int readlength=tmpindex-m_excuteline_index;
                tmpstr = s.Substring(m_excuteline_index,readlength);
                m_excuteline_index = tmpindex+1;
            }
            else
            {
                return null;
            }
            return tmpstr;
        }

 

二、现在我们的已把你的难以解释的脚本语言生成容易解释的中间代码,现在开始解释中间代码,为完成这个目标我们先看下中间语言的语法规则:

中间语法:

Push / 把/压栈

Lvalue /取值压栈

+ 弹出栈顶两个值相加后压栈

function 函数

等等

 

      private void ExectStr()
        {
            string retstr;
            retstr = ReadStrLine(m_zhongJingdaima);
            while (retstr != null)
            {
                if (retstr.StartsWith("lvalue"))
                {
                    string[] split = retstr.Split(new char[] { ' ' });
                    int index=LookUp(split[1]);
                    m_stack.push(Convert.ToString(index));
                }
                else if (retstr.StartsWith("function"))
                {
                    string tmpvalue = retstr.Substring(9);
                    string pushvalue = null;
                    int paramstart = tmpvalue.IndexOf('(') + 1;
                    int paramend = tmpvalue.LastIndexOf(')');
                    int paramlength = paramend - paramstart;
                    string subparam = tmpvalue.Substring(paramstart, paramlength);
                    ArrayList split=new ArrayList();

                    while (true)
                    {
                        string paramstr="";
                        int startindex=0;
                        if (subparam.StartsWith("\""))
                        {
                            startindex = subparam.IndexOf("\"", 1);
                            if (startindex == -1)
                            {
                                break;
                            }
                            paramstr = subparam.Substring(1, startindex - 1);
                            startindex = subparam.IndexOf(",", startindex);

                        }
                        else
                        {
                           
                            startindex = subparam.IndexOf(",", startindex);
                            if (startindex == -1)
                            {
                                paramstr = subparam;
                            }
                            else
                            {
                                paramstr = subparam.Substring(0, startindex);
                            }
                            int tmplookindex = LookUp(paramstr);
                            if (tmplookindex != -1)
                            {
                                paramstr = m_symtable[tmplookindex].value;
                            }
                        }
                        split.Add(paramstr);                     
                        if (startindex == -1)
                        {
                            break;
                        }
                        startindex++;
                        subparam = subparam.Substring(startindex);      
                    }

                   

                    if (tmpvalue.StartsWith("Strcat"))
                    {
                        pushvalue = m_globalFunction.Strcat(split[0].ToString(), split[1].ToString());
                    }
                    else if (tmpvalue.StartsWith("StartSplit"))
                    {
                        pushvalue = m_globalFunction.StartSplit(split[0].ToString(), split[1].ToString());
                    }
                    else if (tmpvalue.StartsWith("NextSplit"))
                    {
                        pushvalue = m_globalFunction.NextSplit(split[0].ToString(), split[1].ToString());
                    }
                    else if (tmpvalue.StartsWith("GetSplit"))
                    {
                        pushvalue = m_globalFunction.GetSplit(split[0].ToString(), split[1].ToString(), Convert.ToInt32(split[2]));
                    }
                    else
                    {
                        CException.ScriptError("错误格式!");
                    }
                    if (pushvalue != null)
                    {
                        m_stack.push(pushvalue);
                    }
                }
                else if (retstr.StartsWith("push"))
                {
                    //int index=retstr.IndexOf(' ', 0);
                    string tmpstr = retstr.Substring(5);
                    m_stack.push(tmpstr);
                }
                else if (retstr.StartsWith("oppvalue"))
                {
                    string[] split = retstr.Split(new char[] { ' ' });
                    int index = LookUp(split[1]);
                    bool tmpbool = !Convert.ToBoolean(m_symtable[index].value);
                    m_stack.push(Convert.ToString(tmpbool));
                }
                else if (retstr.StartsWith("rvalue"))
                {
                    string[] split = retstr.Split(new char[] { ' ' });
                    int index = LookUp(split[1]);
                    m_stack.push(m_symtable[index].value);
                }
                else if (retstr.StartsWith(":="))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    m_symtable[Convert.ToInt32(ltmpvalue)].value = rtmpvalue;
                }
                else if (retstr.StartsWith("+"))
                {
                    string ltmpvalue = m_stack.pop();
                    string rtmpvalue = m_stack.pop();
                    string totalvalue = Convert.ToString(Convert.ToInt32(ltmpvalue) + Convert.ToInt32(rtmpvalue));
                    m_stack.push(totalvalue);
                }
                else if (retstr.StartsWith("*"))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    string totalvalue = Convert.ToString(Convert.ToInt32(ltmpvalue) * Convert.ToInt32(rtmpvalue));
                    m_stack.push(totalvalue);
                }
                else if (retstr.StartsWith("/"))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    string totalvalue = Convert.ToString(Convert.ToInt32(ltmpvalue) / Convert.ToInt32(rtmpvalue));
                    m_stack.push(totalvalue);
                }
                else if (retstr.StartsWith("-"))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    string totalvalue = Convert.ToString(Convert.ToInt32(ltmpvalue) - Convert.ToInt32(rtmpvalue));
                    m_stack.push(totalvalue);
                }
                else if (retstr.StartsWith(">="))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    if (Convert.ToInt32(ltmpvalue) >= Convert.ToInt32(rtmpvalue))
                    {
                        m_stack.push("true");
                    }
                    else
                    {
                        m_stack.push("false");
                    }
                }
                else if (retstr.StartsWith("!="))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    if (Convert.ToInt32(ltmpvalue) != Convert.ToInt32(rtmpvalue))
                    {
                        m_stack.push("true");
                    }
                    else
                    {
                        m_stack.push("false");
                    }
                }
                else if (retstr.StartsWith("<="))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    if (Convert.ToInt32(ltmpvalue) <= Convert.ToInt32(rtmpvalue))
                    {
                        m_stack.push("true");
                    }
                    else
                    {
                        m_stack.push("false");
                    }
                }
                else if (retstr.StartsWith(">"))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    if (Convert.ToInt32(ltmpvalue) > Convert.ToInt32(rtmpvalue))
                    {
                        m_stack.push("true");
                    }
                    else
                    {
                        m_stack.push("false");
                    }
                }
                else if (retstr.StartsWith("<"))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    if (Convert.ToInt32(ltmpvalue) < Convert.ToInt32(rtmpvalue))
                    {
                        m_stack.push("true");
                    }
                    else
                    {
                        m_stack.push("false");
                    }
                }
                else if (retstr.StartsWith("=="))
                {
                    string rtmpvalue = m_stack.pop();
                    string ltmpvalue = m_stack.pop();
                    if (ltmpvalue == rtmpvalue)
                    {
                        m_stack.push("true");
                    }
                    else
                    {
                        m_stack.push("false");
                    }
                }
                else if (retstr.StartsWith("gofalse"))
                {
                    string rtmpvalue = m_stack.pop();
                    if (!Convert.ToBoolean(rtmpvalue))
                    {
                        string[] split = retstr.Split(new char[] { ' ' });
                        string strtofind = split[1] + "\n";
                        int tmppos = m_zhongJingdaima.IndexOf(strtofind);
                        m_excuteline_index = tmppos;
                    }
                }
                else if (retstr.StartsWith("gotrue"))
                {
                    string rtmpvalue = m_stack.pop();
                    if (Convert.ToBoolean(rtmpvalue))
                    {
                        string[] split = retstr.Split(new char[] { ' ' });
                        string strtofind = split[1] + "\n";
                        int tmppos = m_zhongJingdaima.IndexOf(strtofind);
                        m_excuteline_index = tmppos;
                    }
                }
                else if (retstr.StartsWith("goto"))
                {
                    string[] split = retstr.Split(new char[] { ' ' });
                    string strtofind = split[1] + "\n";
                    int tmppos = m_zhongJingdaima.IndexOf(strtofind);
                    m_excuteline_index = tmppos;
                }
                retstr = ReadStrLine(m_zhongJingdaima);
            }
        }

 

发表在 article | 标签为 , | 编写简单的脚本解释器已关闭评论

窥视生命的本质

美国科学家制造出完全由人造基因控制的单细胞细菌

20日,美国科学家宣布世界首例人造生命———完全由人造基因控制的单细胞细菌诞生,并将它命名为“人造儿”。这项具有里程碑意义的实验表明,新的生命体可以在实验室里“被创造”,而不是一定要通过“进化”来完成。

“一个新时代到来”

这项研究由美国基因遗传学顶尖科学家克莱格·凡特主持,历时10多年,耗资超过4000万美元。研究团队共有20多位科学家。

名为“人造儿”的人造细菌内核是移植于实验室、完全人工合成的基因组。凡特博士表示这意味着“一个新时代的到来”。

科学家们首先选取一种名为丝状支原体的细菌,对其基因组进行解码并复制,产生人造的合成基因组。然后,将人造基因组移植入另一种称为山羊支原体的细菌,通过分裂和增生,细菌内部的细胞逐渐为人造基因所控制,最终成为一种全新的生命。在培养皿中,合成细菌的分裂等行为就像天然细菌一样。

科学家们在“人造儿”DNA上写入4个“水印序列”,使其有别于同类的天然细菌,以及在这种生物的后代中识别它的“祖先”。

“当带着水印的细胞活了过来,我们欣喜若狂,它是一个活生生的生物了,成为了我们地球上各种生命的一部分。”凡特博士说。

应用前景广阔

尽管这种技术目前仍处于实验阶段,但研究人员相信其运用前景广阔。

研究小组计划,先合成出可供生命存在的最小数量的基因,然后通过向其中弥补其他基因,制造一系列新的微生物,比如可生产生物燃料的细菌、有用的药品、可以从空气中吸收二氧化碳和其他污染物的细菌或是制造合成疫苗所需的蛋白质。

人造生命原理

1. 科学家选取一种名为丝状支原体的细菌,将它的染色体解码。然后利用化学方法一点一点地重新排列DNA。

2. 将重组的DNA碎片放入酵母液中,令其慢慢地重新聚合。

3. 将人造DNA放入另外一个受体细菌中。通过生长和分离,受体细菌产生两个细胞,一个带有人造DNA,另外一个带有天然DNA。

4. 培养皿中的抗生素将带有天然DNA的细胞杀死,只留下人造细胞不断增生。

5. 几个小时之内,受体细菌内原有DNA的所有痕迹全部消失,人造细胞不断繁殖。新的生命诞生了。

■ 链接

反对者称“打开潘多拉魔盒”

“创造生命”再次激起了古老的争论:人类是否可以扮演上帝的角色?

英国牛津大学的伦理学教授朱利安·萨乌莱斯库认为:“凡特推开了人类历史上最重要、最基础的那扇大门———窥视生命的本质。他直接扮演了上帝的角色———创造出自然界原本不存在的新生命。”

一个名为“人类基因学警告”的团体负责人戴维·金说:“凡特的研究无异于打开了潘多拉的魔盒。”反对者认为,人造的有机体如果扩散到自然界,引发生物基因变化,有可能造成环境灾难,它们还有可能被用来制造生物武器。

发表在 info | 窥视生命的本质已关闭评论

用户体验设计

------------------------------------------------------------

UED = user experience design,用户体验设计

 

  UED的本意是用户体验设计,是英文User Experience Design的缩写。通常的理解,我们做的一切都是为了呈现在您眼前的页面。

全称是Customer Research & User Experience Design Center(即用户研究与体验设计中心)

-------------------------------------------------------------

观察各领导先驱者,他们走在你前面

是反省还是遥望,成功是必然还是偶然?

淘宝UED

蓝色理想

携程UED

网易UED

人人网FED

腾讯CDC

腾讯ISD

盛大UED

搜狐UED

口碑网UED

支付宝UED

发表在 mood | 用户体验设计已关闭评论

HTTP(CODE)代码

Information Codes | Success Codes | Redirection Codes | Failure Codes | Server Error Codes | Internet API Error Codes | FTP API Error Codes | Gopher API Error Codes | HTTP API Error Codes | Additional Internet API Error Codes

Information Codes

100 - Continue
101 - Switching Protocols

Top

Success Codes

200 - OK
201 - Created
202 - Accepted
203 - Non-Authoritative Information (for DNS)
204 - No Content
205 - Reset Content
206 - Partial Content

Top

Redirection Codes

300 - Multiple Choices
301 - Moved Permanently
302 - Moved Temporarily
303 - See Other
304 - Not Modified
305 - Use Proxy
307 - Redirect Keep Verb

Top

Failure Codes

400 - Bad Request
401 - Unauthorized
402 - Payment Required
403 - Forbidden
404 - Not Found
405 - Bad Request
406 - Not Acceptable
407 - Proxy Authentication Required
408 - Request Timed-Out
409 - Conflict
410 - Gone
411 - Length Required
412 - Precondition Failed
413 - Request Entity Too Large
414 - Request, URI Too Large
415 - Unsupported Media Type

Top

Server Error Codes

500 - Internal Server Error
501 - Not Implemented
502 - Bad Gateway
503 - Server Unavailable
504 - Gateway Timed-Out
505 - HTTP Version not supported

Top

Internet API Error Codes

12001 - Out of Handles
12002 - Timeout
12003 - Extended Error
12004 - Internal Error
12005 - Invalid URL
12006 - Unrecognized Scheme
12007 - Name Not Resolved
12008 - Protocol Not Found
12009 - Invalid Option
12010 - Bad Option Length
12011 - Option not Settable
12012 - Shutdown
12013 - Incorrect User Name
12014 - Incorrect Password
12015 - Login Failure
12016 - Invalid Option
12017 - Operation Cancelled
12018 - Incorrect Handle Type
12019 - Inccorect Handle State
12020 - Not Proxy Request
12021 - Registry Value Not Found
12022 - Bad Registry Parameter
12023 - No Direct Access
12024 - No Content
12025 - No Callback
12026 - Request Pending
12027 - Incorrect Format
12028 - Item Not Found
12029 - Cannot Connect
12030 - Connection Aborted
12031 - Connection Reset
12032 - Force Retry
12033 - Invalid Proxy Request
12034 - Need UI
12035 - Not Defined in WinInet
12036 - Handle Exists
12037 - See Cert Date Invalid
12038 - See Cert CN Invalid
12039 - HTTP to HTTPS on Redir
12040 - HTTPs to HTTP on Redir
12041 - Mixed Security
12042 - Chg Post is Non Secure
12043 - Post is Non Secure
12044 - Client Auth Cert Needed
12045 - Invalid CA (Cert)
12046 - Client Auth Not Setup
12047 - Async Thread Failed
12048 - Redirect Scheme Changed
12049 - Dialog Pending
12050 - Retry Dialog
12052 - Https Http Submit Redir
12053 - Insert Cdrom
12171 - Failed DueToSecurityCheck

Top

FTP API Error Codes

12110 - Transfer in Progress
12111 - FTP Dropped

Top

Gopher API Error Codes

12130 - Protocol Error
12131 - Not File
12132 - Data Error
12133 - End of Data
12134 - Invalid Locator
12135 - Invalid Locator Type
12136 - Not Gopher Plus
12137 - Attribute Not Found
12138 - Unknown Locator

Top

HTTP API Error Codes

12150 - Header Not Found
12151 - Downlevel Server
12152 - Invalid Server Response
12153 - Invalid Header
12154 - Invalid Query Request
12155 - Header Already Exists
12156 - Redirect Failed
12157 - Security Channel Error
12158 - Unable to Cache File
12159 - TCP/IP not installed
12160 - Not Redirected
12161 - Cookie Needs Confirmation
12162 - Cookie Declined
12168 - Redirect Needs Confirmation

Top

Additional Internet API Error Codes

12157 - Security Channel Error
12158 - Unable To Cache File
12159 - Tcpip Not Installed
12163 - Disconnected
12164 - Server Unreachable
12165 - Proxy Server Unreachable
12166 - Bad Auto Proxy Script
12167 - Unable To Download Script
12169 - Sec Invalid Cert
12170 - Sec Cert Revoked

发表在 article | HTTP(CODE)代码已关闭评论

Win2003网站服务器的安全配置全攻略

======================= 第一类 ===============================

本配置仅适合Win2003,部分内容也适合于Win2000。很多人觉得3389不安全,其实只要设置好,密码够长,攻破3389也不是件容易的事情,我觉得别的远程软件都很慢,还是使用了3389连接。

经测试,本配置在Win2003 + IIS6.0 + Serv-U + SQL Server 的单服务器多网站中一切正常。以下配置中打勾的为推荐进行配置,打叉的为可选配置。

一、系统权限的设置

1、磁盘权限

系统盘只给 Administrators 组和 SYSTEM 的完全控制权限

其他磁盘只给 Administrators 组完全控制权限

系统盘\Documents and Settings 目录只给 Administrators 组和 SYSTEM 的完全控制权限

系统盘\Documents and Settings\All Users 目录只给 Administrators 组和 SYSTEM 的完全控制权限

系统盘\windows\system32\config\ 禁止guests组

系统盘\Documents and Settings\All Users\「开始」菜单\程序\ 禁止guests组

系统盘\windowns\system32\inetsrv\data\ 禁止guests组

系统盘\Windows\System32\ at.exe、attrib.exe、cacls.exe、net.exe、net1.exe、netstat.exe、regedit.exe 文件只给 Administrators 组和 SYSTEM 的完全控制权限

系统盘\Windows\System32\ cmd.exe、format.com 仅 Administrators 组完全控制权限

把所有(Windows\system32和Windows\ServicePackFiles\i386) format.com 更名为 format_nowayh.com

2、本地安全策略设置

开始菜单->管理工具->本地安全策略

A、本地策略-->审核策略

审核策略更改 成功 失败

审核登录事件 成功 失败

审核对象访问失败

审核过程跟踪 无审核

审核目录服务访问失败

审核特权使用失败

审核系统事件 成功 失败

审核账户登录事件 成功 失败

审核账户管理 成功 失败

B、本地策略-->用户权限分配

关闭系统:只有Administrators组、其它全部删除。

通过终端服务拒绝登陆:加入Guests组

通过终端服务允许登陆:加入Administrators、Remote Desktop Users组,其他全部删除

C、本地策略-->安全选项

交互式登陆:不显示上次的用户名 启用

网络访问:不允许SAM帐户和共享的匿名枚举 启用

网络访问:不允许为网络身份验证储存凭证 启用

网络访问:可匿名访问的共享 全部删除

网络访问:可匿名访问的命全部删除

网络访问:可远程访问的注册表路径全部删除

网络访问:可远程访问的注册表路径和子路径全部删除

帐户:重命名来宾帐户重命名一个帐户

帐户:重命名系统管理员帐户 重命名一个帐户

D、账户策略-->账户锁定策略

将账户设为“5次登陆无效”,“锁定时间为30分钟”,“复位锁定计数设为30分钟”

二、其他配置

√·把Administrator账户更改

管理工具→本地安全策略→本地策略→安全选项

√·新建一无任何权限的假Administrator账户

管理工具→计算机管理→系统工具→本地用户和组→用户

更改描述:管理计算机(域)的内置帐户

×·重命名IIS来宾账户

1、管理工具→计算机管理→系统工具→本地用户和组→用户→重命名IUSR_ComputerName

2、打开 IIS 管理器→本地计算机→属性→允许直接编辑配置数据库

3、进入Windows\system32\inetsrv文件夹→MetaBase.xml→右键编辑→找到"AnonymousUserName"→写入"IUSR_"新名称→保存

4、关闭"允许直接编辑配置数据库"

√·禁止文件共享

本地连接属性→去掉"Microsoft网络的文件和打印共享"和"Microsoft 网络客户端"前面的"√"

√·禁止NetBIOS(关闭139端口)

本地连接属性→TCP/IP属性→高级→WINS→禁用TCP/IP上的NetBIOS

管理工具→计算机管理→设备管理器→查看→显示隐藏的设备→非即插即用驱动程序→禁用 NetBios over tcpip→重启

√·防火墙的设置

本地连接属性→高级→Windows防火墙设置→高级→第一个"设置",勾选FTP、HTTP、远程桌面服务

√·禁止ADMIN$缺省共享、磁盘默认共享、限制IPC$缺省共享(匿名用户无法列举本机用户列表、禁止空连接)

新建REG文件,导入注册表

Windows Registry Editor Version 5.00
 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters]
 "AutoshareWks"=dword:00000000
 "AutoShareServer"=dword:00000000
 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
 "restrictanonymous"=dword:00000001
 

√·删除以下注册表主键

WScript.Network
 WScript.Network.1
 {093FF999-1EA0-4079-9525-9614C3504B74}
 WScript.Shell
 WScript.Shell.1
 {72C24DD5-D70A-438B-8A42-98424B88AFB8}
 Shell.Application
 Shell.Application.1
 {13709620-C279-11CE-A49E-444553540000}
 

√·更改3389端口为12344

这里只介绍如何更改,既然本端口公布出来了,那大家就别用这个了,端口可用windows自带的计算器将10进制转为16进制,16进制数替换下面两个的dword:后面的值(7位数,不够的在前面补0),登陆的时候用10进制,端口更改在服务器重启后生效。新建REG文件,导入注册表

Windows Registry Editor Version 5.00
 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp]
 "PortNumber"=dword:0003038
 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp]
 "PortNumber"=dword:00003038
 

最后别忘了Windows防火墙允许12344端口,关闭3389端口

√·禁止非管理员使用at命令,新建REG文件,导入注册表

Windows Registry Editor Version 5.00
 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
 "SubmitControl"=dword:00000001
 

√·卸载最不安全的组件

运行"卸载最不安全的组件.bat",重启后更名或删掉Windows\System32\里的wshom.ocx和shell32.dll

----------------卸载最不安全的组件.bat-----------------
 regsvr32/u %SystemRoot%\System32\wshom.ocx
 regsvr32/u %SystemRoot%\System32\shell32.dll
 regsvr32/u %SystemRoot%\System32\wshext.dll
 -------------------------------------------------------
 

√·Windows日志的移动

打开"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\"
 

Application 子项:应用程序日志

Security 子项:安全日志

System 子项:系统日志

分别更改子项的File键值,再把System32\config目录下的AppEvent.Evt、SecEvent.Evt、SysEvent.Evt复制到目标文件夹,重启。
√·Windows日志的保护

1、移动日志后的文件夹→属性→安全→高级→去掉"允许父系的继承权限……"→复制→确定

2、保留System账户和User组,System账户保留除完全控制和修改之外的权限,User组仅保留只读权限

3、AppEvent.Evt、SysEvent.Evt保留Administrator、System账户和User组,Administrator、System账户保留除完全控制和修改之外的权 限,User组仅保留只读权限;

DnsEvent.Evt、SecEvent.Evt保留System账户和User组,System账户保留除完全控制和修改之外的权限,User组仅保留只读权限

√·要手动停止/禁用的服务:Computer Browser、Error reporting service、Microsoft Serch、Print Spooler、Remote Registry、Server 、TCP/IP NetBIOS Helper、Workstation

√·解决在 IIS 6.0 中,无法下载超过4M的附件(现改为10M)

停止IIS服务→打开WINDOWS\system32\inetsrv\→记事本打开MetaBase.xml→找到 AspBufferingLimit 项→值改为 10485760

√·设置Web上传单个文件最大值为10 MB

停止IIS服务→打开WINDOWS\system32\inetsrv\→记事本打开MetaBase.xml→找到 AspMaxRequestEntityAllowed 项→值改为 10485760

×·重新定位和设置 IIS 日志文件的权限

1、将 IIS 日志文件的位置移动到非系统分区:在非系统的NTFS分区新建一文件夹→打开 IIS 管理器→右键网站→属性→单击"启用日志 记录"框架中的"属性"→更改到刚才创建的文件夹

2、设置 IIS 日志文件的权限:浏览至日志文件所在的文件夹→属性→安全→确保Administrators和System的权限设置为"完全控制"

×·配置 IIS 元数据库权限

打开 Windows\System32\Inetsrv\MetaBase.xml 文件→属性→安全→确认只有 Administrators 组的成员和 LocalSystem 帐户拥有对元 数据库的完全控制访问权,删除所有其他文件权限→确定

解释 Web 内容的权限

打开IIS管理器→右键想要配置的网站的文件夹、网站、目录、虚拟目录或文件

脚本源文件访问,用户可以访问源文件。如果选择"读",则可以读源文件;如果选择"写",则可以写源文件。脚本源访问包括脚本的源代码 。如果"读"或"写"均未选择,则此选项不可用。

读(默认情况下选择):用户可以查看目录或文件的内容和属性。

写:用户可以更改目录或文件的内容和属性。

目录浏览:用户可以查看文件列表和集合。

日志访问:对网站的每次访问创建日志项。

检索资源:允许检索服务检索此资源。这允许用户搜索资源。

√·关闭自动播放

运行组策略编辑器(gpedit.msc)→计算机配置→管理模板→系统→关闭自动播放→属性→已启用→所有驱动器

√·禁用DCOM

运行Dcomcnfg.exe。控制台根节点→组件服务→计算机→右键单击“我的电脑”→属性”→默认属性”选项卡→清除“在这台计算机上启用分布式 COM”复选框。

√·启用父路径

IIS管理器→右键网站→属性→主目录→配置→选项→启用父路径

√·IIS 6.0 系统无任何动作超时时间和脚本超时时间

IIS管理器→右键网站→属性→主目录→配置→选项→分别改为40分钟和180秒

√·删除不必要的IIS扩展名映射

IIS管理器→右击Web站点→属性→主目录→配置→映射,去掉不必要的应用程序映射,主要为.shtml, .shtm, .stm

√·增加IIS对MIME文件类型的支持

IIS管理器→选择服务器→右键→属性→MIME类型(或者右键web站点→属性→HTTP头→MIME类型→新建)添加如下表内容,然后重启IIS,扩展名MIME类型

.iso application/octet-stream
 .rmvb application/vnd.rn-realmedia
 

√·禁止dump file的产生

我的电脑→右键→属性→高级→启动和故障恢复→写入调试信息→无。

dump文件在系统崩溃和蓝屏的时候是一份很有用的查找问题的资料(不然我就照字面意思翻译成垃圾文件了)。然而,它也能够给黑客提供 一些敏感信息比如一些应用程序的密码等。

三、Serv-U FTP服务的设置

√·本地服务器→设置→拦截"FTP_bounce"攻击和FXP

对于60秒内连接超过10次的用户拦截5分钟

√·本地服务器→域→用户→选中需要设置的账号→右边的"同一IP只允许2个登录"

√·本地服务器→域→设置→高级→取消"允许MDTM命令来更改文件的日期/时间"

设置Serv-U程序所在的文件夹的权限,Administrator组完全控制,禁止Guests组和IIS匿名用户有读取权限

服务器消息,自上而下分别改为:

服务器工作正常,现已准备就绪...
 错误!请与管理员联系!
 FTP服务器正在离线维护中,请稍后再试!
 FTP服务器故障,请稍后再试!
 当前账户达到最大用户访问数,请稍后再试!
 很抱歉,服务器不允许匿名访问!
 您上传的东西太少,请上传更多东西后再尝试下载!
 

四、SQL安全设置

审核指向SQL Server的连接

企业管理器→展开服务器组→右键→属性→安全性→失败

修改sa账户密码

企业管理器→展开服务器组→安全性→登录→双击sa账户

SQL查询分析器

use master
 exec sp_dropextendedproc xp_cmdshell
 exec sp_dropextendedproc xp_dirtree
 exec sp_dropextendedproc xp_enumgroups
 exec sp_dropextendedproc xp_fixeddrives
 exec sp_dropextendedproc xp_loginconfig
 exec sp_dropextendedproc xp_enumerrorlogs
 exec sp_dropextendedproc xp_getfiledetails
 exec sp_dropextendedproc Sp_OACreate
 exec sp_dropextendedproc Sp_OADestroy
 exec sp_dropextendedproc Sp_OAGetErrorInfo
 exec sp_dropextendedproc Sp_OAGetProperty
 exec sp_dropextendedproc Sp_OAMethod
 exec sp_dropextendedproc Sp_OASetProperty
 exec sp_dropextendedproc Sp_OAStop
 exec sp_dropextendedproc Xp_regaddmultistring
 exec sp_dropextendedproc Xp_regdeletekey
 exec sp_dropextendedproc Xp_regdeletevalue
 exec sp_dropextendedproc Xp_regenumvalues
 exec sp_dropextendedproc Xp_regread
 exec sp_dropextendedproc Xp_regremovemultistring
 exec sp_dropextendedproc Xp_regwrite
 drop procedure sp_makewebtask
 

(完)

*****************************第二************************************

引用
补充
1终端服务默认端口号:3389。
更改原因:不想让非法用户连接到服务器进行登录实验。当这台服务器托管在外时更不希望发生这种情况,呵呵,还没忘记2000的输入法漏洞吧?
更改方法:
  (1)、第一处[HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Terminal Server \ Wds \ rdpwd \ Tds \ tcp],看到右边的PortNumber了吗?在十进制状态下改成你想要的端口号吧,比如7126之类的,只要不与其它冲突即可。
  (2)、第二处[HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Terminal Server \ WinStations \ RDP-Tcp,方法同上,记得改的端口号和上面改的一样就行了。

2系统盘\Windows\System32\cacls.exe、cmd.exe、net.exe、net1.exe、telnet.exe、ftp.exe 文件只给 Administrators 组和 SYSTEM 的完全控制权限

注册表删除 WScript.Shell、WScript.Shell.1、Wscript.Network、Wscript.Network.1、Shell.application
注册表改名 adodb.stream、Scripting.Dictionary、Scripting.FileSystemObject

3启用防火墙和tcp/ip过滤,再serv-u开启一组端口映射
  80 \ 20 \ 21 \ 2121 \ * 以及serv-u端口组
  

4关闭默认共享
  
  在Windows 2000中,有一个“默认共享”,这是在安装服务器的时候,把系统安装分区自动进行共享,虽然对其访问还需要超级用户的密码,但这是潜在的安全隐患,从服务器的安全考虑,最好关闭这个“默认共享”,以保证系统安全。方法是:单击“开始/运行”,在运行窗口中输入“Regedit”,打开注册表编辑器,展开“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters”项,添加键值AutoShareServer,类型为REG_DWORD,值为0。 这样就可以彻底关闭“默认共享”。

[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run]
"deletenetshare"="c:\\\\deletenetshare.bat"

5防范拒绝服务攻击
禁止响应ICMP重定向报文。此类报文有可能用以攻击,所以系统应该拒绝接受ICMP重定向报文。
"EnableICMPRedirects"=dword:00000000

6 iis部分的配置,mdb防止下载,添加数据库名的如MDB的扩展映射 iislog.dll

7 如何解除FSO上传程序小于200k限制?
 先在服务里关闭IIS admin service服务,找到Windows\System32\Inesrv目录下的Metabase.xml并打开,找到ASPMaxRequestEntityAllowed,将其修改为需要的值。默认为204800,即200K,把它修改为51200000(50M),然后重启IIS admin service服务。

Windows2003下的IIS权限设置
前提:仅针对windows 2003 server SP1 Internet(IIS) 服务器

系统安装在C:\盘

系统用户情况为:
administrators 超级管理员(组)
system 系统用户(内置安全主体)
guests 来宾帐号(组)
iusr_服务器名 匿名访问web用户
iwam_服务器名 启动iis进程用户
www_cnnsc_org 自己添加的用户、添加后删除Users(组)、删除后添加到guests来宾帐号(组)
为加强系统安全、(guest)用户及(iusr_服务器名)用户均被禁用
将访问web目录的全部账户设为guests组、去除其他的组

■盘符 安全访问权限
△C:\盘 administrators(组) 完全控制权限、system(内置安全主体) 完全控制权限
△D:\盘 (如果用户网站内容放置在这个分区中)、administrators(组) 完全控制权限
△E:\盘 administrators(组) 完全控制权限、system(内置安全主体) 完全控制权限
△f:\盘 administrators(组) 完全控制权限、system(内置安全主体) 完全控制权限
△如有其他盘符类推下去.

■禁止系统盘下的EXE文件:
net.exe、cmd.exe、tftp.exe、netstat.exe、regedit.exe、regedt32.exe、at.exe、attrib.exe、cacls.exe
△些文件都设置成 administrators 完全控制权限

■禁止下载Access数据库
△Internet 信息服务(IIS)管理器→网站→属性→主目录→配置→添加
△可执行文件:C:\WINDOWS\twain_32.dll
△扩展名:.mdb
▲如果你还想禁止下载其它的东东
△Internet 信息服务(IIS)管理器→网站→属性→主目录→配置→添加
△可执行文件:C:\WINDOWS\twain_32.dll
△扩展名:.(改成你要禁止的文件名)
▲然后删除扩展名:shtml stm shtm cdx idc cer

■防止列出用户组和系统进程:
△开始→程序→管理工具→服务
△找到 Workstation 停止它、禁用它

■卸载最不安全的组件:
△开始→运行→cmd→回车键
▲cmd里输入:
△regsvr32/u C:\WINDOWS\system32\wshom.ocx
△del C:\WINDOWS\system32\wshom.ocx
△regsvr32/u C:\WINDOWS\system32\shell32.dll
△del C:\WINDOWS\system32\shell32.dll
△也可以设置为禁止guests用户组访问

■解除FSO上传程序小于200k限制:
△在服务里关闭IIS admin service服务
△打开 C:\WINDOWS\system32\inetsrv\MetaBase.xml
△找到ASPMaxRequestEntityAllowed
△将其修改为需要的值、默认为204800、即200K、把它修改为51200000(50M)、然后重启
IIS admin service服务

■禁用IPC连接
△开始→运行→regedit
△找到如下组建(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa)中的
(restrictanonymous)子键
△将其值改为1即

■清空远程可访问的注册表路径:
△开始→运行→gpedit.msc
△依次展开“计算机配置→Windows 设置→安全设置→本地策略→安全选项”
△在右侧窗口中找到“网络访问:可远程访问的注册表路径”
△然后在打开的窗口中、将可远程访问的注册表路径和子路径内容全部设置为空即

■关闭不必要的服务
△开始→程序→管理工具→服务
△Telnet、TCP\IP NetBIOS Helper

■解决终端服务许可证过期的办法
△如果你服务器上已经开着终端服务、那就在添加删除程序里删除终端服务和终端授权
服务
△我的电脑--右键属性--远程---远程桌面、打勾、应用
△重启服务器、OK了、再也不会提示过期了

■取消关机原因提示
△开始→运行→gpedit.msc
△打开组策略编辑器、依次展开
△计算机配置→管理模板→系统
△双击右侧窗口出现的(显示“关闭事件跟踪程序”)
△将(未配置)改为(已禁用)即可

***************************第三******************************
1、按照Windows2003安装光盘的提示安装,默认情况下2003没有把IIS6.0安装在系统里面。
2、IIS6.0的安装
  开始菜单—>控制面板—>添加或删除程序—>添加/删除Windows组件
  应用程序 ———ASP.NET(可选)
  |——启用网络 COM+ 访问(必选)
  |——Internet 信息服务(IIS)———Internet 信息服务管理器(必选) 
    |——公用文件(必选)
    |——万维网服务———Active Server pages(必选)
    |——Internet 数据连接器(可选)
          |——WebDAV 发布(可选)
         |——万维网服务(必选)
         |——在服务器端的包含文件(可选)
  然后点击确定—>下一步安装。(具体见本文附件1)

3、系统补丁的更新
  点击开始菜单—>所有程序—>Windows Update
  按照提示进行补丁的安装。

4、备份系统
  用GHOST备份系统。

5、安装常用的软件
  例如:杀毒软件、解压缩软件等;安装完毕后,配置杀毒软件,扫描系统漏洞,安装之后用GHOST再次备份系统。

6、先关闭不需荊4a4 ??的端口 开启防火墙 导入IPSEC策略
在”网络连接”里,把不需要的协议和服务都删掉,这里只安装了基本的Internet协议(TCP/IP),由于要控制带宽流量服务,额外安装了Qos数据包计划程序。在高级tcp/ip设置里–”NetBIOS”设置”禁用tcp/IP上的NetBIOS(S)”。在高级选项里,使用”Internet连接防火墙”,这是windows 2003 自带的防火墙,在2000系统里没有的功能,虽然没什么功能,但可以屏蔽端口,这样已经基本达到了一个IPSec的功能。

修改3389远程连接端口
修改注册表.
开始–运行–regedit
依次展开 HKEY_LOCAL_MACHINE/SYSTEM

/CURRENTCONTROLSET/CONTROL/
TERMINAL SERVER/WDS/RDPWD/TDS/TCP
右边键值中 PortNumber 改为你想用的端口号.注意使用十进制(例 10000 )

HKEY_LOCAL_MACHINE/SYSTEM/CURRENTCONTROLSET

/CONTROL/TERMINAL SERVER/
WINSTATIONS/RDP-TCP/
右边键值中 PortNumber 改为你想用的端口号.注意使用十进制(例 10000 )
注意:别忘了在WINDOWS2 45d 003自带的防火墙给+上10000端口
修改完毕.重新启动服务器.设置生效.

二、用户安全设置
1、禁用Guest账号
在计算机管理的用户里面把Guest账号禁用。为了保险起见,最好给Guest加一个复杂的密码。你可以打开记事本,在里面输入一串包含特殊字符、数字、字母的长字符串,然后把它作为Guest用户的密码拷进去。
2、限制不必要的用户
去掉所有的Duplicate User用户、测试用户、共享用户等等。用户组策略设置相应权限,并且经常检查系统的用户,删除已经不再使用的用户。这些用户很多时候都是黑客们入侵系统的突破口。
3、把系统Administrator账号改名
大家都知道,Windows 2003 的Administrator用户是不能被停用的,这意味着别人可以一遍又一遍地尝试这个用户的密码。尽量把它伪装成普通用户,比如改成Guesycludx。
4、创建一个陷阱用户
什么是陷阱用戍 487 ??即创建一个名为“Administrator”的本地用户,把它的权限设置成最低,什么事也干不了的那种,并且加上一个超过10位的超级复杂密码。这样可以让那些 Hacker们忙上一段时间,借此发现它们的入侵企图。
5、把共享文件的权限从Everyone组改成授权用户
任何时候都不要把共享文件的用户设置成“Everyone”组,包括打印共享,默认的属性就是“Everyone”组的,一定不要忘了改。
6、开启用户策略
使用用户策略,分别设置复位用户锁定计数器时间为20分钟,用户锁定时间为20分钟,用户锁定阈值为3次。 (该项为可选)
7、不让系统显示上次登录的用户名
默认情况下,登录对话框中会显示上次登录的用户名。这使得别人可以很容易地得到系统的一些用户名,进而做密码猜测。修改注册表可以不让对话框里显示上次登录的用户名。方法为:打开注册表编辑器并找到注册表“HKLM\Software\Microsoft\Windows T

\CurrentVersion\Winlogon\Dont-DisplayLastUserName” 4ad ,把REG_SZ的键值改成1。
密码安全设置
1、使用安全密码
一些公司的管理员创建账号的时候往往用公司名、计算机名做用户名,然后又把这些用户的密码设置得太简单,比如“welcome”等等。因此,要注意密码的复杂性,还要记住经常改密码。
2、设置屏幕保护密码
这是一个很简单也很有必要的操作。设置屏幕保护密码也是防止内部人员破坏服务器的一个屏障。
3、开启密码策略
注意应用密码策略,如启用密码复杂性要求,设置密码长度最小值为6位 ,设置强制密码历史为5次,时间为42天。
4、考虑使用智能卡来代替密码
对于密码,总是使安全管理员进退两难,密码设置简单容易受到黑客的攻击,密码设置复杂又容易忘记。如果条件允许,用智能卡来代替复杂的密码是一个很好的解决方法。
三、系统权限的设置
1、磁盘权限
  系统盘及所有磁盘只给 Administrators 组和 SYSTEM 的完全控制 4ce 权限
  系统盘\Documents and Settings 目录只给 Administrators 组和 SYSTEM 的完全控制权限
  系统盘\Documents and Settings\All Users 目录只给 Administrators 组和 SYSTEM 的完全控制权限
  系统盘\Windows\System32\cacls.exe、cmd.exe、net.exe、

net1.exe、ftp.exe、tftp.exe、telnet.exe 、

netstat.exe、regedit.exe、at.exe、

attrib.exe、format.com、del文件只给 Administrators 组和SYSTEM 的完全 控制权限
另将\System32\cmd.exe、format.com、ftp.exe转移到其他目录或更名
  Documents and Settings下所有些目录都设置只给adinistrators权限。并且要一个一个目录查看,包括下面的所有子目录。
删除c:\inetpub目录

2、本地安全策略设置
  开始菜单—>管理工具—>本地安全策略
  A、本地策略——>审核策略
  审核策略更改   成功 失败  
  审核登录事件   成功 失败
  审核对象访问      失败
  审核过程跟踪  4ed   无审核
  审核目录服务访问    失败
  审核特权使用      失败
  审核系统事件   成功 失败
  审核账户登录事件 成功 失败
  审核账户管理   成功 失败

  B、本地策略——>用户权限分配
  关闭系统:只有Administrators组、其它全部删除。
  通过终端服务允许登陆:只加入Administrators,

Remote Desktop Users组,其他全部删除

  C、本地策略——>安全选项
  交互式登陆:不显示上次的用户名       启用
  网络访问:不允许SAM帐户和共享的匿名枚举  启用
  网络访问:不允许为网络身份验证储存凭证   启用
  网络访问:可匿名访问的共享         全部删除
  网络访问:可匿名访问的命          全部删除
  网络访问:可远程访问的注册表路径      全部删除
  网络访问:可远程访问的注册表路径和子路径  全部删除
  帐户:重命名来宾帐捊509 ??            重命名一个帐户
  帐户:重命名系统管理员帐户         重命名一个帐户

3、禁用不必要的服务 开始-运行-services.msc
TCP/IPNetBIOS Helper提供 TCP/IP 服务上的 NetBIOS 和网络上客户端的 NetBIOS 名称解析的支持而使用户能够共享
文件、打印和登录到网络
Server支持此计算机通过网络的文件、打印、和命名管道共享
  Computer Browser 维护网络上计算机的最新列表以及提供这个列表
Task scheduler 允许程序在指定时间运行
Messenger 传输客户端和服务器之间的 NET SEND 和 警报器服务消息
  Distributed File System: 局域网管理共享文件,不需要可禁用
  Distributed linktracking client:用于局域网更新连接信息,不需要可禁用
  Error reporting service:禁止发送错误报告
  Microsoft Serch:提供快速的单词搜索,不需要可禁用
  NTLMSecuritysupportprovide:telnet服务和Microsoft Serch用的,不需要可禁用
  PrintSpooler:如果没有打印机可 521 禁用
  Remote Registry:禁止远程修改注册表
  Remote Desktop Help Session Manager:禁止远程协助
Workstation 关闭的话远程NET命令列不出用户组
  以上是在Windows Server 2003 系统上面默认启动的服务中禁用的,默认禁用的服务如没特别需要的话不要启动。

4、修改注册表
修改注册表,让系统更强壮
1、隐藏重要文件/目录可以修改注册表实现完全隐藏
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\ Current-Version\Explorer\Advanced\Folder\Hi-dden\SHOWALL”,鼠标右击 “CheckedValue”,选择修改,把数值由1改为0

2、防止SYN洪水攻击
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet

\Services\Tcpip\Parameters
新建DWORD值,名为SynAttackProtect,值为2
新建EnablePMTUDiscovery REG_DWORD 0
新建NoNameReleaseOnDemand REG_DWORD 1
新建EnableDeadGWDetect REG_DWORD 0
新建KeepAliveTime REG_DWORD 300,000
新建PerformRouterDiscovery REG_DWORD 0
新建EnableICMPRedirects REG_DWORD 0

3. 禁止响应ICMP路由通告报文
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

\Tcpip\Parameter 538 s\Interfaces\interface
新建DWORD值,名为PerformRouterDiscovery 值为0

4. 防止ICMP重定向报文的攻击
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\

Services\Tcpip\Parameters
将EnableICMPRedirects 值设为0

5. 不支持IGMP协议
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

\Tcpip\Parameters
新建DWORD值,名为IGMPLevel 值为0
6、禁止IPC空连接:
cracker可以利用net use命令建立空连接,进而入侵,还有net view,

nbtstat这些都是基于空连接的,禁止空连接就好了。
Local_Machine\System\CurrentControlSet\Control\

LSA-RestrictAnonymous 把这个值改成”1”即可。

7、更改TTL值
cracker可以根据ping回的TTL值来大致判断你的操作系统,如:
TTL=107(WINNT);
TTL=108(win2000);
TTL=127或128(win9x);
TTL=240或241(linux);
TTL=252(solaris);
TTL=240(Irix);
实际上你可以自己改的:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet

\Services\Tcpip\Parameters:DefaultTTL REG_DWORD 0-0xff(0-255 十进制,默认值128)改成一个莫名其妙的数字如258,起码让那些小菜鸟晕上半天,就此放弃入侵你也不一定哦

8. 删除默荊54c ??共享
有人问过我一开机就共享所有盘,改回来以后,重启又变成了共享是怎么回事,这是2K为管理而设置的默认共享,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

\LanmanServer\Parameters:AutoShareServer类型是REG_DWORD把值改为0即可

9. 禁止建立空连接
默认情况下,任何用户通过通过空连接连上服务器,进而枚举出帐号,猜测密码。我们可以通过修改注册表来禁止建立空连接:
Local_Machine\System\CurrentControlSet\Control\

LSA-RestrictAnonymous 的值改成”1”即可。

10、建立一个记事本,填上以下代码。保存为*.bat并加到启动项目中
net share c$ /del
net share d$ /del
net share e$ /del
net share f$ /del
net share ipc$ /del
net share admin$ /del

5、IIS站点设置:
1、将IIS目录&数据与系统磁盘分开,保存在专用磁盘空间内。
2、启用父级路径
3、在IIS管理器中删除必须之外的任何没有用到的映射(保留asp等必要映射即可)
4、在IIS中将HTTP404 Object Not Found出错页面通过URL重定向到一个定制HTM文件
5、Web站点权限设定(建议)
读 允许
写 55e ? 不允许
脚本源访问 不允许
目录浏览 建议关闭
日志访问 建议关闭
索引资源 建议关闭
执行 推荐选择 “仅限于脚本”
6、建议使用W3C扩充日志文件格式,每天记录客户IP地址,用户名,服务器端口,方法,URI字根,HTTP状态,用户代理,而且每天均要审查日志。(最好不要使用缺省的目录,建议更换一个记日志的路径,同时设置日志的访问权限,只允许管理员和system为Full Control)。
7、程序安全:
1) 涉及用户名与口令的程序最好封装在服务器端,尽量少的在ASP文件里出现,涉及到与数据库连接地用户名与口令应给予最小的权限;
2) 需要经过验证的ASP页面,可跟踪上一个页面的文件名,只有从上一页面转进来的会话才能读取这个页面。
3) 防止ASP主页.inc文件泄露问题;
4) 防止UE等编辑器生成some.asp.bak文件泄露问题。

6、IIS权限设置的思路
?要为每个独立的要保护的个体(比如一个网站或者一个虚拟目录)创建一个系统用户,让这个站点在系统中具有惟一的可以设置权限的身份。
?在IIS的【站点属性或者虚拟盍 4e1 ?录属性→目录安全性→匿名访问和验证控制→编辑→匿名访问→编辑】填写刚刚创建的那个用户名。
?设置所有的分区禁止这个用户访问,而刚才这个站点的主目录对应的那个文件夹设置允许这个用户访问(要去掉继承父权限,并且要加上超管组和SYSTEM组)。

7、卸载最不安全的组件
最简单的办法是直接卸载后删除相应的程序文件。将下面的代码保存为一个.BAT文件,( 以下均以 WIN2000 为例,如果使用2003,则系统文件夹应该是 C:\WINDOWS\ )
regsvr32/u C:\WINDOWS\System32\wshom.ocx
del C:\WINDOWS\System32\wshom.ocx
regsvr32/u C:\WINDOWS\system32\shell32.dll
del C:\WINNT\WINDOWS\shell32.dll

然后运行一下,WScript.Shell, Shell.application, WScript.Network就会被卸载了。可能会提示无法删除文件,不用管它,重启一下服务器,你会发现这三个都提示“×安全”了。
 

发表在 article | 标签为 | Win2003网站服务器的安全配置全攻略已关闭评论

ASP.NET视图状态验证MAC失败 解决办法

验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.Web.HttpException: 验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。不能在群集中使用 AutoGenerate。
分析:

分 析后找到了问题的根源。首先,文章中提到,如果用GridView,并且指定了DataKeyNames属性,则出于安全的理由(因为 DataKeyNames指定的字段代表数据的主键,且该主键值需要保存在视图状态中发送到客户端,用户如果篡改主键值,会导致安全问题), GridView会要求加密视图状态。为此会自动在页面表单</forms>之前添加一个<input type="hidden" name="__VIEWSTATEENCRYPTED" id="__VIEWSTATEENCRYPTED" value="" /> 。

然 而,Atlas的UpdatePanel要求放置在<form></form>内部,也就是</form>之前。这 就意味着添加的隐藏input控件没有被放置在UpdatePanel内,而是放置在UpdatePanel和</form>之间。

当UpdatePanel 更新时,UpdatePanel内部的控件被提交到服务器进行处理(Patrial Rendering),而整个页面并没有被提交。也就是说隐藏的input控件没有随着一起提交。因此服务器并不知道提交的ViewState被加密了, 从而导致MAC验证错误。

解决方法有二,仅供参考:

1.可以在当前页面的<page ...>里加两个属性:
enableEventValidation="false" viewStateEncryptionMode ="Never"

2.当然还可以在web.config里加入:(<system.web>之间)
<pages enableEventValidation="false" viewStateEncryptionMode ="Never" />

发表在 article | 标签为 , | ASP.NET视图状态验证MAC失败 解决办法已关闭评论

flash与后台数据交换方法整理

1.LoadVars(XML)
2.Flash Remoting
3.Webservice
4.XMLSocket

一.LoadVars篇
我之所以把XML也放在这里说,是因为XML和LoadVars数据交互的方式大体相同,就是传递时的数据内容有点不一样而已!
我现在列出在开发过程最常用的"用户密码验证"实例,加以说明!

引用
// Flash代码;
//=======================================================;
//定义LoadVars对象;
var data_lv = new LoadVars();
//提交的用户名变量和参数值;
data_lv.username = "kinglong";
//提交的密码变量和参数值;
data_lv.password = "king";
//提交后返回结果;
data_lv.onLoad = function(success){
//success,数据提交是否成功;
//这个只是表示数据传输是否成功,并不是用户验证的结果;
if(success){
trace("数据提交成功!");
//result也是用户验证返回的实际结果!
if(this.result=="true"){
trace("yes");
}else{
trace("no");
}
}else{
trace("数据提交失败!");
}
}
//数据提交方法调用;
//第一参数就是提交的页面地址;
//第二参数就是返回结果对象(只要是LoadVars对象就可以了);
//第三参数就是提交方式(这个和html中form表单类似,分为"post"和"get"两种方式)
data_lv.sendAndLoad("http://www.klstudio.com/save.asp
",data_lv,"post");
//=======================================================;
//后台服务端页面处理及返回内容;
//=======================================================;
//接收flash提交过来的变量和接收一个页面提交过来的变量一致的;
Request("username") 就是flash端username变量传过来的值"kinglong";
Request("password") 就是flash端password变量传过来的值"kinglong";
....数据库验证.....
//如果用户验证通过
&result=true
//如果用户验证失败
&result=false
//整个页面返回内容就是上面那一行内容,&result对应用着flash端的result变量;
//如果是多个返回值的话,就是&result=xxx&result1=xxx这种形式就可以了;
如有不清楚的地方,你可查看flash帮助文档!
至于XML的方式,请对应地查看flash帮助文档就可以了!
LoadVars方式的优点:
1.flash代码实现起来简单,方便.
2.服务端接收页面和接收一个表单过来的数据一样处理,不需要专门的技术,所有服务端程序都可以实现!

LoadVars方式的缺点:
1.传递的变量不宜过多.
2.变量传递的值不能过长.
3.变量传递值只能使用"字符串"这一种数据类型,数据类型单一.
4.数据返回值当中不能有"&"字符,因此比较复杂的返回值都需进行URL编码处理.

  Flash Remoting这种数据接口是四个之中效率最高的!
其优点:
1.支持数据类型比较多(Converting from application server data types to ActionScript);
2.传递数据量比较大;
3.运行效率是现有几个当中最高的;
4.对各种后台的支持也比较好;
5.其还有调试模块(NetConnection Debugger)

其缺点:
1.需要flash端装Flash Remoting MX Components(这个是免费提供的);
2.需要后台服务端装相应版本的Flash Remoting模块才可以使用,MM提供的模块有j2ee和.net两个版本是要收费的,好在网上还有两个开源的(OpenAMF,AMFPHP);
3.好像Remoting对虚拟主机的支持不太好(可以去google搜索一下,有没有解决方法).
Flash端代码说明:(我这里用as1.0版本为例,其他版本到MM站查找)
//加载Remoting Component代码,这个是必须的;
#include "NetServices.as"
//加载Remoting 调试模块代码,这个是可选择的,用NetConnection Debugger查看调试信息;
#include "NetDebug.as"
if (inited == null){
inited = true;
//设置默认网关;
NetServices.setDefaultGatewayUrl("http://localhost:8500/flashservices/gateway
");
//建立网关连接;
gateway_conn = NetServices.createGatewayConnection();
//获取一个服务;
myService = gateway_conn.getService("myservice", this);
}

//定义调用方法的函数;
function getString(name){
//调用Remoting的getString方法;
myService.getString(name);
}
//定义返回结果的函数;
function getString_Result(result){
//result就为返回的结果;
trace(result);
}
//定义返回状态的函数,此为可选的;
function getString_Status(error){
trace("getString_Status");
trace(error.code);
trace(error.description);
trace(error.details);
}

//调用函数;
getString("kinglong"); 服务端方法定义(我这里以Coldfusion Component为例,其他版本请参考相应的资料)

<!---文件名为myservice.cfc--->
<cfcomponent displayname="我的服务">
<!---定义了getString方法,需将access设为remote,否则Flash remoting无法调用此方法--->
<cffunction name="getString" access="remote" returntype="string">
<cfargument name="name" type="string" required="true">
<cfset myResult = arguments.name & ",欢迎你!">
<cfreturn myResult>
</cffunction>
</cfcomponent>
另附上Flash Remoting的在线帮助文件(Flash Remoting LiveDocs),MM网站上的Remoting相关的资料

发表在 article | 标签为 | 443条评论