diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewViewComponentResult.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewViewComponentResult.cs index 5a43927ebb..c7c8ad3ec1 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewViewComponentResult.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponents/ViewViewComponentResult.cs @@ -5,7 +5,6 @@ using System; using System.Globalization; using System.Threading.Tasks; using Microsoft.AspNet.Mvc.Rendering; -using Microsoft.AspNet.Mvc.ViewComponents; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Internal; @@ -18,6 +17,7 @@ namespace Microsoft.AspNet.Mvc { // {0} is the component name, {1} is the view name. private const string ViewPathFormat = "Components/{0}/{1}"; + private const string DefaultViewName = "Default"; /// /// Gets or sets the view name. @@ -63,9 +63,11 @@ namespace Microsoft.AspNet.Mvc { var viewEngine = ViewEngine ?? ResolveViewEngine(context); var viewData = ViewData ?? context.ViewData; + var isNullOrEmptyViewName = string.IsNullOrEmpty(ViewName); 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. qualifiedViewName = ViewName; @@ -83,11 +85,13 @@ namespace Microsoft.AspNet.Mvc // Areas/Blog/Views/Shared/Components/Cart/Default.cshtml // // This supports a controller or area providing an override for component views. + var viewName = isNullOrEmptyViewName ? DefaultViewName : ViewName; + qualifiedViewName = string.Format( CultureInfo.InvariantCulture, ViewPathFormat, context.ViewComponentDescriptor.ShortName, - ViewName ?? "Default"); + viewName); } var view = FindView(context.ViewContext, viewEngine, qualifiedViewName); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs index 9e4f658d69..baf62486e4 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs @@ -275,22 +275,53 @@ namespace Microsoft.AspNet.Mvc Assert.Equal(expected, ex.Message); } - [Fact] - public void Execute_CallsFindPartialView_WithExpectedPath() + [Theory] + [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().Object, viewData); + componentContext.ViewComponentDescriptor.ShortName = shortName; + var expectedViewName = $"Components/{shortName}/Default"; + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(v => v.FindPartialView(It.IsAny(), expectedViewName)) + .Returns(ViewEngineResult.Found(string.Empty, new Mock().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 var viewEngine = new Mock(MockBehavior.Strict); viewEngine - .Setup(v => v.FindPartialView(It.IsAny(), - It.Is(view => view.Contains("Components")))) + .Setup(v => v.FindPartialView(It.IsAny(), viewName)) .Returns(ViewEngineResult.Found(string.Empty, new Mock().Object)) .Verifiable(); - var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); var componentContext = GetViewComponentContext(new Mock().Object, viewData); - var componentResult = new ViewViewComponentResult(); - componentResult.ViewEngine = viewEngine.Object; - componentResult.ViewData = viewData; + var componentResult = new ViewViewComponentResult + { + ViewEngine = viewEngine.Object, + ViewData = viewData, + ViewName = viewName + }; // Act & Assert componentResult.Execute(componentContext);