ASP.Net MVC小知识

创建一个ASP.Net MVC Web 应用程序(.NETFramework)

微软文档教程在这里。
ASP.NET MVC使用的是Razor结合的html界面,第一次接触的时候还有点不适应,看了看文档发现跟<%=var%> aspx页面是差不多的,熟悉熟悉Razor语法就可以正常使用了。还是听不难的(为什么不是挺简单…)
这是创建好的MVC项目。
image.png
App_Start文件夹里面是一些配置cs文件。
Controllers文件夹里面是控制器,主要语法写在这里。
Models文件夹里面是实体数据模型,与数据库交互的地方。下面有介绍的。
Views文件夹里面是视图文件,也就是HTML(cshtml)文件。
用户通过请求控制器来获得视图里面的内容。

做一个注册页

首先创建一个实体数据库模型(介绍在下面。往下翻)
然后打开HomeController.cs文件,在里面追加一个方法。

  1. public ActionResult Register()
  2. {
  3. ViewBag.Message = "这是注册页.";
  4. return View();
  5. }

然后右击方法名,–添加视图
ok,视图就创建好了。视图采用的是默认模板。
打开视图文件,优雅的写上一段form提交模板。写上ajax

  1. <script src="~/Scripts/jquery-3.3.1.min.js"></script>
  2. <script>
  3. $(function () {
  4. $("#btnRegister").click(function () {
  5. var pars = $("#form1").serializeArray();
  6. $.post( "/home/Regist",pars, function(data) {
  7. alert(data);
  8. });
  9. });
  10. });
  11. </script>
  12. //这里呢,是跳转到home控制器下面的Regist方法中。在下面
  13. <form method="post" action="/home/Regist" id="form1">
  14. <label id="tips"></label>
  15. @*把name赋值为usersinfo里的内容*@
  16. 账号:<input type="text" id="userName" @*name="username"*@ name="uaccount"/><br />
  17. 密码:<input type="text" id="userPass" @*name="userpass"*@ name ="upassword"/><br />
  18. 邮箱:<input type="text" id="userEmail" @*name="useremail"*@ name="uemail"/><br />
  19. 手机:<input type="text" id="userPhone" @*name="userphone"*@ name ="uphone"/><br />
  20. <input type="submit" value="注册" />
  21. <input type="button" value="异步注册" id="btnRegister" />
  22. </form>

然后再HomeController.cs中这么写。

  1. //这就是跳转到的注册方法。
  2. //如果表单元素的name属性的值和实体类中的属性的名字保持一致,
  3. //那么表单中的数据会自动赋值给实体中的属性
  4. //public ActionResult Regist()
  5. //{
  6. public ActionResult Regist(usersinfo ui){
  7. //usersinfo ui = new usersinfo();
  8. //ui.uaccount = Request["username"];
  9. //ui.upassword = Request["userpass"];
  10. //ui.uemail = Request["useremail"];
  11. //ui.uphone = Request["userphone"];
  12. ui.udatetime = DateTime.Now.ToString();
  13. ztest01Entities db = new ztest01Entities();
  14. db.usersinfo.Add(ui);
  15. if (db.SaveChanges() > 0)
  16. {
  17. return Content("成功");
  18. }else
  19. {
  20. return Content("失败");
  21. }
  22. }

这样的话,就完成了。
还可以定义重载,用来区分getOrPost请求,这样看起来代码比较清晰。

  1. public ActionResult Register()
  2. {
  3. ViewBag.Message = "这是注册页.";
  4. return View();
  5. }
  6. [HttpPost]//只能接收post,优先处理post请求
  7. public ActionResult Register(usersinfo ui)
  8. {
  9. ui.udatetime = DateTime.Now.ToString();
  10. ztest01Entities db = new ztest01Entities();
  11. db.usersinfo.Add(ui);
  12. if (db.SaveChanges() > 0)
  13. {
  14. return Content("成功");
  15. }
  16. else
  17. {
  18. return Content("失败");
  19. }
  20. //return View();
  21. }

MVC小语法

小知识

  1. MVC表示不应该再次编码的HTML字符串
  2. @MvcHtmlString.Create(ViewData["usersinfo"].ToString())
  3. 这样可以让html字符串正确显示
  4. 初始化页面的时候进行id赋值
  5. <li>@Html.ActionLink("用户详情", "UsersInfoView", "UsersInfo",new {id=1},"")</li>
  6. //第三个是routeValues ,是用来赋值id的。
  7. 增删改查代码在下面
  8. MVC RouteConfig.cs路由规则的匹配。
  9. routes.MapRoute(
  10. name: "Default",
  11. url: "{controller}/{action}/{id}",
  12. defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  13. );routes.MapRoute(
  14. name: "Default2",
  15. url: "{controller}-{action}/{id}",
  16. defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  17. );
  18. 如果第一个匹配失败,则会匹配第二个..第三个..第N个直到匹配成功
  19. 如果都匹配失败,则报错。
  20. 如果第一个匹配成功了,则直接跳出,不会再匹配第二个,即使第二个也是对的

MVC UsersInfoController增删改查 源代码

UsersInfoView.cshtmlUsersInfoController.cs

MVC使用ajax获取json

  1. HTML代码
  2. <script src="~/Scripts/jquery-3.3.1.min.js"></script>
  3. <script>
  4. $(function () {
  5. $("#btnGet").click(function(){
  6. $.post("/Demo/GetList", {}, function (data) {
  7. for (var i = 0; i < data.length; i++) {
  8. $("#div1").append(data[i].uaccount);
  9. }
  10. });
  11. });
  12. });
  13. </script>
  14. <h2>Index</h2>
  15. <div>
  16. <input type="button" value="ajax获取数据" id="btnGet" />
  17. </div>
  18. <div id="div1"></div>
  19. 控制器代码
  20. public ActionResult GetList()
  21. {
  22. ztest01Entities db = new ztest01Entities();
  23. //把获得的数据转成list离合
  24. List<usersinfo> list = db.usersinfo.Where<usersinfo>(u => true).ToList();
  25. //然后反序列化为json返回到前端
  26. return Json(list);
  27. }

Routing路由

路由的作用:
确定Controller
确定Action
确定其他参数
根据识别出来的数据,将请求传递给Controller和Action

Area区域

可以用来存放网站的后台,以及其他需要分类的MVC项目。
image.png

Filter过滤器

AOP:面向切口编程
在用户输入网址到显示页面的过程中做一些操作。

  1. Attribute 是属性,可以附加在方法和类上面,用来进行验证
  2. public class FilterDemoAttribute : ActionFilterAttribute
  3. {
  4. public string Messages { get; set; }
  5. /// <summary>在执行操作方法之前由 ASP.NET MVC 框架调用。</summary>
  6. /// <param name="filterContext">筛选器上下文。</param>
  7. public override void OnActionExecuting(ActionExecutingContext filterContext)
  8. {
  9. filterContext.HttpContext.Response.Write("在执行操作方法之前由 ASP.NET MVC 框架调用" +"\n" + Messages);
  10. base.OnActionExecuting(filterContext);
  11. }
  12. /// <summary>在执行操作方法后由 ASP.NET MVC 框架调用。</summary>
  13. /// <param name="filterContext">筛选器上下文。</param>
  14. public override void OnActionExecuted(ActionExecutedContext filterContext)
  15. {
  16. filterContext.HttpContext.Response.Write("在执行操作方法之后由 ASP.NET MVC 框架调用" + "\n" + Messages);
  17. base.OnActionExecuted(filterContext);
  18. }
  19. /// <summary>在执行操作结果之前由 ASP.NET MVC 框架调用。</summary>
  20. /// <param name="filterContext">筛选器上下文。</param>
  21. public override void OnResultExecuting(ResultExecutingContext filterContext)
  22. {
  23. filterContext.HttpContext.Response.Write("在执行操作结果之前由 ASP.NET MVC 框架调用" + "\n" + Messages);
  24. base.OnResultExecuting(filterContext);
  25. }
  26. /// <summary>在执行操作结果后由 ASP.NET MVC 框架调用。</summary>
  27. /// <param name="filterContext">筛选器上下文。</param>
  28. public override void OnResultExecuted(ResultExecutedContext filterContext)
  29. {
  30. filterContext.HttpContext.Response.Write("在执行操作结果后由 ASP.NET MVC 框架调用" + "\n" + Messages);
  31. base.OnResultExecuted(filterContext);
  32. }
  33. }

例如附加在Controller上。

  1. [FilterDemo]
  2. public class HomeController : Controller
  3. {
  4. }

这样Controller里面所有的页面加载之前之后都会进行验证
所以可以把验证的代码写在这里面进行统一的验证,
修改起来也方便。

ASP.Net小知识点(一)

EntityFramework的安装(2020-08-17测试)

第一步:首先下载 (1)和(2)
(1):mysql-connector-net-6.10.7.msi
这个一定要安装这个!!(下面有详细解释)
(2):mysql-for-visualstudio-1.2.8.msi 或者1.2.7 下载
第二步:打开visual studio 2019
新建一个 .net web项目
然后通过 Nuget 安装 MySql.Data.Entity-6.10.7
安装 MySql.Data.Entity-6.10.7 的时候会同步安装其他依赖,所以安装这一个就可以了。一定要和 mysql-connector-net 版本相同。
image.png
重点来了,如果 MySql.Data.Entity 的版本和 mysql-connector-net 的版本不一样,而且 mysql-for-visualstudio 这个的版本高于这两个配套得版本时,创建 实体数据模型 的时候就会闪退。
所以,一定要按照这个模板安装。(如果后来更新的话,可以再重新尝试新的搭配。)
在进行连接数据库的时候,这里的 Old Guids 一定要选true 。
然后下面的端口号,如果不是3306的话,就需要填入自己的端口号才能进行连接。
image.pngimage.png
然后选择要操作的表,进行勾选,然后点击完成,就创建完成了。

还有就是本地的mysql在进行这项操作的时候可能会报错,我的就是这样,使用了云数据库以后就不会报错了,网上也查不到,不知道是不是特例。

最后!不要轻易升级这些包。升级以后可能都不能用了。

使用实体数据模型创建MySQL数据表

先创建一个空的实体数据模型。
image.png
然后点击新建的数据模型,在空白处右键 — 新增实体
image.pngimage.png
然后给新建的实体添加属性就可以了
当设计好数据表以后,右键这个数据表
image.png
点击 根据模型生成数据库。
这里可能会报错,如果报错的话,可能就是生成工具的版本错误了。
点击数据表所在的空白处,右键,选择 -属性
修改DDL生成模板
image.png
可能有很多选项,选择一个不会出错的 就可以了。
生成完毕以后,会出现一个sql文件。
如果是SQLserver的话可以直接右键文件–运行
image.png
如果是MySQL的话,就需要把这段数据库代码粘贴到数据库查询页面,然后执行。
注意!这里有一段话,是判断是否存在当前数据库的,如果存在就会直接DROP数据库,如果数据库有东西的话,不删除这段话可能会欲哭无泪。。记得删除。
好啦,这样就完成从数据库模型到数据表的转换了。

EntityFramework相关知识

.tt的都是模板的文件,是自动生成的,不需要修改。

通过Entity向数据库添加数据

  1. //当添加按钮点击时,通过Entity向数据库添加数据
  2. protected void Button1_Click(object sender, EventArgs e)
  3. {
  4. var mb = new MemberInfo();
  5. mb.mitypeid = 7;
  6. mb.miname = "EF我叫EF";
  7. mb.miphone = "这是phone";
  8. mb.mimoney = 333333;
  9. mb.miisdelete = false;
  10. //找到 Model1.Context.tt 里的类名,也就是数据表名加上Entities
  11. //通过它向数据库添加操作
  12. var mtd = new myTestDatabaseEntities();
  13. //将数据添加到EF并添加了添加标记。
  14. mtd.MemberInfo.Add(mb);
  15. //把数据保存到数据库 自动生成语句添加到数据库。
  16. //返回受影响的行数 int
  17. var lines = mtd.SaveChanges();
  18. //获得刚插入的id
  19. Response.Write(mb.miid);
  20. }

通过Entity向数据库查询数据 — linq表达式

linq Doc

  1. //当查询按钮点击时
  2. protected void Button2_Click(object sender, EventArgs e)
  3. {
  4. //new 一个数据库操作类
  5. myTestDatabaseEntities db = new myTestDatabaseEntities();
  6. //使用 Linq 表达式
  7. IQueryable<MemberInfo> memberList = from mem in db.MemberInfo where mem.miid == 28 select mem;
  8. //遍历得到的数据
  9. //延迟加载机制 --当数据使用到的时候,才会进行查询 例子中当语句走到 in 的时候,才开始进行数据库查询
  10. foreach (MemberInfo mebInfo in memberList)
  11. {
  12. Response.Write(mebInfo.miphone);
  13. }
  14. }

通过Entity向数据库删除数据

  1. //当删除按钮点击的时候
  2. protected void Button3_Click(object sender, EventArgs e)
  3. {
  4. var db = new myTestDatabaseEntities();
  5. //var memberList = from mem in db.MemberInfo
  6. // where mem.miid == 28
  7. // select mem;
  8. ////返回第一个元素或者null(没有元素的时候) FirstOrDefault();
  9. //MemberInfo mbi = memberList.FirstOrDefault();
  10. //if (mbi != null)
  11. //{
  12. // //删除查出来的数据
  13. // //db.MemberInfo.Remove(mbi);
  14. // //通过枚举标记数据的状态 标记为删除状态
  15. // db.Entry<MemberInfo>(mbi).State = System.Data.Entity.EntityState.Deleted;
  16. // //更新到数据库中
  17. // db.SaveChanges();
  18. //}
  19. //else
  20. //{
  21. // Response.Write("删除的数据不存在");
  22. //}
  23. //方法2 常用
  24. MemberInfo mbi = new MemberInfo(){miid = 29};
  25. db.Entry<MemberInfo>(mbi).State = System.Data.Entity.EntityState.Deleted;
  26. db.SaveChanges();
  27. }

通过Entity向数据库更新数据

  1. //更新按钮点击的时候
  2. protected void Button4_Click(object sender, EventArgs e)
  3. {
  4. var db = new myTestDatabaseEntities();
  5. var memberList = from mem in db.MemberInfo where mem.miid == 31 select mem;
  6. var mbi = memberList.FirstOrDefault();
  7. mbi.miphone = "新的phone新的phone";
  8. //把状态标记为更新
  9. db.Entry<MemberInfo>(mbi).State = EntityState.Modified;
  10. db.SaveChanges();
  11. }

EntityFramework错误指示

找不到连接字符串

错误:No connection string named ‘XXXXX’ could be found in the application config file.
出现这个错误的原因是因为虽然在类库中的AppConfig里面设定了Entity的连接字符串,但是在主项目中没有这个连接字符串,所以就会报这个错误,只要把连接字符串从类库中复制到主项目的AppConfig里面,就不会报错了。


ASP.Net小知识点(二)

委托Action<>();

  1. if (this.textBox1.InvokeRequired)//是否要对文本框进行跨线程访问。
  2. {
  3. //Invoke:去找创建TextBox的线程(主线程(UI线程)),有主线程完成委托方法的调用。
  4. this.textBox1.Invoke(new Action<TextBox, string>(ShowTextBoxValue), this.textBox1, a.ToString());//
  5. }
  6. else
  7. {
  8. this.textBox1.Text = a.ToString();
  9. }
  10. private void ShowTextBoxValue(TextBox txt, string value)
  11. {
  12. txt.Text = value;
  13. }
  14. 当两个线程共同调用一个方法的时候,可以定义一个公共资源锁。
  15. 在锁死的时候,其他线程无法进行访问。
  16. private void button5_Click(object sender, EventArgs e)
  17. {
  18. // this.textBox1.Text = "safasdfd";
  19. Thread thread1 = new Thread(AddSum);
  20. thread1.IsBackground = true;
  21. thread1.Start();
  22. Thread thread2 = new Thread(AddSum);
  23. thread2.IsBackground = true;
  24. thread2.Start();
  25. }
  26. private static readonly object obj = new object();
  27. private void AddSum()
  28. {
  29. lock (obj)
  30. {
  31. for (int i = 0; i < 2000; i++)
  32. {
  33. int a = Convert.ToInt32(this.textBox1.Text);
  34. a++;
  35. this.textBox1.Text = a.ToString();
  36. }
  37. }
  38. }
  39. 自定义跨线程访问方法
  40. private void button4_Click(object sender, EventArgs e)
  41. {
  42. Thread thread1 = new Thread(ShowResult);
  43. thread1.IsBackground = true;
  44. thread1.Start();
  45. }
  46. private void ShowResult()
  47. {
  48. int a = 0;
  49. for (int i = 0; i < 600000000; i++)
  50. {
  51. a = i;
  52. }
  53. //MessageBox.Show(a.ToString());
  54. if (this.textBox1.InvokeRequired)//是否要对文本框进行跨线程访问。
  55. {
  56. //Invoke:去找创建TextBox的线程(主线程(UI线程)),有主线程完成委托方法的调用。
  57. this.textBox1.Invoke(new Action<TextBox, string>(ShowTextBoxValue), this.textBox1, a.ToString());//
  58. }
  59. else
  60. {
  61. this.textBox1.Text = a.ToString();
  62. }
  63. }

JSON转义

  1. using Newtonsoft.Json;
  2. ....
  3. var s = JsonConvert.ToString(@"a\b");
  4. Console.WriteLine(s);
  5. ....

web.config

image.png
这里的debug在正式上线网站的时候一定要设置为false。

  1. //错误页面配置
  2. <customErrors mode="On" defaultRedirect="MyErrorPage.html">
  3. <error statusCode="403" redirect="NoAccess.htm" />
  4. <error statusCode="404" redirect="FileNotFound.html" />
  5. </customErrors>

IsPostBack

IsPostBack 判断是不是post请求
是根据VIEWSTATE隐藏域进行判断的。是post的话,隐藏域的value也会提交
所以属性就是true了。
如果去掉了form的标签 runat 就不能用该属性进行判断了。
因为去掉了runat 就不会有
VIEWSTATE隐藏域了。

更新网页信息

替换占位符的内容  重新写入网页中
string filePath = context.Request.MapPath("UserInfoList.html");
string fileContent = File.ReadAllText(filePath);
fileContent = fileContent.Replace("@tbody", sb.ToString());
context.Response.Write(fileContent);
上传文件的时候 form中必须加入这个编码。才能把文件流发送到服务器。
<form action="/Upload.ashx" method="post" enctype="multipart/form-data">
        <input type="file" name="fileup" value="" />
        <input type="submit" name="submit2" value="提交" />
    </form>

mysql实现分页查询

搜索这个表 在第10行往后搜索25个。结果是 11 -35
SELECT * FROM usersInfo LIMIT 10, 25
分25个每页查询
int infoIndex = pages * 25;
StringBuilder sb = new StringBuilder();
if (infoIndex < 25)
{
sb.AppendFormat("select * from usersInfo LIMIT {0},{1}", 0, 25);
}
else
{
sb.AppendFormat("select * from usersInfo LIMIT {0},{1}", (pages - 1)*25, 25);
}
string sqlUrl = sb.ToString();

接受总数据库的行数

string
conUrl=ConfigurationManager.ConnectionStrings["connectStr"].ConnectionString;
string sqlUrl5 = "select count(*) from usersInfo";
            MySqlConnection msc = new MySqlConnection(conUrl);
            msc.Open();
            MySqlCommand mcmd = new MySqlCommand(sqlUrl5, msc);
int counts = Convert.ToInt32(mcmd.ExecuteScalar());
            msc.Close();
return counts;

mysql实现联合查询

//联合查询
SELECT mi.*,mti.`memtitle` FROM MemberInfo AS mi INNER JOIN MemberTypeInfo AS mti ON mi.`mitypeid`=mti.`memid`

创建cookie

//创建cookies
//Response.Cookies["ck1"].Value = "123345";
//创建cookie并指定过期时间
Response.Cookies["ck1"].Value = "12334242";
Response.Cookies["ck1"].Expires = DateTime.Now.AddDays(3);
//获取cookie
Response.Write(Request.Cookies["ck1"].Value);
//删除cookie
Response.Cookies["ck1"].Value = "12334242";
Response.Cookies["ck1"].Expires = DateTime.Now.AddMilliseconds(-1);
//cookie跨域
Response.Cookies["ck1"].Value = "12334242";
Response.Cookies["ck1"].Domain = "";//该处设置为主域名
子域名的cookie默认不会发送给主域。
反之则可以。

创建session

//创建session
Session["user"] = userA;
Session["pass"] = MD5Helper.CreateMd5(userP).ToString();
//要在普通类中使用session,要使其继承System.Web.UI.page
//继承之前要先进行引用,然后就可以使用session了。
//因为一个网站会有很多网页,所以每一个网页进行验证session的时候
//要写很多代码,所以可以封装一个验证类。需要验证的时候调用类就行了
//session主要是用来验证登录,存储重要信息的。因为信息存储在web端
//不会造成泄露的风险。
//指定session的过期时间
session默认过期时间是二十分钟。是滑动过期时间。
ashx中使用session 
1.命名空间中要加入using System.Web.SessionState;
2.接口名要加入IRequiresSessionState或IReadOnlySessionState;
3.不管是Session还是QueryString都要通过HttpContext来获取。
//统一验证session的方法。
定义一个类继承System.Web.UI.Page
public partial class UniteCheckSession : System.Web.UI.Page
    {
public void Page_Init(object sender, EventArgs e)
        {
if (Session["userAccount"] == null || Session["userPass"] == null)
            {
                Response.Redirect("/Login.aspx");
            }
        }
    }
这样就重写了Page_Init方法,继承子类同时也继承父类
所以直接继承子类就行了。就可以在想要的网页中添加验证
session是每个用户特有的。每个用户都有自己的session对象。
但是放在cache里的数据是大家共享的。

创建Cache

创建cache
Cache["thisCache"] = "This is a cache";
Cache.Insert("thisCache","This is a cache",null,DateTime);
如果cache不指定过期时间,那么cache就会一直存在服务器内存中,知道服务器关闭。
cache文件依赖
string filePath = Request.MapPath("File.txt");
if (Cache["fileContent"] == null)
            {
//文件缓存依赖.
                CacheDependency cDep = new CacheDependency(filePath);
string fileContent = File.ReadAllText(filePath);
                Cache.Insert("fileContent", fileContent, cDep);
                Response.Write("数据来自文件");
            }
else
            {
                Response.Write("数据来自缓存:"+Cache["fileContent"].ToString());
            }

内容类型

image.png
这里的text/html要和刷进去的代码样式一样。。不能是plain刷html,不然就写不出代码。

JQuery失效的问题

image.png
这个样子是正确引用
image.png
这个则是错误引用,是不能操作jQuery的。