- #1468
- Always use `ModelExplorer` in `<select/>`, `DropDownListFor()` and `ListBoxFor()` cases
- allows evaluation of more-complex expressions
- Use `ViewData.Model` in `DropDownList()` and `ListBox()` template cases
- `ViewData` was previously ignored in these cases
nit: change `ViewDataDictionary.Eval()` to return `Model` if `expression` is `null` or empty
- now `throw` on `null` or empty `expression` name in `ViewDataEvaluator.Eval()`
- simplifies some of the higher-level code
- no change to `selectList` fallback; `Model` incorrect for that case
- no change to `GenerateRadioButton()`; would change behaviour unrelated to #1468
- this helper uses incorrect `ViewData` lookup text, see #1487
- `ViewDataDictionary<TModel>` constructors now pass `typeof(TModel)` to base
`protected` constructors
- move type compatibility checks into base `ViewDataDictionary`
- remove `ViewDataDictionary<TModel>.ModelMetadata` override
- don't retrieve `ModelMetadata` twice in a single constructor invocation
- remove newly-unused `protected` properties and use `private` fields in copy
constructors
Address longstanding problems found (see #1466)
- avoid reusing `ModelMetadata` after `Model` value changes
- reset `ModelMetadata` backing field in `Model` setter
- `Model` and `ModelMetadata.Model` could previously get out of sync
- carry `ModelMetadata` forward from an outer scope only if `Model` matches
- previously two scopes could have different `Model` values but share their
`ModelMetadata` (and `ModelMetadata.Model`)
- related to previous item but didn't require `Model` setting; switching
to a property of the same type as containing `Model` was enough
- avoid NRE if `ViewDataDictionary<int>.Model` is read before it's written
- problem affected all non-`Nullable` value types
- `ViewDataDictionary.ModelMetadata` setter should throw if value is `null`
nits:
- add and reword doc and code comments
- `ViewDataDictionary<TModel>` constructors should only inherit base's
parameter descriptions; have more information in the derived class
- make a few `ViewDataDictionary` properties get-only
- clean up `using` statements in `ViewDataDictionary<TModel>`
- make two constructors `internal`
never that for `object`
- `ViewDataDictionary<TModel>.ModelMetadata` was for `object` after base
copy constructor got value from `ViewDataDictionary<object>`
- problem led to #1426 symptoms
- with copy constructor leaving `base.ModelMetadata==null` more often,
`ViewDataDictionary<TModel>.ModelMetadata` usually tracks `TModel` if
`Model==null`
nit:
- fix existing comment in main `ViewDataDictionary` copy constructor
- fix problems at least with Roslyn compiler and VS IntelliSense or the Object Browser
- `<see langref="keyword"/>` generates nothing
- `<example>` at top level (outside `<summary>`) generates nothing
- curly braces don't become angle brackets outside `<see cref="reference"/>` references
- yeah, a point @yishaigalatzer asked about in a previous PR
- `<see href="reference"/>` is not valid
- correct some invalid use of angle brackets and remove useless empty elements
- correct unresolved XML comment references; generally, add namespace prefix
Symptoms for some of the above issues included
- generated XML comments such as `<!-- Badly formed XML comment ... -->`, usually indicating an unclosed element
- generated XML attributes such as `cref="!:..."`, indicating a broken reference
- in a couple of cases we had `<typeparamref cref="TOption"/>`; attribute should be `"name"`
Few wording changes beyond
- `"opening </form> tag"` -> `"<form> start tag"`
- `"closing </form> tag"` -> `"</form> end tag"`
Also correct two typos in `HtmlHelper`
Will create a unit test to ensure XML syntax doesn't degrade going forward. Separate PR.
- for now, check using `dir -r *.xml | sls '!'`