Asp.net 前后台操作cookie 实现数据的循环下载

首先简单叙述一下问题的由来,由于数据的获取是通过调用相应的WebService从其他系统获取的,因此每次获取的数据有限制,并且需要要满足一次最多只能下载一定数量的记录,若filter出来的数据大于这个最大值的时候,我们就要分批循环进行下载。由于每次从前台调用后台方法都是一次post-back过程,那么记录上一次的下载位置以及整体的filter条件 就不能用简单的局部变量进行记录了。因此这里才用到了cookie进行记录,并且后续的下载要自动的弹出popup,所以前台要简单的写个timer job,定时的检测对应的cookie,若条件满足那么弹出popup,若所有的数据都下载完成,那么关闭这个timer job。当然了第一次触发timer job的时机我们可以选择在用户第一次点击下载数据之后。

接下来完整简单的叙述下载整体的设计流程:

前台:对JQuery进行扩展实现对Cookie的操作 --> 模拟timer job定时对相应的Cookie进行检测

后台:定义四个Cookie值(filter的条件、上一次下载的位置、继续下载、下载完成),前两个Cookie是后台取具体数据时用到,后两个是完成循环弹出popup用到 --> 根据第二个Cookie值的属性判断是否下载完成 --> 将第三个或者第四个Cookie添加到Response中 以提供前台的定时检测

 

如下将主要的代码段贴出:

 1): 对JQuery进行扩展实现对Cookie的操作

/*!
 * jQuery Cookie Plugin v1.3.1
 * https://github.com/carhartl/jquery-cookie
 *
 * Copyright 2013 Klaus Hartl
 * Released under the MIT license
 */
(function ($, document, undefined) {

    var pluses = /\+/g;

    function raw(s) {
        return s;
    }

    function decoded(s) {
        return unRfc2068(decodeURIComponent(s.replace(pluses, ' ')));
    }

    function unRfc2068(value) {
        if (value.indexOf('"') === 0) {
            // This is a quoted cookie as according to RFC2068, unescape
            value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
        }
        return value;
    }

    function fromJSON(value) {
        return config.json ? JSON.parse(value) : value;
    }

    var config = $.cookie = function (key, value, options) {

        // write
        if (value !== undefined) {
            options = $.extend({}, config.defaults, options);

            if (value === null) {
                options.expires = -1;
            }

            if (typeof options.expires === 'number') {
                var days = options.expires, t = options.expires = new Date();
                t.setDate(t.getDate() + days);
            }

            value = config.json ? JSON.stringify(value) : String(value);

            return (document.cookie = [
                encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value),
                options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
                options.path    ? '; path=' + options.path : '',
                options.domain  ? '; domain=' + options.domain : '',
                options.secure  ? '; secure' : ''
            ].join(''));
        }

        // read
        var decode = config.raw ? raw : decoded;
        var cookies = document.cookie.split('; ');
        var result = key ? null : {};
        for (var i = 0, l = cookies.length; i < l; i++) {
            var parts = cookies[i].split('=');
            var name = decode(parts.shift());
            var cookie = decode(parts.join('='));

            if (key && key === name) {
                result = fromJSON(cookie);
                break;
            }

            if (!key) {
                result[name] = fromJSON(cookie);
            }
        }

        return result;
    };

    config.defaults = {};

    $.removeCookie = function (key, options) {
        if ($.cookie(key) !== null) {
            $.cookie(key, null, options);
            return true;
        }
        return false;
    };

})(jQuery, document);

2): 在Client端模拟timer job定时对相应的Cookie进行检测(每2秒钟检测一次)

//=================================================
// export activity monitor
//=================================================
var downloadJob;
var exportCount = 0;
function checkDownload() {
    clearInterval(downloadJob);
    downloadJob = setInterval(processDownloadStatus, 2000); //check cookie each 2 second
}

function closeDownload() {
    clearInterval(downloadJob);
    downloadJob = "undefined"; //mark
}

function processDownloadStatus() {
    var c1 = $.cookie("TradeDetailsExport-MoreExport");
    if (c1 != null && c1 != 'undefined' && c1 != '') {
        _spFormOnSubmitCalled = false; //continue post-back on SharePoint
        exportCount++;
        ExportMorePopUpClick(exportCount); //popup function
        $.cookie("TradeDetailsExport-MoreExport", null, { path: '/' });
        return;
    }

    var c2 = $.cookie("TradeDetailsExport-DoneExport");
    if (c2 != null && c2 != 'undefined' && c2 != '') {
        if ($.colorbox != null && $.colorbox != "undefined") {
            $.colorbox.close();
        }
        exportCount = 0;
        _spFormOnSubmitCalled = false; //continue post-back on SharePoint
        $.cookie("TradeDetailsExport-DoneExport", null, { path: '/' });
        setNoRecordText();
        closeDownload();
        return;
    }
}

3): 在Server端操作Cookie并且实现数据的下载

        public static void Export(int rows, bool needCookie, bool moreExport, Collection<string> columns)
        {
            HttpContext context = HttpContext.Current;
            System.Web.Script.Serialization.JavaScriptSerializer oSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();

            TradeDetailsRequest request = null; // class for query....
            TradeDetailsCursor tradeDetailsCursor = null; // class for mark download last key...

            if (context.Request.Cookies[TradesConstants.TRADE_DETAIL_REQUEST] != null)
            {
                request = oSerializer.Deserialize<TradeDetailsRequest>(DecodeCookie(context, TradesConstants.TRADE_DETAIL_REQUEST));
            }

            if (context.Request.Cookies[TradesConstants.TRADE_DETAIL_CURSOR] != null)
            {
                tradeDetailsCursor = oSerializer.Deserialize<TradeDetailsCursor>(DecodeCookie(context, TradesConstants.TRADE_DETAIL_CURSOR));
            }

            //// No request provided - return error
            if (request == null)
            {
                // to-do: should redirect to an error page
                context.Response.ContentType = "text/plain";
                context.Response.Write("Error: No request found.");
                context.Response.End();
            }

            //// Last Request does not match current - cannot be resuming
            //if (!request.Equals(lastRequest))
            if (!moreExport)
            {
                tradeDetailsCursor = null;
            }

            //// Retrieve Trade Items
            TradeItems tradeItems = TradeDetailsFacade.GetTradeDetailRequest(request, rows, tradeDetailsCursor); // get data item based on query and last time key

            /// Prepare to respond With a CSV file
            context.Response.Clear();

            bool overLimit = tradeItems.LastKey.LastRecordStatus != TradesConstants.NO_MORE_RECORD_INDICATOR; // have more data to download next time

            if (needCookie)
            {
                HttpCookie exportCookie = null;
                if (overLimit)
                {
                    exportCookie = new HttpCookie(TradesConstants.MORE_EXPORT);
                    exportCookie.Value = "1"; // arbitrary data; not used in code logic
                }
                else
                {
                    exportCookie = new HttpCookie(TradesConstants.NO_MORE_EXPORT);
                    exportCookie.Value = "0"; // arbitrary data; not used in code logic
                }
                exportCookie.Expires.AddHours(1);
                exportCookie.HttpOnly = false;
                context.Response.Cookies.Add(exportCookie);
            }

            // Set Cursor Cookie
            HttpCookie tradeDetailsCursorCookie = new HttpCookie(TradesConstants.TRADE_DETAIL_CURSOR);
            tradeDetailsCursorCookie.Value = Encryption.EncryptString(oSerializer.Serialize(tradeItems.LastKey), TradesConstants.ENCRYPTION_KEY);
            tradeDetailsCursorCookie.Path = "/";
            tradeDetailsCursorCookie.Expires.AddHours(1);
            context.Response.Cookies.Add(tradeDetailsCursorCookie);

            // if there are no columns, use the default set.
            if (columns.Count < 1)
            {
                columns = TradesConstants.AllTradeColumnFieldNames();
            }


            // do not buffer the output!
            string filename = TradesConstants.DEFAULT_EXPORT_FILENAME;
            context.Response.BufferOutput = false;
            context.Response.ContentType = "text/csv";
            context.Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);

            // iterate over trade entities
            for (int i = 0; i < tradeItems.Trades.Count; i++)
            {
                // create the csv line, will need to pull the list from query string
                context.Response.Write(tradeItems.Trades[i].GetCsvFormattedEntity(columns));
            }
            
            context.Response.End();
            context.Response.Flush();

        }

        private static string DecodeCookie(HttpContext context, string cookieName)
        {
            string encodedString = context.Request.Cookies[cookieName].Value;
            return Encryption.DecryptString(encodedString, TradesConstants.ENCRYPTION_KEY);
        }

4): 一些用到的常量声明

    /// <summary>
    /// This class provides constants and mappings of constants for the RTTA aspect of FNX
    /// </summary>
    public static class TradesConstants
    {
        /// <summary>
        /// default export filename.
        /// </summary>
        public const string DEFAULT_EXPORT_FILENAME = "TradeDetails.csv";

        ///Export completion indicator.
        /// </summary>
        public const string NO_MORE_RECORD_INDICATOR = "C";

        ///More Export cookie name.
        /// </summary>
        public const string MORE_EXPORT = "TradeDetailsExport-MoreExport";

        ///No more Export cookie name.
        /// </summary>
        public const string NO_MORE_EXPORT = "TradeDetailsExport-DoneExport";

        /// <summary>
        /// Trade detail cursor cookie name.
        /// </summary>
        public const string TRADE_DETAIL_CURSOR = "TradeDetailsExport-TradeDetailsCursor";

        /// <summary>
        /// Trade detail request cookie name.
        /// </summary>
        public const string TRADE_DETAIL_REQUEST = "TradeDetailsExport-Request";

        /// <summary>
        /// Trade detail last request cookie name.
        /// </summary>
        public const string TRADE_DETAIL_LAST_REQUEST = "TradeDetailsExport-LastRequest";
    }

 

ps:如果此行为是应用在SharePoint中的话,那么要修改对应的属性,来屏蔽postback的失效。 即:第二段代码中的 _spFormOnSubmitCalled = false;

 

posted @ 2013-05-25 13:58  Eric Sun  阅读(12085)  评论(0编辑  收藏  举报