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

Wrong name and id in input after upgrade to ASP Core 1.1.0 #5655

Closed
rneeft opened this issue Jan 4, 2017 · 17 comments
Closed

Wrong name and id in input after upgrade to ASP Core 1.1.0 #5655

rneeft opened this issue Jan 4, 2017 · 17 comments

Comments

@rneeft
Copy link

rneeft commented Jan 4, 2017

Hi all,
I’ve upgraded our ASP Core 1.0.1 solution to ASP Core 1.1. We hit an issue with one of our pages after the upgrade. We have the following code in razor:

@for (var i = 0; i < Model.ContactPersons.Count(); i++)
{
    <tr>
        <th >
            <input asp-for="@Model.ContactPersons[i].Name" />
            <span asp-validation-for="@Model.ContactPersons[i].Name" class="text-danger"></span>
        </th>
        <th >
            <input asp-for="@Model.ContactPersons[i].PhoneNumber" />
            <span asp-validation-for="@Model.ContactPersons[i].PhoneNumber" class="text-danger" style=""></span>
        </th>
    </tr>
}

This code result in 1.0.1 into the following HTML:

<tr>
    <td>
        <input type="text" data-val="true" data-val-required="The Name field is required." id="ContactPersons_0__Name" name="ContactPersons[0].Name" value="" />
        <span class="text-danger field-validation-valid" data-valmsg-for="ContactPersons[0].Name" data-valmsg-replace="true"></span>
    </td>
    <td>
        <input type="tel" data-val="true" (...) id="ContactPersons_0__PhoneNumber" name="ContactPersons[0].PhoneNumber" value="" />
        <span class="text-danger field-validation-valid" style="" data-valmsg-for="ContactPersons[0].PhoneNumber" data-valmsg-replace="true"></span>
    </td>
</tr>

This worked great until we upgraded to ASP Core 1.1.0. The razor code above now results into the following HTML:

<tr>
    <td >
        <input type="text" data-val="true" data-val-required="The Name field is required." id="Name" name="Name" value="" />
        <span class="text-danger field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
    </td>
    <td>
        <input type="tel" data-val="true" (...) id="PhoneNumber" name="PhoneNumber" value="" />
        <span class="text-danger field-validation-valid" style="" data-valmsg-for="PhoneNumber" data-valmsg-replace="true"></span>
    </td>
</tr>

Please pay attention to the ‘name’ and ‘id’ properties of the input fields. Not having the ‘_{id}__’ layout results in zero items in the list upon submit.

We have been able to narrow the issues down to the following package: Microsoft.AspNetCore.Mvc. When having version 1.0.1 the page is working, but having version 1.1.0 it kills our submit in the page.

Is this a bug?

Thanks!
Rick

For completeness this is the complete project.json file we have:

{
  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },
  "configurations": {
    "iOS": {}
  },
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.1.0",
      "type": "platform"
    },
    "MasterData": "1.0.0-*",
    "CountModels": "1.0.0-*",
    "WindowsAzure.Storage": "8.0.0",
    "Swashbuckle": "6.0.0-beta902",
    "SyncFusion.EJ.AspNet.Core": "14.4600.0.15-preview2-final",
    "Syncfusion.Compression.AspNet.Core": "14.4600.0.15-preview2-final",
    "Syncfusion.DocIO.AspNet.Core": "14.4600.0.15-preview2-final",
    "Syncfusion.XlsIO.AspNet.Core": "14.4600.0.15-preview2-final",
    "Microsoft.ApplicationInsights.AspNetCore": "1.0.2",
    "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0",
    "Microsoft.Extensions.Logging.Console": "1.1.0",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
    "System.ComponentModel.Annotations": "4.3.0",
    "Microsoft.AspNetCore.Authentication.JwtBearer": "1.1.0",
    "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.1.0",
    "Microsoft.AspNetCore.Diagnostics": "1.1.0",
    "Microsoft.AspNetCore.Mvc": "1.0.1",
    "Microsoft.AspNetCore.Mvc.Versioning": "1.0.3",
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.1.0-preview4-final",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
    "Microsoft.AspNetCore.StaticFiles": "1.1.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
    "Microsoft.Extensions.Configuration.Json": "1.1.0",
    "Newtonsoft.Json": "9.0.2-beta1",
    "bootstrap": "4.0.0-alpha5",
    "Microsoft.AspNetCore.Razor.Tools": "1.1.0-preview4-final"
  },
  "frameworks": {
    "netcoreapp1.1": {
      "dependencies": {},
      "imports": [
        "dotnet5.6",
        "portable-net45+win8"
      ]
    }
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "web.config",
      "Views",
      "appsettings.json"
    ]
  },
  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  },
  "tools": { "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.1.0-preview4-final" },
  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  },
}
@frankabbruzzese
Copy link

@rneeft ,
It works for me!
Probably a third party library (ie Syncfusion) adds some more input TagHelper that provides a different naming strategy. This may depend on the third party library being not compatible with 1.1.

In order to be sure open the _ViewImports.cshtml and remove third parties tag helpers dlls.

@Eilon
Copy link
Member

Eilon commented Jan 4, 2017

@dougbu any idea on this? Could it be the 3rd party lib?

@dougbu
Copy link
Member

dougbu commented Jan 4, 2017

I also cannot reproduce this behaviour with 1.1.0 bits. Suspect Microsoft.AspNetCore.Mvc.Versioning is causing oddities; it requires MVC 1.0.0.

However, I'll file a separate Task in this repo about ensuring our functional tests cover IList<T> properties. We currently only confirm handling of top-level lists.

@dougbu
Copy link
Member

dougbu commented Jan 4, 2017

@rneeft closing because @frankabbruzzese and I cannot reproduce the issue. Please reopen if you have a repro that does not involve 3rd party dependencies (which might be doing weird stuff).

@dougbu dougbu closed this as completed Jan 4, 2017
@dougbu dougbu added the no repro label Jan 4, 2017
@frankabbruzzese
Copy link

@dougbu ,

  1. In my test the property path was analogous to the one of @rneeft
  2. I think Microsoft.AspNetCore.Mvc": "1.0.1" because @rneeft switched between 1.1 and and 1.0.1 in order to proove that the wrong behavior comes from this dll.

@joosthaneveer
Copy link

joosthaneveer commented Jan 5, 2017

@dougbu

I've build an example solution that can reproduce this behavior.
I'm working together with @rneeft on the same project, so it was easy to replicate the situation.

When the package "Microsoft.AspNetCore.Mvc": "1.1.0" is present in project.json the output code will look like this:

<tr>
	<th style="padding-right: 8px; padding-left: 0; border-top: none; padding-bottom: 0">
		<input class="form-control col-xs-5" type="text" data-val="true" data-val-required="The Name field is required." id="Name" name="Name" value="" />
		<span class="text-danger field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
	</th>
	<th style="padding-right: 0px; padding-left: 8px; border-top: none; padding-bottom: 0">
		<input class="form-control col-xs-5" type="tel" (...) id="PhoneNumber" name="PhoneNumber" value="" />
		<span class="text-danger field-validation-valid" style="" data-valmsg-for="PhoneNumber" data-valmsg-replace="true"></span>
	</th>
</tr>

When you change the package version back in the project.json: "Microsoft.AspNetCore.Mvc": "1.0.1" the output code will look like this:

<tr>
	<th style="padding-right: 8px; padding-left: 0; border-top: none; padding-bottom: 0">
		<input class="form-control col-xs-5" type="text" data-val="true" data-val-required="The Name field is required." id="ContactPersons_0__Name" name="ContactPersons[0].Name" value="" />
		<span class="text-danger field-validation-valid" data-valmsg-for="ContactPersons[0].Name" data-valmsg-replace="true"></span>
	</th>
	<th style="padding-right: 0px; padding-left: 8px; border-top: none; padding-bottom: 0">
		<input class="form-control col-xs-5" type="tel" (...) id="ContactPersons_0__PhoneNumber" name="ContactPersons[0].PhoneNumber" value="" />
		<span class="text-danger field-validation-valid" style="" data-valmsg-for="ContactPersons[0].PhoneNumber" data-valmsg-replace="true"></span>
	</th>
</tr>

As you can see there are no external libraries used, it is the default VS2015 project template updated to .Net Core 1.1.

So this replicates the issue @rneeft describes.

@rneeft
Copy link
Author

rneeft commented Jan 5, 2017

@dougbu It seems I'm unable to reopen this issue :(

@frankabbruzzese
Copy link

@joosthaneveer , @rneeft ,
I can confirm the issue.
However, project.json doesnt appear well configure. For instance you have netcoreapp1.0 instead of netcoreapp1.0. I fixed those imprecisions, but the issues persists. Something wrong is happening with Nuget packages that probably pick up some wrong dll version of some stuff.

I advice starting an 1.1 project from scratch using VS scaffolder, and adding your specific files on it (ViewModels, Controllers), because I cant easily see the differences between you project and a "standard 1.1 project" that works properly. Maybe some reference mismatch is the culprit but I was not anle to locate it. I changed als some package version to match the one of a standard 1.1 project but with no luck...the issue persists.

@dougbu
Copy link
Member

dougbu commented Jan 5, 2017

Reopening while I double-check my repro.

@dougbu dougbu reopened this Jan 5, 2017
@dougbu
Copy link
Member

dougbu commented Jan 5, 2017

🆗 I've successfully reproduced the bug and debugged enough to see where everything heads South. Next steps are to see if my current repro (a subset of @joosthaneveer's application) works with MVC 1.0.2 and then 1.2.0.

@dougbu
Copy link
Member

dougbu commented Jan 6, 2017

Workaround: Use asp-for="ContactPersons[0].Name" instead of asp-for="ContactPersons.FirstOrDefault().Name" when using 1.1.0 (well, that'll work everywhere). Same in the <label> for PhoneNumber.

@dougbu dougbu removed their assignment Jan 6, 2017
@dougbu
Copy link
Member

dougbu commented Jan 6, 2017

Clearing label and assignment for triage. FYI I have the outline of a fix but no test additions.

This looks like a candidate for 1.1.1 given workaround could be far from the broken element(s).

@frankabbruzzese
Copy link

frankabbruzzese commented Jan 6, 2017

@dougbu ,
I removed all code (but the form) outside fhe for but I missed those labels, because I kept the whole table. Anyway difficult to imagine those labels might have connections with the wrong name problem. How an exception thrown there(because unable to find the label target) might cause a so strange effect? Somehow connected to Razor TagHelper-Caching ?

@dougbu
Copy link
Member

dougbu commented Jan 6, 2017

@frankabbruzzese there's no Exception in this case. The problem is the expression name ("Name") is incorrectly cached for ContactPersons.FirstOrDefault().Name. And, the comparer used thinks ContractPersons[i].Name is the same expression; it doesn't expect either to be in the cache.

@frankabbruzzese
Copy link

@dougbu ,
O yes, right! Label are shown! This means, target property is located by label, but since FirstOrDefault() is interpreted as a function call instead of an access operator string expression is computed as "Name" (by removing everything before the function), so sincestring expressions are cached with methadata, also all other occurrences of the same property are rendered with wrong names!
Unluckly, performance gains one has with caching are obtained at price of not-local interactions.

@Eilon Eilon added this to the 1.1.1 milestone Jan 20, 2017
@Eilon
Copy link
Member

Eilon commented Feb 8, 2017

This patch bug is approved. Please use the normal code review process w/ a PR and make sure the fix is in the correct branch, then close the bug and mark it as done.

dougbu added a commit that referenced this issue Feb 10, 2017
- #5655
- also make `ExpressionTextCache` more robust for defence-in-depth

nits:
- two `null` expression nodes are equal
- declare data properties as `TheoryData<T>`
dougbu added a commit that referenced this issue Feb 10, 2017
- #5655
- also make `ExpressionTextCache` more robust for defence-in-depth

nits:
- two `null` expression nodes are equal
- declare data properties as `TheoryData<T>`
@dougbu
Copy link
Member

dougbu commented Feb 11, 2017

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

5 participants