Domanda

Ora che ho visto alcune domande come questa, ma non è esattamente quello che voglio chiedere, quindi per tutti coloro che urla duplicato, mi scuso:)

.

Ho appena toccato ASP.NET MVC, ma da quello che ho capito non v'è alcuna ViewState / ControlState ... bene. Quindi la mia domanda è: qual è l'alternativa a mantenere lo stato di un controllo? Andiamo di nuovo al vecchia scuola ASP dove potremmo simulare ciò che ASP.NET ViewState / ControlState fa con la creazione di input di form nascosti con lo stato del controllo, oppure con MVC, possiamo solo supporre AJAX sempre e manteniamo tutto lo stato sul lato client e fare AJAX chiamate ad aggiornare?

Questa domanda ha delle risposte, Mantenere ViewState in Asp.net MVC? , ma non è esattamente quello che sto cercando in una risposta.

UPDATE: Grazie per tutte le risposte finora. Giusto per chiarire quello che non sto cercando e quello che sto cercando:

Non ho bisogno di:

  • soluzione Session
  • soluzione cookie
  • Non ho bisogno di imitare WebForms in MVC

Quello che mi / cercavo:

  • Un metodo che conserva solo lo Stato il postback se i dati non è rimbalzo a un controllo. Pensare WebForms con lo scenario di vincolante solo una griglia sul carico pagina iniziale, ossia solo rebinding i dati quando necessario. Come ho già detto, io non sto cercando di imitare WebForms, chiedo solo quali meccanismi offerte MVC.
È stato utile?

Soluzione

La convenzione è già disponibile senza saltare attraverso troppi cerchi. Il trucco è quello di cablare i valori TextBox in base al largo del modello si passa nella vista.

[AcceptVerbs(HttpVerbs.Get)]   
public ActionResult CreatePost()
{
  return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(FormCollection formCollection)
{
  try
  {
    // do your logic here

    // maybe u want to stop and return the form
    return View(formCollection);
  }
  catch 
  {
    // this will pass the collection back to the ViewEngine
    return View(formCollection);
  }
}

Cosa succede dopo è il ViewEngine prende il FormCollection e le partite le chiavi all'interno della collezione con i nomi ID / valori che avete nella vostra vista, utilizzando gli helper HTML. Ad esempio:

<div id="content">

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: <%= Html.TextBox("Title", Model["Title"], 50) %><br />
  Enter the Post Body: <%= Html.TextArea("Body", Model["Body"]) %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

Si noti la casella di testo e textarea ha gli ID di titolo e il corpo? Ora, si noti come io pongo i valori dal di oggetto View modello? Dal momento che avete passato in un FormCollection (ed è necessario impostare la visualizzazione per essere fortemente tipizzato con un FormCollection) ora è possibile accedervi. Oppure, senza fortemente digitazione, si può semplicemente utilizzare Viewdata [ "Titolo"] (credo).

POOF Il tuo ViewState magico. Questo concetto si chiama convenzione sulla configurazione.

Ora, il codice di cui sopra è nella sua forma più cruda semplice utilizzando FormCollection. Le cose si fanno interessanti quando si inizia utilizzando ViewModels, al posto del FormCollection. È possibile iniziare ad aggiungere la tua validazione dei modelli / ViewModels e hanno la bolla di controllo sugli errori di validazione personalizzata automaticamente. Questa è una risposta per un altro giorno però.

Io suggerirei di usare un PostFormViewModel anziché l'oggetto Post, ma a ciascuno il suo,-own. In entrambi i casi, richiedendo un oggetto sul metodo di azione, è ora ottenere un metodo IsValid () si può chiamare.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(Post post)
{

  // errors should already be in the collection here
  if (false == ModelState.IsValid())
    return View(post);

  try
  {
    // do your logic here

    // maybe u want to stop and return the form
    return View(post);
  }
  catch 
  {
    // this will pass the collection back to the ViewEngine
    return View(post);
  }
}

E la tua vista fortemente tipizzato avrebbe bisogno di essere ottimizzato:

<div id="content">

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: <%= Html.TextBox("Title", Model.Title, 50) %><br />
  Enter the Post Body: <%= Html.TextArea("Body", Model.Body) %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

Si può prendere un ulteriore passo avanti e visualizzare gli errori, nonché nella vista, direttamente dal ModelState impostato nel controller.

<div id="content">

  <%= Html.ValidationSummary() %>

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: 
    <%= Html.TextBox("Title", Model.Title, 50) %>
    <%= Html.ValidationMessage("Title") %><br />

  Enter the Post Body: 
    <%= Html.TextArea("Body", Model.Body) %>
    <%= Html.ValidationMessage("Body") %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

La cosa interessante di questo approccio è che si noterà che non pongo il riassunto di convalida, né le singole messaggi di validazione nella vista. A me piace praticare i concetti DDD, il che significa che i miei messaggi di validazione (e sintesi) sono controllati nel mio dominio e viene passato nella forma di una collezione. Poi, ho ciclo ATTRAVERSO lui di raccolta (se esistono eventuali errori) e aggiungerli alla collezione ModelState.AddErrors corrente. Il resto è automatico quando si torna View (post).

Un sacco di un sacco di convenzione è fuori. Alcuni libri che consiglio vivamente che la copertura di questi modelli in modo molto più dettagliato sono:

E in questo ordine prima copre i dadi e bulloni prime dell'intero framework MVC. Quest'ultimo si estende su tecniche avanzate di fuori del RELM ufficiale di Microsoft, con diversi strumenti esterni per rendere la vita molto più facile (Castello di Windsor, MOQ, ecc).

Altri suggerimenti

The View si suppone essere muto nel modello MVC, proprio mostrando ciò che il controller dà (ovviamente facciamo spesso finiscono con una certa logica lì, ma la premessa è per non essere) a seguito, controlli aren' t responsabili per il loro stato, si arriverà dal controller ogni volta.

Non posso consigliare il libro di Steven Sanderson Pro ASP.NET MVC da Apress sufficiente per sempre alle prese con questo modello e questa implementazione di esso.

Nel Web Form, i valori di controllo sono mantenuti nel ViewState in modo da (in teoria) non c'è bisogno di reinizializzare e tale ad ogni postback. I valori sono (ancora teoricamente) mantenuti dal quadro.

In ASP.NET MVC, se si segue il paradigma, non c'è bisogno di mantenere lo stato su elementi del modulo. I valori degli elementi modulo sono disponibili sul post in cui il controller può agire su di essi (convalida, aggiornamenti del database, ecc). Per eventuali elementi dei moduli che vengono visualizzati una volta che il post è elaborato, voi (lo sviluppatore) sono responsabili per loro l'inizializzazione - il quadro non fa automaticamente per voi

.

Detto questo, ho letto su un meccanismo chiamato TempData che consente al controller per passare i dati ad un altro controllore a seguito di un reindirizzamento. In realtà è una variabile di sessione (o biscotto se si configura come tale), ma è pulito automaticamente dopo la successiva richiesta.

La risposta dipende molto dal tipo di controlli si sta cercando di mantenere lo stato per. Per i controlli HTML di base, allora è molto facile da mantenere lo stato con le modelle, per fare questo è necessario creare una vista fortemente tipizzato.

Quindi, se abbiamo avuto un modello User con le proprietà: Nome utente, FullName, e-mail, si può fare il seguente nella vista:

<%= Html.ValidationSummary() %>

<% using (Html.BeginForm()) { %>
  <fieldset>
    <legend>User details</legend>
    <%= Html.AntiForgeryToken() %>

    <p>
      <label for="Username">Username:</label>
      <%= Html.Textbox("Username", Model.Username, "*") %>
    </p>
    <p>
      <label for="FullName">FullName:</label>
      <%= Html.Textbox("FullName", Model.FullName, "*") %>
    </p>
    <p>
      <label for="Email">Email:</label>
      <%= Html.Textbox("Email", Model.Email, "*") %>
    </p>
    <p>
       <input type+"submit" value="Save user" />
    </p>
  </fieldset>
<% } %>

Ci sarebbe poi avere due azioni di controllo che visualizzano questo punto di vista, uno per get e un altro per posta:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult User()
{
  return View(new User())
}

[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult User([Bind(Include = "Username,FullName,Email")]User user)
{
   if (!ModelState.IsValid()) return View(user);

   try
   {
     user.save()
     // return the view again or redirect the user to another page
   }
   catch(Exception e)
   {
     ViewData["Message"] = e.Message;
     return View(user)
   }
}

E 'questo quello che stai cercando? O vuoi per mantenere lo stato di modelli che non vengono visualizzati in una forma tra le richieste?

La cosa fondamentale da ricordare è che il codice viene eseguito sul server per la durata della richiesta e le estremità, le uniche informazioni è possibile passare tra le richieste è dati del modulo HTML di base, parametri URL e informazioni di sessione.

Come altri hanno già detto, mi raccomando Pro ASP.NET MVC Framework di Steve Sandersan per una completa comprensione di lavorare con il framework MVC.

  • campi nascosti, come:

    <% using (Html.BeginForm<SomeController>(c=>c.SomeAction(null))) {%>
      <%= Html.Hidden("SomeField", Model.SomeField)%>
      <%= Html.Hidden("AnotherField", Model.AnotherField)%>
    
  • l'impostazione del modello specifico e non avere alcun campo espliciti (dà u campi nascosti). Nell'esempio che segue, il modello viene riempito dal regolatore con valori ricevuti dall'ultimo post, in modo tale abilita un'opzione no js nella pagina che può filtrare sulla base di uno stato:

    Some Filter: <% using( Html.BeginForm<SomeController>(
            c => c.SomeAction(model.SomeField, model.AnotherField, model.YetAnotherField, null, model.SomeOtherField)
            )) { %>
                <%= Html.DropDownList("status", Model.StatusSelectList)%>
                <input type="submit" value="Filter" class="button" />
                <% } %>
    
  • metodi di utilizzo di estensione per creare campi, se volete solo i campi da compilare con i valori iscritti quando u stanno mostrando messaggi di convalida fallito sul modulo inviato
  • su asp.net MVC 2 hanno introdotto un modo per salvare un'istanza in un campo nascosto ... codificato + (credo) firmato
  • TempData se tutto quanto sopra non lo fa (passa attraverso session - puliti per la richiesta successiva)
  • come u detto, quando si utilizza Ajax lo Stato è già nei campi precedentemente caricate nel sito del cliente. Se u L8R sulla necessità di fare un post pieno, aggiornare qualsiasi campo u potrebbe essere necessario con i tuoi js.

Quanto sopra sono tutte le diverse opzioni indipendenti per realizzarla che possono essere utilizzati in diversi scenari. Ci sono altre opzioni, non ho menzionato ossia biscotti, seduta, roba negozio in dB (come per un mago resumable in più fasi), i parametri passati ad un'azione. Non v'è alcun 1 unico meccanismo per domarli tutti, e non ci dovrebbe essere.

Il modo migliore per farlo, credo, è quello di serializzare il vostro modello originale a un campo nascosto, quindi deserializzare e aggiornare il modello su post. Questo è un po similair all'approccio ViewState, solo è necessario implementare da soli. Io uso questo:

prima ho bisogno di alcuni metodi che rendono le cose più facili:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using LuvDaSun.Extensions;
using System.Web.UI;

namespace LuvDaSun.Web.Mvc
{
    public static class HtmlHelperExtensions
    {
        static LosFormatter _losFormatter = new LosFormatter();
        public static string Serialize(this HtmlHelper helper, object objectInstance)
        {
            var sb = new StringBuilder();
            using (var writer = new System.IO.StringWriter(sb))
            {
                _losFormatter.Serialize(writer, objectInstance);
            }
            return sb.ToString();
        }


    }

    [AttributeUsage(AttributeTargets.Parameter)]
    public class DeserializeAttribute : CustomModelBinderAttribute
    {
        public override IModelBinder GetBinder()
        {
            return new DeserializeModelBinder();
        }
    }

    public class DeserializeModelBinder : IModelBinder
    {
        static LosFormatter _losFormatter = new LosFormatter();

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType.IsArray)
            {
                var type = bindingContext.ModelType.GetElementType();
                var serializedObjects = (string[])bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string[]));
                var deserializedObjects = Array.CreateInstance(bindingContext.ModelType.GetElementType(), serializedObjects.Length);

                for (var index = 0; index < serializedObjects.Length; index++)
                {
                    var serializedObject = serializedObjects[index];
                    var deserializedObject = _losFormatter.Deserialize(serializedObject);

                    deserializedObjects.SetValue(deserializedObject, index);
                }

                return deserializedObjects;
            }
            else
            {
                var serializedObject = (string)bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string));
                var deserializedObject = _losFormatter.Deserialize(serializedObject);

                return deserializedObject;
            }
        }
    }

}

poi nel mio controller ho qualcosa di simile (per aggiornare un prodotto)

    public ActionResult Update(string productKey)
    {
        var model = _shopping.RetrieveProduct(productKey);

        return View(model);
    }
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Update([Deserialize]Shopping.IProduct _model, FormCollection collection)
    {
        UpdateModel(model);

        model.Save();

        return RedirectAfterPost();
    }

e ho bisogno di un campo nascosto che contiene l'oggetto serializzato nella forma:

    <% 
        using (Html.BeginRouteForm("Product", FormMethod.Post, new { id = UniqueID, }))
        {
    %>
<%= Html.Hidden("Model", Html.Serialize(Model)) %>
    <h1>
        Product bewerken</h1>
    <p>
        <label for="<%=UniqueID %>_Name">
            Naam:</label>
        <input id="<%=UniqueID %>_Name" name="Name" type="text" value="<%= Html.AttributeEncode(Model.Name) %>"
            class="required" />
        <br />
    </p>
    <p>
        Omschrijving:<br />
        <textarea id="<%= UniqueID %>_Description" name="Description" cols="40" rows="8"><%= Html.Encode(Model.Description) %></textarea>
        <br />
    </p>
    <p>
        <label for="<%=UniqueID %>_Price">
            Prijs:</label>
        <input id="<%= UniqueID %>_Price" name="Price" type="text" value="<%= Model.Price.ToString("0.00") %>"
            class="required" />
        <br />
    </p>
    <ul class="Commands">
        <li><a href="" class="ClosePopup">Annuleren</a></li>
        <li>
            <input type="submit" value="Opslaan" /></li>
    </ul>
    <% 
        } 
    %>

    <script type="text/javascript">

        jQuery('#<%= UniqueID %>').validate();

    </script>

come si può vedere, un campo nascosto (Model) si aggiunge al modulo. Contiene le informazioni di serializzazione per l'oggetto originale. Quando il modulo viene inviato, il campo nascosto è disponibile anche (naturalmente) ei contenuti sono deserializzato dal modelbinder personalizzato per l'oggetto originale che viene quindi aggiornata e salvata dal controllore.

Da notare che l'oggetto che si sta serializzazione esigenze da decorare con l'attributo Serializable o ha bisogno di avere un TypeConverter che può convertire l'oggetto in una stringa.

Il LosFormatter (serializzazione degli oggetti limitata) viene utilizzato dal ViewState in WebForms. Offre inoltre encryptionn della serializzazione dei dati.

saluta ...

chiamate AJAX è quello che facciamo. Se stai parlando di griglie in generale, controllare le jqGrid e come essi raccomandano l'implementazione AJAX.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top