2

Here are the facts of my issue:

  1. I have a form in an ASP.Net MVC 4 web application.
  2. The fields on the form are not tied to explicit static properties within the model. Instead they are dynamic fields that can change.
  3. When the form is submitted, I use a FormcCollection to retrieve the values entered into the field values.
  4. The first time I submit the form, all is well: The values of the FormCollection accurately reflect the form values.
  5. If there is a problem with the field values due to one or more invalid fields, I redisplay the form.
  6. If the user changes the values of the form to correct the validation errors and then resubmits the same form, the FormCollection is NOT updated to reflect the latest form values. Instead it always contains the field values from the first submit.

Why is this happening and how can I correct it?

<HttpPost()> _
<HttpParamAction()> _
Function Upload(ByVal model As MaxDocument, formcollection As FormCollection) As ActionResult
  Dim sCriteria As String = ""
  Dim nKeyIndex As Integer = 0
  Dim nFieldIndex As Integer = -1
  Dim sFieldValue As String = ""

  Try
    ' Build sCriteria from the submitted formcollection
    model.GetFileCabinetFieldList()
    For nFieldIndex = 0 To (model.IndexFieldCount - 1)
      sFieldValue = ""
      If nFieldIndex > 0 Then
        sCriteria += "~"
      End If
      Dim fcf As MaxServerLib.FileCabinetField = model.criterionAtIndex(nFieldIndex)
        ' Get the field value corresponding to this field
        For Each oKey As Object In formcollection.AllKeys
          If oKey.ToString = fcf.sFieldName Then
            sFieldValue = formcollection(oKey.ToString)
            Exit For
          End If
        Next
        sCriteria += sFieldValue
      Next
      If sCriteria = "" Then sCriteria = "[BlankIndex]"

      ' Set the criteria property of the model, which will be used for both field validation and document export.
      model.Criteria = sCriteria

      ' First thing we do is to perform valiation of the criteria
      model.ValidateFieldValues()
      If Not model.AllFieldValuesValid() Then
        ' Handle case where one or more field values are invalid.
        ' In this case we want to redisplay the form but show an error message listing the invalid fields

        model.HasAttemptedUpload = True
        ' Set tempData before redirect:
        TempData("MaxDocument") = model
        Return RedirectToAction("Index")
      Else
        ' All field values are valid, now attempt to add the document
    ...
      End If

    Catch ex As Exception
      System.Diagnostics.Debugger.Break()
    End Try
  'End If

  ' If we got this far, something failed, redisplay form
  Return View(model)

End Function

EDIT:

What appears to be happening is that the browser has cached the post action from the first post, and on every subsequent post (after the first) it renders the cached results of the first post instead of rendering the results of the current post. Why would it be doing this?

Obi Wan
  • 969
  • 11
  • 26
  • In your POST action are you modifying some of those values? Could you show your code? – Darin Dimitrov Oct 07 '13 at 16:07
  • Take a look at this question, the old data is in the model state and is not updated on the new submit. http://stackoverflow.com/questions/7414351/mvc-3-html-editorfor-seems-to-cache-old-values-after-ajax-call – Marko Oct 07 '13 at 16:39
  • Significant code from POST action shown above. – Obi Wan Oct 07 '13 at 21:48
  • Marko, that is an interesting thread. Could the real issue not be with the FormCollection but instead be with the form fields in the view that are erroneously returning cached values instead of the values that have last been entered into them? – Obi Wan Oct 07 '13 at 21:51
  • Dimitri, I saw your post here http://stackoverflow.com/questions/7414351/mvc-3-html-editorfor-seems-to-cache-old-values-after-ajax-call and I want to clarify that in my case I am not modifying the posted values in the controller. All modification happens in the form view, but I suspect that the modelstate is culprit in my issue. – Obi Wan Oct 07 '13 at 21:58
  • We had the same issue you described in our application, the solution was to create our own editor for, that would simply just generate the necessary html code without using the built in helper and clear the model state. To test if this is your issue in your Razor(html) code change the editor for's to their respective html representation. I also searched back in the comments on the check-ins related to this issue this is the reference article http://stackoverflow.com/questions/594600/possible-bug-in-asp-net-mvc-with-form-values-being-replaced – Marko Oct 07 '13 at 22:08
  • @ObiWan: This seems like a pretty strange issue. No specific reason comes to mind to explain why this might be happening. I would suggest starting by using your browser's dev tools to look at the HTML that gets produced after your first submit, as well as the Network traffic that comes out of posting that form. Is the browser actually sending the original values over the wire again? Are there other (hidden?) inputs on the same page that might be interfering the the values entered by the user? – StriplingWarrior Oct 07 '13 at 23:00
  • Marko, I am using @Html.TextBox, but if I replace that with a non-Html helper and just use an input tag control, the issue still happens. As a test, I also tried to clear the entire ModelState in the controller before redisplaying the form (after the first submit), and it made no difference. – Obi Wan Oct 08 '13 at 15:19
  • Marko, I believe some kind of caching is happening to cause this. The values from the first submit are being cached somewhere and being used in place of the most recent form values, but I do not yet know the source of the caching. – Obi Wan Oct 08 '13 at 15:29
  • Ok, I downloaded Fiddler and used it to examine the values being posted/sent to the controller on the resubmit and found they are the old values (not the values in the form). So the caching is taking place in the view/browser. The FormCollection is accurately reflecting the values being posted. What is the source of this caching? – Obi Wan Oct 08 '13 at 19:31

1 Answers1

0

I have created a class NoCacheControlAttribute

NoCacheControlAttribute.cs:

using System;
using System.Web;
using System.Web.Mvc;
namespace Company.Common.Web.MVC
{
    public class NoCacheControlAttribute : ActionFilterAttribute
    {
        private readonly HttpCacheability _cacheability;
        public NoCacheControlAttribute(HttpCacheability cacheability)
        {
            _cacheability = cacheability;
        }
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
            cache.SetAllowResponseInBrowserHistory(false);
            cache.SetCacheability(_cacheability);
            cache.SetExpires(DateTime.Now);
            cache.SetNoServerCaching();
            cache.SetNoStore();
        }
    }
}

I get the cacheability parameter via Autofac Dependency Injection / Constructor Injection.

...Controller.cs

using ...
using System.Web;
using System.Web.Mvc;
using Company.Common.Web.MVC;
using ...
namespace Company.Project.Web.Controllers
{
    [NoCacheControl(HttpCacheability.NoCache)]
    public class ContractController : Controller
    {
        private readonly IRepository _repository;
        public ContractController(IRepository repository)
        {
            _repository = repository;
        }
        [HttpGet]
        public ActionResult ActionTest(string id)
        {
            ...
            return ...;
        }
    }
}

And so, caching is disabled!

florian.isopp
  • 834
  • 2
  • 12
  • 36
  • I appreciate your effort Florian, but unfortunately your solution did not resolve the issue. The caching involved in my issue appears to be browser caching, not server-side caching. The browser appears to have cached the results from the first post, so that all subsequent posts use those results instead of the current post results. – Obi Wan Oct 11 '13 at 19:59