Por que estou perdendo referências de objetos no postback?
-
21-09-2019 - |
Pergunta
Estou desenvolvendo um aplicativo ASP.NET (3.5) e estou intrigada com o comportamento dos postagens.
Considere o seguinte cenário: tenho um controle do usuário da Web que é basicamente um formulário. No entanto, cada campo de formulário é um controle do usuário da Web em si.
No evento de cliques do botão Salvar, Itreado através de todos os controles no meu formulário e recupero o valor do campo e o nome do campo que se refere ao campo do banco de dados para o qual estou salvando o valor.
O evento de cliques aciona um postback e é durante o postback que visito os controles e aqui está o engraçado: o valor da propriedade para o campo do banco de dados se tornou nulo! Alguém poderia lançar uma luz aqui?
Aqui está algum código básico:
[Serializable]
public partial class UserProfileForm : CustomIntranetWebappUserControl
{
protected override void OnInit(EventArgs e)
{
//AutoEventWireup is set to false
Load += Page_Load;
CancelLinkButton.Click += CancelButtonClickEvent;
SaveLinkButton.Click += SaveButtonClickEvent;
base.OnInit(e);
}
private void SaveButtonClickEvent(object sender, EventArgs e)
{
VisitFormFields();
}
private void VisitFormFields()
{
var userProfileVisitor = new UserProfileVisitor();
foreach (var control in Controls)
{
if (control is FormFieldUserControl)
{
var formField = (FormFieldUserControl) control;
formField.Visit(userProfileVisitor);
}
}
userProfileVisitor.Save();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindText();
}
}
private void BindText()
{
LastNameFormLine.LabelText = string.Format("{0}:", HomePage.Localize("Last Name"));
LastNameFormLine.InputValue = UserProfile.LastName;
LastNameFormLine.IsMandatoryField = true;
LastNameFormLine.IsMultilineField = false;
LastNameFormLine.ProfileField = "UserProfile.LastName";
//... the rest of this method is exactly like the 4 lines above.
}
}
[Serializable]
public abstract class FormFieldUserControl : CustomIntranetWebappUserControl
{
public string ProfileField { get; set; }
public abstract void Visit(UserProfileVisitor userProfileVisitor);
}
[Serializable]
public partial class FormLineTextBox : FormFieldUserControl
{
//... irrelevant code removed...
public override void Visit(UserProfileVisitor userProfileVisitor)
{
if (userProfileVisitor == null)
{
Log.Error("UserProfileVisitor not defined for the field: " + ProfileField);
return;
}
userProfileVisitor.Visit(this);
}
}
[Serializable]
public class UserProfileVisitor
{
public void Visit(FormLineTextBox formLine)
{
// The value of formLine.ProfileField is null!!!
Log.Debug(string.Format("Saving form field type {1} with profile field [{0}] and value {2}", formLine.ProfileField, formLine.GetType().Name, formLine.InputValue));
}
// ... removing irrelevant code...
public void Save()
{
Log.Debug("Triggering the save operation...");
}
}
Solução
Lembre -se de que asp.net está apátrida. Quaisquer propriedades criadas são destruídas depois que a página foi renderizada ao navegador. Portanto, você deve recriar objetos em cada postagem ou armazená -los à vista, sessão ou estado de aplicação.
Quando você faz uma propriedade, você deve dizer para salvar o estado de visualização, não o faz automaticamente. Aqui está uma amostra de uma propriedade do estado de exibição.
public string SomePropertyAsString
{
get
{
if (this.ViewState["SomePropertyAsString"] == null)
return string.Empty;
return (string)this.ViewState["SomePropertyAsString"];
}
set { this.ViewState["SomePropertyAsString"] = value; }
}
public MyCustomType ObjectProperty
{
get
{
if (this.ViewState["ObjectProperty"] == null)
return null;
return (MyCustomType)this.ViewState["ObjectProperty"];
}
set { this.ViewState["ObjectProperty"] = value; }
}
Outras dicas
O primeiro palpite seria que o bindText () não deveria estar em Page_load, mas em Page_init, para que o estado de controle seja salvo.
@David Basarab, isso não é verdadeiro Afaik e foi apenas o caso no .NET 1.1, no .NET2 e isso é todo tratado pela estrutura se você fizer todas as coisas mágicas no init.
Seu problema é que o 'perfilfield' não está disponível no postback, certo?
A solução é armazenar o valor para o ViewState (em vez de uma propriedade implementada automaticamente). Sem isso, não estará disponível no postback.