ASP.Net MVC小知识
创建一个ASP.Net MVC Web 应用程序(.NETFramework)
微软文档教程在这里。
ASP.NET MVC使用的是Razor结合的html界面,第一次接触的时候还有点不适应,看了看文档发现跟<%=var%> aspx页面是差不多的,熟悉熟悉Razor语法就可以正常使用了。还是听不难的(为什么不是挺简单…)
这是创建好的MVC项目。
App_Start文件夹里面是一些配置cs文件。
Controllers文件夹里面是控制器,主要语法写在这里。
Models文件夹里面是实体数据模型,与数据库交互的地方。下面有介绍的。
Views文件夹里面是视图文件,也就是HTML(cshtml)文件。
用户通过请求控制器来获得视图里面的内容。
做一个注册页
首先创建一个实体数据库模型(介绍在下面。往下翻)
然后打开HomeController.cs文件,在里面追加一个方法。
public ActionResult Register()
{
ViewBag.Message = "这是注册页.";
return View();
}
然后右击方法名,–添加视图
ok,视图就创建好了。视图采用的是默认模板。
打开视图文件,优雅的写上一段form提交模板。写上ajax
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script>
$(function () {
$("#btnRegister").click(function () {
var pars = $("#form1").serializeArray();
$.post( "/home/Regist",pars, function(data) {
alert(data);
});
});
});
</script>
//这里呢,是跳转到home控制器下面的Regist方法中。在下面
<form method="post" action="/home/Regist" id="form1">
<label id="tips"></label>
@*把name赋值为usersinfo里的内容*@
账号:<input type="text" id="userName" @*name="username"*@ name="uaccount"/><br />
密码:<input type="text" id="userPass" @*name="userpass"*@ name ="upassword"/><br />
邮箱:<input type="text" id="userEmail" @*name="useremail"*@ name="uemail"/><br />
手机:<input type="text" id="userPhone" @*name="userphone"*@ name ="uphone"/><br />
<input type="submit" value="注册" />
<input type="button" value="异步注册" id="btnRegister" />
</form>
然后再HomeController.cs中这么写。
//这就是跳转到的注册方法。
//如果表单元素的name属性的值和实体类中的属性的名字保持一致,
//那么表单中的数据会自动赋值给实体中的属性
//public ActionResult Regist()
//{
public ActionResult Regist(usersinfo ui){
//usersinfo ui = new usersinfo();
//ui.uaccount = Request["username"];
//ui.upassword = Request["userpass"];
//ui.uemail = Request["useremail"];
//ui.uphone = Request["userphone"];
ui.udatetime = DateTime.Now.ToString();
ztest01Entities db = new ztest01Entities();
db.usersinfo.Add(ui);
if (db.SaveChanges() > 0)
{
return Content("成功");
}else
{
return Content("失败");
}
}
这样的话,就完成了。
还可以定义重载,用来区分getOrPost请求,这样看起来代码比较清晰。
public ActionResult Register()
{
ViewBag.Message = "这是注册页.";
return View();
}
[HttpPost]//只能接收post,优先处理post请求
public ActionResult Register(usersinfo ui)
{
ui.udatetime = DateTime.Now.ToString();
ztest01Entities db = new ztest01Entities();
db.usersinfo.Add(ui);
if (db.SaveChanges() > 0)
{
return Content("成功");
}
else
{
return Content("失败");
}
//return View();
}
MVC小语法
小知识
MVC表示不应该再次编码的HTML字符串
@MvcHtmlString.Create(ViewData["usersinfo"].ToString())
这样可以让html字符串正确显示
初始化页面的时候进行id赋值
<li>@Html.ActionLink("用户详情", "UsersInfoView", "UsersInfo",new {id=1},"")</li>
//第三个是routeValues ,是用来赋值id的。
增删改查代码在下面
MVC RouteConfig.cs路由规则的匹配。
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);routes.MapRoute(
name: "Default2",
url: "{controller}-{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
如果第一个匹配失败,则会匹配第二个..第三个..第N个直到匹配成功
如果都匹配失败,则报错。
如果第一个匹配成功了,则直接跳出,不会再匹配第二个,即使第二个也是对的
MVC UsersInfoController增删改查 源代码
UsersInfoView.cshtml — UsersInfoController.cs
MVC使用ajax获取json
HTML代码
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script>
$(function () {
$("#btnGet").click(function(){
$.post("/Demo/GetList", {}, function (data) {
for (var i = 0; i < data.length; i++) {
$("#div1").append(data[i].uaccount);
}
});
});
});
</script>
<h2>Index</h2>
<div>
<input type="button" value="ajax获取数据" id="btnGet" />
</div>
<div id="div1"></div>
控制器代码
public ActionResult GetList()
{
ztest01Entities db = new ztest01Entities();
//把获得的数据转成list离合
List<usersinfo> list = db.usersinfo.Where<usersinfo>(u => true).ToList();
//然后反序列化为json返回到前端
return Json(list);
}
Routing路由
路由的作用:
确定Controller
确定Action
确定其他参数
根据识别出来的数据,将请求传递给Controller和Action
Area区域
Filter过滤器
AOP:面向切口编程
在用户输入网址到显示页面的过程中做一些操作。
Attribute 是属性,可以附加在方法和类上面,用来进行验证
public class FilterDemoAttribute : ActionFilterAttribute
{
public string Messages { get; set; }
/// <summary>在执行操作方法之前由 ASP.NET MVC 框架调用。</summary>
/// <param name="filterContext">筛选器上下文。</param>
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("在执行操作方法之前由 ASP.NET MVC 框架调用" +"\n" + Messages);
base.OnActionExecuting(filterContext);
}
/// <summary>在执行操作方法后由 ASP.NET MVC 框架调用。</summary>
/// <param name="filterContext">筛选器上下文。</param>
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("在执行操作方法之后由 ASP.NET MVC 框架调用" + "\n" + Messages);
base.OnActionExecuted(filterContext);
}
/// <summary>在执行操作结果之前由 ASP.NET MVC 框架调用。</summary>
/// <param name="filterContext">筛选器上下文。</param>
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("在执行操作结果之前由 ASP.NET MVC 框架调用" + "\n" + Messages);
base.OnResultExecuting(filterContext);
}
/// <summary>在执行操作结果后由 ASP.NET MVC 框架调用。</summary>
/// <param name="filterContext">筛选器上下文。</param>
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("在执行操作结果后由 ASP.NET MVC 框架调用" + "\n" + Messages);
base.OnResultExecuted(filterContext);
}
}
例如附加在Controller上。
[FilterDemo]
public class HomeController : Controller
{
}
这样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 版本相同。
重点来了,如果 MySql.Data.Entity 的版本和 mysql-connector-net 的版本不一样,而且 mysql-for-visualstudio 这个的版本高于这两个配套得版本时,创建 实体数据模型 的时候就会闪退。
所以,一定要按照这个模板安装。(如果后来更新的话,可以再重新尝试新的搭配。)
在进行连接数据库的时候,这里的 Old Guids 一定要选true 。
然后下面的端口号,如果不是3306的话,就需要填入自己的端口号才能进行连接。
然后选择要操作的表,进行勾选,然后点击完成,就创建完成了。
还有就是本地的mysql在进行这项操作的时候可能会报错,我的就是这样,使用了云数据库以后就不会报错了,网上也查不到,不知道是不是特例。
使用实体数据模型创建MySQL数据表
先创建一个空的实体数据模型。
然后点击新建的数据模型,在空白处右键 — 新增实体
然后给新建的实体添加属性就可以了
当设计好数据表以后,右键这个数据表
点击 根据模型生成数据库。
这里可能会报错,如果报错的话,可能就是生成工具的版本错误了。
点击数据表所在的空白处,右键,选择 -属性
修改DDL生成模板
可能有很多选项,选择一个不会出错的 就可以了。
生成完毕以后,会出现一个sql文件。
如果是SQLserver的话可以直接右键文件–运行
如果是MySQL的话,就需要把这段数据库代码粘贴到数据库查询页面,然后执行。
注意!这里有一段话,是判断是否存在当前数据库的,如果存在就会直接DROP数据库,如果数据库有东西的话,不删除这段话可能会欲哭无泪。。记得删除。
好啦,这样就完成从数据库模型到数据表的转换了。
EntityFramework相关知识
通过Entity向数据库添加数据
//当添加按钮点击时,通过Entity向数据库添加数据
protected void Button1_Click(object sender, EventArgs e)
{
var mb = new MemberInfo();
mb.mitypeid = 7;
mb.miname = "EF我叫EF";
mb.miphone = "这是phone";
mb.mimoney = 333333;
mb.miisdelete = false;
//找到 Model1.Context.tt 里的类名,也就是数据表名加上Entities
//通过它向数据库添加操作
var mtd = new myTestDatabaseEntities();
//将数据添加到EF并添加了添加标记。
mtd.MemberInfo.Add(mb);
//把数据保存到数据库 自动生成语句添加到数据库。
//返回受影响的行数 int
var lines = mtd.SaveChanges();
//获得刚插入的id
Response.Write(mb.miid);
}
通过Entity向数据库查询数据 — linq表达式
//当查询按钮点击时
protected void Button2_Click(object sender, EventArgs e)
{
//new 一个数据库操作类
myTestDatabaseEntities db = new myTestDatabaseEntities();
//使用 Linq 表达式
IQueryable<MemberInfo> memberList = from mem in db.MemberInfo where mem.miid == 28 select mem;
//遍历得到的数据
//延迟加载机制 --当数据使用到的时候,才会进行查询 例子中当语句走到 in 的时候,才开始进行数据库查询
foreach (MemberInfo mebInfo in memberList)
{
Response.Write(mebInfo.miphone);
}
}
通过Entity向数据库删除数据
//当删除按钮点击的时候
protected void Button3_Click(object sender, EventArgs e)
{
var db = new myTestDatabaseEntities();
//var memberList = from mem in db.MemberInfo
// where mem.miid == 28
// select mem;
////返回第一个元素或者null(没有元素的时候) FirstOrDefault();
//MemberInfo mbi = memberList.FirstOrDefault();
//if (mbi != null)
//{
// //删除查出来的数据
// //db.MemberInfo.Remove(mbi);
// //通过枚举标记数据的状态 标记为删除状态
// db.Entry<MemberInfo>(mbi).State = System.Data.Entity.EntityState.Deleted;
// //更新到数据库中
// db.SaveChanges();
//}
//else
//{
// Response.Write("删除的数据不存在");
//}
//方法2 常用
MemberInfo mbi = new MemberInfo(){miid = 29};
db.Entry<MemberInfo>(mbi).State = System.Data.Entity.EntityState.Deleted;
db.SaveChanges();
}
通过Entity向数据库更新数据
//更新按钮点击的时候
protected void Button4_Click(object sender, EventArgs e)
{
var db = new myTestDatabaseEntities();
var memberList = from mem in db.MemberInfo where mem.miid == 31 select mem;
var mbi = memberList.FirstOrDefault();
mbi.miphone = "新的phone新的phone";
//把状态标记为更新
db.Entry<MemberInfo>(mbi).State = EntityState.Modified;
db.SaveChanges();
}
EntityFramework错误指示
找不到连接字符串
错误:No connection string named ‘XXXXX’ could be found in the application config file.
出现这个错误的原因是因为虽然在类库中的AppConfig里面设定了Entity的连接字符串,但是在主项目中没有这个连接字符串,所以就会报这个错误,只要把连接字符串从类库中复制到主项目的AppConfig里面,就不会报错了。
ASP.Net小知识点(二)
委托Action<>();
if (this.textBox1.InvokeRequired)//是否要对文本框进行跨线程访问。
{
//Invoke:去找创建TextBox的线程(主线程(UI线程)),有主线程完成委托方法的调用。
this.textBox1.Invoke(new Action<TextBox, string>(ShowTextBoxValue), this.textBox1, a.ToString());//
}
else
{
this.textBox1.Text = a.ToString();
}
private void ShowTextBoxValue(TextBox txt, string value)
{
txt.Text = value;
}
当两个线程共同调用一个方法的时候,可以定义一个公共资源锁。
在锁死的时候,其他线程无法进行访问。
private void button5_Click(object sender, EventArgs e)
{
// this.textBox1.Text = "safasdfd";
Thread thread1 = new Thread(AddSum);
thread1.IsBackground = true;
thread1.Start();
Thread thread2 = new Thread(AddSum);
thread2.IsBackground = true;
thread2.Start();
}
private static readonly object obj = new object();
private void AddSum()
{
lock (obj)
{
for (int i = 0; i < 2000; i++)
{
int a = Convert.ToInt32(this.textBox1.Text);
a++;
this.textBox1.Text = a.ToString();
}
}
}
自定义跨线程访问方法
private void button4_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(ShowResult);
thread1.IsBackground = true;
thread1.Start();
}
private void ShowResult()
{
int a = 0;
for (int i = 0; i < 600000000; i++)
{
a = i;
}
//MessageBox.Show(a.ToString());
if (this.textBox1.InvokeRequired)//是否要对文本框进行跨线程访问。
{
//Invoke:去找创建TextBox的线程(主线程(UI线程)),有主线程完成委托方法的调用。
this.textBox1.Invoke(new Action<TextBox, string>(ShowTextBoxValue), this.textBox1, a.ToString());//
}
else
{
this.textBox1.Text = a.ToString();
}
}
JSON转义
using Newtonsoft.Json;
....
var s = JsonConvert.ToString(@"a\b");
Console.WriteLine(s);
....
web.config
这里的debug在正式上线网站的时候一定要设置为false。
//错误页面配置
<customErrors mode="On" defaultRedirect="MyErrorPage.html">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.html" />
</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());
}
内容类型
这里的text/html要和刷进去的代码样式一样。。不能是plain刷html,不然就写不出代码。
JQuery失效的问题
这个样子是正确引用
这个则是错误引用,是不能操作jQuery的。