序列化ASP.NET Web表单

时间:2009-08-03 04:18:45

标签: asp.net serialization

是否可以序列化ASP.NET Web表单,包括用户输入的所有数据?我想让用户能够保存一个半完成的表单,并希望我可以通过序列化完成此任务。任何简单的例子将不胜感激。

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

9 个答案:

答案 0 :(得分:8)

麦克,

您不必序列化整个asp.net表单来捕获半满的数据。最好捕获在卸载(或whaterver触发器)字段中输入的数据并将其保存在db中。并且你只需在重新加载页面时将数据重新分配给控件..这比序列化整个页面更好......

编辑::

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

  • 将半满的数据与完整数据一起保留
  • 和你的数据非常敏感
  • 并且您希望存储序列化的页面形式并进行渲染 需要直接使用...

但你认为序列化是在这种情况下推荐的,它将解决你所有的问题.. NO ..

考虑以下事实

  1. 如果你序列化整个 形式,你可能最终存储数据 甚至不需要。 (如果你的 表单包含15个文本框和用户 只填写了2个条目。然后 wats使用持久整体 形式对象)。
  2. 转移的数据量会更高 (增加数据包大小,慢 传输率)。
  3. 您对页面的控制(从序列化渲染 对象)少了。考虑一下你 想要显示一些通知 序列化的形式..可能是 某种方式可以做到这一点..但是我 知道它不那么简单..
  4. 考虑一下ppl给出的所有事实,他们都有这方面的经验,并自己做一些分析并选择最好的方法......一切顺利

    修改

    我刚刚看到JQuery AutoSave插件..它的功能与我上面提到的相同,但是以一种非常简单的方式....(在指定的某个时间间隔内运行并且保存未保存的内容。你可以很容易地调整这个以满足你的需要)只是看看..

答案 1 :(得分:4)

对于不完整的表单,您无法真正避免单独的存储位置。你需要在某个地方坚持它们,你不能把它们放在完整的地方,因为显然你对底层数据库表有一些数据库约束,你想保留它们。我建议@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 :(得分:1)

您说要将表单序列化为部分完成状态。从您的问题和各种评论中,您可能会尝试使用序列化作为避免使用单独存储的方法。但是,这不是序列化的内容。

序列化正在将某些对象(通常在内存中)转换为已知格式(例如,XML文件),以便可以通过网络传输或保存在数据库中。序列化不会暗示您使用序列化形式的对象,只是 序列化形式。

很抱歉,如果这是千篇一律,但我认为这很明确:http://en.wikipedia.org/wiki/Serialization

编辑:也许您已经理解我上面已经说过的内容了 - 您是否希望将序列化表单放入会话中?

编辑2:好的,我想我明白了。您可以将序列化表单保存到数据库,但是您不希望将单个表单输入保存到数据库 - 就像保存已完成的表单一样。因此,您正在寻找一种方法来保持不完整的表单完全不同。 为此,我将在您的数据库中为此创建一个新表。它可以有一个数据列(存储序列化数据)或与普通(完成表单)表相同的列,只是没有您提到的约束。这有意义吗?

答案 3 :(得分:1)

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

答案 4 :(得分:0)

序列化对您没有帮助,除非您乐意将加密数据存储在某处,可能是作为db表中的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)。你可以从这个表中读取和写入,只在表单数据完成时才迁移数据,我使用“迁移”这个词意味着数据离开了保存表并以某种方式进入完整的表。 如果您的表单包含适合多个表的数据,那么序列化可能是正确的答案,但是准备将这些数据存储在某个地方,可能与您现有的数据模型不相符,或者准备创建“副本”对于存储数据的所有表,没有约束的表。

序列化数据并不意味着您正在创建xml,但我认为这就是您想要的。我采取从Request.Form返回NameValueCollection然后序列化的方法。如果您使用的是webforms,则可能需要执行此操作。

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

不需要任何额外的逻辑,viewstate被设计为像这样使用。

任何回帖在技术上都是新的页面渲染,但是使用来自viewstate的值,而op正在尝试做同样的事情,不仅仅是回发,而是其他时间,但需要相同的东西

答案 7 :(得分:0)

我采用多种形式(主要是多页面,但同样适用于单页面)的方法是每个表单页面从公共基类继承,该基类具有许多属性。其中一个属性是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对象。

基类还包含2个方法,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。

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

答案 8 :(得分:0)

过去使用过的一种方法是从Form对象捕获POST值并使用可以使用soapformatter序列化的momemto类进行存储。当需要恢复时,我所做的就是使用查询字符串参数获取HttpHandler类,该参数解析目标id并对恢复状态进行deserilize,这将呈现隐藏字段以模拟用户从原始页面执行帖子。这是两个类。

请注意,您正在捕获FORM的状态,因此在还原表单时,您将状态还原到要求还原的状态,如果发现问题,可能需要处理此问题。 / p>

''' <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