//----------------Day1----------------
一章 Web基本原理
1节
课程说明
web窗体--设计界面--加法
使用Chrome
2节
浏览器与服务器的交互
登陆如鹏网时--工具---headers--Form Data中用户名和密码
Response返回的信息
www.rupeng.com---status code 301(重定向首页)
浏览器向服务器发送请求,服务器处理之后,返回给浏览器(html)
3节
Socket原理和编写控制台浏览器代码
Socket是进行网路通讯的技术
qq用户发送的信息通过Socket把信息发送给qqServer,qqServer返回给用户
Socket原理性代码: (TCP UDP两种方式)
1、编写“控制台浏览器”
//把本机网址的html写入socket
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);//TCP、UDP。
socket.Connect(new DnsEndPoint("127.0.0.1", 8080));//连接服务器。http协议默认的端口号是80。每个服务器软件监听一个端口(别的软件就不能监听这个端口了),发送给这个端口的数据只会被这个服务器软件接收到。
using (NetworkStream netStream = new NetworkStream(socket))//读写socket通讯数据的流
using (StreamWriter writer = new StreamWriter(netStream))
{
writer.WriteLine("GET /index.html HTTP/1.1");//每一行指令都回车一下
writer.WriteLine("Host: 127.0.0.1:8080");
writer.WriteLine();//空行回车,表示指令结束
}
//从socket读取html
using (NetworkStream netStream = new NetworkStream(socket))
using (StreamReader reader = new StreamReader(netStream))
{
string line;
while ((line = reader.ReadLine())!=null)
{
Console.WriteLine(line);
}
}
socket.Disconnect(false);
4节
编写"网站服务器"
//自己写的最简单的webservice
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//宿舍大妈
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
serverSocket.Listen(10);
while (true)
{
Console.WriteLine("等着请求");
Socket socket = serverSocket.Accept();//男女通讯通道。返回大妈给你的这个人的通讯通道
Console.WriteLine("来了请求");
using(NetworkStream stream = new NetworkStream(socket))
using (StreamReader reader = new StreamReader(stream))
{
//读取出第一行
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
if (line.Length <= 0)
{
break;//遇到空行了,请求结束了不用再等了
//如果不break,就一直卡在ReadLine()等着浏览器发后续的数据
}
}
}
using (NetworkStream stream = new NetworkStream(socket))
using(StreamWriter writer = new StreamWriter(stream))
{
writer.WriteLine("HTTP/1.1 200 OK");
writer.WriteLine();
writer.WriteLine("welcome to rupeng.com");
}
socket.Disconnect(false);
}
5节
编写"网站服务器" 范虎请求的页面
//自己写的最简单的webservice
namespace MyWeb服务器2
{
class Program
{
static void Main(string[] args)
{
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//宿舍大妈
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
serverSocket.Listen(10);
while (true)
{
Console.WriteLine("等着请求");
Socket socket = serverSocket.Accept();//男女通讯通道。返回大妈给你的这个人的通讯通道
Console.WriteLine("来了请求");
string firstLine;
using (NetworkStream stream = new NetworkStream(socket))
using (StreamReader reader = new StreamReader(stream))
{
firstLine = reader.ReadLine();//读取GET /1.htm HTTP/1.1
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
if (line.Length <= 0)
{
break;//遇到空行了,请求结束了不用再等了
//如果不break,就一直卡在ReadLine()等着浏览器发后续的数据
}
}
}
// Regex.Match(firstLine, "GET (.+) HTTP/1\\.1");
string[] strs = firstLine.Split(‘ ‘);
string url = strs[1];///分析出文件名1.htm
Console.WriteLine("url="+url);
using (NetworkStream stream = new NetworkStream(socket))
using (StreamWriter writer = new StreamWriter(stream))
{
string filePath = @"F:\快盘\NextBig\NET课程\ASP.net\myweb服务器" + url;
Console.WriteLine("filePath=" + filePath);
if (File.Exists(filePath))
{
writer.WriteLine("HTTP/1.1 200 OK");
writer.WriteLine();
string html =
File.ReadAllText(filePath);
Console.WriteLine(html);
writer.Write(html);
}
else
{
writer.WriteLine("HTTP/1.1 404 NOT FOUND");
writer.WriteLine();
writer.Write("没有找到");
}
}
socket.Disconnect(false);
}
}
}
}
6节
服务器动态的计算
add?i=1&j=2
//把add?i=1&j=2转换为字典
ParseQueryString(string str)
//分割后获得name和value ,及i和1,加入返回dictonary中
//练习:login?username=‘admin‘&password=‘123‘
namespace MyWeb服务器3
{
class Program
{
static void Main(string[] args)
{
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//宿舍大妈
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
serverSocket.Listen(10);
while (true)
{
Console.WriteLine("等着请求");
Socket socket = serverSocket.Accept();//男女通讯通道。返回大妈给你的这个人的通讯通道
Console.WriteLine("来了请求");
string firstLine;
using (NetworkStream stream = new NetworkStream(socket))
using (StreamReader reader = new StreamReader(stream))
{
firstLine = reader.ReadLine();//读取GET /1.htm HTTP/1.1
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
if (line.Length <= 0)
{
break;//遇到空行了,请求结束了不用再等了
//如果不break,就一直卡在ReadLine()等着浏览器发后续的数据
}
}
}
// Regex.Match(firstLine, "GET (.+) HTTP/1\\.1");
string[] strs = firstLine.Split(‘ ‘);
string url = strs[1];///分析出文件名add?i=1&j=2
string[] strs2 = url.Split(‘?‘);
string fileAction = strs[0];//add
string qs = strs2[1];
Dictionary<string, string> dict = ParseQueryString(qs);
int i = Convert.ToInt32(dict["i"]);
int j = Convert.ToInt32(dict["j"]);
using (NetworkStream stream = new NetworkStream(socket))
using (StreamWriter writer = new StreamWriter(stream))
{
writer.WriteLine("HTTP/1.1 200 OK");
writer.WriteLine();
writer.WriteLine(i+j);
}
socket.Disconnect(false);
}
}
/// <summary>
/// 把i=1&j=2&w=aaa转换为一个Dictionary
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
static Dictionary<string, string> ParseQueryString(string qs)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
string[] strs = qs.Split(‘&‘);
foreach (string str in strs)
{
string[] kv = str.Split(‘=‘);
string name = kv[0];
string value = kv[1];
dict.Add(name, value);
}
return dict;
}
}
}
7节
服务器知道浏览器什么时候关闭吗?
除非浏览器请求,否则服务器无法主动向浏览器发送数据
8节
web服务器和asp.net服务器能做什么
自己写webservice: 太累 并发性 安全性
现成的webservice: Apache Ngix IIS
先用微软的Cassini,然后才用IIS
//请求的处理,报文的处理,参数的处理,用现成的Web服务器
新建Web--一旦处理程序
9节
HttpHandler(ashx)
ashx下面有个ashx.cs就是C#代码,ashx是微软傻瓜化的结果
当用户访问test1.ashx时,服务器调用ashx.cs中test1的ProcessRequest方法
项目--属性--Web--服务器--默认勾上了IIS Express(IIS简化版) //推荐使用IIS Web服务器--报错目录--可以直接使用地址
项目--属性--Web--特定页--把页面地址写入进去
选择一个浏览器--选择浏览器的安装目录
调试时不能修改
虽然停止调试了,只要IIS还在运行的,改了代码后重新生成,就可以直接刷新访问,html不用生成也可以访问
10节
context.Response.ContentType = "text/html";
string username = context.Request["username"];
string password = context.Request["password"];
context.Response.Write("<html><head></head><body>");
if (username == "admin" && password == "123")
{
context.Response.Write("<h1>欢迎光临</h1>");
}
else
{
context.Response.Write("<img src=‘3.jpg‘/>");
}
11节
表单提交
重复的name也会被提交,没有name就不会提交给服务器
input textarea select 只有这3中属性的value值才能被提交给web服务器
submit比较特殊,只有被点击的submit的name和value才会提交给服务器,其他的不会提交给服务器
对于select是选中的那个select才提交给服务器
//----------------Day2-------------
二章 一般处理程序
12节
http协议
Restart、Reinstall、Reboot
favicon.ico 就是一个默认的图标,浏览器每次访问,服务器都尝试去访问这个网页,如果存在就显示这个图标
后缀名是可以骗人的
浏览器不知道服务器内部发生了什么,只接收结果,返回什么就显示什么
连接Connection :浏览器与服务器之间传输数据的通道。http协议在请求期间还是支持保持连接Keep-Alice的,但是结束还是会断开连接
请求Request
处理Process
响应Response
13节
请求
浏览器就是骗人的: 浏览器发出的所有请求都是可以被伪造的,一定不能信任浏览器的请求
User-Agent:UA 用户代理,代理用户发出http请求的,就是一些当前浏览器信息
Referer:这个请求来自于那个网页
Accept-Encoding:服务器支持什么压缩算法
Accept-Language:该浏览器支持哪种语言
响应
服务器也是可以骗人的,可以欺骗黑客
HTTP/1.0 200 OK //200返回的状态码,如果为404就是not found //500为internal server error //跳出"黄页",可以根据报错信息,找到出现错误的异常
Content-Type: 服务器返回的是什么类型的数据 (后缀名是可以造假的) charset=utf-8;报文体采用的编码
Accept-Rangge: 服务器是否支持断点续传
Server: 哪种服务器
Date:返回日期
Content-Length:内容长度
HTTP/1.0 302 Found //302重定向到Localing的页面
context.Response.Redirect(); //重定向
HTTP/1.0 304 Not Modified // 表示没有修改,从缓存取,没有报文体
If-Modifed-Since:保存的修改日期,再次访问表示没有修改,如果没有修改就直接重缓存中加载数据的
状态码 -->
2XX:表示没问题
3XX: 需要浏览器干点啥
4XX:浏览器提交的数据有问题(客服端的访问未授权)
5XX: 服务器错误
响应码:
“200” : OK;
“302” : Found 暂时转移,用于重定向, Response.Redirect()会让浏览器再请求一次重定向的地址,重定向的请求是Get方式;
"404" : Not Found 未找到。
500 服务器错误(一般服务器出现异常),通过报错信息找出异常的点。
403:客户端访问未被授权。
304(服务器把文件的修改日期通过Last-Modified返回给浏览器,浏览器缓存这个文件,下次向服务器请求这个文件的时候,通过If-Modified-Since问服务器说“我本地的文件的修改日期是。。。”,服务器端如果发现文件还是那个文件,则告诉浏览器(304 Not Modified)文件没修改,还用本地的吧。ctrl+f5)。
2xx:没问题;3xx代表浏览器需要干点啥;4***浏览器的问题;5xx服务器错误
14节
Get和Post的区别
get把数据放在地址栏,post把数据放到报文体中,提交大数据,传密码安全
对于post请求只要在地址栏中输入一个网址回车就是get请求;刷新,重新发出post请求,部分浏览器会提示是否重新提交
反编译器搜索httpRequest这个类
15节
ASP.Net内核几大对象HttpContext;
context.Request对象
请求参数都是字符串,因为http协议是string
只要浏览器没提交,服务器就获取不了
//HttpContext和当前线程相关的对象,在子线程中拿不到这个对象
//1
void Test(HttpContext context)
{
if() context.Request["a"]不存在
}
//2
void Test()
{
HttpContext context=HttpContext.current;
if() context.Request["a"]不存在
}
//3 post
string name=context.Request.Form["name"]; //只获得通过报文体传输的参数
//4 get
string name=context.Request.QueryString["name"]; //只获取通过get方式获得参数
//5
context.Response.Write("‘+context.Request.Browser.Browser+‘\n"); //返回打印浏览器的浏览器名 Platform Version
i < context.Request.Headers.AllKeys.Length
string k=context.Request.Headers.AllKeys[i];
string v=context.Request.Headers[k];
namespace Web1
{
/// <summary>
/// RequestTest1 的摘要说明
/// </summary>
public class RequestTest1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
//context.Request.Form["name"]获得通过报文体传输的参数
// string name = context.Request.Form["name"];
//string age = context.Request.Form["age"];//拿到的都是String,Convert.ToInt32()
//context.Request.QueryString获得GET方式中“GET /Test.ashx?id=5 HTTP/1.1”中的
//"id=5"值
//string name = context.Request.QueryString["name"];
//string age = context.Request.QueryString["age"];
//context.Request["name"]无论是Get还是Post都能获得
// string name = context.Request["name"];//[""]索引器
// string age = context.Request["age"];
context.Response.Write("" + context.Request.Browser.Browser+ "\n");
context.Response.Write("" + context.Request.Browser.Platform + "\n");
context.Response.Write("" + context.Request.Browser.Version + "\n");
context.Response.Write("------------------------\n");
for (int i = 0; i < context.Request.Headers.AllKeys.Length; i++)//Request.Headers请求报文头
{
string key = context.Request.Headers.AllKeys[i];
string value = context.Request.Headers[key];
context.Response.Write(key+"="+value+"\n");
}
context.Response.Write("------------------------\n");
context.Response.Write(context.Request.HttpMethod + "\n");
//context.Response.Write(context.Request.InputStream);//请求报文体的流
context.Response.Write(context.Request.Path + "\n");
context.Response.Write(context.Request.QueryString + "\n");
context.Response.Write(context.Request.PhysicalPath + "\n");//被请求的文件的服务器上的物理路径
context.Response.Write(context.Request.UserAgent + "\n");
context.Response.Write(context.Request.UserHostAddress + "\n");//客户端的IP地址
context.Response.Write(context.Request.UrlReferrer + "\n");
context.Response.Write(String.Join(",",context.Request.UserLanguages) + "\n");//浏览器支持什么语言
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
16节
context.Response对象
ContentType :
OutputStream :图片,二进制输出流
Redirect:重定向
//性能并不是唯一追求的指标
if(username为nullOrEmpty)
{
context.Response.Write("用户名为空");
//return;
context.Response.End(); //终止httpHandler的执行 //因为它抛了一个异常,所以没有继续执行,可以用try catch抓住这个异常,因为异常处理效率低,所以尽量不用response.end()
}
void Test()
{
HttpContext.Current.Respnse.Write("数据库插入失败");
//return; //只是终止Test()的执行
HttpContext.Current.Response.End();
}
End()将当前所有缓冲的输出发送到客户端,停止该页的执行。通过对End()进行try,发现是是抛出了异常。所以End()之后的代码就不会执行了。
17节
context.Server对象
Server.Transfer:控制权的转移
Server.Mapth:获得绝对路径
Server.HtmlEncode:HTML编码解码
Server.UrlEncode:url编码解码
context.Server.Transfer("sayhello?name=admin&age=18"); //有错,以后讲
FileInfo fi=new FileInfo(@"E:\s1.jpg"); //永远不用相对路劲,容易进坑
context.Server.MapPath("~/3.jpg"); //获得文件的绝对路径,~表示网站的根目录
string csCode="helllo List<T> list=new List<T>()";
context.Server.HtmlEncode(csCode);
context.Server.HtmlDecode(csCode);
string str="如鹏 12什么么";
context.Server.UrlEncode(str); //转换为url编码
Server是一个HttpServerUtility类型的对象,不是一个类名
MapPath:MapPath("~/a.htm")将虚拟路径(~代表项目根目录)转换为磁盘上的绝对路径,操作项目中的文件使用。
HtmlEncode、 HtmlDecode:HTML编码解码。Encode为的是把特殊字符转义显示,举例子:"< 如鹏+网 rupeng.com>"
UrlEncode、 UrlDecode:url编码解码。汉字、特殊字符(空格、尖括号)等通过Url传递的时候要编码,举例子“"<如鹏+网 rupeng.com>”
18节
ContentType = "image/jpg";
//浏览器是不知道服务器上有3.jpg的存在的,浏览器只是发请求,显示图片
//把文件流的数据拷贝到outputstream输出流
//输出一个动态创建的图片
//图片中显示访问者浏览器信息
//把名字写入泡妞证
//生成验证码,动态生成一200*50的图片,显示一个随机的4位数
//context.Response.ContentType = "image/jpeg";//image/gif image/png
//1
/*
string filepath = context.Server.MapPath("~/3.jpg");
//浏览器是不知道服务器上有3.jpg的存在的,浏览器只是发请求,接收请求,显示图片
//别的一概不知
using (Stream inStream = File.OpenRead(filepath))//new FileStream(...);
{
inStream.CopyTo(context.Response.OutputStream);
}*/
//2
/*
using (Bitmap bmp = new Bitmap(500, 500))//创建一个尺寸为500*500的内存图片
using (Graphics g = Graphics.FromImage(bmp))//得到图片的画布
{
g.DrawString("如鹏网万岁", new Font(FontFamily.GenericSerif, 30), Brushes.Red, 100, 100);//Font应该被释放
g.DrawEllipse(Pens.Blue, 100, 100, 100, 100);
//bmp.Save(@"d:\1.jpg", ImageFormat.Jpeg);
//直接保存到网页输出流中
bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
} */
//3
// string name = context.Request["name"];
/*
using (Bitmap bmp = new Bitmap(500, 500))//创建一个尺寸为500*500的内存图片
using (Graphics g = Graphics.FromImage(bmp))//得到图片的画布
{
g.DrawString(name+"万岁", new Font(FontFamily.GenericSerif, 30), Brushes.Red, 100, 100);//Font应该被释放
g.DrawEllipse(Pens.Blue, 100, 100, 100, 100);
//bmp.Save(@"d:\1.jpg", ImageFormat.Jpeg);
//直接保存到网页输出流中
bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}*/
/*
context.Response.ContentType = "image/jpeg";
using (Bitmap bmp = new Bitmap(500, 200))//创建一个尺寸为500*500的内存图片
using (Graphics g = Graphics.FromImage(bmp))//得到图片的画布
using (Font font = new Font(FontFamily.GenericSerif, 30))
{
HttpRequest request = context.Request;
g.DrawString("IP:" + request.UserHostAddress, font, Brushes.Red, 0, 0);
g.DrawString("浏览器:" + request.Browser.Browser + request.Browser.Version, font, Brushes.Red, 0, 50);
g.DrawString("操作系统:" + request.Browser.Platform, font, Brushes.Red, 0, 100);
bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);//图片保存到输出流
}*/
context.Response.ContentType = "image/jpeg";
string name = context.Request["name"];
string imgFullPath = context.Server.MapPath("~/PaoNiuZheng.jpg");
using (Image bmp = Bitmap.FromFile(imgFullPath))//读取一张已有的图片
using (Graphics g = Graphics.FromImage(bmp))//得到图片的画布
using (Font font1 = new Font(FontFamily.GenericSerif, 12))
using (Font font2 = new Font(FontFamily.GenericSerif, 5))
{
{
g.DrawString(name, font1, Brushes.Black, 125, 220);//Font应该被释放
g.DrawString(name, font2, Brushes.Black, 309, 55);//Font应该被释放
bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);//图片保存到输出流
}
}
//对浏览器来讲,只知道“服务器哥哥给我返回了一个image/jpeg,正文就是图片”
19节
文件下载
对于.ashx右键下载,其实是l向f发送http请求
context.Response.ContentType = "application/ms-excel";
/*
//增加Content-Disposition是告诉浏览器,这个返回的内容是“附件形式”要给用户保存
//filename是建议的文件名
context.Response.AddHeader("Content-Disposition", "attachment;filename=" +
context.Server.UrlEncode("动态文件.txt")); //-------------???---格式不对-----------------
DataTable dt = SqlHelper.ExecuteQuery("select * from t_persons");
foreach (DataRow row in dt.Rows)
{
context.Response.Write(row["Name"]+"!"+row["Age"]+"\r\n");
}*/
context.Response.AddHeader("Content-Disposition", "attachment;filename=" +
context.Server.UrlEncode("人员列表.xls"));
IWorkbook workbook = new HSSFWorkbook() ;//new XSSFWorkbook();//xlsx
ISheet sheet = workbook.CreateSheet("人员列表");
DataTable dt = SqlHelper.ExecuteQuery("select * from t_persons");
for (int i=0;i<dt.Rows.Count;i++)
{
IRow excelRow = sheet.CreateRow(i);
DataRow dataRow = dt.Rows[i];
ICell cell0 = excelRow.CreateCell(0);
cell0.SetCellValue((string)dataRow["Name"]);
ICell cell1 = excelRow.CreateCell(1);
cell1.SetCellValue((int)dataRow["Age"]);
}
workbook.Write(context.Response.OutputStream);
20节
文件上传
post
enctype="multipart/form-data"
HttpPostFile
file1.SaveAs(全路径);
//判断文件大小,不能超过1M
//根据文件后缀判断文件类型,ContentType可以伪造
context.Response.ContentType = "text/html";
HttpPostedFile file1 = context.Request.Files["file1"];//上传的文件,可以是多个
HttpPostedFile filehaha = context.Request.Files["filehaha"];
string name = context.Request["name"];
//HttpPostedFile.FileName是文件名,通过查看报文发现,FileName是浏览器提交过去的
if (file1.ContentLength > 1024 * 1024)
{
context.Response.Write("文件不能超过1MB");
return;
}
//为什么根据ContentType判断文件类型不安全。
//因为ContentType是浏览器提交的,是可以造假的,文件内容是病毒,filename是1.exe
//ContentType伪造成了"image/jpeg"。
/*
if(file1.ContentType!="image/jpeg"&&file1.ContentType!="image/gif"
&&file1.ContentType!="image/png")
{
context.Response.Write("文件类型不允许");
return;
}*/
string fileExt = Path.GetExtension(file1.FileName);
if(fileExt!=".jpg"&&fileExt!=".gif"&&fileExt!=".png")
{
context.Response.Write("文件类型不允许");
return;
}
string localFileName = context.Server.MapPath("~/upload") + "/" + file1.FileName;
file1.SaveAs(localFileName);//把文件保存到服务器上
context.Response.Write(localFileName+"<br/>");
context.Response.Write(name);
}
//判断文件大小和类型,并在图片上画上一行字
context.Response.ContentType = "text/html";
HttpPostedFile file1 = context.Request.Files["file1"];
if (file1.ContentLength > 1024 * 1024)
{
context.Response.Write("文件不能超过1MB");
return;
}
string fileExt = Path.GetExtension(file1.FileName);
if (fileExt != ".jpg" && fileExt != ".jpeg")
{
context.Response.Write("只允许jpg图片");
return;
}
//用户上传的文件尽量“不落地”,也就是不保存到本地,可以避免:上传文件把服务器撑爆;
//上传非法文件造成安全性问题。
//只能证明一段代码有漏洞,不能证明代码没有漏洞。
using (Image img = Bitmap.FromStream(file1.InputStream))//**
{
using (Graphics g = Graphics.FromImage(img))
using (Font font = new Font(FontFamily.GenericSerif, 18))
{
g.DrawString("如鹏网 rupeng.com", font, Brushes.Red, 0, 0);
}
string filename = DateTime.Now.ToString("yyyyMMdd");//20150308
img.Save(context.Server.MapPath("~/upload/" + filename + fileExt));
}
/----------------------Day3---------------------
三章 ashx增删改查
21节
作业讲解
//Excel上传
//保存文件到yyyy\mm\dd.png中
每次return输出打印结束,都输出html结束标签
if(file1.COntentLength<=0){未上传文件};
以调试方式启动,才可以进行断点调试
不需要别人告诉结论,你试验的结果就是真理
IWrokbook workbook=WorkbookFactory.Create(file1.InputStream);
sheet.SheetName //获得sheet名
i<sheet.LastRowNum 从i=1开始
j<excelRow.LastCellNum 从j=ecelRow.FirstCellNum开始
string fileFullPath=Path.Combine(dirFullPath,file1.FileName);
if(!Directory.Exists(dirFullPath)){就创建这个文件夹}
22节
模板文件
Id Name Age Gender
//从数据库查询Person,通过html拼接,在.ashx输出信息
//html中的占位符@Name用.ashx中的值替换
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
//判断id时否合法
int id = Convert.ToInt32(context.Request["id"]);
DataTable table =
SqlHelper.ExecuteQuery("select * from T_Persons where [email protected]", new SqlParameter("@Id", id));
if (table.Rows.Count <= 0)
{
return;
}
DataRow row = table.Rows[0];
string name = (string)row["Name"];
int age = (int)row["age"];
string pesronViewHtmlFileName = context.Server.MapPath("~/Day3/PersonView2.txt");
string personViewHtml = File.ReadAllText(pesronViewHtmlFileName);
personViewHtml = personViewHtml.Replace("@name", name).Replace("@age",age.ToString());
// personViewHtml = personViewHtml.Replace("@name", name);
//personViewHtml = personViewHtml.Replace("@age", age.ToString());
context.Response.Write(personViewHtml);
}
23节
通过抽象提取方法优化例子
模板优化:如果报错,输出报错信息
"{msg}" --> 占位符
封装:读取虚拟路劲下的.html文件,返回html字符串 CommonHelper.cs
封装:输出错误信息
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
//判断id是否合法
string strId = context.Request["id"];
if (string.IsNullOrEmpty(strId))
{
// string errorFileName = context.Server.MapPath("~/Day3/PersonViewError.html");
//string errorHtml = File.ReadAllText(errorFileName);
// string errorHtml = CommonHelper.ReadHtml("~/Day3/PersonViewError.html");
//errorHtml = errorHtml.Replace("{msg}", "id不能为空!");
//context.Response.Write(errorHtml);
OutputError("id不能为空!");
return;
}
int id = Convert.ToInt32(strId);
DataTable table =
SqlHelper.ExecuteQuery("select * from T_Persons where [email protected]", new SqlParameter("@Id", id));
if (table.Rows.Count <= 0)
{
// string errorFileName = context.Server.MapPath("~/Day3/PersonViewError.html");
//string errorHtml = File.ReadAllText(errorFileName);
// string errorHtml = CommonHelper.ReadHtml("~/Day3/PersonViewError.html");
//errorHtml = errorHtml.Replace("{msg}", "id不存在!");
//context.Response.Write(errorHtml);
OutputError("id不存在!");
return;
}
DataRow row = table.Rows[0];
string name = (string)row["Name"];
int age = (int)row["age"];
//DRY:Don‘t Repeat YourSelf:别拷代码
//string pesronViewHtmlFileName = context.Server.MapPath("~/Day3/PersonView2.txt");
// string personViewHtml = File.ReadAllText(pesronViewHtmlFileName);
string personViewHtml = CommonHelper.ReadHtml("~/Day3/PersonView2.txt");
personViewHtml = personViewHtml.Replace("@name", name).Replace("@age",age.ToString());
// personViewHtml = personViewHtml.Replace("@name", name);
//personViewHtml = personViewHtml.Replace("@age", age.ToString());
context.Response.Write(personViewHtml);
}
private void OutputError(string msg)
{
string errorHtml = CommonHelper.ReadHtml("~/Day3/PersonViewError.html");
errorHtml = errorHtml.Replace("{msg}", msg);
HttpContext.Current.Response.Write(errorHtml);
}
24节
T_Persons列表
<table>标签中不能出现文本,但是没什么关系
<table>中{Persons}被.ashx替换
模板的好处是不用改C#代码,显示什么只需改.html就行了
//删除
删除之后重定向到列表页面,发生了2次请求 context.Response.Redirect("PersonList.ashx");//删除完成后重定向回列表页面
判断是否要删除,在js中去转义,需要在C#中加上一个 \"
//1
.Append("<td><td><a onclick=‘return confirm(\"你真的要删除吗?\")‘ href=‘PersonDelete.ashx?id=")
.Append(row["id"]).Append("‘>删除</a></td>");
//2
onclick=\"if(!confirm(‘您确定要删除吗?‘)){return false;}\"
25节
新增和编辑
context.Response.ContentType = "text/html";
//PesonEditAddNew.ashx?action=addnew,新增
//PesonEditAddNew.ahsx?action=edit&id=1
string action = context.Request["action"];
string html = CommonHelper.ReadHtml("~/Day3/PersonEditAddNew.html");
if (action == "addnew")
{
html = html.Replace("{actionName}", "新增").Replace("{name}", "").Replace("{age}", "18")
.Replace("{gender}", "checked");
context.Response.Write(html);
}
else if (action == "edit")
{
int id = Convert.ToInt32(context.Request["id"]);
DataTable table = SqlHelper.ExecuteQuery("Select * from T_Persons where [email protected]",
new SqlParameter("@Id",id));
if (table.Rows.Count <= 0)
{
CommonHelper.OutputError("没找到id="+id+"的人员");
return;
}
if (table.Rows.Count > 1)
{
CommonHelper.OutputError("找到多条id=" + id + "的人员");
return;
}
DataRow row = table.Rows[0];
string name = (string)row["name"];
int age = (int)row["age"];
bool gender = (bool)row["gender"];
html = html.Replace("{actionName}", "编辑").Replace("{name}", name).Replace("{age}", age.ToString())
.Replace("{gender}",gender?"checked":"");
context.Response.Write(html);
}
else
{
CommonHelper.OutputError("action错误");
}
}
26节
保存
只有浏览器提交的,服务器才能知道,action是addnew还是edit必须由浏览器提交
27节
公司的增删改查(下拉列表)
T_Company( Id Name Address ManageId)
T_Boss( Id Name Age Gender)
sql语句:联合查询
//作业:学生管理系统
//班级---List
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
//获得所有班级
DataTable dtCla = SqlHelper.ExecuteQuery(@"select c.CId CId,c.CName CName,c.CClassroomNum CClassroomNum,t.TName TName
from T_Classes c left join T_Teachers t on c.TId=t.TId");
if(dtCla.Rows.Count<=0)
{
CommonHelper.OutputErrorHtml("没有查到任何班级");
}
//遍历班级,拼接字符串<tr>
StringBuilder sb = new StringBuilder();
foreach(DataRow row in dtCla.Rows)
{
sb.Append("<tr><td>").Append(row["CName"]).Append("</td><td>").Append(row["CClassroomNum"]).Append("</td><td>").Append(row["TName"]).Append("</td>");
sb.Append("<td>").Append("<a onclick=\"return confirm(‘您确定要删除吗?‘);\" href=‘Delete.ashx?id=").Append(row["CId"]).Append("‘>删除</a></td>");
sb.Append("<td><a href=‘Edit.ashx?action=edit&id=").Append(row["CId"]).Append("‘>修改</a></td>").Append("</tr>");
}
//获得html并替换输出
string htmlStr = CommonHelper.OutputHtml("~/Class/List.html");
string html = htmlStr.Replace("{classes}", sb.ToString());
context.Response.Write(html);
}
//班级---Edit
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
string save = context.Request["save"];
string action = context.Request["action"];
//判断直接范问还是保存
if(string.IsNullOrEmpty(save))
{
//判断新增还是编辑
if(action=="addnew")
{
//获得所有的老师
DataTable dtTea = SqlHelper.ExecuteQuery("select * from T_Teachers");
StringBuilder sb = new StringBuilder();
foreach(DataRow row in dtTea.Rows)
{
sb.Append("<option value=‘").Append(row["TId"]).Append("‘>").Append(row["TName"]).AppendLine("</option>");
}
//获得html并替换
string htmlStr = CommonHelper.OutputHtml("~/Class/Edit.html");
string html = htmlStr.Replace("actionName","新增").Replace("action","addnew").Replace("@CName","").Replace("@CClassroomNum","").Replace("{teachers}",sb.ToString());
context.Response.Write(html);
}
else if(action=="edit")
{
//获得id
string idStr=context.Request["id"];
long id = CommonHelper.CheckStringIsLong(idStr);
//获得所有的老师
DataTable dtTea = SqlHelper.ExecuteQuery("select * from T_Teachers");
StringBuilder sb = new StringBuilder();
foreach(DataRow row in dtTea.Rows)
{
if(row["TId"].ToString()==idStr)
{
sb.Append("<option selected value=‘").Append(row["TId"]).Append("‘>").Append(row["TName"]).AppendLine("</option>");
}
else
{
sb.Append("<option value=‘").Append(row["TId"]).Append("‘>").Append(row["TName"]).AppendLine("</option>");
}
}
//获得指定id的班级
DataTable dtCla = SqlHelper.ExecuteQuery("select * from T_Classes where [email protected]",
new SqlParameter(){ParameterName="@CId",Value=id});
if(dtCla.Rows.Count<=0)
{
CommonHelper.OutputErrorHtml("没有查到该id的数据:"+id);
}
else if (dtCla.Rows.Count == 1)
{
DataRow row = dtCla.Rows[0];
//获得html并替换
string htmlStr = CommonHelper.OutputHtml("~/Class/Edit.html");
string html = htmlStr.Replace("actionName", "编辑").Replace("action", "edit").Replace("@CId", idStr).Replace("@CName", row["CName"].ToString()).Replace("@CClassroomNum", row["CClassroomNum"].ToString()).Replace("{teachers}", sb.ToString());
context.Response.Write(html);
}
else
{
CommonHelper.OutputErrorHtml("存在多个id的数据:"+id);
}
}
else
{
CommonHelper.OutputErrorHtml("action错误:" + action);
}
}
else if(save=="save") //保存-------------------------------------------------------------------------
{
//获得共同的项
string cname = context.Request["CName"];
string cclassroomNum = context.Request["CClassroomNum"];
string tidStr = context.Request["TId"];
long tid = CommonHelper.CheckStringIsLong(tidStr);
//获得共同的参数
List<SqlParameter> list = new List<SqlParameter>();
SqlParameter[] param = {
new SqlParameter("@CName",cname),
new SqlParameter("@CClassroomNum",cclassroomNum),
new SqlParameter(){ParameterName="@TId",Value=tid}
};
list.AddRange(param);
//判断新增还是编辑
int i = -1;
if (action == "addnew")
{
i = SqlHelper.ExecuteNonQuery("insert into T_Classes(CName,CClassroomNum,TId) values(@CName,@CClassroomNum,@TId)", param);
}
else if (action == "edit")
{
//huode id
string cidStr = context.Request["CId"];
long cid = CommonHelper.CheckStringIsLong(cidStr);
list.Add(new SqlParameter() { ParameterName = "@CId", Value = cid });
i = SqlHelper.ExecuteNonQuery("update T_Classes set [email protected],[email protected],[email protected] where [email protected]", list.ToArray());
}
else
{
CommonHelper.OutputErrorHtml("action错误:" + action);
}
if(i>0)
{
context.Response.Redirect("~/Class/List.ashx");
}
else
{
CommonHelper.OutputErrorHtml("操作失败");
}
}
else
{
CommonHelper.OutputErrorHtml("save错误:" + save);
}
}
//班级---Delete
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
string cidStr = context.Request["id"];
long cid = CommonHelper.CheckStringIsLong(cidStr);
//删除指定cid的班级,需要先删除指定cid的学生
int count = (int)SqlHelper.ExecuteScalar("select COUNT(*) from T_Students where [email protected]",
new SqlParameter() { ParameterName = "@CId", Value = cid });
int i = -1;
if(count>0) //有该班级的学生
{
i = SqlHelper.ExecuteNonQuery("delete from T_Students where [email protected]",
new SqlParameter() { ParameterName = "@CId", Value = cid });
}
i = SqlHelper.ExecuteNonQuery("delete from T_Classes where [email protected]",
new SqlParameter() { ParameterName = "@CId", Value = cid });
if(i>0)
{
context.Response.Redirect("~/Class/List.ashx");
}
else
{
CommonHelper.OutputErrorHtml("删除失败");
}
}
28节
NET代码运行在服务器JS运行在客服端
//1
alert(‘哈哈‘); //是阻塞执行,只有窗口关闭才会执行后面的代码
//2
alert(‘删除成功‘); //输出给浏览器是js代码,但是对服务器就是一段字符串,alert是运行在浏览器端得,所以不会等用户关闭alert之后才向后执行
context.Response.Redirect(‘sefe1.html‘);
//3
MessageBox.Show("删除成功"); //可以阻塞C#运行,但是这个对话框是弹在服务器的,用户右看不到
context.Response.Redirect(‘errorMsg.html‘);
//4 正确的实现
response.write("<script type=‘text/javascript‘>alert(‘删除成功‘);location href=‘errorMsg.html‘;</script>")
File.WriteAllBytes("d:\\1.exe",new byte[]{3,5,6,7,5543}); //用户访问时,写的.exe病毒也是写在服务器端的
29节
网站安全(不要相信浏览器)
//取款
因为用户可以通过各种手段伪造http请求,服务器必须做教验
如果只是把id藏起来,依然不安全,因为可以通过地址拿到数据
//IP地址不可以造假,但是可以通过代码服务器来转发,服务器拿到的就是代理服务器的IP
//投票网站如何避免刷票 (不用用IP,互联网中也无法获得用户的MAC地址,使用验证码、手机号)
//-------------------Day4-----------------
四章
30节
文本自增演示HttpHandler不记状态
//复制一个.ashx需要改类名,再改文件中的class名
浏览器记不住上次提交的值,下次再提交给服务器相当于重新再来
每次请求都会重新new一个新的对象HttpHandler
HttpHandler记忆--隐藏字段hidden,Cookie,Session
//1 hidden:html的hidden记忆ashx的值并表单提交给HttpHandler
context.Response.ContentType = "text/html";
string save = context.Request["save"];
string htmlStr = CommonHelper.OutputHtml("~/IncAddself2.html");
if(string.IsNullOrEmpty(save)) //第一次进入
{
string html = htmlStr.Replace("@number", "0");
context.Response.Write(html);
}
else //提交进入
{
int number =Convert.ToInt32( context.Request["number"]);
number++;
string html = htmlStr.Replace("@number", number.ToString());
context.Response.Write(html);
}
<form action="IncAddSelf2.ashx" method="post">
@number
<input type="text" name="number" value="@number" />
<input type="submit" name="save" style="width:@number0px" value="提交" />
</form>
31节
Cookie入门
每次向服务器请求,除了表单信息,还需把和站点有关的(服务器给它的)所有Cookie都提交给服务器
在服务器把cookie写入浏览器
//CookieTest1.ashx
HttpCookie cookie=new HttpCookie("test");
cookie.Value="rupeng.com"; //Cookie:键值对
context.Response.SetCookie(cookie);
读取Cookie
//CookieTest2.ashx
HttpCookie cookie1 = context.Request["test"];
context.Response.Write(cookie==null?"没有cookie":cookie.Value); //cookie的值发生改变,下次响应才会改变
//2 Cookie:上次在服务器设置的Cookie,下次可以直接读取和更改该Key的Cookie值
//CookieTest1.ashx
HttpCookie cookie = new HttpCookie("test");
cookie.Value = "rupeng.com";
context.Response.SetCookie(cookie);
//CookieTest2.ashx
HttpCookie cookie1 = context.Request.Cookies["test"];
context.Response.Write(cookie1 == null ? "没有该key的Cookie" : cookie1.Value);
cookie1.Value = "iloveyou"; //更改cookie的值
context.Response.SetCookie(cookie1.Value);
32节
Cookie的细节问题
cookie的有效时间是程序运行期间
cookie.Expires=DateTime.Now.AddSeconds(20); //在DateTime的基础上增加20秒,返回新的DateTIme对象
如果不设定Expires超时时间,则关闭浏览器Cookie失效
如果设定Expires超时时间,,除非到期,否则下次访问浏览器Cookie依然存在
不同浏览器的Cookie是不能共享的
cookie.Value=context.Request.UserAgent; //把UserAgent存入Cookie
浏览器的隐身模式、小号模式,所有的Cookie信息都与主浏览器不一致,达到隐身的效果
Cookie的大小是有限的,不能存储过多的信息
机密信息不能存入Cookie
Cookie是可以被清除的,也许没到Expires就已经过期了
33节
Cookie实现记住用户名
用户第一次进入首先看看Cookie中有没有值
//直接进入时,从Cookie中获得用户名
Http cookieLastUserName = context.Request.Cookies["LastUserName"];
//登陆进入后,把用户名设置到Cookie中
HttpCookie cookieUserName = new HttpCookie("LastUserName");
cookieUserName.Value = username;
cookieUserName.Expires = DateTime.Now.AddDays(7);
context.Response.SetCookie(cookieUserName);
34节
Cookie的深入(*)
//1
关于Cookie的Path(路径)问题
cookie.Path=null;
cookie.Path="/Day4/CookiePath1.ashx"; //Path:谁能读我
如果没有设定Path,则Path的默认值是 "/" ,即当前域名下所有的页面都可以操作这个Cookie
//2
不同域名下的Cookie不相干,但是一个主域名下的两个子域名通过设置Cookie.Domain是可以互相操作(共用)的
www.rupeng.comm
pps.rupeng.comm //这个2个域名为同一个主域名repeng.com下的子域名,他们默认的Cookie也不能互相操作;但是设置Cookie.Domain=‘.rupeng.com‘,则他们的子域名都可以操作这个Cookie
35节
Session(会话)入门
服务器端的Cookie,无法造假
给客户一个“身份证”,可以唯一标识这个用户,核心信息放到服务器上,客户端无法去篡改
ASP.net内置了Session机制,.ashx要操作Session必须实现IRequiresSessionState接口,不实现的话Session会为null
这个接口没有任何方法,为标记接口,因为Session处理会稍微降低系统性能,所以这种HttpHandler默认不处理Session,如果实现接口才处理
context.Session["test2"]=888; //cookie只能写string,而session可以是任意类型
int i1=(int)context.Session["test2"]; //错误,因为万一session中为Null,应该int?
Session依赖于Cookie,所在在别的浏览器没有,关闭后也没有了
Cookie存在浏览器中,Session存在服务器中,当前网站的任何一个页面都可能取到Session
服务器会定期销毁服务器端的Session
Session的失效时间是在Web.Config中设置的<SessionState timeout="20"> 设置超时时间,默认时20minutes,也许服务器压力大10minutes就失效了
//Session的保存
context.Session["test1"] = "rupeng.com";
context.Session["test2"] = 888;
//Session的获取
string test1 = (string)context.Session["test1"];
int? test2 = (int?)context.Session["test2"];
context.Response.Write(test1 + "," + test2);
//只有admin这个用户才能访问页面1、页面2,其他用户没有权限访问
//Login1.ashx
if (string.IsNullOrEmpty(context.Request["login"])) //直接进入
{
string username = (string)context.Session["username"];
context.Response.Write(username == null ? "请先登陆" : "username=" + username + ",登陆成功!");
}
else //登陆进入
{
string username = context.Request["username"];
string password = context.Request["password"];
if (password == "123")
{
//登陆成功
context.Session["username"] = username;
context.Response.Write("登陆成功"+username);
}
else
{
context.Response.Write("登陆失败");
}
}
//Page1.ashx
string username = (string)context.Session["username"];
context.Response.Write(username == "admin" ? "登陆成功" : "username=" + username + ",没有权限进入该页面!");
36节
Session案例:登陆后返回到之前页面
登陆,修改密码,查询余额
//移除google上的自动填充表单内容
//最好把key这些不变值定义为常量,避免写错
public const string LOGINUSERNAME;
web.config中timeout设置session的有效时间
如果访问某个页面进行登陆,登陆之后返回之前的页面(从哪个页面来,登陆后,返回原来页面)
context.Session[Login.LOGNURL]=context.Request.Url.ToString(); //把当前地址存到session
关闭浏览器,服务器的Session还会存在一段时间,而Abandon是立即销毁
context.Session.Abandon(); //销毁
//Login.ashx
public const string LOGINUSERNAME = "loginUserName";
public const string LOGINURL = "loginUrl"; //记录登陆前,进入的页面
public const string YZM = "yanzhengCode";
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
string html = CommonHelper.OutputHtml("~/Login/Login.html");
if (string.IsNullOrEmpty(context.Request["subLogin"])) //直接进入
{
string lastusername = (string)context.Session[LOGINUSERNAME];
if (lastusername == null) //session中没有登陆信息
{
html = html.Replace("@msg", "");
context.Response.Write(html);
}
else //session中有值
{
context.Response.Redirect("ExchangePassword.ashx");
}
}
else //登陆进入
{
string username = context.Request["username"];
string password = context.Request["password"];
string yzm = context.Request["yanzhengCode"];
//先判断验证码
string yzmInServer = context.Session[YZM].ToString(); //服务器中的验证码
if(yzm!=yzmInServer)
{
html = html.Replace("@msg", "验证码错误");
context.Response.Write(html);
return;
}
//判断用户名与密码
int i = (int)SqlHelper.ExecuteScalar("select COUNT(*) from T_UserInfoes where [email protected] and [email protected]
new SqlParameter("@UserName",username),
new SqlParameter("@Password",password));
if(i<=0)
{
html = html.Replace("@msg","用户名或密码错误");
context.Response.Write(html);
}
else if(i==1) //登陆成功
{
context.Session[LOGINUSERNAME] = username;
string loginUrl = (string)context.Session[LOGINURL];
//从哪个界面进入,就跳转到哪个界面
if (loginUrl == null) //没有最先的跳转页面
{
context.Response.Redirect("ExchangePassword.ashx");
}
else
{
context.Response.Redirect(loginUrl);
}
}
else
{
html = html.Replace("@msg", "服务器错误,存在相同用户名");
context.Response.Write(html);
}
}
//ExchangePasword.ashx,QueryMoney.ashx
context.Response.ContentType = "text/plain";
string lastusername = (string)context.Session[Login.LOGINUSERNAME];
if (lastusername == null) //Session中没有登陆信息
{
context.Session[Login.LOGINURL] = context.Request.Url.ToString();
context.Response.Redirect("Login.ashx");
}
else
{
context.Response.Write("修改" + lastusername + "的密码.....<a href=‘EndLogin.ashx‘>退出(销毁Session,取消当前会话)</a>" );
}
EndLogin.ashx
context.Session.Abandon(); //销毁Session,取消当前会话
context.Response.Redirect("Login.ashx");
//37节
Session案例:验证码
如果没有验证码,可以通过不断试验密码进行暴力破解
验证码是用来区分发出请求信息的是人还是计算机,因为复杂的图片计算机很难识别,而人却可以比较轻松的识别出来的
正确的验证码放在服务器的Session中,用户名输入的与之进行比对
//首先需要生成一张验证码图片(复杂图片需要很多计算机图形学的理论基础)
刷新验证码图片时,如果还是原来的路径YanZhengMa.ashx,因为路径被缓存了,所以不会再刷新,只有路径后+new Date();让这次的src路径与上次不一样,才会重新创建一个随机数,刷新验证码
//然后验证用户名输入验证码是否正确
//generateYanZhengCode.ashx
context.Response.ContentType = "image/jpeg";
//产生随机数
Random ran = new Random();
int num = ran.Next(1000, 10000);
context.Session[Login.YZM] = num; //把验证码存入会话
//new一个图片,在画布上画上随机数
using (Bitmap bmp = new Bitmap(40, 20))
{
using (Graphics g = Graphics.FromImage(bmp))
using(Font font=new Font(FontFamily.GenericSansSerif,10))
{
g.DrawString(num.ToString(), font, Brushes.Red, new PointF(0, 0));
}
bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
//Login.ashx
function refreshCode() {
var im = document.getElementById("im");
im.src = "generateYanZhengCode.ashx?" + new Date();
};
<td>验证码</td><td><img src="generateYanZhengCode.ashx" id="im" onclick="refreshCode();" /><input type="text" style="width:60px;" name="yanzhengCode" /></td>
38节
Session的原理
在一个请求期间,为同一个SessionId
Guid算法:Guid guid=Guid.NewGuid();
Guid用于产生全球唯一的字符串,是根据网卡mac地址、系统时间、CPU时钟周期,在同一台多次调用不会重复、在不同电脑同一时间也不会重复
浏览器放了一个SessionId,服务器保存了SessionId的值的对应关系
创建一个SessionId,并设置到Cookie中;保存时,把Value保存到指定SessionId的文件中;取值时,从指定SessionId的文件中取Value-----------------(*)
//原理:浏览器请求服务器,判断Cookie中有没有"SessionId"这样一个Cookie的值,如果Cookie中有个SessionId,如果查到SessionId的值,则在磁盘中找这个文件,如果没有这个文件,则创建一个文件,这个文件就用来保存这个Session的相关信息;如果没有这个SessionId,则创建一个Guid.NewGuid(),然后返回给浏览器.总之,服务器中有放SessionId的文件,保存Session的数据库,浏览器通过这个文件的SessionId来向服务器请求Session数据.
//1CreateSession():创建一个SessionId,设置到Cookie中
//2构造函数:
//如果SessionId不存在,就创建,否则获得这个SessionId,以局部变量存起来
//判断请求中是否有这个SessionId
HttpCookie cookie=context.Request.Cookies[RUPENGSESSIONID];
return cookie!=null; //有SessionId
//3SetValue():把SessionId写入文件(把context用局部变量存起来,方便每次使用)
File.WriteAllText(fullPath,value);
//4GetValue()
File.ReadAllText(fullPath);
//Session原理:RupengSesion.cs
public class RupengSession
{
private const string RUPENGSESSIONID = "RupengSessionId";
private string sessionId;
private HttpContext context;
public RupengSession(HttpContext context)
{
this.context = context;
//判断Cookie中有没有RupengSessionId
HttpCookie cookie = context.Request.Cookies[RUPENGSESSIONID];
if (cookie == null)
{
CreateSession();
}
else
{
this.sessionId = cookie.Value;
}
}
//创建Session
private void CreateSession()
{
Guid guid = Guid.NewGuid();
this.sessionId = guid.ToString();
HttpCookie cookie = new HttpCookie(RUPENGSESSIONID);
cookie.Value = sessionId;
context.Response.SetCookie(cookie);
}
//设值(存入MySession的值)
public void SetValue(string value)
{
string fullPath = context.Server.MapPath("~/MySession/SessionId/" + this.sessionId);
File.WriteAllText(fullPath, value);
}
//取值
public string GetValue()
{
string fullPath = context.Server.MapPath("~/MySession/SessionId/" + this.sessionId);
if(!File.Exists(fullPath))
{
return null;
}
return File.ReadAllText(fullPath);
}
//登录(写入Sessioin):Login1.ashx
RupengSession rupengSession = new RupengSession(context); //把SessionId设置到了Cookie中
rupengSession.SetValue(username); //把username存入SessionId所对应的文件中
context.Response.Redirect("MainPage.ashx");
//读取Session:MainPage.ashx
RupengSession rupengSession = new RupengSession(context);
string username = rupengSession.GetValue();
if (username != null)
{
context.Response.Write("您当前登录用户名为:" + username);
}
else
{
context.Response.Write("未登录");
}
39节
改造RupengSession
怎么样使Session放入多个值:对象序列化
序列化:把内存中对象保存为二进制数据
被序列化的对象必须标上[Serializable]
//1序列化对象:把对象保存到流中
Person per=new Person();
BinaryFormatter bf=new BinaryFormatter();
using(Stream stream=File.OpenWrite("d:\\1.bin"))
{
bf.Serialize(stream,per); //序列化指定对象到指定stream中
}
//2反序列化:从流中读取出来
BinaryFormatter bf=new BinaryFormatter();
using(Stream stream=File.OpenRead("d:\\1.bin"))
{
Person per=(Person)df.Deserialize(stream);
}
//SetValue(string name,string value)设值时,如果文件存在,就反序列化文件中的内容,放入dict中;如果不存在,创建一个空的dict;添加一个dict,再把dict序列化到指定SessionId文件中
//GetValue(string name)如果文件存在,反序列化为dict,获得指定dict[name];如果文件不存在,返回null
//MySerializeSession.RupengSession.cs
//设值:把这个值保存到指定sessionId的文件中
public void SetValue(string name, string value)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
string path = context.Server.MapPath("~/MySerializeSession/SessionId/" + this.sessionId);
if (File.Exists(path)) //如果文件存在,就从指定文件流中反序列化出其中内容,加入新的值后,再重新序列化到流文件中
{
dict = DeserializeFormStream(path);
}
dict[name] = value;
//再重新序列化到流文件中
using(Stream stream=File.OpenWrite(path))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, dict); //把指定对象序列化到指定流中
}
}
//取值:从指定SessionId的文件中获得资格值
public string GetValue(string name)
{
string path = context.Server.MapPath("~/MySerializeSession/SessionId/" + this.sessionId);
if(!File.Exists(path))
{
return null;
}
//如果文件存在
Dictionary<string, string> dict = new Dictionary<string, string>();
dict = DeserializeFormStream(path);
return dict[name];
}
//从流中读取文件并反序列化为对象
private Dictionary<string,string> DeserializeFormStream(string path)
{
using (Stream stream = File.OpenRead(path))
{
BinaryFormatter bf = new BinaryFormatter();
return (Dictionary<string, string>)bf.Deserialize(stream);
}
}
//Login1.ashx
RupengSession rupengSession = new RupengSession(context); //把SessionId设置到了Cookie中
rupengSession.SetValue("username", username); //把username存入SessionId所对应的文件中
rupengSession.SetValue("lastLoginTime", DateTime.Now.ToString());
//MainPage.ashx
RupengSession rupengSession = new RupengSession(context);
string username = rupengSession.GetValue("username");
if (username != null)
{
context.Response.Write("您当前登录用户名为:" + username);
context.Response.Write("您当前登录时间为:" + rupengSession.GetValue("lastLoginTime"));
}
else
{
context.Response.Write("未登录");
}
39节
进程外Session
Asp.net中的Session默认保存在Web服务器内存中的(Inprov),Web服务器重启,所有Session数据都会消失
session.web中sessionState中的timeout="10"
避免Session重启后就消失:把Session存在别的地方,如本次的练习,以及把Session存到进程外SqlServer和sessionState
//1 Session保存到SQLServer中配置方法
Windows--NET---4.0.30319--aspnet_regsql.exe--ssadd···(哪个数据库:ip,db,uid,pwd;参数见http://www.cnblogs.com/China-Dragon/archive/2009/05/12/1455147.html)
然后修改web.config中sessionState节点的配置:<sessionState mode="SQLServer" timeout="20" sqlConnectionString="server=.;uid=sa;password=123456;"></sessionState>
//2 Session保存到Windows服务中的StateServer中---怎么配置自己到百度搜
网络项目最好用这种进程外Session
http://www.cnblogs.com/China-Dragon/archive/2009/05/12/1455147.html ----------------------------???---------------------
-E是使用Windows认证,也可以使用数据库认证
aspnet_regsql.exe -ssadd -sstype c -d [DB] -S [Server] –U [User Name] – P [Password]
2. 修改web.config:
<sessionState mode="SQLServer" allowCustomSqlDatabase="true" sqlConnectionString="data source=[Server];initial catalog=[DB];user id=[User Name];password=[Password]"
cookieless="false"
timeout="20" />
如果使用默认的数据库名称,如下:
<sessionState mode="SQLServer" sqlConnectionString="data source=[Server];user id=[User Name];password=[Password]"
cookieless="false"
timeout="20" />
//------------------------------------
40节