代码之家  ›  专栏  ›  技术社区  ›  Mike Cole

序列化ASP.NET Web窗体

  •  2
  • Mike Cole  · 技术社区  · 16 年前

    是否可以序列化ASP.NET Web窗体,包括用户输入的所有数据?我想让用户能够保存一个完成了一半的表单,并希望我可以通过序列化来完成这一点。任何简单的例子都会受到极大的赞赏。

    编辑: 我想避免“不完整”表单必须有单独的数据层,以反映已完成表单的层。我不想将不完整的表单与完整的表单一起存储,因为它们可能无法通过我的DB约束。

    9 回复  |  直到 13 年前
        1
  •  4
  •   Mehmet Aras    15 年前

    对于不完整的表单,不能避免单独存放。您需要将它们持久化到某个地方,而不能将它们与完整的表放在一起,因为显然您在基础数据库表上有一些数据库约束,并且希望保留它们。我建议像@ramesh将表单数据封装在类中那样。

    public class FormData
    {
      public int IntField { get;set;}
      public string StringField {get;set;}
      public decimal DecimalField {get;set;}
      public decimal DateTimeField {get;set;}
    }
    

    将FormData对象绑定到UI控件。当用户希望保存不完整的数据时,请将FormData对象序列化为XML,因为您确实希望在此处使用序列化。

    XmlSerializer serializer = new XmlSerializer(typeof(FormData));
    StringWriter writer = new StringWriter(new StringBuilder());
    serializer.Serialize(writer,formDataObject);
    string serializedFormDataObject = writer.GetStringBuilder().ToString();
    

    然后可以将serializedFormDataObject保存到单独的表中。当用户加载表单时,可以检查表以查看表单是否不完整。如果是,则可以反序列化窗体加载事件上的数据,例如:

    string serializedFormDataObject = GetFromDatabase(formId,userId); //you get the idea I guess
    StringReader reader = new StringReader(serializedFormDataObject);
    XmlSerializer serializer = new XmlSerializer(typeof(FormData));
    formDataObject = serializer.Deserialize(reader) as FormData;
    

    然后可以将FormData绑定到控件。表单完成后,可以删除未完成的表单条目,并将已完成的表单保存到已完成表单的表中。

        2
  •  8
  •   RameshVel    13 年前

    迈克,

    您不必序列化整个ASP.NET窗体来捕获填充了一半的数据。最好是在卸载(或Whaterver触发器)时捕获字段中输入的数据并将其保存到数据库中。您只需在再次加载页面时将数据重新分配给控件。这比序列化整个页面要好…

    编辑:

    我理解根据你在这篇文章中的几条评论,你的要求是

    • 保留半填充数据而不是完整数据
    • 而且你的数据非常敏感
    • 你要存储页面的序列化形式并呈现它 当需要时…

    但是你认为在这种情况下重新开始序列化,它会解决所有的问题吗?不。。

    考虑以下事实

    1. 如果你把整个 形式,可能最终存储数据 这甚至不是必需的。(如果你 表单包含15个文本框和用户 只填写了2个条目。然后 坚持整体的使用 表单对象)。
    2. 数据传输量会更大 (增加包大小,慢 传输速率)。
    3. 以及对页面的控制(从序列化 对象)更少。考虑一下你 想在上显示一些通知 序列化窗体..可能是 一定有办法……但我 知道这不是那么简单……

    考虑一下PPL在这里给出的所有事实,这些事实都是有经验的,并做一些分析,然后选择最佳的方法。所有最好的

    编辑

    我刚遇到 JQuery AutoSave 插件…它和我上面建议的一样,但是以一种非常简单的方式……(以指定的时间间隔运行并保存未保存的内容)。你可以很容易地调整这个来满足你的需求)看看……

        3
  •  1
  •   Matt Ball    15 年前

    您表示希望在表单的部分完成状态下对其进行序列化。从您的问题和各种注释来看,您似乎试图使用序列化来避免使用单独的存储。然而,这不是序列化的目的。

    序列化将一些对象(通常在内存中)转换为已知格式(例如XML文件),以便可以通过网络传输或持久化到数据库中。序列化并不意味着什么 如果对象的序列化形式为, 在里面 序列化窗体。

    很抱歉,如果这是曲奇刀,但我认为已经很清楚了: http://en.wikipedia.org/wiki/Serialization

    编辑:也许你已经明白我上面说的了——例如,你想把序列化的表单放到会话中吗?

    编辑2:好吧,我想我明白了。您可以将序列化表单保存到数据库中,但不希望将单个表单输入保存到数据库中—与保存已完成表单的方式相同。因此,您正在寻找一种方法来保持不完整的表单 不同地 从完成的。 为此,我将在您的数据库中为此确切的内容创建一个新表。它可以有一个单独的数据列(存储序列化数据)或与普通(已完成的表单)表相同的列,而不需要您提到的约束。这有道理吗?

        4
  •  1
  •   Vinay Sajip    15 年前

    不幸的是,viewstate还不够;您还需要考虑发布数据和查询参数,以便能够准确地保存和恢复页面状态。 Here 是关于所涉及问题的非常全面的报告,其中包括工作代码。

        5
  •  0
  •   Glenn    15 年前

    考虑发展 google gears 允许用户脱机工作。基本上,这意味着表单数据将在本地保存,直到提交到服务器。虽然谷歌本身对授权微软开发者不感兴趣,但开发者社区中也有这样的人。这里是一个 tutorial 获取一个ASP.NET应用程序以利用Google Gears。

        6
  •  0
  •   Lewis    15 年前

    序列化不会帮助您,除非您愿意将序列化数据存储在某个地方,可能是数据库表中的XML片段,也可能是文件(yuk)。 对我来说,这似乎是错误的方法,但是如果您真的想使用序列化,那么有很多选择。我能想到的最简单的方法是将request.form集合序列化为XML,可以使用XmlSerializer,也可以通过循环并自己构建一个XML字符串。

    我的建议是…

    如果您愿意使用javascript,为什么不尝试在客户机上这样做呢?

    例如,您可以通过单击“保存”按钮从表单中收集数据,并将其保存到cookie中。

    当用户返回时,您可以检查cookie并从cookie重新加载数据。

    只有在表单完成后,才能将表单数据发回服务器。这样可以避免数据库约束问题。

    试试这个: http://www.bigresource.com/Tutorial/PHP/Saving_Form_Data_Into_A_Cookie.htm

    更新

    以下评论: 好吧,如果你想接近 将你的表格序列化 您需要将数据存储在某个地方。

    基于我认为你想做的:

    如果您的表单数据适合一个单独的表,我建议您使用一个不带db约束的“副本表”,并将其称为类似于FormDataHolding(您的原始表是FomrData)的表。您可以从这个表中读和写,并且只在表单数据完成时迁移数据,我使用migrate这个词意味着数据离开保留表并以某种方式进入完整的表。 如果您的表单包含适合于多个表的数据,那么序列化可能是正确的答案,但要准备将此数据存储在某个地方,以一种可能与现有数据模型不匹配的方式,或者准备为存储数据的所有表创建不受约束的“副本表”。

    序列化数据并不一定意味着您正在创建XML,但我假设这是您想要的。我将采用从request.form返回nameValueCollection的方法,然后对其进行序列化。如果您使用的是WebForms,则可能需要做不同的操作。

    以下是序列化NameValueCollection的人的URL: http://nayyeri.net/blog/Serialize-NameValueCollection/

        7
  •  0
  •   mamu    15 年前

    我没有经历过这个大问题,但对我来说,似乎只需要持久化viewstate并使用持久化viewstate,而不是在需要输入一半的表单时创建新的viewstate。

    不需要任何额外的逻辑,viewstate的设计就是这样使用的。

    任何回发在技术上都是新的页面呈现,但使用的是来自ViewState的值,而Op正试图做同样的事情,不仅仅是回发,而是其他一些时间,但需要同样的事情。

        8
  •  0
  •   Macros    15 年前

    我对许多表单(主要是多页表单,但单页表单也是这样)采用的一种方法是让每个表单页面继承一个公共的基类,该类具有许多属性。其中一个属性是FormData,可以定义为:

    public FormData FormDataStore
    {
        get
        {
            if (Session["FormDataStore"] == null)
            {
                Session["FormDataStore"] = new FormData();
            }
    
            return (FormData)Session["FormDataStore"];
        }
        set
        {
            Session["FormDataStore"] = value;
        }
    }
    

    FormData是一个包含所有属性(窗体字段)的类,例如

    public class FormData
    {
      public string name {get; set;}
      public string email {get; set;}
    }
    

    每个表单页都有一个“loadData”和“saveData”函数,分别负责用来自FormDataObject对象的数据填充表单,并将数据保存到FormDataObject对象。

    基类还包含两个方法savedraft和loaddraft。savedraft将formdataobject序列化为xml并保存到db表(可以简单为2列、id和xmldata):

                StringWriter sw_wf = new StringWriter();
                XmlSerializer xs_wf = new XmlSerializer(FormData.GetType(), new System.Type[] { typeof(additionalObjects)});
                xs_wf.Serialize(sw_wf, FormDataObject);
                string WebFormData = sw_wf.ToString();
                sw_wf.Close();
    
                //write WebFormData to database
    

    loadDraft只需加载XML并将其反序列化回一个对象,表单将自动提取并填充字段。LoadDraft的工作方式取决于ISTE的性质和数据的敏感性,例如,如果表单是由登录用户完成的,或者它可能是匿名的,并且是存储在数据库和cookie中的唯一ID。

    我构建了许多提交给1个或多个Web服务的站点,当从WSDL文件构建存根并将其用作FormData类时,这种方法非常有效。

        9
  •  0
  •   almog.ori    15 年前

    我过去使用的一种方法是从表单对象捕获post值,并使用可使用soapformatter序列化的momemto类存储这些值。当需要还原时,我所要做的就是使用querystring参数获取一个httphandler类,该类解析预期的ID并反序列化要还原的状态,该状态呈现隐藏字段,以模拟用户从原始页面执行发布。这是两个班。

    请注意,您正在捕获表单的状态,因此当您恢复表单时,您将恢复到请求恢复的状态,如果发现问题,您可能需要处理此问题。

    ''' <summary>
    ''' This class encapsulates the form state
    ''' </summary>
    <Serializable()> _
    Public NotInheritable Class FormState
    
        Private _path As String
        Private _form As NameValueCollection
    
        ''' <summary>
        ''' Constructor.
        ''' </summary>
        ''' <param name="path">The path of the original form post request.</param>
        ''' <param name="form">The form to save.</param>
        Public Sub New(ByVal path As String, ByVal form As NameValueCollection)
            _path = path
            _form = form
        End Sub
    
    
        ''' <summary>
        ''' Serializer Ctor.
        ''' </summary>
        ''' <remarks></remarks>
        Sub New()
        End Sub
    
    
        ''' <summary>
        ''' The path of the original form post request.
        ''' </summary>
        Public ReadOnly Property Path() As String
            Get
                Return _path
            End Get
        End Property
    
        ''' <summary>
        ''' The saved form.
        ''' </summary>
        Public ReadOnly Property Form() As NameValueCollection
            Get
                Return _form
            End Get
        End Property
    
    End Class
    
        ''' <summary>
        ''' This http handler will render a small page that will reconstruct the form as it was before session timeout, using hidden fields.
        ''' The page will submit itself upon loading, meaning that the user will barely see it.
        ''' </summary>
        Public Class FormStateRestoreHandler
            Implements IHttpHandler, IRequiresSessionState
    
            Private _state As FormState
            Private _dealGuid As Guid
    
            ''' <summary>
            ''' The form state.
            ''' </summary>
            Protected ReadOnly Property FormState() As FormState
                Get
                    Return _state
                End Get
            End Property
    
            ''' <summary>
            ''' Gets a value indicating whether another request can use this IHttpHandler instance.
            ''' </summary>
            Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
                Get
                    Return False
                End Get
            End Property
    
    
            ''' <summary>
            ''' Processes the web request - this is where the page is rendered.
            ''' </summary>
            ''' <param name="context"></param>
            Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
                Dim Id = context.Request.QueryString("id")
    
                If Id Is Nothing Then Return
    
                _state = LoadFormState(Id)
    
                Using writer As HtmlTextWriter = CreateHtmlTextWriter(context.Response.Output, context.Request.Browser)
                Me.Render(writer)
            End Using
    
       End Sub
    
       ''' <summary>
       ''' Loads the specified FormState by id
       ''' </summary>
       ''' <param name="id">The unique id of the saved form state.</param>
       ''' <returns></returns>
       Private Shared Function LoadFormState(ByVal id As Guid) As FormState
           Dim _storageProvider = ConfigurationFacade.GetUnityContainer.Resolve(Of IDealProvider)()
           Dim result As FormState = Nothing
           Dim bytes = _storageProvider.LoadUserState(id)
    
           Dim soapFormatter = New SoapFormatter
           Using ms = New IO.MemoryStream(bytes)
               result = soapFormatter.Deserialize(ms)
               ms.Close()
           End Using
    
    
           Return result
       End Function
    
    
    
       ''' <summary>
       ''' Renders a small page that will resubmit the saved form
       ''' </summary>
       ''' <param name="writer"></param>
       Protected Overridable Sub Render(ByVal writer As HtmlTextWriter)
           writer.RenderBeginTag(HtmlTextWriterTag.Html)
           writer.RenderBeginTag(HtmlTextWriterTag.Head)
           writer.RenderBeginTag(HtmlTextWriterTag.Title)
           writer.Write("Restoring form")
           writer.RenderEndTag()
           ' TITLE
           writer.RenderEndTag()
           ' HEAD
           writer.AddAttribute("onload", "document.forms[0].submit();")
           writer.RenderBeginTag(HtmlTextWriterTag.Body)
    
           writer.AddAttribute("method", "post")
           writer.AddAttribute("action", Me.FormState.Path)
    
           writer.RenderBeginTag(HtmlTextWriterTag.Form)
    
           Dim form As NameValueCollection = Me.FormState.Form
           For Each name As String In form.Keys
               RenderHiddenField(writer, name, form(name))
           Next
    
           writer.AddAttribute(HtmlTextWriterAttribute.Align, "center")
           writer.RenderBeginTag(HtmlTextWriterTag.P)
           writer.Write("You should be redirected in a moment.")
           writer.WriteFullBeginTag("br")
           writer.Write("If nothing happens, please click ")
           RenderSubmitButton(writer, "Submit")
           writer.RenderEndTag()
           ' P
           writer.RenderEndTag()
           ' FORM
           writer.RenderEndTag()
           ' BODY
           writer.RenderEndTag()
           ' HTML
       End Sub
    
       ''' <summary>
       ''' Renders a hidden field.
       ''' </summary>
       ''' <param name="writer">The writer to use.</param>
       ''' <param name="name">The name of the hidden field.</param>
       ''' <param name="value">The value of the hidden field.</param>
       Protected Shared Sub RenderHiddenField(ByVal writer As HtmlTextWriter, ByVal name As String, ByVal value As String)
           writer.AddAttribute(HtmlTextWriterAttribute.Type, "hidden")
           writer.AddAttribute(HtmlTextWriterAttribute.Name, name)
           writer.AddAttribute(HtmlTextWriterAttribute.Value, value)
           writer.RenderBeginTag(HtmlTextWriterTag.Input)
           writer.RenderEndTag()
           ' INPUT
       End Sub
    
       ''' <summary>
       ''' Renders a submit button.
       ''' </summary>
       ''' <param name="writer">The writer to use.</param>
       ''' <param name="text">The text of the button.</param>
       Protected Shared Sub RenderSubmitButton(ByVal writer As HtmlTextWriter, ByVal text As String)
           writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit")
           writer.AddAttribute(HtmlTextWriterAttribute.Value, text)
           writer.RenderBeginTag(HtmlTextWriterTag.Input)
           writer.RenderEndTag()
           ' INPUT
       End Sub
    
       ''' <summary>
       ''' Gets a HtmlTextWriter to write output to, based on a TextWriter.
       ''' </summary>
       ''' <param name="writer">The Text writer holding the output stream.</param>
       ''' <param name="browser">The browser capabilities of the client browser.</param>
       ''' <returns></returns>
       Protected Shared Function CreateHtmlTextWriter(ByVal writer As TextWriter, ByVal browser As HttpCapabilitiesBase) As HtmlTextWriter
           If browser Is Nothing Then
               Return New HtmlTextWriter(writer)
           End If
           Return browser.CreateHtmlTextWriter(writer)
       End Function
      End Class