欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

分享几个asp.net开发中的小技巧

程序员文章站 2022-03-13 10:56:46
下面这几个,是在实际开发或阅读中发现的一些问题,有些甚至是有很多年开发人员写出的代码,也是很多人经常犯的错误。各位可以看看,你有没有躺着中枪。     第...
下面这几个,是在实际开发或阅读中发现的一些问题,有些甚至是有很多年开发人员写出的代码,也是很多人经常犯的错误。各位可以看看,你有没有躺着中枪。

 

 

第一个,对整型变量进行非null判断。

 

// a 是int型 (不是int?)

if(a != null){

    //操作

}

 

 

个人点评:无意义判断,值类型永远不可能为null。

 

第二个,用static来保持页面回发

 

复制代码

static int id;

protected void Page_Load(object sender, EventArgs e)

{

    if (Request.QueryString["ID"] != null && Request.QueryString["ID"].ToString() != "")

    {

        id = Convert.ToInt32(Request.QueryString["ID"].ToString());

    }

}

复制代码

 

 

个人点评:这个不解释,不知道怎么说。但最近还真就遇到了,而且也不是什么小项目,WebForm无服务器控件开发。

 

第三个,用编程方式绑定数据控件时,数据源为DataSet时判断null而不判读DataSet内的Tables数。

 

DataSet ds = bll.GetList(); 

if (ds != null)

{

    Repeater1.DataSource = ds;

    Repeater1.DataBind();

}

 

 

个人点评:当bll.GetList()返回的DataSet非null但里面没有包含数据表时,执行DataBind()方法时会报HttpException异常(IListSource 不包含任何数据源)。正确写法应该是

 

复制代码

DataSet ds = bll.GetList();

if (ds != null && ds.Tables.Count > 0)

{

    Repeater1.DataSource = ds;

    Repeater1.DataBind(); 

}

//或

DataSet ds = bll.GetList()??new DataSet();

if (ds.Tables.Count > 0)

{

    Repeater1.DataSource = ds;

    Repeater1.DataBind(); 

}

复制代码

 

 

第四个,用编程方式绑定数据控件时,数据源为DataTable或List<T>时判断null。

 

DataTable dt = bll.GetList();

if (dt!=null)

{

    Repeater1.DataSource = dt;

    Repeater1.DataBind();

}

 

 

个人点评:无意义判断,下面的写法没有任何问题,即使dt=null

 

DataTable dt = bll.GetList();

Repeater1.DataSource = dt;

Repeater1.DataBind();

 

 

第五个

 

Model m = new Model(); 

m = bll.GetModel(id);

m.name;

 

 

个人点评:以为只要声明时不为null,后面就不需要做非空非null判断了。万一第二步BLL层返回的model就为null呢?

 

第六个,在Repeater1_ItemDataBound中写这样的代码

 

Label lblPMID = (Label)e.Item.FindControl("lblPMID");

if (lblPMID.Text != "")

{

    //操作

}

 

 

个人点评:低效,无意义判断,很可能出现NullReferenceException(未将对象引用设置到对象的实例)异常。

正确写法:

 

Label lblPMID = e.Item.FindControl("lblPMID") as Label;

if (lblPMID!=null && lblPMID.Text != "") //视里面使用情况决定是否判断lblPMID.Text为“”或空白

{

    //操作

}

 

 

第七个

 

复制代码

string txtName = Request["txtName"] == null ? "" : Request["txtName"].ToString();

string strWhere += "and ID=" + userId + ""; //userId是int

if (txtName != "")

{

    strWhere += " and NAME='" + txtName + "'"; 

}

strWhere += " order by id desc";

//项目本身都是采用参数化查询的,这里是一些暴露给Web层的高级查询条件。

复制代码

 

 

个人点评:1、值类型和字符串拼接会隐式装箱,2、SQL注入危险。正确做法是userId.ToString()并且过滤txtName中特殊字符,限制字符串长度。

注意,拼接SQL时过滤字符串并不能完全防止SQL注入,但很多时候在高级查询时拼接SQL是最简单也是最方便的,这时候过滤不应该只过滤一些指定的特殊字符,

比如只过滤单引号,等号,大于/小于/等于,空格,括号之类的危险字符。应该对除中文字符、英文字母、和数字外的所有字符全部过滤掉(视情况而定)。

并且严格限制字符串长度,一般查询时输入的关键字不会太长,如果用户输入的有空格,就拆分成多个条件。这样能尽可能的减小SQL注入的机会。

 

 

最后,给大家分享几个小经验,虽说有些只是语法糖,但却可以帮助我们更高效编写或阅读代码。

 

一、引用类型的null值很麻烦,因为类型为null时使用点运算符 (.)会报异常,所以经常要做非null判断,可以用?? null 合并运算符减少代码量。例如:

 

复制代码

//写法一

int ID;

if (Request.Form["ID"] != null && Request.Form["ID"].ToString() != "")

{

ID = Convert.ToInt32(Request.Form["ID"].ToString());

}

 

//写法二

int id;

if (int.TryParse(Request.Form["ID"]??"",out id))

{

 

}

 

//方法一

string userName2=string.Empty;

if (Session["userName"]!=null)

{

    userName2 = Session["userName"].ToString();

}

 

//方法二

string userName1 = Session["userName"] == null ? "" : Session["userName"].ToString();

 

//方法三

string userName = (Session["userName"] ?? "").ToString();

复制代码

 

 

二、Web项目中的所有Session或cookie最好统一放到一个类中管理。最重要的目的是把Session中索引名独立出来管理,也就是除了本类外的所有页面都不要输入Session名。

可能用语言表达不够直白,直接上代码。

看到很多人是这样,包括网上流行的一些很常见的辅助类库。

 

 View Code

我想知道,这样做有什么实际意义么?而且HttpContext.Current还不做null检查。

项目中还到处都是SessionHelper.SetSession("name"),SessionHelper.GetSession("name")这样编译器无法找到具体引用的代码,当你有很多页面用到这个会话后,

你再想更改会话名称或删除这个会话那将是一场灾难,而且这样的代码多了还可能出现多个会话重名造成冲突,名称写错造成会话丢失。

要克服以上问题,Web项目的Session会话你应该这样写

 

 View Code

这样写,项目中使用时:

登录成功就添加会话SessionManager.AddUserLoginMark(当前登录用户对象);

页面登录检查时判断 SessionManager.GetUserLogin();返回是否为null就行。

退出登录时SessionManager.RemoveUserLoginMark();即可。

这样就只管调用就行,不用再去管Session名是什么,删除、更改也更方便,当然也不会出现Session重名现象了(如果这样都能整成会话重名的话,那你真成人才了)。

 

当然,这样写也不是一点缺点都没有,和前一种相比,这种方法可能就不能做到一次书写,到处使用了,需要跟据当前项目具体灵活改动相应代码,但好处是很明显的。这样的方法同样适用于Cache和Cookie。

 

 

 

三、最好不要用Request[]代替Request.Form[]和Request.QueryString[]。

 

如果页面有很多Request.Form[]、Request.QueryString[]、Session[]最好在页面Page_Load中就把所有值取出来存放在变量中,并转换成需要的类型。

满篇的Request.Form[]、Request.QueryString[]、Session[]编译器没法检查[]中的字符串,容易出错,影响阅读,还可能同一参数需要多次类型转换(这一条针对WebFrom无服务器控件开发时特别有用)。

 

 

 

四、尽量使用 as 代替引用类型间转换(见上面第六个)。

 

这个大家都知道,但还是发现很多人在用强制转换,包括一些优秀的开源项目。

 

 

五、RegisterClientScriptBlock、RegisterClientScriptInclude、RegisterStartupScript、RegisterOnSubmitStatement、RegisterClientScriptResource等方法要求前台页面必须有form服务器控件(<form runat="server"></form>)。

也就意味着在WebForm无服务器控件开发时,这几个没什么用了(同样的还有Page.IsPostBack要小心了)。

 

 

六、微软不推荐直接在后台使用Response.Write()输出JS,并且有的浏览器的确会造成页面变形。

 

但发现很多人在用,包括一些很优秀的开源项目。我暂时用在前台加入<%= strMsg %>来接收后台传过来的消息,不知道各位都有什么好的方法。

 

 

七、最后向大家分享一段自己写的小代码,为Repeater控件添加EmptyDataTemplate模板(EmptyDataTemplate在FooterTemplate之前)。