zoukankan      html  css  js  c++  java
  • Ajax+Ashx实现以及封装成控件的实现

    asp.net 后台多线程异步处理时的 进度条实现一(Ajax+Ashx实现以及封装成控件的实现)

      工作好长时间了,这期间许多功能也写成了不少的控件来使用,但是,都只是为了代码的结构清析一些而已。而这一次,我决定完成一个我一直在网上寻找却没寻找到的功能。就是,在异步(比如说,后台的数据库备份、后台的文件加解密这类操作)时,前台假死的情况。asp自带了updatePanel,里面可以放一个自带的progress控件,怎么说呢,这就是一个显示而已,而且根本不能动。当你在备份数据的时候,你点备份,然后上面显示“请等待....”,这叫progress,我擦。不过,微软官方给了解释了,说许多人习惯了观察浏览器状态栏上面的进度条,我想说那个条子好假,不信你试试。

      好了,下面来说一下我做的这个东西,当然,我先用ajax+ashx的方式想办法让它实现,下面是我设计前期自己画的一张图:

    这张图上面有错误,但是,作为我的第一个想法,我觉得它功不可没,后面的图都是在它的基础上修改而来了,它也代表了我的初始想法,以及相关的知识残缺。

      图中已经可以把我大部分的想法表达出来了,当然会有人说,通常ajax轮询进度都是这么实现的。但是,却没有人将它封装成服务器控件。

      先说图中明显的错误:

        1、异步操作的时候,一旦请求终断,线程则无法再访问到session,这是一个致命的异常。因为,我本来打算以session来保存信息,并依靠session的机制来释放我已经保存的内容,可以省下好多流程与精力,但事实证明,我还是太年轻了~~。所以,我改用了application,写就了我的第一个后台ashx文件:

      

    复制代码
     1 public class AjaxAction : IHttpHandler, IReadOnlySessionState
     2     {
     3 
     4         public void ProcessRequest(HttpContext context)
     5         {
     6             context.Response.ContentType = "text/plain";
     7             if (context.Request.QueryString["Action"] != null)
     8             {
     9                 string command = context.Request.QueryString["Action"].ToString();
    10                 System.Reflection.MethodInfo method = this.GetType().GetMethod(command);
    11                 if (method != null)
    12                 {
    13                     method.Invoke(this, new object[] { context });
    14                 }
    15             }
    16         }
    17 
    18         public void ProgressMothed(HttpContext context)
    19         {
    20             string guid = HttpContext.Current.Session.SessionID.ToString().Trim() + DateTime.Now.ToString("HHmmssffffff").Trim();
    21             Thread th = new Thread(
    22                 delegate()
    23                 {
    24                     for (int i = 0; i < 101; i++)
    25                     {
    26                         Thread.Sleep(100);
    27                         context.Application[guid] = i;
    28                         context.Response.Write(i.ToString());
    29                     }
    30                     
    31                 }
    32                 );
    33             th.IsBackground = true;
    34             try
    35             {
    36                 th.Start();
    37                 context.Application.Add(guid, 0);
    38                 context.Response.Write(guid);
    39             }
    40             catch (Exception ex)
    41             {
    42                 context.Response.Write("-1");
    43             }
    44         }
    45         public void GetPercentMethod(HttpContext context)
    46         {
    47             try
    48             {
    49                 string guid = context.Request.QueryString["guid"].ToString();
    50                 string per = context.Application[guid].ToString();
    51                 context.Response.Write(per);
    52             }
    53             catch (Exception ex)
    54             {
    55                 context.Response.Write("-1");
    56             }
    57         }
    58         public bool IsReusable
    59         {
    60             get
    61             {
    62                 return false;
    63             }
    64         }
    复制代码
    复制代码
     1 <script type="text/javascript"> 8     function AjaxMethod() {
     9         $.ajax({
    10             url:location.href,
    12             data: { Action: "ProgressMethod", ts: (new Date).getTime() },
    13             success: function (data) {
    14                 if (!(data == undefined || data == null || data == "")) {
    15                     if (data != "-1") {
    16                         AjaxGetPercent(data);
    17                     } else {
    18                         alert("此处理过程暂时无法连接,请稍后再试");
    19                     }
    20                 } else {
    21                     alert("访问的处理不存在,请刷新后重试["+data+"]");
    22                 }
    23             }
    24         });
    25     }
    26     function AjaxGetPercent(guid) {
    27         $.ajax({
    28             url: location.href,
    30             data: { Action: "GetPercentMethod",guid:guid, ts: (new Date).getTime() },
    31             success: function (data) {
    32                 if (data != "-1") {
    33                     if (data < 100) {
    34                         $("#progress_ensleep_pb").css("display", "block");
    35                         $("#progress_ensleep_text").html(data);
    36                         $("#progress_ensleep_pgress").css("width", data + "%");
    37                         setTimeout(AjaxGetPercent(guid), 50);
    38                     } else {
    39                         $("#progress_ensleep_pgress").css("width", "100%");43                         $("#progress_ensleep_text").html(100);
    45                     }
    46                 } else {
    47                     alert("操作过程中出现异常,请重试");
    48                 }
    49             }
    50         });
    51     }
    52 </script>
    复制代码

      可以看出,我完全按照我当初的想法来做的,只是加了一些容错机制,试验了一下,一个进度条在一个页面上,完成正常,并且加入了样式,非常好看。但是,如果一个页面上有十个怎么办?这种情况很多,很常见。而且,每一个方法都要写在ashx这个文件中,人家aspx.cs里面的东西凭什么往你ashx里面写?这样的结果当然就是,我的整个项目乱成面条(打了两局dota的时间煮的面条)——看看不清,理理不起来。想做成引入型的,只能做成控件。

      但是,做成控件有以下几个问题:

        1、一个页面上要放n个控件,前台要为每个控件完成情况执行相应的js回调函数。

        2、这个控件正在执行的时候,如果页面回传,完了之后,它必须继续跑,并且像没回传一样。

        3、事件!!!!

      先说第三个,事件:

      因为控件的目的是执行异步操作,可以看见,我使用了子线程来处理,而子线程是由委托控件。一开始我是想,这是控件,我为什么放着事件不用呢?我把这个子线程要用到的方法写成一个事件,由aspx.cs给这个事件写方法体,不就可以了么?事实证明,我又秀了一次我的年轻~~~,ajax回传的时候,根本就不会触发控件的这一类事件,之所以说这一类,是因为像on_load()这些还是触发的,但是,它是要处理管道管理的,而按钮的onclick之类的无法触发,因为ajax没有带viewstate过来。这就导致了,我的每一次ajax都不是postback,我了个擦啊~~0~~。然后我开始收集信息,就像三国杀逆风时你要数数剩余的牌,dota逆风时你要看一看地图上每一个红点闪现时它的装备,war3时拼死一个步兵或者大g小g冲进对面看一看对面建筑一样……,然后我发现,我可以用的只有ajax带一的context以及session这两个东西,当然后台还有一个application,我不把它放入我的考虑范围(你被虐惨了,你会想着你家还有一个牛逼的泉水么?)。然后我使用了委托,是的,写了一个委托成员。然后爆露出一个成员方法以释放被使用的application(编码习惯良好,反正比南京的空气要好得多~~~)。

      再说第第一个和第二个,

        js回调方法:我把这个抛给使用者写了,放在aspx页面,只要把函数设到控件的属性里面就可以了,然后在控件生成的时候,将这个方法名写到回调的地方。然后为控件生成的所有的js方法都起唯一的名字,即 将控件的ClientID放在方法的后面。这使得一个页面上可以实现多个控件。

        回调后状态的还原继续:我在控件的On_load方法里面,每一次都查找看是否有可用的application,如果有,即会生成一个$(documeent).ready(function(){...}),里面会直接调用对percent(即当前进度)的ajax请求。

      下面上代码:

    复制代码
     1 <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="AjaxProgress.ascx.cs" Inherits="ESLib.Controls.AjaxProgress" %>
     2 <script type="text/javascript">if (!window.jQuery) alert("使用AjaxProgress必须引用jquery!");</script>
     3 <script type="text/javascript">
     4     $(document).ready(function () {
     5         <% if (this.guid != null && this.guid != "")
     6            {%>
     7                <%="AjaxGetPercent_"+this.ClientID+"('"+this.guid+"');"%>
     8            <%}%>
     9     });
    10     function AjaxMethod_<%=this.ClientID%>(clientid) {
    11         $.ajax({
    12             url:location.href,
    13             //content: "Action=ProgressMethod&ClientID=" + clientid + "&ts=" + (new Date).getTime(),
    14             data: { Action: "ProgressMethod", ClientID: '<%=this.ClientID%>', ts: (new Date).getTime() },
    15             success: function (data) {
    16                 if (!(data == undefined || data == null || data == "")) {
    17                     if (data != "-1") {
    18                         AjaxGetPercent_<%=this.ClientID%>(data);
    19                     } else {
    20                         alert("此处理过程暂时无法连接,请稍后再试");
    21                     }
    22                 } else {
    23                     alert("访问的处理不存在,请刷新后重试["+data+"]");
    24                 }
    25             }
    26         });
    27     }
    28     function AjaxGetPercent_<%=this.ClientID%>(guid) {
    29         $.ajax({
    30             url: location.href,
    31             //content: "Action=GetPercentMethod&ClientID=" + clientid + "&guid=" + guid + "&ts=" + (new Date).getTime(),
    32             data: { Action: "GetPercentMethod", ClientID: '<%=this.ClientID%>',guid:guid, ts: (new Date).getTime() },
    33             success: function (data) {
    34                 if (data != "-1") {
    35                     if (data < 100) {
    36                         $("#progress_ensleep_pb_<%=this.ClientID%>").css("display", "block");
    37                         $("#progress_ensleep_text_<%=this.ClientID%>").html(data);
    38                         $("#progress_ensleep_pgress_<%=this.ClientID%>").css("width", data + "%");
    39                         setTimeout(AjaxGetPercent_<%=this.ClientID%>(guid), 50);
    40                     } else {
    41                         $("#progress_ensleep_pgress_<%=this.ClientID%>").css("width", "100%");
    42                         if ("<%=this.CloseWhenEnd.Trim()%>" == "true") {
    43                             $("#progress_ensleep_pb_<%=this.ClientID%>").css("display", "none");
    44                         }
    45                         $("#progress_ensleep_text_<%=this.ClientID%>").html(100);
    46                         <%=this.JsSuccessCallBack%>
    47                     }
    48                 } else {
    49                     alert("操作过程中出现异常,请重试");
    50                 }
    51             }
    52         });
    53     }
    54 </script>
    55 <style type="text/css">
    56         .progressContentensleep{
    57             background-color:blue;
    58             height:30px;
    59             float:left;
    60             width:300px;
    61         }
    62         .progressInnerensleep {
    63             background-color:green;
    64             height:30px;
    65         }
    66         .progressSpanensleep{
    67             color:white;
    68             height:30px;
    69             line-height:30px;
    70             margin-top:-30px;
    71         }
    72     </style>
    73 <div>
    74     <div style="display:none">
    75     </div>
    76     <div id='progress_ensleep_pb_<%=this.ClientID.Trim() %>' class='<%=this.OuterCssClass %>' style='display: none'>
    77         <div id='progress_ensleep_pgress_<%=this.ClientID.Trim() %>' class='<%=this.InnerCssClass %>' style="0%">
    78         </div>
    79          <div id='progress_ensleep_span_<%=this.ClientID.Trim() %>' class='<%=this.TextCss %>'><%=this.WarmText.Substring(0,this.WarmText.IndexOf('{')) %><span id='progress_ensleep_text_<%=this.ClientID.Trim() %>'"></span><%=this.WarmText.Substring(this.WarmText.IndexOf('}')+1,this.WarmText.Length-this.WarmText.IndexOf('}')-1) %></div>
    80     </div>
    81 </div>
    复制代码

    控件的cs代码:

    复制代码
      1 using System;
      2 using System.Collections.Generic;
      3 using System.ComponentModel;
      4 using System.Linq;
      5 using System.Threading;
      6 using System.Web;
      7 using System.Web.UI;
      8 using System.Web.UI.WebControls;
      9 
     10 namespace ESLib.Controls
     11 {
     12     [ToolboxData("<{0}:AjaxProgress runat=server></{0}:AjaxProgress>")]
     13     [ToolboxItem(true)]
     14     public partial class AjaxProgress : System.Web.UI.UserControl
     15     {
     16         [Description("完成提示,如‘完成{0}%’")]
     17         public string WarmText
     18         {
     19             get { return ViewState[this.ClientID.Trim()+"hfWarmText"].ToString() == "" ? "目前已完成{0}%" : ViewState[this.ClientID.Trim()+"hfWarmText"].ToString(); }
     20             set {
     21                 ViewState[this.ClientID.Trim()+"hfWarmText"] = value;
     22             }
     23 
     24         }
     25         [Description("进度条内芯样式类")]
     26         public string InnerCssClass
     27         {
     28             get { return ViewState[this.ClientID.Trim()+"hfinnerCss"].ToString() == "" ? "progressInnerensleep" : ViewState[this.ClientID.Trim()+"hfinnerCss"].ToString(); }
     29             set {
     30                 ViewState[this.ClientID.Trim()+"hfinnerCss"] = value;
     31             }
     32         }
     33 
     34         public string CloseWhenEnd
     35         {
     36             get { return ViewState[this.ClientID.Trim()+"hfCloseWhenEnd"].ToString() == "" ? "true" : ViewState[this.ClientID.Trim()+"hfCloseWhenEnd"].ToString() == "true" ? "true" : "false"; }
     37             set { 
     38                 ViewState[this.ClientID.Trim()+"hfCloseWhenEnd"]= value;
     39             }
     40         }
     41         [Description("进度条容器样式类")]
     42         public string OuterCssClass
     43         {
     44             get { return ViewState[this.ClientID.Trim()+"hfouterCss"].ToString() == "" ? "progressContentensleep" : ViewState[this.ClientID.Trim()+"hfouterCss"].ToString(); }
     45             set
     46             {
     47                 ViewState[this.ClientID.Trim()+"hfouterCss"] = value;
     48             }
     49         }
     50 
     51         [Description("进度条文字样式类")]
     52         public string TextCss
     53         {
     54             get { return ViewState[this.ClientID.Trim()+"hftextCss"].ToString() == "" ? "progressSpanensleep" : ViewState[this.ClientID.Trim()+"hftextCss"].ToString(); }
     55             set
     56             {
     57                 ViewState[this.ClientID.Trim()+"hftextCss"] = value;
     58             }
     59         }
     60         [Description("达到100%后要执行的js方法,如:js()")]
     61         public string JsSuccessCallBack
     62         {
     63             get { return ViewState[this.ClientID.Trim() + "hfJsSuccessCallBack"].ToString(); }
     64             set {
     65                 ViewState[this.ClientID.Trim()+"hfJsSuccessCallBack"] = value;
     66             }
     67         }
     68         [Description("进度条唯一标志符")]
     69         public string guid
     70         {
     71             get {
     72                 try
     73                 {
     74                     return HttpContext.Current.Request.Cookies[this.ClientID.Trim() + "guid"] == null ? "" : HttpContext.Current.Request.Cookies[this.ClientID.Trim() + "guid"].Value.ToString();
     75                 }
     76                 catch (Exception ex)
     77                 {
     78                     return "";
     79                 }
     80             }
     81             set
     82             {
     83                 HttpCookie c = new HttpCookie(this.ClientID.Trim() + "guid");
     84                 c.Value = value;
     85                 HttpContext.Current.Response.Cookies.Add(c);
     86             }
     87         }
     88 
     89         public delegate void DoMethodDelegate(object guid);
     90         public DoMethodDelegate DoMethod;
     91 
     92         public void End(object guid)
     93         {
     94             Application.Remove(guid as String);
     95         }
     96         protected void Page_Load(object sender, EventArgs e)
     97         {
     98             if (!IsPostBack)
     99             {
    100                 ViewState[this.ClientID.Trim()+"hfWarmText"] = ViewState[this.ClientID.Trim()+"hfWarmText"] == null ? "" : ViewState[this.ClientID.Trim()+"hfWarmText"];
    101                 ViewState[this.ClientID.Trim()+"hfinnerCss"] = ViewState[this.ClientID.Trim()+"hfinnerCss"] == null ? "" : ViewState[this.ClientID.Trim()+"hfinnerCss"];
    102                 ViewState[this.ClientID.Trim()+"hfouterCss"] = ViewState[this.ClientID.Trim()+"hfouterCss"] == null ? "" : ViewState[this.ClientID.Trim()+"hfouterCss"];
    103                 ViewState[this.ClientID.Trim()+"hftextCss"] = ViewState[this.ClientID.Trim()+"hftextCss"] == null ? "" : ViewState[this.ClientID.Trim()+"hftextCss"];
    104                 ViewState[this.ClientID.Trim()+"hfJsSuccessCallBack"] = ViewState[this.ClientID.Trim()+"hfJsSuccessCallBack"] == null ? "" : ViewState[this.ClientID.Trim()+"hfJsSuccessCallBack"];
    105                 ViewState[this.ClientID.Trim() + "hfCloseWhenEnd"] = ViewState[this.ClientID.Trim() + "hfCloseWhenEnd"] == null ? "" : ViewState[this.ClientID.Trim() + "hfCloseWhenEnd"];
    106             }
    107             else
    108             {
    109             }
    110             if (HttpContext.Current.Request.QueryString["Action"] != null)
    111             {
    112                 HttpContext.Current.Response.Clear();
    113                 if (HttpContext.Current.Request.QueryString["ClientID"] != null && (HttpContext.Current.Request.QueryString["ClientID"].ToString().Trim() == this.ClientID.Trim()))
    114                 {
    115                     HttpContext.Current.Response.ContentType = "text/plain";
    116                     if (HttpContext.Current.Request.QueryString["Action"] != null)
    117                     {
    118                         string command = HttpContext.Current.Request.QueryString["Action"].ToString();
    119                         System.Reflection.MethodInfo method = this.GetType().GetMethod(command);
    120                         if (method != null)
    121                         {
    122                             method.Invoke(this,null);
    123                         }
    124                     }
    125                 }
    126             }
    127         }
    128 
    129         public void ProgressMethod()
    130         {
    131             string guid = HttpContext.Current.Session.SessionID.ToString().Trim() + DateTime.Now.ToString("HHmmssffffff").Trim();
    132             //Thread th = new Thread(DoMethod(guid));
    133             try
    134             {
    135                 ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoMethod), guid);//未找到处理程序
    136                 Application.Add(guid, 0);
    137                this.guid= guid;
    138                 HttpContext.Current.Response.Write(guid);
    139             }
    140             catch (Exception ex)
    141             {
    142                 HttpContext.Current.Response.Write("-1");
    143 
    144             }
    145             HttpContext.Current.Response.End();
    146         }
    147         public void GetPercentMethod()
    148         {
    149             try
    150             {
    151                 string guid = HttpContext.Current.Request.QueryString["guid"].ToString();
    152                 if (Application[guid] != null)
    153                 {
    154                     HttpContext.Current.Response.Write(Application[guid].ToString());
    155                 }
    156                 else
    157                 {
    158                     HttpCookie c = new HttpCookie(this.ClientID.Trim() + "guid");
    159                     c.Expires = DateTime.Now.AddDays(-1);
    160                     HttpContext.Current.Response.Cookies.Add(c);
    161                     HttpContext.Current.Response.Write("100");
    162                 }
    163             }
    164             catch (Exception ex)
    165             {
    166                 HttpContext.Current.Response.Write("-1");
    167             }
    168             HttpContext.Current.Response.End();
    169         }
    170     }
    171 }
    复制代码

    由于时间问题,就不多说了,代码全在这里了,我是觉得,我被这个东西挡了好多次了,然后网上一直没有类似的控件,让人着实难受。

    写好的文件在这里,http://url.cn/OK26ls (密码:SEvf)

    下面是用法,测试的童鞋可以看一下:

    使用说明:

     

                <UC:AjaxProgress runat = "server" ID = "AjaxProgress2" JsSuccessCallBack = "sucessajax3()" InnerCssClass = "progressInner" OuterCssClass = "progressContent" WarmText = "{0}%" TextCss = "progressSpan" CloseWhenEnd="false" />

    说明:

         属性

    1. JsSuccessCallBack       进度达到100%后执行的js函数
    2. InnerCssClass           进度条内条样式类
    3. OuterCssClass           进度条窗口样式类
    4. WarmText                提示文字,{0}为百分数(无百分号)的通配符
    5. TextCss             显示进度文件样式类
    6. CloseWhenEnd            进度完成后是否关闭进度条,false不关闭,其它情况默认为关闭

    事件:

     

    AjaxProgress2.DoMethod = DoMethod2;
    public void DoMethod2(object guid)

           {

                for (int i = 0; i < 101; i++)

                {

                    Thread.Sleep(500);

                    Application[guid as String] = i;

                }

    }

    在aspx.cs中,必须要声明一个方法,并且将此方法赋值给控件的委托DoMethod

    触发进度条函数为:   

                AjaxMethod _【AjaxProgress的ClientID】()

        解析:

    AjaxProgress的ClientID,即在浏览器中的id,由于没有呈现器,所以,此处与ID相同,即样例中的AjaxProgress2。

    例如:

         <asp:Button runat = "server" ID="Button2" Text = "执行3" OnClientClick = "AjaxMethod_AjaxProgress2();return false;" />

    进度条后台执行事件:

        数据委托定义:public delegate void DoMethodDelegate(object guid);

        所以,可以定义成如下:


    public void DoMethod2(object guid)
    {
    for (int i = 0; i < 101; i++)
    {
    Thread.Sleep(500);
    Application[guid as String] = i;
    }
    AjaxProgress2.End(guid);
    }

     
     
  • 相关阅读:
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第4章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第3章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第1,2章 读书笔记(待更新)
    Tkinter的Message组件
    Git 实操/配置/实践
    mysq5.7.32-win安装步骤
    行为型模式之模板方法
    结构型模式之组合模式
    结构型模式之享元模式
    结构型模式之外观模式
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3460084.html
Copyright © 2011-2022 走看看