Сериализация веб-формы ASP.NET - PullRequest
2 голосов
/ 03 августа 2009

Можно ли сериализовать веб-форму ASP.NET, включая все данные, введенные пользователем? Я хочу дать пользователям возможность сохранить наполовину заполненную форму и надеялся, что смогу добиться этого с помощью сериализации. Будем весьма благодарны за любые простые примеры.

Edit: Я хочу избежать необходимости иметь отдельный слой данных для «неполных» форм, который отражает слои для заполненных форм. Я не хочу хранить неполные формы с полными формами, потому что они могут не соответствовать моим ограничениям БД.

Ответы [ 9 ]

8 голосов
/ 03 августа 2009

Mike

Вам не нужно сериализовать всю форму asp.net, чтобы получить наполовину заполненные данные. Лучше захватить данные, введенные в поля при выгрузке (или любой другой триггер), и сохранить их в БД. и вы просто переназначаете данные на элементы управления при повторной загрузке страницы ... это лучше, чем сериализация всей страницы ...

РЕДАКТИРОВАТЬ ::

Я понимаю, что по вашим комментариям в этом посте, ваше требование к

  • сохранить наполовину заполненные данные не вместе с полными данными
  • и ваши данные очень чувствительны
  • и вы хотите сохранить сериализованную форму страницы и отобразить ее непосредственно когда нужен ...

но думаете ли вы, что в этом контексте рекомендуется сериализация, и она решит все ваши проблемы? НЕТ ..

рассмотрите следующие факты

  1. если вы сериализуете весь форма, вы можете в конечном итоге хранить данные это даже не требуется. (если твой Форма содержит 15 текстовых полей и пользователя только заполнены только 2 записи. затем Ватс использования упорства целого объект формы).
  2. И объем передаваемых данных будет выше (увеличивает размер пакета, медленно скорость передачи).
  3. И ваш контроль над страницей (будет отображаться из сериализованного объект) меньше. рассмотреть, если вы хотел показать некоторое уведомление о сериализованная форма .. там может быть какой-то способ сделать это точно .. но я знаю, что это не так просто ..

рассмотрите все факты, приведенные здесь, кто получил опыт в этой области, проведите некоторый анализ и выберите лучший подход .. всего наилучшего

EDIT

Я только что наткнулся на плагин JQuery AutoSave ... и он делает то же самое, что я предлагаю выше, но довольно простым способом .... (который работает через определенный промежуток времени и сохраняет несохраненный контент. Вы можете легко настроить его, чтобы удовлетворить ваши потребности) просто посмотрите ..

4 голосов
/ 12 августа 2009

Вы не можете избежать отдельного места для хранения неполных форм.Вам нужно где-то сохранить их, и вы не можете поместить их вместе с полными, потому что, очевидно, у вас есть некоторые ограничения базы данных на базовые таблицы базы данных, и вы хотите их сохранить.Я бы предложил, как @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 к элементам управления вашего пользовательского интерфейса.Когда пользователь хочет сохранить неполные данные, сериализуйте объект 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 к вашим элементам управления.После заполнения формы вы можете удалить неполную запись формы и сохранить заполненную форму в таблицу для заполненных форм.

1 голос
/ 18 августа 2009

Viewstate, к сожалению, недостаточно; вам также нужно учитывать данные поста и параметры запроса, чтобы иметь возможность точно сохранять и восстанавливать состояние страницы. Здесь - это исчерпывающая статья о проблемах, включающая рабочий код.

1 голос
/ 12 августа 2009

Вы говорите, что хотите сериализовать форму в частично заполненном состоянии. Из вашего вопроса и различных комментариев кажется, что вы пытаетесь использовать сериализацию как способ избежать использования отдельного хранилища. Тем не менее, это не то, что сериализация.

Сериализация превращает некоторый объект, обычно в памяти, в известный формат (например, файл XML), чтобы его можно было передавать по сети или сохранять в базе данных. Сериализация не подразумевает ничего, что вы делаете с объектом в его сериализованной форме, только то, что это в сериализованной форме.

Извините, если это печенья, но я думаю, это довольно ясно: http://en.wikipedia.org/wiki/Serialization

Редактировать: возможно, вы понимаете, что я уже сказал выше - вы, например, хотите поместить сериализованную форму в сеанс?

Редактировать 2: Хорошо, я думаю, я понял. Вы можете сохранить сериализованную форму в базе данных, но не хотите сохранять отдельные входные данные формы в БД - так же, как вы сохраняете заполненную форму. Итак, вы ищете способ сохранить неполные формы в отличие от завершенных. Для этого я бы создал новую таблицу в вашей базе данных именно для этого. Он может иметь один столбец данных (в котором хранятся сериализованные данные) или те же столбцы, что и ваша обычная таблица (заполненная форма), только без упомянутых вами ограничений. Имеет ли это смысл?

0 голосов
/ 18 августа 2009

Один из способов, которыми я пользовался в прошлом, - это получить значения POST из объекта формы и сохранить их, используя класс momemto, который можно сериализовать с использованием soapformatter. Когда требуется восстановить, все, что я делаю, это GET в классе HttpHandler с параметрами строки запроса, который анализирует намеченный идентификатор и десерилизует состояние для восстановления, которое отображает скрытые поля для имитации того, что пользователь делает сообщение с исходной страницы. Вот два класса.

ОБРАТИТЕ ВНИМАНИЕ, что вы фиксируете состояние ФОРМЫ, поэтому, когда вы восстанавливаете форму, вы восстанавливаете состояние до состояния, в котором вы запрашиваете восстановление, вам может потребоваться справиться с этим, если вы обнаружите проблему.

''' <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
0 голосов
/ 18 августа 2009

Подход, который я использовал для ряда форм (в основном многостраничных, но одинаковых для одной страницы), заключается в том, что каждая страница формы наследуется от общего базового класса, который имеет ряд свойств. Одно из свойств будет 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 и сохраняет в таблицу БД (которая может быть проста: 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, зависит от характера процесса и чувствительности данных - например, если форма заполняется вошедшим в систему пользователем или она может быть анонимной и иметь уникальный идентификатор, сохраненный в БД и в файле cookie.

Я создаю множество сайтов, которые предоставляют одну или несколько веб-служб, и этот подход очень хорошо работает при создании заглушки из файла WSDL и использовании этого в качестве класса FormData.

0 голосов
/ 13 августа 2009

Я не прошел через эти большие ответы, но мне кажется, что мне просто нужно сохранить постоянное состояние представления и использовать постоянное состояние представления вместо создания нового, когда нужно наполовину ввести форму.

Нет необходимости в какой-либо дополнительной логике, viewstate разработан для использования именно так.

Любое сообщение назад является технически новым рендером страницы, но использует значение из viewstate, и op точно пытается сделать то же самое, только не с обратной передачей, а в другое время, но требует того же самого

0 голосов
/ 13 августа 2009

Рассмотрите возможность разработки для Google Gears , которая позволяет пользователю работать в автономном режиме. По сути, это означает, что данные формы сохраняются локально, пока не будут зафиксированы на сервере. В то время как сам Google не заинтересован в расширении возможностей разработчиков Microsoft, в сообществе разработчиков есть такие. Вот учебник о том, как получить приложение ASP.NET для использования Google Gears.

0 голосов
/ 13 августа 2009

Сериализация вам не поможет, если только вы не будете рады хранить сериализованные данные где-либо, возможно, в виде фрагмента XML в таблице БД или в виде файла (юк). Мне кажется, что это неправильный подход, но если вы действительно хотите использовать сериализацию, есть много вариантов. Самое простое, что я могу придумать, - это сериализовать коллекцию request.form в xml, либо используя xmlserializer, либо зацикливая его, и самостоятельно собирая строку xml.

Мое предложение будет ...

Если вы счастливы использовать javascript, почему бы не попробовать это сделать на клиенте?

Вы можете собрать данные из формы, например, нажатием кнопки «Сохранить» и сохранить их в файле cookie.

Когда пользователь возвращается, вы можете проверить наличие файла cookie и перезагрузить данные из файла cookie.

Вы отправите данные формы обратно на сервер только после заполнения формы. Это позволит избежать проблемы с вашими БД.

Попробуйте это: http://www.bigresource.com/Tutorial/PHP/Saving_Form_Data_Into_A_Cookie.htm

UPDATE

следующие комментарии: Хорошо, если вы хотите использовать сериализацию , вам нужно где-то хранить данные.

Исходя из того, что я думаю, вы хотите сделать:

Если ваши данные формы помещаются в одну таблицу, я бы предложил, чтобы у вас была «таблица реплик» без ограничений db, и назовите ее чем-то вроде formDataHolding (где ваш оригинал был fomrData). Вы читали и писали из этой таблицы и переносили данные только после заполнения данных формы. Я использую слово перенос, означающее, что данные покидают таблицу хранения и каким-то образом попадают в полную таблицу. Если ваша форма содержит данные, которые вписываются в несколько таблиц, то сериализация вполне может быть правильным ответом, но будьте готовы хранить эти данные где-то таким образом, который может не соответствовать вашей существующей модели данных или быть готовым к созданию «реплики». таблиц без ограничений для всех таблиц, в которых хранятся данные.

Сериализация данных не обязательно означает, что вы создаете XML, но я предполагаю, что это то, что вы хотите. Я бы взял подход, возвращая NameValueCollection из Request.Form, а затем сериализовал его. Возможно, вы захотите сделать это по-другому, если вы используете веб-формы.

Вот URL для того, кто сериализовал коллекцию NameValueCollection: http://nayyeri.net/blog/Serialize-NameValueCollection/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...