ViewViewComponentResult doesn't handle `~/` in view paths correctly
Fixes #2856
This commit is contained in:
parent
18c3ad25fb
commit
93d07147b2
|
|
@ -5,7 +5,6 @@ using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
|
|
@ -18,6 +17,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
// {0} is the component name, {1} is the view name.
|
// {0} is the component name, {1} is the view name.
|
||||||
private const string ViewPathFormat = "Components/{0}/{1}";
|
private const string ViewPathFormat = "Components/{0}/{1}";
|
||||||
|
private const string DefaultViewName = "Default";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the view name.
|
/// Gets or sets the view name.
|
||||||
|
|
@ -63,9 +63,11 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
var viewEngine = ViewEngine ?? ResolveViewEngine(context);
|
var viewEngine = ViewEngine ?? ResolveViewEngine(context);
|
||||||
var viewData = ViewData ?? context.ViewData;
|
var viewData = ViewData ?? context.ViewData;
|
||||||
|
var isNullOrEmptyViewName = string.IsNullOrEmpty(ViewName);
|
||||||
|
|
||||||
string qualifiedViewName;
|
string qualifiedViewName;
|
||||||
if (ViewName != null && ViewName.Length > 0 && ViewName[0] == '/')
|
if (!isNullOrEmptyViewName &&
|
||||||
|
(ViewName[0] == '~' || ViewName[0] == '/'))
|
||||||
{
|
{
|
||||||
// View name that was passed in is already a rooted path, the view engine will handle this.
|
// View name that was passed in is already a rooted path, the view engine will handle this.
|
||||||
qualifiedViewName = ViewName;
|
qualifiedViewName = ViewName;
|
||||||
|
|
@ -83,11 +85,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Areas/Blog/Views/Shared/Components/Cart/Default.cshtml
|
// Areas/Blog/Views/Shared/Components/Cart/Default.cshtml
|
||||||
//
|
//
|
||||||
// This supports a controller or area providing an override for component views.
|
// This supports a controller or area providing an override for component views.
|
||||||
|
var viewName = isNullOrEmptyViewName ? DefaultViewName : ViewName;
|
||||||
|
|
||||||
qualifiedViewName = string.Format(
|
qualifiedViewName = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
ViewPathFormat,
|
ViewPathFormat,
|
||||||
context.ViewComponentDescriptor.ShortName,
|
context.ViewComponentDescriptor.ShortName,
|
||||||
ViewName ?? "Default");
|
viewName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var view = FindView(context.ViewContext, viewEngine, qualifiedViewName);
|
var view = FindView(context.ViewContext, viewEngine, qualifiedViewName);
|
||||||
|
|
|
||||||
|
|
@ -275,22 +275,53 @@ namespace Microsoft.AspNet.Mvc
|
||||||
Assert.Equal(expected, ex.Message);
|
Assert.Equal(expected, ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Theory]
|
||||||
public void Execute_CallsFindPartialView_WithExpectedPath()
|
[InlineData(null)]
|
||||||
|
[InlineData("")]
|
||||||
|
public void Execute_CallsFindPartialView_WithExpectedPath_WhenViewNameIsNullOrEmpty(string viewName)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var shortName = "SomeShortName";
|
||||||
|
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||||
|
var componentContext = GetViewComponentContext(new Mock<IView>().Object, viewData);
|
||||||
|
componentContext.ViewComponentDescriptor.ShortName = shortName;
|
||||||
|
var expectedViewName = $"Components/{shortName}/Default";
|
||||||
|
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||||
|
viewEngine
|
||||||
|
.Setup(v => v.FindPartialView(It.IsAny<ActionContext>(), expectedViewName))
|
||||||
|
.Returns(ViewEngineResult.Found(string.Empty, new Mock<IView>().Object))
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
var componentResult = new ViewViewComponentResult();
|
||||||
|
componentResult.ViewEngine = viewEngine.Object;
|
||||||
|
componentResult.ViewData = viewData;
|
||||||
|
componentResult.ViewName = viewName;
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
componentResult.Execute(componentContext);
|
||||||
|
viewEngine.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("~/Home/Index/MyViewComponent1.cshtml")]
|
||||||
|
[InlineData("~MyViewComponent2.cshtml")]
|
||||||
|
[InlineData("/MyViewComponent3.cshtml")]
|
||||||
|
public void Execute_CallsFindPartialView_WithExpectedPath_WhenViewNameIsSpecified(string viewName)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||||
viewEngine
|
viewEngine
|
||||||
.Setup(v => v.FindPartialView(It.IsAny<ActionContext>(),
|
.Setup(v => v.FindPartialView(It.IsAny<ActionContext>(), viewName))
|
||||||
It.Is<string>(view => view.Contains("Components"))))
|
|
||||||
.Returns(ViewEngineResult.Found(string.Empty, new Mock<IView>().Object))
|
.Returns(ViewEngineResult.Found(string.Empty, new Mock<IView>().Object))
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||||
var componentContext = GetViewComponentContext(new Mock<IView>().Object, viewData);
|
var componentContext = GetViewComponentContext(new Mock<IView>().Object, viewData);
|
||||||
var componentResult = new ViewViewComponentResult();
|
var componentResult = new ViewViewComponentResult
|
||||||
componentResult.ViewEngine = viewEngine.Object;
|
{
|
||||||
componentResult.ViewData = viewData;
|
ViewEngine = viewEngine.Object,
|
||||||
|
ViewData = viewData,
|
||||||
|
ViewName = viewName
|
||||||
|
};
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
componentResult.Execute(componentContext);
|
componentResult.Execute(componentContext);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue