MVC的验证(模型注解和非侵入式脚本的结合使用) .Net中初探Redis .net通过代码发送邮件 Log4net (Log for .net) 使用GDI技术创建ASP.NET验证码 Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

时间:2023-03-09 09:41:42
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

MVC的验证(模型注解和非侵入式脚本的结合使用)

@HtmlHrlper方式创建的标签,会自动生成一些属性,其中一些属性就是关于验证

如图示例:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式


模型注解

通过模型注解后,MVC的验证,包括前台客户端,后台服务器的验证,MVC统统都做了包含,即使用户在客户端禁用Javascript,服务器也会将非法操作进行验证,当前前提是针对Model实体标识了注解的情况。

要能够正常进行非空等合法性验证必须做如下步骤(前提条件):

1.必须在实体的每个类型上加上Required特性,但是数字型的属性默认已经加上了。

2.必须在视图上导入如下脚本:

<script src="~/Scripts/jquery-1.7.1.js"></script>   

<script src="~/Scripts/jquery.validate.js"></script>

<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>  ——非嵌入式脚本

3.配置文件里的属性配置如下:

  <appSettings>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>

MVC默认自带的样式:

<link href="~/Content/Site.css" rel="stylesheet" />

关键命名空间:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Web.Mvc;

使用实例

一、非空验证

在属性上打标:

  [Required(ErrorMessage="不能为空")]
  public string dUserName { get; set; }

在视图创建标签处加上@Html.ValidationMessageFor,此标签是当验证错误时,会有相应提示,本质是一个span标签

  @Html.TextBoxFor(d=>d.dUserName)
  @Html.ValidationMessageFor(d=>d.dUserName)

二、约束文本框输入的长度

关键代码:

[StringLength(10, MinimumLength = 4, ErrorMessage = "名称长度只能介于4到10之间")]
public string dUserName { get; set; }

三、给表单项的控件加上描述表示

关键代码:

[DisplayName("姓名")]
public string dUserName { get; set; }

视图代码加上相应代码:

@Html.DisplayNameFor(d=>d.dUserName)

相应效果:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

四、约束整数的取值范围,在属性上打标如下:

[Range(100,1000,ErrorMessage="最小为100元,最多捐1000元")]

五,保证该文本框输入与另一个要相同 (可用于两次密码输入保持一致)

[Compare("Pwd1",ErrorMessage="两次输入密码不一致")]

第一个参数是要匹配的属性名称

六、使用正则表达式

[RegularExpression("\\d+",ErrorMessage="密码必须为纯数字")]

七、自定义类型表单标签

后台代码:

     [DataType(DataType.EmailAddress)]
        [DisplayName("电子邮件")]
        public string Email { get; set; }

前台使用:

  @Html.DisplayNameFor(d=>d.Email)  ----提示文本
  @Html.EditorFor(d=>d.Email)    -----自定义类型标签 为email格式
  @Html.ValidationMessageFor(d=>d.Email)  ---提示错误消息标签

这里输入错误的提示消息,默认是英文,需要修改文件可以改成中文,修改图解:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

八、Remote标注属性对,文本框输入,通过Ajax连接数据库,判断有效性 (此方法是效验时配合ajax连接数据库)

例:注册时可用于检查用户名是否被使用过,神奇效果:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

注意:Remote是通过Ajax请求来进行验证,为了防止缓存一般写成post请求

打标:

[Remote("checkUsername","Donation",ErrorMessage="用户名已经存在",HttpMethod="post")]   

checkUsername (action方法)

Donation (控制器名称)

Action方法配合使用示例:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
    [HttpPost]
        public ActionResult checkUsername()
        {
                    //1.获取检查的值
            string uname = Request["dUserName"];

            //2.连接数据库判断
         DonationEntities db=new DonationEntities ();
          var model=db.DonationDetail.FirstOrDefault(d=>d.dUserName==uname);

            if (model!=null&&model.dUserName==uname)
            {
                return Content("false");
            }

            return Content("true");
        }
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

九、后台验证

MVC验证客户端,需要依赖js脚本文件,如果用户在浏览器里禁用了JavaScript,

这时我在后台可使用以下相应对策。

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
//表示验证实体对象中所有标注了特性标签的属性是否合法,如果其中有一个不合法则返回false
            if (ModelState.IsValid==false)
            {
                /*
                 对于验证失败返回视图相应的提示消息
                 * 视图中需要 @Html.ValidateionSummry(true)标签配合使用
                 */
                ModelState.AddModelError("","实体验证失败");
                return View();
            }
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

.Net中初探Redis

一、简介

Redis是著名的NOSQL数据库,本质就是存储键值对结构的数据,为存储键值对数据做了优化,在大型网站中应用很多。Redis提供了数据的自动过期处理,因此适合存储临时数据。

和Redis类似的还有Memcached, Redis可以把数据持久化到硬盘中,而Memcached是放到内存中,重启后就消失,一般用Memcached做缓存。


二、Redis服务器的部署(Windows)

Redis服务器有Linux、Windows版,Linux版性能好适合生产环境。这里只说明Windows里配置Redis服务器,用于开发。

1.安装Redis服务

文件下载:redisbin_x32

安装路径不要包含中文或其他特殊符号,解压后服务相关文件如下:

redis-server.exe单击该文件虽然可以开启服务,但是要一直保证这个文件不能关闭,双击点开如图:

2.把Redis服务配置到Windows服务里

说明:配置此项后,不必去通过找到“redis-server.exe”文件单击打开一直挂着,才能使用服务。

文件下载:RedisWatcher1

解压安装后相关文件如下:

修改“watcher.conf”文件里,打开文件,进行图片说明的操作

修改后去Windows服务里开启Redis服务,如图:


三、在.net中操作Redis

1.在项目中导入相关的.dll文件的引用

文件下载:Redis.Net驱动

相关.dll如图:

2.创建一个RedisManage类

写入以下关键代码:

 1 using ServiceStack.Redis;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7
 8 namespace Redis_Test
 9 {
10     class RedisManage
11     {
12
13         public static PooledRedisClientManager ClientManager { get; private set; }
14         static RedisManage()
15         {
16             RedisClientManagerConfig redisConfig = new RedisClientManagerConfig();
17             redisConfig.MaxWritePoolSize = 128;
18             redisConfig.MaxReadPoolSize = 128;
19
20             //可以读写分离,指定一台服务器读,一台写。
21             // new PooledRedisClientManage(读写的服务器地址,只读的服务器地址
22             ClientManager = new PooledRedisClientManager(new string[] { "127.0.0.1" },
23                 new string[] {"127.0.0.1"}, redisConfig);
24         }
25
26
27     }
28 }

3.存储信息的方法

 1
 2             using (IRedisClient con = RedisManage.ClientManager.GetClient())
 3             {
 4                 //存数据
 5                 con.Set<int>("age", 18);
 6                 Dictionary<string, string> dic = new Dictionary<string, string>();
 7                 dic["yzk"] = "test";
 8                 con.Set<Dictionary<string, string>>("dic", dic);
 9
10             }

 4.读取数据

1  using (IRedisClient con = RedisManage.ClientManager.GetClient())
2             {
3                 //取数据
4                 int age = con.Get<int>("age");
5                 Console.WriteLine(age);
6                 Dictionary<string, string> dic = con.Get<Dictionary<string, string>>("dic");
7                 Console.WriteLine(dic["yzk"]);
8
9             }

5. 支持写入数据设置超时:

bool Set<T>(string key, T value, DateTime expiresAt);

第三个参数DateTime,可以指定数据到期时间,到期数据将不存在服务器里


四、在项目解决的一些问题

1.同一个用户名只能在一台电脑或者一个浏览器中登陆,严格来说是一个Session,Web中很难区别是否是同一台电脑,

 这里的本质是使用用户名与SessionID进行键值对关联,存储到Redis中。

技术思路:在编写用户登陆代码处,将用户名(唯一)做为键,当前的SessionId作为值,存储到Redis数据库中。然后在每次请求页面时,

就把当前SessionID取出,在把对应的Redis中的SessionId取出,两者进行比较,假如这时用户已经换了浏览器登陆,那么Redis中对应的SessionID将覆盖了,

两者不对等,那么就证明该用户在其他地方进行了登陆。

俗语:但凡登陆就要用当前SessionID覆盖Redis中的SessionID,只要每当请求,发现当前SessionID与Redis中的不同,该页面就要清除登陆,清除Session,说明这个用户去了其他位置登陆了。

代码参考,登录成功某处:

1   context.Session["user"] = model;
2             //用户名与SessionId键值对关系存储到Redis中
3             using (var con = RedisManage.ClientManager.GetClient())
4             {
5                 //存数据
6                 con.Set<string>(model.username,context.Session.SessionID);
7
8             }

由于,用户每次请求页面都要检查,我将此操作配置到Global文件中:

参考代码:

 1 using Common;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Security;
 7 using System.Web.SessionState;
 8 using Model;
 9 namespace rupeng
10 {
11     public class Global : System.Web.HttpApplication
12     {
13
14         public override void Init()
15         {
16             base.Init();
17             //必须到Init()中监听
18             //每个需要Seesion页面启动都会执行AcquireRequestState事件
19             //AcquireRequestState事件执行的时候Session已经准备好了
20             this.AcquireRequestState += Global_AcquireRequestState;
21         }
22
23         void Global_AcquireRequestState(object sender, EventArgs e)
24         {
25             if (HttpContext.Current.Session==null)
26             {
27                 return;
28             }
29
30
31             if (Context.Session["user"]==null)   //排除用户没有登录
32             {
33                 return;
34             }
35             user_guest model= Context.Session["user"] as user_guest;
36             using (var con = RedisManage.ClientManager.GetClient())
37             {
38                 string redis_sId = con.Get<string>(model.username);
39
40                 //发现不对等,用户在其他位置登陆了,销毁当前Seesion
41                 if (redis_sId!=Context.Session.SessionID)
42                 {
43                     Context.Session.Clear();
44                     Context.Session.Abandon();
45                 }
46
47             }
48
49
50         }
51
52
53         protected void Application_Start(object sender, EventArgs e)
54         {
55
56         }
57
58         protected void Session_Start(object sender, EventArgs e)
59         {
60
61         }
62
63         protected void Application_BeginRequest(object sender, EventArgs e)
64         {
65
66         }
67
68         protected void Application_AuthenticateRequest(object sender, EventArgs e)
69         {
70
71         }
72
73         protected void Application_Error(object sender, EventArgs e)
74         {
75
76         }
77
78         protected void Session_End(object sender, EventArgs e)
79         {
80
81         }
82
83         protected void Application_End(object sender, EventArgs e)
84         {
85
86         }
87     }
88 }

.net通过代码发送邮件

关键代码:

需要引用命名空间:

using System.Net.Mail;
using System.Net;

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
 1    MailMessage mailObj = new MailMessage();
 2
 3             mailObj.From = new MailAddress("mayun@qq.com"); //发送人邮箱地址
 4             mailObj.To.Add("mahuateng@qq.com");   //收件人邮箱地址
 5             mailObj.Subject = "账户激活";    //主题
 6             mailObj.Body = mailbody;    //正文,
 7             mailObj.IsBodyHtml = true; //表示正文内容是HTML
 8
 9             SmtpClient smtp = new SmtpClient();
10             smtp.Host = "smtp.sina.cn";         //smtp服务器名称
11             smtp.UseDefaultCredentials = true;
12             smtp.Credentials = new NetworkCredential("mayun@qq.com", "pwd");  //发送人的登录名和密码
13             smtp.Send(mailObj);                
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

注意细节:

一、smtp

SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组由于源地址到目的地址传送邮件的规则。

在使用时,要保证邮件里该项服务已经开启!新浪邮箱设置例如:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

二、出现 “不允许使用邮箱名称。 服务器响应为:Envolope sender mismatch with login user..” 的错误

 MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

Log4net (Log for .net)

Log4net (Log for .net)

开源的记录日志的组件,是从java的Log4J移植到.net


日志文件存放的位置

在项目新建“App_Code”和“App_Data”,该文件夹客户端无法访问


滚动日志文件

例:每个日志最多100MB,一个日志满了,就新建一个日志保存,最多可以容纳10个日志文件,超过10个文件,覆盖最老的日志文件


日志级别

日志对象根据你使用的级别,匹配webconfig设置日志级别,如果使用的级别大于配置的级别,那么才把日志内容记录到日志文件中。

常用级别项:Fatal>Error>Warn>Debug ,即 严重>错误>警告>调试。


在Web.config中配置Log4net

一、

在<configuration>节点下新建节点< configSections>节点

然后在< configSections>下新增:

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

注意:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

二、

然后

<configuration>

根节点下新增:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
 1  <log4net>
 2     <!-- OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
 3     <!-- Set root logger level to ERROR and its appenders -->
 4     <root>
 5       <level value="ERROR" />
 6       <appender-ref ref="RollingFileTracer" />
 7     </root>
 8     <!-- Print only messages of level DEBUG or above in the packages -->
 9     <appender name="RollingFileTracer" type="log4net.Appender.RollingFileAppender,log4net">
10       <param name="File" value="App_Data/Log/" />
11       <param name="AppendToFile" value="true" />
12       <param name="RollingStyle" value="Date" />
13       <param name="MaxSizeRollBackups" value="10" />
14       <param name="MaximumFileSize" value="1MB" />
15       <param name="DatePattern" value="&quot;Logs_&quot;yyyyMMdd&quot;.txt&quot;" />
16       <param name="StaticLogFileName" value="false" />
17       <layout type="log4net.Layout.PatternLayout,log4net">
18         <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
19       </layout>
20     </appender>
21   </log4net>
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

三、

在Global文件的Application_Start中写(程序启动的时候读取配置)

log4net.Config.XmlConfigurator.Configure();

四、

在编写程序时,如何使用

ILog logger = LogManager.GetLogger(typeof(当前类名));

logger.Error("记录日志的内容",);

注意:Error方法代表log对象调用Error的级别写入到日志文件中,如果配置文件配置的级别高于Error,那么内容将不会记录到日志文件中


项目中常规使用处

在Global文件配置

Application_Error中记录未处理异常

protected void Application_Error(object sender, EventArgs e)

{

ILog log = LogManager.GetLogger(typeof(Global));

log.Error("系统发生未处理异常",Context.Error);

}


Web.config范例

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
 1 <?xml version="1.0" encoding="utf-8"?>
 2
 3 <!--
 4   有关如何配置 ASP.NET 应用程序的详细信息,请访问
 5   http://go.microsoft.com/fwlink/?LinkId=169433
 6   -->
 7
 8 <configuration>
 9
10   <!--配置Log4net-->
11   <configSections>
12     <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
13   </configSections>
14
15     <system.web>
16       <compilation debug="true" targetFramework="4.5" />
17       <httpRuntime targetFramework="4.5" />
18
19
20
21     </system.web>
22
23   <!--连接字符串-->
24   <connectionStrings>
25     <add connectionString="Data Source=.;Initial Catalog=repengDb;User ID=sa;Password=84879825" name="sqlCon" />
26   </connectionStrings>
27
28
29
30
31
32   <log4net>
33     <!-- 日志级别类型: OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
34     <root>
35       <level value="ERROR" />  <!--设置日志写入级别-->
36       <appender-ref ref="RollingFileTracer" />
37     </root>
38
39     <!-- Print only messages of level DEBUG or above in the packages -->
40     <appender name="RollingFileTracer" type="log4net.Appender.RollingFileAppender,log4net"><!-- type= 设置日志的记录类型,这里采用的是滚动日志-->
41
42       <!--日志信息存储到哪个文件夹下-->
43       <param name="File" value="App_Data/Log/" />
44
45       <!--是否将内容追加到日志文件-->
46       <param name="AppendToFile" value="true" />
47
48       <!--根据日期作为日志滚动-->
49       <param name="RollingStyle" value="Date" />
50
51       <!--最大容纳10个日志文件-->
52       <param name="MaxSizeRollBackups" value="10" />
53
54       <!--一个日志文件的大小-->
55       <param name="MaximumFileSize" value="1MB" />
56
57       <!--日志文件命名方式-->
58       <param name="DatePattern" value="&quot;Logs_&quot;yyyyMMdd&quot;.txt&quot;" />
59
60       <!--有很多节点,需要时根据需求查找配置,没必要全都记住。。。。-->
61       <param name="StaticLogFileName" value="false" />
62       <layout type="log4net.Layout.PatternLayout,log4net">
63         <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
64       </layout>
65     </appender>
66   </log4net>
67
68
69 </configuration>
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

使用GDI技术创建ASP.NET验证码

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Web;
  5 using System.Drawing;
  6 using System.IO;
  7 using System.Text;
  8 using System.Text.RegularExpressions;
  9 using System.Drawing.Drawing2D;
 10 using System.Drawing.Imaging;
 11 using System.Web.SessionState;
 12 namespace yzm
 13 {
 14     /// <summary>
 15     /// yzm 的摘要说明
 16     /// </summary>
 17     public class yzm : IHttpHandler,IRequiresSessionState
 18     {
 19         private const string yzmName = "yzm";
 20
 21         public void ProcessRequest(HttpContext context)
 22         {
 23
 24             //表头需要修改 MIME类型为:image/jpeg,因为此页面要以图片流的形式响应给客户端
 25             context.Response.ContentType = "image/jpeg";
 26
 27
 28
 29             //获取验证码的内容
 30             string code = CreateCode(context, 4);
 31
 32
 33             //将内容保存到Seesion,在效验时取客户端提交的值在服务器里与此Session内容验证
 34             context.Session[yzmName] = code;
 35
 36
 37
 38
 39             /*
 40              绘制样式
 41              */
 42             using (Bitmap map =new Bitmap (120,50)) //创建位图对象,构造函数指定宽、高
 43             using(Graphics grap=Graphics.FromImage(map)) //创建绘图的图纸
 44
 45             {
 46                 grap.Clear(Color.White);  //让图纸为白色
 47
 48                 /*创建一个矩形对象
 49                     构造函数(x坐标,y坐标,宽,高)
 50                  * 该参数的填写,其实是填满了整个图纸
 51                  */
 52                 Rectangle rec = new Rectangle(0,0,map.Width,map.Height);
 53
 54                 /*创建了一个画线性,并且颜色是渐变的一个画笔对象
 55                  构造函数:   画在矩形对象上,起始颜色,结束颜色,角度,是否比例
 56                  */
 57                 using (LinearGradientBrush brush = new LinearGradientBrush(rec,Color.Blue,Color.Red,1.2f,true))
 58                 using(  Font font = new Font("隶书", 20, FontStyle.Strikeout))   //为验证码指定字体
 59                 {
 60                     grap.DrawString(code, font, brush, 3, 8);  //画到图纸上,传入相应对象:内容、字体、画笔、坐标
 61                 }
 62
 63                 //画一些随机的直线,增加验证码识别度
 64                 Random random = new Random();
 65                 for (int i = 0; i < 18; i++)
 66                 {
 67                     //第一个点
 68                     int x1 = random.Next(map.Width);
 69                     int y1 = random.Next(map.Height);
 70
 71                     //第二个点
 72                     int x2 = random.Next(map.Width);
 73                     int y2 = random.Next(map.Height);
 74
 75                     /*在画纸上绘画线
 76                      * 构造函数:
 77                      * pen:创建画笔(画笔颜色,宽度)
 78                        x1, y1, x2, y2 随机生成 两个坐标点连成一条线
 79                      */
 80                     grap.DrawLine(new Pen(Color.FromArgb(random.Next()), 3), x1, y1, x2, y2);
 81
 82                 }
 83
 84
 85                 //保存到响应对象的流中 ,返回给客户端一个jpg格式图片
 86                 map.Save(context.Response.OutputStream, ImageFormat.Jpeg);
 87
 88
 89
 90
 91             } //--end
 92
 93
 94
 95         }
 96
 97
 98
 99         /// <summary>
100         /// 用txt里的汉字作为验证码数据源
101         /// </summary>
102         private string Get_yzm_DataSource(HttpContext context)
103         {
104             StringBuilder sb = new StringBuilder();
105
106             string path = context.Server.MapPath(@"~\yzmDataSource.txt");
107
108             using (Stream fs = new FileStream(path, FileMode.Open))
109             using (StreamReader read = new StreamReader(fs, Encoding.UTF8))
110             {
111                 string len;
112                 while ((len = read.ReadLine()) != null)
113                 {
114                     Regex rg = new Regex("[\\W\\s]+");
115                     sb.Append(rg.Replace(len, ""));
116                 }
117             }
118
119
120             return sb.ToString();
121         }
122
123
124         /// <summary>
125         /// 随机生成,指定个数的验证码内容
126         /// </summary>
127         /// <returns></returns>
128         private string CreateCode(HttpContext context, int length)
129         {
130             string str = Get_yzm_DataSource(context);
131
132             Random ran = new Random();
133
134
135
136             string code = "";
137             for (int i = 0; i < length; i++)
138             {
139                 int sjIndex = ran.Next(0, str.Length);
140                 code += str[sjIndex];
141             }
142
143             return code;
144         }
145
146
147         public bool IsReusable
148         {
149             get
150             {
151                 return false;
152             }
153         }
154     }
155 }
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

Razor模板引擎 (RazorEngine)

Razor模板引擎不仅在ASP.NET MVC中内置了Razor模板引擎,还有一个开源的RazorEngine,

这样以来我们可以在非ASP.NET MVC项目中使用Razor引擎,甚至在控制台,WinForm项目中都可以使用。

文件的创建

文件是一个后缀名为cshtml的文件,如果在非MVC项目中创建Razor文件,可以新建一个html,把后缀名该为cshtml。


RazorEngine使用初体验

一、前台:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

二、后台代码

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

解释:

使用RazorEngine需提前在项目中引入它的程序集文件dll。

后台代码首先获得cshtml文件将其读成文本文件,在通过Razor.Parse将文本解析为,含义为Razor的模板,将其展出。访问的话应访问代码页面,cshtml只是一个展示模板,等待代码动态绘制内容使用cshtml模板展示.


Razor.Parse()方法

1.通过第二个参数,可以传一个object类型的对象,到前台(cshtml)模板。

string razor = RazorEngine.Razor.Parse(html, new { name = "zs", age = 12 });

注意:传入对象的访问权限,需为public

前台输出这个对象的值:

<h1>@Model.name</h1>

<h2>@Model.age</h2>


RazorEngine原理

1.net在编译的时候会把.cshtml文件生成一个动态程序集,每次调用,就会每次生成一个不重复的动态程序集,这样看出会给服务器造成不容小视的压力。

解决办法:

Razor.Parse()方法的第三个参数cacheName

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

如果传入一个cacheName(名字随意),一旦编译成功,下次会使用缓存,不会重复生成新的动态程序集。

2.关于cacheName的问题

从上面的原理得知,如果给Razor.Parse()传入cacheName,下次调用可以使用缓存,那么会产生一个问题,cshtml文件如果发生了修改,如果还去调用缓存的话,那么结果会不如意。

解决办法:

将cacheName的值转为动态的:

1.根据文件名+修改时间

2.文件的MD5值作为cacheName

3.文件流转换为新的文本字符串(获取文件内容)

........

cacheName细节:

即使cacheName写成一个固定的值,当cshtml发生改变的时候Parse()方法执行后的结果,也会是发生改变的内容。


自己封装一个Razor.Parse()方法

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
 1     /// <summary>
 2         /// 自己封装一个Razor.Parse()方法
 3         /// </summary>
 4         /// <param name="context">上下文对象</param>
 5         /// <param name="cshtmlPath">.cshtml文件的相对路径</param>
 6         /// <param name="obj">要传入的对象参数</param>
 7         /// <returns>返回一个解析过的Razor模板字符串</returns>
 8         private string RazorParse(HttpContext context, string cshtmlPath,params object[] obj)
 9         {
10             //获得.cshtml文件的绝对路径
11             string path = context.Server.MapPath(cshtmlPath);
12             //通过路径将文件读成文本
13             string txt = File.ReadAllText(path);
14
15             //为模板准备一个缓冲,根据文件的修改时间动态组合
16             string cacheName = path + File.GetLastWriteTime(path);
17
18             //根据需求是否要传入对象参数,在调用Razor.Parse方法返回解析好的Razor模板
19             return obj.Length > 0 ? RazorEngine.Razor.Parse(txt, obj[0], cacheName) : RazorEngine.Razor.Parse(txt, cacheName);
20
21         }
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

HtmlEncodeString()方法

在往模板传入字符串的格式,如果为html格式,该方法会将其转义,在模板显示字符串本身,而不会被模板解析为html标签

代码:

public static HtmlEncodedString Test1()

{

return new HtmlEncodedString("<input type='text' />");

}


RawString()方法

可以将类似于html的字符串,传入前台模板,可以被解析标签相应的含义

代码:

public static RawString Test2()

{

return new RawString("<input type='text' />");

}


Razor模板调用外部方法(在.cshtml模板页上调用在后台用C#写好的一个方法)

1.在.cshtml顶部引入方法的命名空间

@using 命名空间名称

2.调用

@类名.方法() ,不需要";"号。  如:@Handler1.Test1()

业务实例

通过外部方法生成一个Checked标签

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
 1     public static RawString CreateChecked_input(string id,bool isChecked)
 2
 3         {
 4
 5             StringBuilder sb = new StringBuilder();
 6
 7             sb.Append("<input type='checkbox' id=" + id).Append("  checked="+ (isChecked==true?"checked":"")).Append(" />");
 8
 9
10             return new RawString(sb.ToString());
11
12
13
14         }
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

调用

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
 1 @using Demo.Razor
 2 <!DOCTYPE html>
 3 <html xmlns="http://www.w3.org/1999/xhtml">
 4 <head>
 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 6     <title></title>
 7 </head>
 8 <body>
 9
10      @Handler1.CreateChecked_input("t1", true)
11
12 </body>
13 </html>
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

总结:因为在后台很多数据时动态读取数据库的信息而组成的,将繁琐的拼接封装在后台,前台页面清晰,而封装的方法还可以重复利用到其他业务中


.Net程序员应该掌握的正则表达式

Regular Expression

Net程序员必然要掌握正则的核心内容:匹配提取替换常用元字符

正则表达式是用来进行文本处理的技术,是语言无关的,在几乎所有语言中都有实现。


常用元字符

.:代表除了换行之外的任意字符,一个字符占位。

*:代表前面的子表达式出现0次或者多次。如果需要*代表的子表达式是多个字符,就将多个字符用()包含。

+:代表前面的表达式出现1次或者多次。

?:代表前面的表达式出现0次或者出现1次。

{n}:代表前面的子表达式要出现n次。

^代表开始$代表结束

{n,m}:代表前面的子表达式最少出现n次,最多出现m次。

{n,}:说明前面的子表达式最少出现n次,最多没有限制。

[]:输入的内容必须是在括号内有的一个字符。

():改变优先级、分组。

\d:代表0-9的数字。

\D:代表非数字。

\w:代表0-9a-zA-Z_中文   (经过实例证明C#里\w包含中文,JavaScript里不包含中文)

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

\W:代表其他特殊字符(除了0-9a-zA-Z_中文)

\s:代表看不到的字符,如:回车、空格、制表符。

\S:代表所有可见字符

项目实战:

1.运用场合:不包含某些特定的字符情况下

((?![@:]).)+:代表不是@和:的字符。

2.匹配中文

[\u4E00-\u9FFF]

 


正则表达式进行匹配的原则:

1.(有没有)只关注是否存在,而不关注它的位置,也就意味着只需要能够匹配其中一个就可以 。

2.贪婪模式:如果找到了能匹配的字符,那么他还继续往下匹配尽可能多的字符,只到最后


.net中的正则表达式

正则表达式在.net中就是用字符串来表示,这个字符串格式比较特殊,无论多么特殊,在C#语言看来都是普通的字符出,具体什么含义由Regex类内部进行语法分析。

常用的4种情况:

  1. 判断是否匹配(是否有):Regex.IsMatch("字符串","正则表达式");
  2. 字符串提取:Regex.Match("字符串","要提取的字符出的正则表达式"); ——只能提取一个(提取一次)。
  3. 字符串提取(循环提取所有):Regex.Matches(),可以提取所有匹配的字符串。
  4. 字符串替换:Regex.Replace("字符串","正则","替换内容");

提取只有一个匹配项的字符串,进行分组,提取。

string str = "tiantianjcx@qq.com";

Match match = Regex.Match(str, @"^(\w+)[@](\w+)[.](\w+)$");

if (match.Success) //匹配成功

{

Console.WriteLine(match.Groups[0].Value);  //结果:tiantianjcx@qq.com

Console.WriteLine(match.Groups[1].Value);  //结果:tiantianjcx

Console.WriteLine(match.Groups[2].Value);  //结果:qq

Console.WriteLine(match.Groups[3].Value);  //结果:com

}


JavaScript正则表达式

创建:

字面值:var regex=/元字符/;

构造函数:var regex=new RegExp("元字符");

匹配:

bool 正则表达式对象.test("字符串");

var regex = /\d*/;

alert(regex.test("122"));   //true

提取:

像数组的对象 正则表达式对象.exec("字符串");

这个对象的[0]是匹配到的结果,[1],[2]....是各个组

1.单个提取

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

2.单个提取并分组

var str = "我的邮箱是tiantianjcx@qq.com";

var regex = /(\w+)@(\w+[.]\w{2,3})/;

var arr= regex.exec(str);

alert(arr.length);

for (var i = 0; i < arr.length; i++) {

alert(arr[i]);

}

3.循环提取

var str = "我的邮箱是tiantianjcx@qq.com,你的是sukun@163.com号吧";

var regex = /\w+@\w+[.]\w{2,3}/g;

var arr = [];

var item = null;

while ((item = regex.exec(str)) != null) {

arr.push(item);

}

注意:创建正则表达式对象里的字符必须加上g(全局匹配),否则会陷入是循环

4.替换

javascript的正则替换,是使用String的Replace()方法将正则表达式作为参数处理。

var str = "a--b---------c---------------d---------------e---------------f";

str = str.replace(/-+/g,"-");

var str = "2016年7月26日";

str = str.replace(/(\d+)年(\d+)月(\d+)日/,"$1-$2-$3");


自测题:

MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
 1     /*
 2              192.168.10.5[port=21,type=ftp]”,这个字符串表示IP地址为192.168.10.5的服务器的21端口提供的是ftp服务,
 3              * 其中如果“,type=ftp”部分被省略,则默认为http服务。请用程序解析此字符串,然后打印出“IP地址为***的服务器的***端口提供的服务为***”
 4              */
 5
 6
 7             string str = "192.168.10.5[port=21,type=ftp]";
 8             Match match = Regex.Match(str, @"^(\d{1,3}[.]?\d{1,3}[.]?\d{1,3}[.]?\d{1,3}[.]?)[[]\w+=(\w+),?\w*=?(\w*)[]]$");
 9             if (match.Success) //匹配成功
10             {
11                 Console.WriteLine("IP地址为:{0}", match.Groups[1].Value);
12                 Console.WriteLine("端口::{0}", match.Groups[2].Value);
13                 if (string.IsNullOrEmpty(match.Groups[3].Value))
14                 {
15                     Console.WriteLine("端口提供的服务为:http");
16                 }
17                 else
18                 {
19                     Console.WriteLine("端口提供的服务为:{0}", match.Groups[3].Value);
20                 }
21             }
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式
 1             /*
 2              读取网站的内容,用正则表达式匹配邮箱,并提取
 3              * 注意:做循环匹配不能加"^"和$(开始和结束),否则就只能匹配一项
 4              */
 5             string path = @"E:\视频大全\传智播客.NET2014.3.26-07.09期\6--2014-4-03 文件操作和正则表达式\资料\正则表达式-素材\正则表达式\大家留下email交友吧_email_天涯社区.htm";
 6
 7             string txt = File.ReadAllText(path);
 8
 9             MatchCollection arr = Regex.Matches(txt, @"[a-zA-Z0-9]+[@][a-zA-Z0-9]+[.]+[a-zA-Z]{2,3}");
10
11             using (Stream fs = new FileStream("E:\\mail.txt", FileMode.Create))
12             using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
13             {
14
15                 for (int i = 0; i < arr.Count; i++)
16                 {
17                     Match match = arr[i];
18                     sw.WriteLine(match.Groups[0].Value);
19
20                 }
21             }
MVC的验证(模型注解和非侵入式脚本的结合使用)   .Net中初探Redis   .net通过代码发送邮件  Log4net (Log for .net)  使用GDI技术创建ASP.NET验证码  Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式