Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Html.ValidationSummary(ValidationSummary.All) throws NullReferenceException #4989

Closed
rsheptolut opened this issue Jul 8, 2016 · 18 comments
Closed
Assignees

Comments

@rsheptolut
Copy link

rsheptolut commented Jul 8, 2016

This started after I've updated my project from RC1 to ASP.NET Core 1.0. The tag helper also throws this exception.
If instead you specify ValidationSummary.ModelOnly, there's no exception. But also no property-level errors, which is bad.
Workarond: traverse ViewData.ModelState.Values manually and generate appropriate html markup.

Stack trace:

System.NullReferenceException.
   в Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidationHelpers.Visit(ModelStateDictionary dictionary, ModelStateEntry modelStateEntry, ModelMetadata metadata, List1 orderedModelStateEntries)
   в Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidationHelpers.Visit(ModelStateDictionary dictionary, ModelStateEntry modelStateEntry, ModelMetadata metadata, List1 orderedModelStateEntries)
   в Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidationHelpers.GetModelStateList(ViewDataDictionary viewData, Boolean excludePropertyErrors)
   в Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateValidationSummary(ViewContext viewContext, Boolean excludePropertyErrors, String message, String headerTag, Object htmlAttributes)
   в Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.GenerateValidationSummary(Boolean excludePropertyErrors, String message, Object htmlAttributes, String tag)
   в Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.ValidationSummary(Boolean excludePropertyErrors, String message, Object htmlAttributes, String tag)
   в Microsoft.AspNetCore.Mvc.Rendering.HtmlHelperValidationExtensions.ValidationSummary(IHtmlHelper htmlHelper)
@dougbu
Copy link
Member

dougbu commented Jul 8, 2016

We definitely test w/ ValidationSummary.All. This issue is likely specific to your model types. Please share those class definitions.

@rsheptolut
Copy link
Author

rsheptolut commented Jul 11, 2016

@dougbu No, nothing specific to a model, this fails on all my models. I feed EF6 objects directly to the views, by the way. Such is life.

Example (simplified, but verified):

[Table("Currency", Schema = "dic")]
public class Currency
{
    [Timestamp]
    [Column(Order = int.MaxValue)]
    public byte[] Ts { get; set; }

    [Key]
    [StringLength(3, MinimumLength = 3)]
    [Column(TypeName = "nchar")]
    public string Id { get; set; }

    [StringLength(3)]
    public string CurrencySymbol { get; set; }
}

public class CurrencyController
{
    [ValidateAntiForgeryToken]
    [HttpPost]
    [ActionName("Edit")]
    public IActionResult ApplyEdit(Currency model)
    {
        ModelState.AddModelError(nameof(model.CurrencySymbol), "Lame!");
        return View(model);
    }
}

Currency/Edit.cshtml (simplified, I posted values to it via refreshing browser which remembers 'real' post values)

@model object
@Html.ValidationSummary();

Debugger says that Model is of type "Currency", so is ModelMetadata.ModelType == typeof(Currency), so everything seems legit. And my other 100 tons of code that depend heavily on ModelMetadata continue to work perfectly.

@dougbu dougbu self-assigned this Jul 13, 2016
@dougbu
Copy link
Member

dougbu commented Jul 13, 2016

Looks like a straightforward bug in ValidationHelpers.Visit(). That method (specifically this block) doesn't handle cases where a collection property is not bound. Just needs a null check on modelStateEntry.Children.

@dougbu dougbu removed their assignment Jul 13, 2016
@dougbu
Copy link
Member

dougbu commented Jul 14, 2016

Reassigning to do the straightforward fix.

@pranavkm
Copy link
Contributor

@dougbu is there a workaround for this in 1.0.0 (besides the option @rsheptolut suggested)?

@dougbu
Copy link
Member

dougbu commented Jul 18, 2016

is there a workaround for this in 1.0.0

Since the problematic property is get-only outside ModelStateDictionary, @rsheptolut's workaround is about it. With respect to that workaround, probably best to create a DefaultHtmlGenerator subclass that overrides GenerateValidationSummary(). More generally, stick with ModelOnly and use validation message helpers to ensure property-level issues are visible.

dougbu added a commit that referenced this issue Jul 18, 2016
@dougbu
Copy link
Member

dougbu commented Jul 18, 2016

e5cb6f9

@genusP
Copy link

genusP commented Aug 3, 2016

Workarond for 1.0.0

private void HackModelState(string key)
{
      var modelStateEntry = ModelState[key];
      var nodeType = modelStateEntry.GetType();
      nodeType.GetMethod("GetNode").Invoke(modelStateEntry, new object[] { new Microsoft.Extensions.Primitives.StringSegment("--!!f-a-k-e"), true });
      ((System.Collections.IList)nodeType.GetProperty("ChildNodes").GetValue(modelStateEntry)).Clear();
}

@gdoron
Copy link

gdoron commented Aug 24, 2016

Would it be possible to add it to 1.0.1?
It can't break anything, having to wait several months for it would be a shame.

@prophetal
Copy link

prophetal commented Sep 12, 2016

can someone give me a hint how to implement the Workarond from genusP for 1.0.0 ?

@rsheptolut
Copy link
Author

rsheptolut commented Sep 12, 2016

@prophetal
I use the following workaround in my production code for now:

<form class="form-horizontal" asp-antiforgery="true">
    <fieldset>
        // All of this instead of @Html.ValidationSummary(false) due to a bug in ASP.NET Core 1.0
        @if (!@ViewData.ModelState.IsValid)
        {
            var errors = ViewData.ModelState.Values.Select(item => item.Errors.FirstOrDefault()?.ErrorMessage).Where(item => item != null);
            <div class="alert alert-danger">
                <span>@Localizer["There are problems with your input:"]</span>
                <ul>
                    @foreach (var error in errors)
                    {
                        <li>@error</li>
                    }
                </ul>
            </div>
        }

        // Some actual fields. Don't forget validation messages for fields if you need them (@Html.ValidationMessage)
    </fieldset>
</form>

Maybe it's not suitable for you if you have many views. I have it in my only "Generic.cshtml" editor that's used to edit any entity in the application, so this workaround is in a single place. You can write an extension method that you will then call like @Html.ValidationSummaryFix(false). But I suppose its insides will be a little messy.
And no, I didn't get what genusP was going for.

@prophetal
Copy link

prophetal commented Sep 12, 2016

Thanks rsheptolut that workaround will help me alot!

I had a multi file upload field that throws the NullReferenceException.
I think there are a lot of people that will need this workaround before the 1.0.1 release.

public ICollection <IFormFile> AttachmentFiles { get; set; }

@gdoron
Copy link

gdoron commented Sep 12, 2016

It seems like for some reason, it will be released only in 1.1.0

@genusP
Copy link

genusP commented Sep 13, 2016

need call HackModelState for each enumerable property

public class ClOrderViewModel
{
...
 public AttachmentViewModel[] Attachments { get; set; }
...
}
class OrdersController:Controller
{
...
        [HttpPost]
        public IActionResult Index(int? id, ClOrderViewModel vm, [FromServices] IClOrderRepository repository)
        {
            if (ModelState.IsValid)
            {
                if (id.HasValue)
                    repository.UpdateOrder(id.Value, vm);
                else
                    id = repository.InserOrder(vm);
                return RedirectToAction(nameof(Index), new { id = id.Value });
            }
            HackModelState(nameof(vm.Attachments));
            return View("ClOrder", vm);
        }
...
}

@dougbu
Copy link
Member

dougbu commented Oct 14, 2016

@danroth27 @Eilon should we include this in 1.0.2? @gdoron suggested that above (#4989 (comment)) and in dotnet/efcore#6760.

@Eilon
Copy link
Member

Eilon commented Oct 14, 2016

@dougbu you mean like #5157? 😄

@dougbu
Copy link
Member

dougbu commented Oct 14, 2016

@Eilon hmm, yeah. Fairly similar. 😈

@dougbu
Copy link
Member

dougbu commented Nov 3, 2016

Ported to rel/1.0.2 in f8f9bbc

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants