Merge branch 'release/2.1' into dev

This commit is contained in:
Javier Calvarro Nelson 2018-01-23 17:31:48 -08:00
commit 381ac2946c
2 changed files with 92 additions and 0 deletions

View File

@ -63,6 +63,22 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
}
ViewData = viewContext.ViewData as ViewDataDictionary<TModel>;
if (ViewData == null)
{
// The view data that we have at this point might be of a more derived type than the one defined at compile time.
// For example ViewDataDictionary<Derived> where our TModel is Base and Derived : Base.
// This can't happen for regular views, but it can happen in razor pages if someone modified the model type through
// the page application model.
// In that case, we check if the type of the current view data, 'ViewDataDictionary<TRuntime>' is "covariant" with the
// one defined at compile time 'ViewDataDictionary<TCompile>'
var runtimeType = viewContext.ViewData.ModelMetadata.ModelType;
if (runtimeType != null && typeof(TModel) != runtimeType && typeof(TModel).IsAssignableFrom(runtimeType))
{
ViewData = new ViewDataDictionary<TModel>(viewContext.ViewData, viewContext.ViewData.Model);
}
}
if (ViewData == null)
{
// viewContext may contain a base ViewDataDictionary instance. So complain about that type, not TModel.

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Xunit;
@ -286,6 +287,81 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
Assert.Equal(expectedString, result.ToString());
}
[Fact]
public void Contextualize_WorksWithCovariantViewDataDictionary()
{
// Arrange
var helperToContextualize = DefaultTemplatesUtilities
.GetHtmlHelper<BaseModel>(model: null);
var viewContext = DefaultTemplatesUtilities
.GetHtmlHelper<DerivedModel>(model: null)
.ViewContext;
// Act
helperToContextualize.Contextualize(viewContext);
// Assert
Assert.IsType<ViewDataDictionary<BaseModel>>(
helperToContextualize.ViewData);
Assert.Same(helperToContextualize.ViewContext, viewContext);
}
[Fact]
public void Contextualize_ThrowsIfViewDataDictionariesAreNotCompatible()
{
// Arrange
var helperToContextualize = DefaultTemplatesUtilities
.GetHtmlHelper<BaseModel>(model: null);
var viewContext = DefaultTemplatesUtilities
.GetHtmlHelper<NonDerivedModel>(model: null)
.ViewContext;
var expectedMessage = $"Property '{nameof(ViewContext.ViewData)}' is of type " +
$"'{typeof(ViewDataDictionary<NonDerivedModel>).FullName}'," +
$" but this method requires a value of type '{typeof(ViewDataDictionary<BaseModel>).FullName}'.";
// Act & Assert
var exception = Assert.Throws<ArgumentException>("viewContext", () => helperToContextualize.Contextualize(viewContext));
Assert.Contains(expectedMessage, exception.Message);
}
[Fact]
public void Contextualize_ThrowsForNonGenericViewDataDictionaries()
{
// Arrange
var helperToContextualize = DefaultTemplatesUtilities
.GetHtmlHelper<BaseModel>(model: null);
var viewContext = DefaultTemplatesUtilities
.GetHtmlHelper<BaseModel>(model: null)
.ViewContext;
viewContext.ViewData = new ViewDataDictionary(viewContext.ViewData);
var expectedMessage = $"Property '{nameof(ViewContext.ViewData)}' is of type " +
$"'{typeof(ViewDataDictionary).FullName}'," +
$" but this method requires a value of type '{typeof(ViewDataDictionary<BaseModel>).FullName}'.";
// Act & Assert
var exception = Assert.Throws<ArgumentException>("viewContext", () => helperToContextualize.Contextualize(viewContext));
Assert.Contains(expectedMessage, exception.Message);
}
private class BaseModel
{
public string Name { get; set; }
}
private class DerivedModel : BaseModel
{
}
private class NonDerivedModel
{
}
[Theory]
[InlineData("SomeName", "SomeName")]
[InlineData("Obj1.Prop1", "Obj1_Prop1")]