<?xml version="1.0" encoding="utf-8"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <appSettings> <add key="dmsFolder" value="C:\local.dfs.com\Data\DMS\" /> </appSettings> <connectionStrings> <!--<add name="dfs" connectionString="user id=ProferoTest;password=mimaxxx;Data Source=127.0.0.1;Database=databesename" />--> <!--<add name="ConnectionString" connectionString="Data Source=.;Initial Catalog=ExpUsers;Persist Security Info=True;User ID=sa;password=mima;" providerName="System.Data.SqlClient" />--> <add name="ConnectionString" connectionString=" Data Source=.;Initial Catalog=UserExp2;Persist Security Info=True;User ID=sa;password=mima;" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>
讀取:javascript
string connString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString.ToString();
記得添加引用 using System.Configuration;php
savechange 設計模式:工做單元模式 :一個業務對多張表的操做,只連一次數據庫,完成條記錄的更新css
簡單工廠:返回父類或者接口的多種形態html
抽象工廠:經過反射建立前端
單例:相似靜態類 能夠繼承 擴展 延遲加載.....保證程序只new一次 好比隊列 就能夠放在單列裏面java
對象關係映射(英語:Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程序技術,用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換。從效果上說,它實際上是建立了一個可在編程語言裏使用的「虛擬對象數據庫」。 jquery
EF:Entity Frameworkweb
NHibernateredis
Linqsql
Dapper
PetaPoco
轉自:http://zhan.renren.com/h5/entry/3602888498046723643
後臺代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace JTZK_Handle { public class HandleEr { public static string GetEr() { string html = @"<div style=""text-align: center;border: solid 1px #cacaca; margin-top:20px""> <p style=""border-bottom: solid 1px #cacaca; line-height: 40px;""> <img align=""middle"" src=""/images/weixinico.png"" /> 微信掃一掃,分享到朋友圈 </p> <p style=""margin-bottom: 20px; margin-top: 20px;""> <img src=""http://s.jiathis.com/qrcode.php?url={0}"" width=""140"" height=""130"" /> </p> </div>"; return string.Format(html, HttpContext.Current.Request.Url.ToString()); } } }
前臺代碼:
<%=JTZK_Handle.HandleEr.GetEr() %>
const和readonly都是隻讀的。
可是const修飾的變量必須在聲明時賦值。
readonly修飾的變量能夠在聲明時或者構造函數裏賦值。
private const double pi=3.14;
class A { private readonly int a; public A(int v) { a=v; } }
public ActionResult ExpData() { StringBuilder sb = new StringBuilder(); string timeNow = DateTime.Now.ToString(); Response.Clear(); Response.Buffer = false; //通知瀏覽器 下載文件而不是打開 Response.ContentType = "application/octet-stream"; Response.AppendHeader("content-disposition", "attachment;filename=" + timeNow + ".txt;"); var operLogList = operLogBLL.LoadEntities(o=>o.IsValid==1); foreach (var item in operLogList) { sb.Append("時間:" + item.CreateTime.ToString() + "\n"); sb.Append("類別:" + item.Category.ToString() + "\n"); sb.Append("域:" + item.DomainID.ToString() + "\n"); sb.Append("用戶名:" + item.AccountName.ToString() + "\n"); sb.Append("內容:" + item.Content.ToString() + "\n"); sb.Append("--------------------------------------------------\n\n"); } Response.Write(sb); Response.Flush(); Response.End(); return new EmptyResult(); }
//導出數據 function ExpData() { window.location.href = "/LogManager/ExpData"; //MySuccess("導出成功!"); };
國外成功的案例是國內互聯網創業者的風向標。在Disqus http://disqus.com 得到巨大成功。在沒美國不少網站都用此評論系統
社交評論插件的國內模仿者我見到的幾家就是:
一、多說(http://www.duoshuo.com/ )
二、評論啦(http://www.pinglun.la/)
三、友言(http://uyan.cc/)
四、貝米(http://baye.me/)
剛開始在網上找 看到了DomainRoute這個插件
按照教程弄了,確實好使 也能跑起來
但是以前的好多路由配置再改爲這樣的,很差改,並且這個這個沒有控制器 和方法名的限制參數
並且這個插件和url轉小寫的插件不能一塊兒用
最後仍是打算本身在global裏URL重寫吧
--------------------------------------------------------------------------------------------------------------------------
請求報文 接收報文
http協議 返回的請求狀態碼
post請求 get請求
get請求接收 context.Request.QueryString["catalog"]
post請求接收 context.Request.Form["catalog"]
Response.Redirect重定向
context.Response.Redirect("UserInfoList.ashx");
文件上傳 能夠用文件流的MD5 或者GUID作標識,時間不能惟一不建議
webform調用後臺 變量方法
<strong>1.在前臺html控件調用c#後臺變量。</strong> 在後臺的類代碼裏定義一個字符串。如 public partial class Index : System.Web.UI.Page { public string msg = ""; } 而後能夠寫方法改變此字符串的值。 前臺調用也很簡單: <input id="Text1" type="text" value="<%=msg%>"/> <strong>2.在前臺html調用c#後臺方法</strong> 後臺有一個方法: public string test() { return "message"; } 前臺代碼: <input id="Text2" type="text" value="<%=test()%>"/> <strong>3.在前臺js裏調用c#後臺變量</strong> 後臺代碼: public partial class Index : System.Web.UI.Page { public string msg = ""; } 前臺代碼: <script>alert("<%=msg%>");</script> <strong>4.在前臺js裏調用c#後臺變量</strong> 後臺有一個方法: public string test() { return "message"; } 前臺代碼: <script>alert("<%=test() %>");</script> <strong>5,前臺js裏調用後臺帶參數的方法</strong> public string test(string a) { return a+",我是參數傳進來的"; } <script>alert("<%=test("021") %>");</script> <strong>6,前臺js裏調用後臺帶參數的方法</strong> //商品信息 function getProInfo(t) { var result = ""; result = MallPowerSite.order.ChangeOrderEdit.GetProductInfo(t).value;//後臺的方法,注意這裏不用雙引號 return result; }
值得注意的是,要在js中調用C#的變量和函數返回的結果,js代碼必須寫在頁面的<script>...</script>中,而不能寫在獨立的*.js文件中,這樣會js會將*.js的C#代碼做爲字符串處理,而不是變量或者方法。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="UserInfoList.aspx.cs" Inherits="CZBK.ItcastProject.WebApp._2015_5_29.UserInfoList" %> <!DOCTYPE html> <%@ Import Namespace="CZBK.ItcastProject.Model" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script type="text/javascript"> window.onload = function () { var datas = document.getElementsByClassName("deletes"); var dataLength = datas.length; for (var i = 0; i < dataLength; i++) { datas[i].onclick = function () { if (!confirm("肯定要刪除嗎?")) { return false; } } } }; </script> <link href="../Css/tableStyle.css" rel="stylesheet" /> </head> <body> <form id="form1" runat="server"> <div> <a href="AddUserInfo.aspx">添加用戶</a> <table> <tr><th>編號</th><th>用戶名</th><th>密碼</th><th>郵箱</th><th>時間</th><th>刪除</th><th>詳細</th><th>編輯</th></tr> <%-- <%=StrHtml%>--%> <% foreach(UserInfo userInfo in UserList){%> <tr> <td><%=userInfo.Id %></td> <td><%=userInfo.UserName %></td> <td><%=userInfo.UserPass %></td> <td><%=userInfo.Email %></td> <td><%=userInfo.RegTime.ToShortDateString() %></td> <td><a href="Delete.ashx?id=<%=userInfo.Id %>" class="deletes">刪除</a></td> <td>詳細</td> <td><a href="EditUser.aspx?id=<%=userInfo.Id %>">編輯</a> </td> </tr> <%} %> </table> <hr /> </div> </form> </body> </html>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Fdcxm_Mx.aspx.cs" Inherits="WebApplication.Fdc.Fdcxm_Mx" %> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title></title> <link href="/Css/FDC.css" type="text/css" rel="stylesheet" /> </head> <body> <table border="0" cellspacing="1"> <tr> <td colspan="6" align="center" valign="middle" class="title_0"> <%=this.XmFdcInfo.XmName%> </td> </tr> </table> <table border="0" cellspacing="1"> <tr> <td align="center" valign="middle" class="title_1"> 稅款屬期 </td> <td align="center" valign="middle" class="title_1"> 項目固定信息數據申報表 </td> <td align="center" valign="middle" class="title_1"> 項目按月信息數據申報表 </td> <td align="center" valign="middle" class="title_1"> 施工企業報送數據申報表 </td> </tr> <tbody id="tab"> <tr> <td align="center" valign="middle"> <%=Convert.ToDateTime(this.YYS_SKSQ).ToString("yyyy-MM")%> </td> <td align="center" valign="middle"> <a href="#" onclick="top.frames['MainFrame'].WinClose1('/Fdc/Jcxx.aspx?YYS_SKSQ=<%=this.YYS_SKSQ %>&XM_CODE=<%=this.XmFdcInfo.XmCode%>', '<%=this.XmFdcInfo.XmName%>房地產固定信息');"> <%if (this.GDSB_SH_JG == "審覈未經過" || this.GDSB_SH_JG == "") { %>數據申報<%} %><%else { %>數據修改<%} %></a> </td> <td align="center" valign="middle"> <%if (this.GDSB_SH_JG == "審覈已經過") { %> <a href="#" onclick="top.frames['MainFrame'].WinClose1('/Fdc/AysbMx.aspx?YYS_SKSQ=<%=this.YYS_SKSQ %>&XM_CODE=<%=this.XmFdcInfo.XmCode%>', '<%=this.XmFdcInfo.XmName%>按月數據申報信息');"> <%if (this.AYSB_SH_JG == "審覈未經過" || this.AYSB_SH_JG == "") { %>數據申報<%} %><%else { %>數據修改<%} %></a> <%} else { %>數據申報<%} %> </td> <td align="center" valign="middle"> <%if (AYSB_SH_JG == "審覈已經過" && this.GDSB_SH_JG == "審覈已經過" && this.XmFdcInfo.XmZt != "尾盤") { %> <a href="#" onclick="top.frames['MainFrame'].WinClose1('/Fdc/SGDW.aspx?YYS_SKSQ=<%=this.YYS_SKSQ %>&XM_CODE=<%=this.XmFdcInfo.XmCode%>', '<%=this.XmFdcInfo.XmName%>報送施工企業信息');"> <%if (this.SGDW_SH_JG == "審覈未經過" || this.SGDW_SH_JG == "") { %>數據申報<%} %><%else { %>數據修改<%} %></a> <%} else { %>數據申報<%} %> </td> </tr> <tr> <td align="center" valign="middle" class="title_1"> 歷史數據 </td> <td align="center" valign="middle" class="title_1"> 項目固定信息數據申報表 </td> <td align="center" valign="middle" class="title_1"> 項目按月信息數據申報表 </td> <td align="center" valign="middle" class="title_1"> 施工企業報送數據申報表 </td> </tr> <%=this.Output%> </tbody> </table> <script type="text/javascript" language="JavaScript"> function a() { alert("項目固定信息數據申報表,錯誤,請修改!"); TopView(); } function TopView(){ top.ymPrompt.close(); top.ymPrompt.win({ message: '<div style="width:900px;height:550px;overflow-x: scroll;overflow-y: scroll;"><iframe id="MenuFrame" src="Fdc/AysbMx.aspx" height="100%" width="100%" frameborder="0" ></iframe></div>', width: 905, height: 580, title: "項目固定信息數據申報表", iframe: false, closeBtn: true, dragOut: false }); } <!-- var Ptr=document.getElementById("tab").getElementsByTagName("tr"); function $() { for (i=1;i<Ptr.length+1;i++) { Ptr[i-1].className = (i%2>0)?"t1":"t2"; } } window.onload=$; for(var i=0;i<Ptr.length;i++) { Ptr[i].onmouseover=function(){ this.tmpClass=this.className; this.className = "t3"; }; Ptr[i].onmouseout=function(){ this.className=this.tmpClass; }; } //--> </script> </body> </html>
何時用aspx 是時候用ashx(通常處理程序)
建議:
若是有複雜的界面佈局用aspx
若是沒有佈局例如刪除,用ashx,或者返回json數據
1五、
若是往本頁即post又get請求,能夠在form裏放一個隱藏域(input)
若是有 runat="server" 就自動添加隱藏域,判斷的時候 直接判斷if(isPostBack)就能夠了
<body> <form id="form1" runat="server"> <div> 用戶名:<input type="text" name="txtName" /><br /> 密碼:<input type="password" name="txtPwd" /><br /> 郵箱:<input type="text" name="txtMail" /><br /> <%-- <input type="hidden" name="isPostBack" value="aaa" />--%> <input type="submit" value="添加用戶" /> </div> </form> </body>
sql中的over函數和row_numbert()函數配合使用,可生成行號。可對某一列的值進行排序,對於相同值的數據行進行分組排序。
執行語句:
select row_number() over(order by AID DESC) as rowid,* from bb
dao
/// <summary> /// 根據指定的範圍,獲取指定的數據 /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> public List<UserInfo> GetPageList(int start,int end) { string sql = "select * from(select *,row_number()over(order by id) as num from UserInfo) as t where t.num>=@start and t.num<=@end"; SqlParameter[] pars = { new SqlParameter("@start",SqlDbType.Int), new SqlParameter("@end",SqlDbType.Int) }; pars[0].Value = start; pars[1].Value = end; DataTable da=SqlHelper.GetDataTable(sql, CommandType.Text, pars); List<UserInfo> list = null; if (da.Rows.Count > 0) { list = new List<UserInfo>(); UserInfo userInfo = null; foreach (DataRow row in da.Rows) { userInfo = new UserInfo(); LoadEntity(userInfo, row); list.Add(userInfo); } } return list; } /// <summary> /// 獲取總的記錄數 /// </summary> /// <returns></returns> public int GetRecordCount() { string sql = "select count(*) from UserInfo"; return Convert.ToInt32(SqlHelper.ExecuteScalar(sql,CommandType.Text)); } private void LoadEntity(UserInfo userInfo, DataRow row) { userInfo.UserName = row["UserName"] != DBNull.Value ? row["UserName"].ToString() : string.Empty; userInfo.UserPass = row["UserPass"] != DBNull.Value ? row["UserPass"].ToString() : string.Empty; userInfo.Email = row["Email"] != DBNull.Value ? row["Email"].ToString() : string.Empty; userInfo.Id = Convert.ToInt32(row["ID"]); userInfo.RegTime = Convert.ToDateTime(row["RegTime"]); }
bll
/// <summary> /// 計算獲取數據的訪問,完成分頁 /// </summary> /// <param name="pageIndex">當前頁碼</param> /// <param name="pageSize">每頁顯示的記錄數據</param> /// <returns></returns> public List<UserInfo> GetPageList(int pageIndex,int pageSize) { int start=(pageIndex-1)*pageSize+1; int end = pageIndex * pageSize; return UserInfoDal.GetPageList(start, end); } /// <summary> /// 獲取總的頁數 /// </summary> /// <param name="pageSize">每頁顯示的記錄數</param> /// <returns></returns> public int GetPageCount(int pageSize) { int recoredCount = UserInfoDal.GetRecordCount();//獲取總的記錄數. int pageCount =Convert.ToInt32(Math.Ceiling((double)recoredCount / pageSize)); return pageCount; }
aspx
using CZBK.ItcastProject.Model; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace CZBK.ItcastProject.WebApp._2015_5_30 { public partial class NewList : System.Web.UI.Page { public string StrHtml { get; set; } public int PageIndex { get; set; } public int PageCount { get; set; } protected void Page_Load(object sender, EventArgs e) { int pageSize=5; int pageIndex; if(!int.TryParse(Request.QueryString["pageIndex"],out pageIndex)) { pageIndex=1; } BLL.UserInfoService UserInfoService = new BLL.UserInfoService(); int pagecount = UserInfoService.GetPageCount(pageSize);//獲取總頁數 PageCount = pagecount; //對當前頁碼值範圍進行判斷 pageIndex = pageIndex < 1 ? 1 : pageIndex; pageIndex = pageIndex > pagecount ? pagecount : pageIndex; PageIndex = pageIndex; List<UserInfo>list= UserInfoService.GetPageList(pageIndex,pageSize);//獲取分頁數據 StringBuilder sb = new StringBuilder(); foreach (UserInfo userInfo in list) { sb.AppendFormat("<li><span>{0}</span><a href='#' target='_blank'>{1}</a></li>",userInfo.RegTime.ToShortDateString(),userInfo.UserName); } StrHtml = sb.ToString(); } } }
pagebarHelper
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Common { public class PageBarHelper { public static string GetPagaBar(int pageIndex, int pageCount) { if (pageCount == 1) { return string.Empty; } int start = pageIndex - 5;//計算起始位置.要求頁面上顯示10個數字頁碼. if (start < 1) { start = 1; } int end = start + 9;//計算終止位置. if (end > pageCount) { end = pageCount; //從新計算一下Start值. start = end - 9 < 1 ? 1 : end - 9; } StringBuilder sb = new StringBuilder(); if (pageIndex > 1) { sb.AppendFormat("<a href='?pageIndex={0}' class='myPageBar'>上一頁</a>", pageIndex - 1); } for (int i = start; i <= end; i++) { if (i == pageIndex) { sb.Append(i); } else { sb.AppendFormat("<a href='?pageIndex={0}' class='myPageBar'>{0}</a>",i); } } if (pageIndex < pageCount) { sb.AppendFormat("<a href='?pageIndex={0}' class='myPageBar'>下一頁</a>", pageIndex + 1); } return sb.ToString(); } } }
<%=Common.PageBarHelper.GetPagaBar(PageIndex,PageCount)%>
http協議 超文本傳輸協議 包括請求響應報文 請求報文包括請求頭 請求內容
request 成員
Files 接受文件 Request.Files["FileName"]
UrlReferrer 請求的來源
Url 請求的網址
UserHostAddress 訪問者IP
Cookie 瀏覽器Cookie
MapPath 虛擬路徑轉物理路徑 ../2016/hello.aspx -->E:\web\2016\hello.aspx
response 成員
Flush() 將緩衝區中的數據發送給用戶
Clear() 清空緩衝區
ContentEncoding 輸出流的編碼
ContentType 輸出流的內容類型 HTML(text/html) 普通文本(text/plain) jpeg (image/JPEG)
server成員
Server.Transfer("Child.aspx")
Server.Execute("Child.aspx");
這兩個是同樣的 都是在後臺訪問其餘的頁面 達到ifram的效果
與Response.Redirect的區別。Transfer:服務端跳轉,不會向瀏覽器返回任何內容,因此地址欄中的URL地址不變。
Server.HtmlEncode("<font color='red'></font>")
好比評論的時候,沒有編碼,別人寫了JavaScript代碼,直接能夠跳轉到別的網站
註釋
服務器註釋 不會顯示到HTML <%--這是註釋內容--%>
顯示到HTML裏 <!--這是註釋內容-->
當咱們在寫一個asp.net表單時, 一旦標明瞭 form runat=server ,那麼,asp.net就會自動在輸出時給頁面添加一個隱藏域
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace CZBK.ItcastProject.WebApp._2015_5_30 { public partial class ViewStateDemo : System.Web.UI.Page { public int Count { get; set; } protected void Page_Load(object sender, EventArgs e) { int count = 0; if (ViewState["count"] != null) { count = Convert.ToInt32(ViewState["count"]); count++; Count = count; } ViewState["count"] = Count;//當咱們把數據給了ViewState對象之後,該對象會將數據進行編碼,而後存到__VIEWSTATE隱藏域中,而後返回給瀏覽器。 //當用戶經過瀏覽器單擊「提交」按鈕,會向服務端發送一個POST請求那麼__VIEWSTATE隱藏域的值也會提交到服務端,那麼服務端自動接收__VIEWSTATE隱藏域的值,而且再反編碼,從新賦值給ViewState對象。 } } }
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ViewStateDemo.aspx.cs" Inherits="CZBK.ItcastProject.WebApp._2015_5_30.ViewStateDemo" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <form id="form1" runat="server"> <div> <span><%=Count%></span> <input type="submit" value="計算" /> </div> </form> </body> </html>
存在瀏覽器中 指定時間:存在硬盤中,關閉瀏覽器也會存在,不指定時間存在瀏覽器內存中,關閉就沒了
瀏覽器關閉就不見了 由於ID是一cookie的形式存在瀏覽器以前傳送,沒有指定過時時間,存在瀏覽器內存中
和page_Load()同樣都是自動執行,不過這個在page_Load以前執行
統一的驗證:寫一個pagebase繼承system.web.UI.page 而後在Page_Init()方法裏寫驗證
若是勾選了自動登陸,把用戶名和密碼存在cookie中 記得加密,下次登陸的時候直接進入get請求,給session賦值
using CZBK.ItcastProject.Model; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace CZBK.ItcastProject.WebApp._2015_5_31 { public partial class UserLogin : System.Web.UI.Page { public string Msg { get; set; } public string UserName { get; set; } protected void Page_Load(object sender, EventArgs e) { if (IsPostBack) { //string userName = Request.Form["txtName"]; //UserName = userName; if (CheckValidateCode())//先判斷驗證碼是否正確. { CheckUserInfo(); } else { //驗證碼錯誤 Msg = "驗證碼錯誤!!"; } } else { //判斷Cookie中的值。自動登陸 CheckCookieInfo(); } } #region 判斷用戶名密碼是否正確 protected void CheckUserInfo() { //獲取用戶輸入的用戶名和密碼. string userName = Request.Form["txtName"]; UserName = userName; string userPwd = Request.Form["txtPwd"]; //校驗用戶名密碼. BLL.UserInfoService UserInfoService = new BLL.UserInfoService(); string msg = string.Empty; UserInfo userInfo = null; //判斷用戶名與密碼 if (UserInfoService.ValidateUserInfo(userName, userPwd, out msg, out userInfo)) { //判斷用戶是否選擇了「自動登陸」 if (!string.IsNullOrEmpty(Request.Form["autoLogin"]))//頁面上若是有多個複選框時,只能將選中複選框的的值提交到服務端。 { HttpCookie cookie1 = new HttpCookie("cp1",userName); HttpCookie cookie2 = new HttpCookie("cp2", Common.WebCommon.GetMd5String(Common.WebCommon.GetMd5String(userPwd))); cookie1.Expires = DateTime.Now.AddDays(7); cookie2.Expires = DateTime.Now.AddDays(7); Response.Cookies.Add(cookie1); Response.Cookies.Add(cookie2); } Session["userInfo"] = userInfo; Response.Redirect("UserInfoList.aspx"); } else { Msg = msg; } } #endregion #region 校驗Cookie信息. protected void CheckCookieInfo() { if (Request.Cookies["cp1"] != null && Request.Cookies["cp2"] != null) { string userName = Request.Cookies["cp1"].Value; string userPwd = Request.Cookies["cp2"].Value; //校驗 BLL.UserInfoService UserInfoService = new BLL.UserInfoService(); UserInfo userInfo=UserInfoService.GetUserInfo(userName); if (userInfo != null) { //注意:在添加用戶或註冊用戶時必定要將用戶輸入的密碼加密之後在存儲到數據庫中。 if (userPwd == Common.WebCommon.GetMd5String(Common.WebCommon.GetMd5String(userInfo.UserPass))) { Session["userInfo"] = userInfo; Response.Redirect("UserInfoList.aspx"); } } Response.Cookies["cp1"].Expires = DateTime.Now.AddDays(-1); Response.Cookies["cp2"].Expires = DateTime.Now.AddDays(-1); } } #endregion #region 判斷驗證碼是否正確 protected bool CheckValidateCode() { bool isSucess = false; if (Session["validateCode"] != null)//在使用Session時必定要校驗是否爲空 { string txtCode = Request.Form["txtCode"];//獲取用戶輸入的驗證碼。 string sysCode = Session["validateCode"].ToString(); if (sysCode.Equals(txtCode, StringComparison.InvariantCultureIgnoreCase)) { isSucess = true; Session["validateCode"] = null; } } return isSucess; } #endregion } }
POST GET:context.request["name"] post:context.request.form["name"] get:context.request.Querystring["name"]
<script type="text/javascript"> $(function () { $("#btnGetDate").click(function () { //開始經過AJAX向服務器發送請求. var xhr; if (XMLHttpRequest) {//表示用戶使用的高版本IE,谷歌,狐火等瀏覽器 xhr = new XMLHttpRequest(); } else {// 低IE xhr=new ActiveXObject("Microsoft.XMLHTTP"); } xhr.open("get", "GetDate.ashx?name=zhangsan&age=12", true); xhr.send();//開始發送 //回調函數:當服務器將數據返回給瀏覽器後,自動調用該方法。 xhr.onreadystatechange = function () { if (xhr.readyState == 4) {//表示服務端已經將數據完整返回,而且瀏覽器所有接受完畢。 if (xhr.status == 200) {//判斷響應狀態碼是否爲200. alert(xhr.responseText); } } } }); }); </script>
<script src="../Js/jquery-1.7.1.js"></script> <script type="text/javascript"> $(function () { $("#btnPost").click(function () { var xhr; if (XMLHttpRequest) { xhr = new XMLHttpRequest(); } else { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } xhr.open("post", "GetDate.ashx", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("name=zhangsan&pwd=123"); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status == 200) { alert(xhr.responseText); } } } }); }); </script>
webform:ifram 母版頁 (或者用第三方框架如fineUI) VTemplate模板 MVC:razor視圖
和session的區別
每一個用戶都有本身單獨的session
可是cache的數據是你們共享的
相同:都放在服務器內存中
using CZBK.ItcastProject.Model; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Caching; using System.Web.UI; using System.Web.UI.WebControls; namespace CZBK.ItcastProject.WebApp._2015_6_6 { public partial class CacheDemo : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //判斷緩存中是否有數據. if (Cache["userInfoList"] == null) { BLL.UserInfoService UserInfoService = new BLL.UserInfoService(); List<UserInfo> list = UserInfoService.GetList(); //將數據放到緩存中。 // Cache["userInfoList"] = list; //第二種賦值方式 Cache.Insert("userInfoList", list); //賦值的重載方法 能夠指定緩存時間 //不推薦用這麼多參數的重載,這裏只是介紹一下,緩存依賴性什麼的徹底不必,在數據庫插入的時候作一下操做就能夠了 Cache.Insert("userInfoList", list, null, DateTime.Now.AddSeconds(5), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Normal, RemoveCache); Response.Write("數據來自數據庫"); //Cache.Remove("userInfoList");//移除緩存 } else { List<UserInfo> list = (List<UserInfo>)Cache["userInfoList"]; Response.Write("數據來自緩存"); } } protected void RemoveCache(string key, object value, CacheItemRemovedReason reason) { if (reason == CacheItemRemovedReason.Expired) { //緩存移除的緣由寫到日誌中。 } } } }
文件緩存依賴項
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Web; using System.Web.Caching; using System.Web.UI; using System.Web.UI.WebControls; namespace CZBK.ItcastProject.WebApp._2015_6_6 { public partial class FileCacheDep : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { 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()); } } } }
http://www.cnblogs.com/xiaoshi657/p/5570705.html
webform
在頁面加<%@ OutputCache Duration="5" VaryByParam="*"%> 就能夠了,若是有參數VaryByParam="id" 兩個參數VaryByParam="id;type" 全部參數VaryByParam="*"
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ShOWDetail.aspx.cs" Inherits="CZBK.ItcastProject.WebApp._2015_6_6.ShOWDetail" %> <%@ OutputCache Duration="5" VaryByParam="*"%> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:DetailsView ID="DetailsView1" runat="server" Height="50px" Width="125px"></asp:DetailsView> </div> </form> </body> </html>
MVC
在MVC中要若是要啓用頁面緩存,在頁面對應的Action前面加上一個OutputCache屬性便可。
[HandleError] public class HomeController : Controller { [OutputCache(Duration = 5, VaryByParam = "none")] public ActionResult Index() { return View(); } }
http://www.cnblogs.com/iamlilinfeng/p/4419362.html#t5
其餘機器:session狀態服務器,單獨一臺機器,專門記錄全部機器的session狀態
數據庫
上面兩個性能過低,微軟給的解決方案,不推薦用。建議用memcache,redis
mode 值
On 指定啓用自定義錯誤。若是沒有指定 defaultRedirect,用戶將看到通常性錯誤。
Off 指定禁用自定義錯誤。這容許顯示詳細的錯誤。
RemoteOnly 指定僅向遠程客戶端端顯示自定義錯誤,並向本地主機顯示 ASP.NET 錯誤。這是默認值。
<configuration> <system.web> <customErrors mode="On" defaultRedirect="MyErrorPage.html"><!--默認錯誤頁面--> <error statusCode="403" redirect="NoAccess.htm" /><!--個別錯誤指定錯誤頁面--> <error statusCode="404" redirect="FileNotFound.html" /> </customErrors> </system.web> </configuration>
ps:iis中有一錯誤頁面 選項 也須要配置一下
new線程 比去線程池中取線程效率低不少
線程池的線程是自動建立的,咱們控制不了,若是想控制線程就要本身new了
所有代碼
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { private static readonly object obj = new object(); public Form1() { InitializeComponent(); TextBox.CheckForIllegalCrossThreadCalls = false; } /// <summary> /// 單線程:當程序執行時,有一個線程負責執行該代碼,沒有辦法與用戶進行其它的交互,因此窗體界面卡死了。(與窗體界面交互的線程叫UI線程。) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { int a = 0; for (int i = 0; i < 999999999; i++) { a = i; } MessageBox.Show(a.ToString()); } /// <summary> /// 將計算的任務交給另一個線程來執行,UI線程仍是負責與用戶進行打交道。默認狀況線程所執行的任務完成了,該線程也就終止了。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> //bool isStop = true;//推薦使用這種方式結束線程,不是thread.Abort() private void button2_Click(object sender, EventArgs e) { ThreadStart threadStart=new ThreadStart(StartCacul); Thread thread = new Thread(threadStart); // thread.Priority = ThreadPriority.Normal;//建議. // thread.Name = "shit"; //thread.Abort();//強制終止線程。儘可能不要該方法 // thread.Join(1000);//主線程會阻塞(睡眠、等待1000毫秒)等待 thread.Start();//將該線程標記可運行狀態。 } private void StartCacul() { // while (isStop)//推薦使用這種方式結束線程,不是thread.Abort() //{ int a = 0; for (int i = 0; i < 999999999; i++) { a = i; } // MessageBox.Show(a.ToString()); this.txtNum.Text = a.ToString(); //} } /// <summary> /// 後臺線程:當窗體關閉該線程也就結束了。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button3_Click(object sender, EventArgs e) { Thread thread1 = new Thread(StartCacul); thread1.IsBackground = true; thread1.Start(); } /// <summary> /// 委託調用帶參數的方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button4_Click(object sender, EventArgs e) { List<int> list = new List<int>() {1,2,3,4,5 }; ParameterizedThreadStart paramThread = new ParameterizedThreadStart(ShowList); Thread thread2 = new Thread(paramThread); thread2.IsBackground = true; thread2.Start(list);//傳遞參數 } private void ShowList(object obj) { List<int> list = (List<int>)obj; foreach (int i in list) { MessageBox.Show(i.ToString()); } } /// <summary> /// 解決跨線程訪問。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button5_Click(object sender, EventArgs e) { Thread thread3 = new Thread(ShowStartCacul); thread3.IsBackground = true; thread3.Start(); } private void ShowStartCacul() { int a = 0; for (int i = 0; i < 999999999; i++) { a = i; } if (this.txtNum.InvokeRequired)//解決跨線程訪問。若是該條件成立表示跨線程訪問. { //Invoke:找到最終建立文本框的線程,而後有該線程爲文本框賦值。 this.txtNum.Invoke(new Action<TextBox, string>(SetValue), this.txtNum, a.ToString()); } } private void SetValue(TextBox txt,string value) { txt.Text = value; } /// <summary> /// 線程同步:當多個線程同時在操做同一個資源時,會出現併發問題(例如操做文件)。這是能夠加鎖。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button6_Click(object sender, EventArgs e) { Thread t1 = new Thread(SetTextValue); t1.IsBackground = true; t1.Start(); Thread t2 = new Thread(SetTextValue); t2.IsBackground = true; t2.Start(); } private void SetTextValue() { lock (obj) { //執行操做。寫文件。 for (int i = 0; i <=2000; i++) { int a = Convert.ToInt32(this.txtNum.Text); a++; this.txtNum.Text = a.ToString(); } } } } }
建立httpapplacation以後 會遍歷全部的httpmodule 包括web.config中配置的
https://www.cnblogs.com/xiaoshi657/p/6529777.html
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace CZBK.ItcastProject.Common { //過濾器。 public class CheckSessionModule:IHttpModule { public void Dispose() { throw new NotImplementedException(); } public void Init(HttpApplication context) { //URL重寫。 // context.AcquireRequestState+=context_AcquireRequestState; } public void context_AcquireRequestState(object sender, EventArgs e) { //判斷Session是否有值. HttpApplication application = (HttpApplication)sender; HttpContext context = application.Context; string url = context.Request.Url.ToString();//獲取用戶請求的URL地址. if (url.Contains("AdminManger"))//網站程序全部的後臺頁面都放在該文件夾中。 { if (context.Session["userInfo"] == null) { context.Response.Redirect("/2015-02-27/Login.aspx"); } } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Security; using System.Web.SessionState; namespace CZBK.ItcastProject.WebApp { public class Global : System.Web.HttpApplication { /// <summary> /// 整個WEB應用程序的入口。至關於Main函數.該方法只執行一次,當WEB應用程序第一次啓動時,執行該方法,後續請求其它頁面該方法不在執行。該方法中通常完成對整個網站的初始化。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Application_Start(object sender, EventArgs e) { //這個只執行一次,其餘的是用戶請求一次執行一次,這個和用戶請求無關,只有服務器上網站啓動的時候,初始化啓動 } /// <summary> /// 開啓會話的時候執行該方法。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Session_Start(object sender, EventArgs e) { //統計訪問人數. //訪問人數+1. //Application:服務端狀態保持機制,而且放在該對象中的數據你們共享的。使用該對象時必須加鎖。 Application.Lock(); if (Application["count"] != null) { int count = Convert.ToInt32(Application["count"]); count++; Application["count"] = count; //向永久保存訪客人數必須將該數據存儲到文件或數據庫中。 } else { Application["count"] = 1; } Application.UnLock(); } protected void Application_BeginRequest(object sender, EventArgs e) { } protected void Application_AuthenticateRequest(object sender, EventArgs e) { } /// <summary> /// 注意的方法。該方法會捕獲程序中(全部)沒有處理的異常。而且將捕獲的異常信息寫到日誌中。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Application_Error(object sender, EventArgs e) { HttpContext.Current.Server.GetLastError();//捕獲異常信息. //將捕獲的異常信息寫到日誌中。 } /// <summary> /// 會話結束的時候執行該方法。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Session_End(object sender, EventArgs e) { //不是實時的,和session的默認有效期是20分鐘有關 } /// <summary> /// 整個應用程序結束的時候執行。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Application_End(object sender, EventArgs e) { } } }
//獲取全部的進程的信息 //Process[] ps=Process.GetProcesses(); //foreach (Process p in ps) //{ // //p.Kill(); // Console.WriteLine(p.ProcessName); //} //獲取當前進程 //Process p= Process.GetCurrentProcess();//獲取當前的進程 //Console.WriteLine(p.ProcessName); //啓動別的進程 //Process.Start("notepad.exe"); //flv. ffmpeg.exe//很好的視頻轉換工具 //視頻轉碼解決方案,用戶傳到服務器,經過進行啓動第三方軟件(如:ffmpeg.exe)進行轉換
/// <summary> /// 將計算的任務交給另一個線程來執行,UI線程仍是負責與用戶進行打交道。默認狀況線程所執行的任務完成了,該線程也就終止了。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> //bool isStop = true;//推薦使用這種方式結束線程,不是thread.Abort() private void button2_Click(object sender, EventArgs e) { ThreadStart threadStart=new ThreadStart(StartCacul); Thread thread = new Thread(threadStart); // thread.Priority = ThreadPriority.Normal;//建議. // thread.Name = "shit"; //thread.Abort();//強制終止線程。儘可能不要該方法 // thread.Join(1000);//主線程會阻塞(睡眠、等待1000毫秒)等待 thread.Start();//將該線程標記可運行狀態。 } private void StartCacul() { // while (isStop)//推薦使用這種方式結束線程,不是thread.Abort() //{ int a = 0; for (int i = 0; i < 999999999; i++) { a = i; } // MessageBox.Show(a.ToString()); this.txtNum.Text = a.ToString(); //} }
/// <summary> /// 後臺線程:當窗體關閉該線程也就結束了。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button3_Click(object sender, EventArgs e) { Thread thread1 = new Thread(StartCacul); thread1.IsBackground = true;//這個值表示窗體關閉,線程就關閉 thread1.Start(); }
線程池:
using System; using System.Threading; namespace ThreadDemo { class program { static void Main() { int nWorkThreads; int nCompletionPortThreads; ThreadPool.GetMaxThreads(out nWorkThreads, out nCompletionPortThreads); Console.WriteLine("Max worker threads: {0}, I/O completion threads: {1}",nWorkThreads, nCompletionProtThreads); for(int i = 0; i < 5; i++) { ThreadPool.QueueUserWorkItem(JobForAThread); } Thread.Sleep(3000); } static void JobForAThread(object state) { for(int i = 0; i < 3; i++) { Console.WriteLine("loop {0}, running inside pooled thread {1}", i, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(50); } } } }
剛剛百度了一下redis的隊列,大體應該是兩個redis的方法
EnqueueItemOnList 將一個元素存入指定ListId的List<T>的頭部
DequeueItemFromList 將指定ListId的List<T>末尾的那個元素出列,返回出列元素
應用:
public class MyExceptionFilterAttribute : HandleErrorAttribute { //版本2:使用Redis的客戶端管理器(對象池) public static IRedisClientsManager redisClientManager = new PooledRedisClientManager(new string[] { //若是是Redis集羣則配置多個{IP地址:端口號}便可 //例如: "10.0.0.1:6379","10.0.0.2:6379","10.0.0.3:6379" "127.0.0.1:6379" }); //從池中獲取Redis客戶端實例 public static IRedisClient redisClient = redisClientManager.GetClient(); public override void OnException(ExceptionContext filterContext) { //將異常信息入隊 redisClient.EnqueueItemOnList("ExceptionLog", filterContext.Exception.ToString()); //跳轉到自定義錯誤頁 filterContext.HttpContext.Response.Redirect("~/Common/CommonError.html"); base.OnException(filterContext); } }
http://www.cnblogs.com/edisonchou/p/3825682.html
ps:log4net 早期版本不支持多線程 log4net 1.2.11版本以上支持
循環的時候 儘可能放在外面 否者每次循環都計算一次 不能for(int i=0,i<a.lenght,i++){}
indexOf Contains
RegionsStr = RegionsStr.Remove(RegionsStr.LastIndexOf(","), 1); //去掉最後一個逗號
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Web; using System.Xml; using WebCenter.Model; namespace WebCenter.Service { /// <summary> /// Index 的摘要說明 /// </summary> public class Index : IHttpHandler { protected readonly string CityIpConfigXMLPath = System.Web.HttpContext.Current.Server.MapPath("/config/CityIpConfigXML.xml"); public void ProcessRequest(HttpContext context) { string _province = context.Request.QueryString["_province"]; string _city = context.Request.QueryString["_city"]; City city = GetSkipCity(_province, _city); context.Response.ContentType = "text/plain"; context.Response.Write("{status:'200',data:" + JsonConvert.SerializeObject(city) + "}"); } /// <summary> /// 根據當前登陸的IP的省份和城市,返回要跳轉的城市 /// </summary> /// <param name="ProvinceName">省份</param> /// <param name="CityName">城市</param> /// <returns></returns> public City GetSkipCity(string ProvinceName, string CityName) { City citymodel=null; string SkipCityName = string.Empty; XmlDocument xd = new XmlDocument(); xd.Load(CityIpConfigXMLPath); //獲取根節點 XmlNode root = xd.DocumentElement; //獲取節點列表 XmlNodeList ProvinceList = root.ChildNodes; foreach (XmlNode Province in ProvinceList) { if (ProvinceName == Province.Attributes["ProvinceName"].Value.ToString()) { foreach (XmlNode city in Province) { if (CityName == city.Attributes["CityName"].Value.ToString()) { citymodel = new City(); citymodel.CityCode = city.Attributes["CityCode"].Value.ToString(); citymodel.CityName = city.Attributes["SkipCity"].Value.ToString(); citymodel.CityID = city.Attributes["CityValue"].Value.ToString(); citymodel.CitySkipUrl = city.Attributes["CitySkipUrl"].Value.ToString(); return citymodel; } } if (citymodel==null) { foreach (XmlNode province in Province) { if (province.Attributes["CityName"].Value.ToString() == "其餘") { citymodel = new City(); citymodel.CityCode = province.Attributes["CityCode"].Value.ToString(); citymodel.CityName = province.Attributes["SkipCity"].Value.ToString(); citymodel.CityID = province.Attributes["CityValue"].Value.ToString(); citymodel.CitySkipUrl = province.Attributes["CitySkipUrl"].Value.ToString(); return citymodel; } } } } } if (citymodel==null) { foreach (XmlNode province in ProvinceList) { if (province.Attributes["ProvinceName"].Value.ToString() == "其餘") { citymodel = new City(); citymodel.CityName = province.Attributes["SkipDafualt"].Value.ToString(); citymodel.CitySkipUrl = province.Attributes["CitySkipUrl"].Value.ToString(); return citymodel; } } } return citymodel; } public bool IsReusable { get { return false; } } } }
<?xml version="1.0" encoding="utf-8" ?> <CityIpConfig> <ProvinceIp ProvinceName="北京"> <CityIp CityName="北京" SkipCity="北京" CityCode="" CityValue="" CitySkipUrl="http://webbj.imtfc.com/Index.html" ></CityIp> </ProvinceIp> <ProvinceIp ProvinceName="福建"> <CityIp CityName="廈門" SkipCity="廈門" CityCode="XM" CityValue="4" CitySkipUrl="http://webcenter.imtfc.com/WebConstruction.html" >"</CityIp> <CityIp CityName="福州" SkipCity="福州" CityCode="FZ" CityValue="3" CitySkipUrl="http://webcenter.imtfc.com/WebConstruction.html" ></CityIp> <CityIp CityName="龍巖" SkipCity="廈門" CityCode="XM" CityValue="4" CitySkipUrl="http://webcenter.imtfc.com/WebConstruction.html" ></CityIp> <CityIp CityName="泉州" SkipCity="廈門" CityCode="XM" CityValue="4" CitySkipUrl="http://webcenter.imtfc.com/WebConstruction.html" ></CityIp> <CityIp CityName="其餘" SkipCity="福州" CityCode="FZ" CityValue="3" CitySkipUrl="http://webcenter.imtfc.com/WebConstruction.html" ></CityIp> </ProvinceIp> <ProvinceIp ProvinceName="其餘" SkipDafualt="北京" CitySkipUrl="http://webbj.imtfc.com/Index.html"> </ProvinceIp> </CityIpConfig>
Random rd = new Random(); List<string> liststr = new List<string>(); liststr.Add("aaa"); liststr.Add("bbb"); liststr.Add("ccc"); liststr.Add("111"); liststr.Add("222"); liststr.Add("333"); //隨機一個 var s = liststr.OrderBy(_ => Guid.NewGuid()).First(); //隨機兩個 var ss = liststr.OrderBy(_ => Guid.NewGuid()).Take(2); //亂序 var sss = liststr.OrderBy(o => rd.Next(0, liststr.Count())).ToList();
web.config
<?xml version="1.0"?> <!-- 有關如何配置 ASP.NET 應用程序的詳細信息,請訪問 http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <appSettings> <add key="name" value="name1"/> </appSettings> </configuration>
C#讀取
string name = System.Web.Configuration.WebConfigurationManager.AppSettings["name"];
System.Configuration.ConfigurationManager.AppSettings["SqlConnectionStr"];
C#設置
System.Web.Configuration.WebConfigurationManager.AppSettings.Set("name", "name2");
首先C#基礎應該熟悉,不要把暫時用不到而卻經常使用的東西忘掉。
數據庫
應該掌握oracle,畢竟工做這麼多年一直用的oracle
MSSQL、SQLServer瞭解便可,畢竟SQL類似度很高。
C#開發框架:
MVC EF 三層
第三方組件
Log4net 日誌
json.net json轉換
Npoi office處理
前臺web框架
easyUI js前端框架
bootstrap 很好的
LigerUI
extjs
控件、技術
ECharts 圖標 大文件上傳
有時間能夠了解一下安卓開發,U3D開發。
先整理這些,之後想起來什麼再寫
Lucene.Net+盤古分詞
高清楚 WEBAPI
T4 代碼生成器 powerde.. Npoi Log4