Asp.net 如何保存已完成一半的表单

Asp.net 如何保存已完成一半的表单,asp.net,architecture,Asp.net,Architecture,我正在做一个项目,我们想让用户能够保存他们半完成的表格,以便他们可以回来后完成它。我正在努力弄清楚我到底想怎么做。我是否将它们与已完成的应用程序保存在同一个池中,仅以特殊状态保存?我真的不想牺牲已完成应用程序的完整性,因为当我不希望字段为空时,必须使其为空 我应该在不同的模式中创建相同的数据库结构来保存不完整的应用程序吗?我可以让另一个模式在数据库约束和可空字段上更加宽松,以解释不完整的应用程序 有没有更简单的方法?是否有一种方法可以保存viewstate并在以后还原 谢谢你的建议 我肯定会把它

我正在做一个项目,我们想让用户能够保存他们半完成的表格,以便他们可以回来后完成它。我正在努力弄清楚我到底想怎么做。我是否将它们与已完成的应用程序保存在同一个池中,仅以特殊状态保存?我真的不想牺牲已完成应用程序的完整性,因为当我不希望字段为空时,必须使其为空

我应该在不同的模式中创建相同的数据库结构来保存不完整的应用程序吗?我可以让另一个模式在数据库约束和可空字段上更加宽松,以解释不完整的应用程序

有没有更简单的方法?是否有一种方法可以保存viewstate并在以后还原


谢谢你的建议

我肯定会把它保存到数据库中。使用特殊状态保存的计划(名为Complete的布尔标志将起作用)。然后,您可以创建一个视图,该视图只提取Complete=true的项目,称为CompletedApplications。

您的已完成应用程序与这些“半”状态之间可能存在一些差异:

  • 正如您所说,大多数验证都是不合适的,字段将为空,交叉验证可能无法执行
  • 您可能不需要跨数据进行任意搜索
  • 因此,我将使用另一个数据库,该记录包含几个关键字段,如用户Id、日期、他们填写的表单类型等,以及他们填写的字段的blob。我是一个Java爱好者,所以我不知道.NET获取blob的方法,但在Java中,我可以序列化表单背后的数据对象

    似乎在C#中,这些技术与Java有一些相似之处,至少我正确地理解了这一点


    我认为手工编写一些简单的“SaveAsString”和“readFromString”代码会有点枯燥,但如果没有标准的.Net技术存在,这是可行的。

    您显然无法将其保存到实际的数据表中,因此我将创建一个单独的表,其中包含userid、formid和二进制数据类型。将表单组合成某种可序列化的结构并序列化到数据库。当用户返回时,您可以反序列化并恢复表单状态。

    我也遇到了同样的问题。一个不同之处是,我的方法涉及ajax自动保存,类似于您在Gmail和Blogger中看到的内容。但这不应该改变实现,真的

    问题是我不想保存到常用的表中,因为这需要验证(验证整数、货币、日期等)。我不想在用户真的想离开的时候对他们唠叨

    我最后想到的是一张叫做AjaxSavedData的桌子。它是数据库中的一个永久表,但它包含的数据往往是临时的。换句话说,它将暂时存储用户的数据,直到用户实际完成页面并移动到下一个页面

    该表仅由几列组成:

    AjaxSavedDataID-int:

    主键

    用户ID-int:

    识别用户(非常简单)

    PageName-varchar(100):

    如果要处理多个页面,则需要

    控制ID-varchar(100):

    我称之为ControlID,但它实际上只是.NET为所有WebControl公开的ClientID属性。因此,例如,如果txtEmail位于名为Contact的用户控件中,那么ClientID将是Contact\u txtEmail

    -varchar(最大值):

    用户为给定字段或控件输入的值

    日期更改-日期时间:

    添加或修改值的日期

    除了一些自定义控件外,该系统使所有这些都很容易“正常工作”。在我们的网站上,每个文本框、dropdownlist、radiobuttonlist等的ClientID对于给定页面都是唯一和一致的。所以我能够写下所有这些,以便自动检索保存的数据。换句话说,我不必在每次向表单添加一些字段时都连接此功能

    这种自动保存功能将进入techinsurance.com上的一个非常动态的在线商业保险应用程序,使其更加用户友好

    如果您感兴趣,以下是允许自动保存的Javascript:

    function getNewHTTPObject() {
        var xmlhttp;
    
        /** Special IE only code */
        /*@cc_on
        @if (@_jscript_version >= 5)
        try {
            xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch (e) {
            try {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch (E) {
                xmlhttp = false;
            }
        }
        @else
            xmlhttp = false;
        @end
        @*/
    
        /** Every other browser on the planet */
        if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
            try {
                xmlhttp = new XMLHttpRequest();
            }
            catch (e) {
                xmlhttp = false;
            }
        }
    
        return xmlhttp;
    }
    
    function AjaxSend(url, myfunction) {
        var xmlHttp = getNewHTTPObject();
        url = url + "&_did=" + Date();
        xmlHttp.open("GET", url, true);
        var requestTimer = setTimeout(function() { xmlHttp.abort(); }, 2000);
        xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2005 00:00:00 GMT");
        xmlHttp.onreadystatechange = function() {
            if (xmlHttp.readyState != 4)
                return;
            var result = xmlHttp.responseText;
            myfunction(result);
        };
        xmlHttp.send(null);
    }
    
    // Autosave functions
    var SaveQueue = []; // contains id's to the DOM object where the value can be found
    var SaveQueueID = []; // contains id's for binding references (not always the same)
    
    function ArrayContains(arr, value) {
        for (i = 0; i < arr.length; i++) {
            if (arr[i] == value)
                return true;
        }
    
        return false;
    }
    
    function GetShortTime() {
        var a_p = "";
        var d = new Date();
        var curr_hour = d.getHours();
    
        if (curr_hour < 12)
            a_p = "AM";
        else
            a_p = "PM";
    
        if (curr_hour == 0)
            curr_hour = 12;
        else if (curr_hour > 12)
            curr_hour = curr_hour - 12;
    
        var curr_min = d.getMinutes();
        curr_min = curr_min + "";
    
        if (curr_min.length == 1)
            curr_min = "0" + curr_min;
    
        return curr_hour + ":" + curr_min + " " + a_p;
    }
    
    function Saved(result) {
        if (result == "OK") {
            document.getElementById("divAutoSaved").innerHTML = "Application auto-saved at " + GetShortTime();
            document.getElementById("divAutoSaved").style.display = "";
        }
        else {
            document.getElementById("divAutoSaved").innerHTML = result;
            document.getElementById("divAutoSaved").style.display = "";
        }
    }
    
    function getQueryString(name, defaultValue) {
        var query = window.location.search.substring(1);
        var vars = query.split("&");
        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
            if (pair[0] == name) {
                return pair[1];
            }
        }
    
        return defaultValue;
    }
    
    function urlencode(str) {
        return escape(str).replace(/\+/g, '%2B').replace(/%20/g, '+').replace(/\*/g, '%2A').replace(/\//g, '%2F').replace(/@/g, '%40');
    }
    
    function AutoSave() {
        if (SaveQueue.length > 0) {
            var url = "/AjaxAutoSave.aspx?step=" + getQueryString("step", "ContactInformation");
    
            for (i = 0; i < SaveQueue.length; i++) {
                switch (document.getElementById(SaveQueue[i]).type) {
                    case "radio":
                        if (document.getElementById(SaveQueue[i]).checked)
                            url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value);
                        break;
                    case "checkbox":
                        if (document.getElementById(SaveQueue[i]).checked)
                            url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value);
                    default:
                        url += "&" + SaveQueueID[i] + "=" + urlencode(document.getElementById(SaveQueue[i]).value);
                }
            }
    
            SaveQueue = [];
            SaveQueueID = [];
            AjaxSend(url, Saved);
        }
    }
    
    function AddToQueue(elem, id) {
        if (id == null || id.length == 0)
            id = elem.id;
    
        if (!ArrayContains(SaveQueueID, id)) {
            SaveQueue[SaveQueue.length] = elem.id;
            SaveQueueID[SaveQueueID.length] = id;
        }
    }
    
    要将其应用于文本框、下拉列表、列表框或复选框,只需添加此属性:

    onchange="AddToQueue(this)"
    
    …对于RadioButtonList或CheckBoxList:

    onchange="AddToQueue(this, '" + this.ClientID + "')"
    

    有没有想过使用Silverlight?Silverlight有独立的存储,我已经看到了几个开发人员使用独立存储来存储昂贵的客户端数据的例子

    然后使用js将数据输入输出:

    这使您不需要任何额外的数据库空间,因为用户的所有临时表单条目都存储在独立的存储中,当它们返回页面时,您会询问用户是否要继续编辑。。。然后用独立存储中的数据填充表单

    听起来比添加新数据库更优雅

    有一个缺点是依赖于机器的解决方案

    取决于保存部分表单的确切目标?
    是不是可以在其他机器上运行?如果是这样的话,这不是正确的解决方案,而DB save则是更好的解决方案。

    您能否提供有关序列化Web表单的指导?这是一个包含多个步骤的向导控件的页面。我同意使用序列化的LOB,这意味着您不必在DB中有很多可为空的列。可以在数据库中保存,但我不建议这样做@MikeC-您不会序列化Webform,而是它绑定到的域模型。我认为这是我想要采取的方法,但是
    onchange="AddToQueue(this, '" + this.ClientID + "')"