一种开发模式:ajax + ashx + UserControl

一、ajax+ashx模式的缺点

    在web开发过程中,为了提高网站的用户体验,或多或少都会用到ajax技术,甚至有的网站全部采用ajax来实现,大量使用ajax在增强用户体验的同时会带来一些负面影响,比如:不利于seo;然而,对于asp.net来说,一般会采用ashx文件作为ajax调用的后台,这种情况下,每个ajax请求都会对应一个ashx页面,如果请求过多则会造成项目中有繁多的ashx文件,不利于管理与维护,那么怎样改善这种情况呢?

二、问题分析与改进(反射)

    通过分析发现,每个ajax调用ashx的步骤都是一样,都分为以下三步:
    1、解析请求中的用户数据
    2、处理用户请求
    3、返回处理结果
    这三个步骤中,第一和第三步对于每个请求来说都一样,只有第二部涉及到数据的具体处理,每个请求会有所不同,因此需要针对第二个方面进行改进。
    ashx文件的类作为一个Handler,它是继承于IHttpHandler接口的,在处理业务时,每个请求都会首先进入方法"ProcessRequest"中,为了减少ashx文件的数量,我们可以将同一模块中的操作放在一个ashx文件中进行处理,具体代码类似下面中这样:
    
public void ProcessRequest(HttpContext context)
    {
        // 1、解析请求参数,此处忽略
        // 2、以下为具体处理方式
        string returnString = string.Empty;
        string methodName = context.Request.Form["methodName"];
        switch(methodName)
            case "GetData":
                returnString = GetData();
                break;
            case "InsertNewRow"
                returnString = InsertNewRow();
                break;
            .....等等多个case分支
            default:
            break;
        // 3、向客户端返回结果        
        context.Response.Write(returnString);
    }

 

    这种方式通过在用户请求中添加一个用来表明具体调用方法的参数,可以将同一模块中的操作全部放在一起,并通过switch语句进行判断,然后分别调用,这样可以减少一定数量的ashx文件。但是这种方式存在一个弊端,如果方法很多的话会造成switch语句出现大量的分支,并且每个ashx文件中都需要在ProcessRequest方法中进行相同业务逻辑判断,那么怎样将这些相同的行为进行改进呢?我们知道,请求中包含了需要调用的方法名,为了将这些方法的调用进行统一处理,显然我们可以利用反射。
    通过定义一个Handler基类,让其他所有的ashx类继承此Handler,具体的处理方法写在子类中,这样基类的功能就可以简化为如下形式:
    
//Handler基类中的方法,为所有的Handler子类的方法进行调度
public void ProcessRequest(HttpContext context)
    {
        // 1、解析请求参数,此处忽略其他参数的解析,仅获取方法名
        string methodName = context.Request.Form["Action"];
        // 2、以下为反射的具体处理方式
        Type type = this.GetType();
        Object[] params = new Objece[1];  //方法参数,我们统一将context作为参数,以为用户数据都封装在其中
        MethodInfo method = type.GetMethod(methodName);
        string returnString = (string)method.Invoke(this,params);
        // 3、向客户端返回结果        
        context.Response.Write(returnString);
    }

public String GetRequest(HttpContext context, String paramName)
{
    if (context.Request[paramName] != null)
    {
        return context.Request[paramName].ToString();
    }

     return "";

}


 
然后,继承该Handler的子类只需要实现具体的处理方法即可,该基类可以统一为所有子Handler进行方法调度,再也不会出现可能会越来越臃肿的switch,该方式类似于mvc中的controller调度,通过action来进行判断
    下面是一个子Handler的示例:
/// <summary>
    /// UserHandler 的摘要说明
    /// </summary>
    public class UserHandler : BaseHandler
    {
        /// <summary>
        /// 用户登录处理
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public String Login(HttpContext context)
        {
            String strAccount = "";
            String strPassword = "";
            String strRet;

            try
            {
                //获取页面传值
                strAccount = GetRequest(context, "Account");
                strPassword = GetRequest(context, "Password");

                if (strAccount != "" && strPassword != "")
                {
                    //简单起见,仅返回传递过来的用户账号与密码
                    //在实际应用中利用传递过来的参数值调用业务逻辑层的方法来完成客户端的请求
                    strRet = String.Format("账号:{0},密码:{1}", strAccount, strPassword);
                }
                else
                {
                    //返回提示信息
                    strRet = "未能正确获取参数!";
                }


                return strRet;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
    }

 

前台调用代码如下:
<script type="text/javascript">
        $(document).ready(function () {
            $("#btnLogin").click(function () {
                var account;
                var password;

                account = $("#txtUserName").val();
                password = $("#txtPassword").val();

                $.ajax({
                    type: "POST",
                    async: true,
                    url: "Handler/UserHandler.ashx",
                    dataType: "text",
                    data: { Action: "Login", Account: account, Password: password },
                    success: function (data) {
                        alert(data);
                    },
                    error: function (xhr) {
                        alert(xhr.statusText);
                        return false;
                    }
                });
            });
        });
    </script>

 


    至此,已经完成了ajax + ashx开发模式的改进,但是仍然存在一下两个问题:
    1、因为采用了ajax技术,所以在提交请求时需要手动封装表单中的数据,如果数据过多,封装过程比较繁琐
    2、在输出时需要大量拼接html字符串,这也是一个繁琐的活

三、ajax请求中表单数据的封装

    为了提高数据的封装效率,我们可以使用jquery.form.js插件,该插件提供了便利的操作,可以根据需要封装表单中的全部或者部分数据,使用起来十分简单。
,下面说一下UserControl的用法

四、利用UserControl进行html输出

    在ajax+ashx处理方式中,大部分情况下都需要进行html字符的拼接,这种拼接非常繁琐却又不得不做,如果是非常简短的字符串还倒可以,如果遇到大量数据的显示,恐怕单单这一项任务就够让人烦的了,这里我们可以利用用户控件(UserControl)来帮我们完成html的呈现,具体思路如下:
    定义一个视图控制器类(ViewManage),专门用来创建用户控件的实例和生成用户控件的html,该试图控制器内部主要通过定义一个空的Page类,然后将该用户控件加载到Page中创建其实例,然后将Page对象的整个生命周期运行一遍,并将结果html输出。
    通过用户控件输出html还不会影响页面的SEO,因为在客户端<a/>的href还是有效的
 

总结:

该开发模式在利用ajax的同时,采用 "控制器+反射" 的模式进行方法调度,利用form插件来进行表单数据封装,对于大数据量的输出利用"用户控件"进行html生成。
对于ajax与SEO,需要遵循以下几点:
1、AJAX、SEO同等重要,在同一个WEB项目中为他们各自选择合适的使用领域。
2、会员管理、帐户中心、购物车、后台管理等操作界面可以使用AJAX,以提高用户体验和UI交互。
3、网站前台展示的页面,如新闻内容、商品介绍、帮助、文档类页面,不要使用AJAX,以SEO为主。
4、当我们认清楚AJAX什么时候该用,什么时候不该用,一个网站的SEO与AJAX技术结合就变得很简单了。
posted @ 2013-12-11 16:54  眼神与背影  阅读(595)  评论(0编辑  收藏  举报