parent
fbaac1095a
commit
5119d16b64
13
Mvc.sln
13
Mvc.sln
|
|
@ -98,6 +98,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "WebApiCompatShimWebSite", "
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.WebApiCompatShimTest", "test\Microsoft.AspNet.Mvc.WebApiCompatShimTest\Microsoft.AspNet.Mvc.WebApiCompatShimTest.kproj", "{5DE8E4D9-AACD-4B5F-819F-F091383FB996}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ViewComponentWebSite", "test\WebSites\ViewComponentWebSite\ViewComponentWebSite.kproj", "{24B59501-5F37-4129-96E6-F02EC34C7E2C}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TagHelperSample.Web", "samples\TagHelperSample.Web\TagHelperSample.Web.kproj", "{2223120F-D675-40DA-8CD8-11DC14A0B2C7}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHelpers", "src\Microsoft.AspNet.Mvc.TagHelpers\Microsoft.AspNet.Mvc.TagHelpers.kproj", "{B2347320-308E-4D2B-AEC8-005DFA68B0C9}"
|
||||
|
|
@ -524,6 +526,16 @@ Global
|
|||
{5DE8E4D9-AACD-4B5F-819F-F091383FB996}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{5DE8E4D9-AACD-4B5F-819F-F091383FB996}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{5DE8E4D9-AACD-4B5F-819F-F091383FB996}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2223120F-D675-40DA-8CD8-11DC14A0B2C7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
|
@ -601,6 +613,7 @@ Global
|
|||
{23D30B8C-04B1-4577-A604-ED27EA1E4A0E} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{B2B7BC91-688E-4C1E-A71F-CE948D958DDF} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{5DE8E4D9-AACD-4B5F-819F-F091383FB996} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{24B59501-5F37-4129-96E6-F02EC34C7E2C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{2223120F-D675-40DA-8CD8-11DC14A0B2C7} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
|
||||
{B2347320-308E-4D2B-AEC8-005DFA68B0C9} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{860119ED-3DB1-424D-8D0A-30132A8A7D96} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,23 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Result type of a <see cref="ViewComponent"/>.
|
||||
/// </summary>
|
||||
public interface IViewComponentResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the result of a <see cref="ViewComponent"/> using the specified <paramref name="context"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/> for the current component execution.</param>
|
||||
void Execute([NotNull] ViewComponentContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously executes the result of a <see cref="ViewComponent"/> using the specified
|
||||
/// <paramref name="context"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/> for the current component execution.</param>
|
||||
/// <returns>A <see cref="Task"/> that represents the asynchronous execution.</returns>
|
||||
Task ExecuteAsync([NotNull] ViewComponentContext context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ using Microsoft.AspNet.Mvc.Rendering;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IViewComponentResult"/> that renders a partial view when executed.
|
||||
/// </summary>
|
||||
public class ViewViewComponentResult : IViewComponentResult
|
||||
{
|
||||
// {0} is the component name, {1} is the view name.
|
||||
|
|
@ -27,11 +30,20 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public ViewDataDictionary ViewData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Locates and renders a view specified by <paramref name="context"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/> for the current component execution.</param>
|
||||
/// <remarks>
|
||||
/// This method synchronously calls and blocks on <see cref="ExecuteAsync(ViewComponentContext)"/>.
|
||||
/// </remarks>
|
||||
public void Execute([NotNull] ViewComponentContext context)
|
||||
{
|
||||
throw new NotImplementedException("There's no support for syncronous views right now.");
|
||||
var task = ExecuteAsync(context);
|
||||
TaskHelper.WaitAndThrowIfFaulted(task);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ExecuteAsync([NotNull] ViewComponentContext context)
|
||||
{
|
||||
string qualifiedViewName;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,77 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public class ViewViewComponentResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void Execute_RendersPartialViews()
|
||||
{
|
||||
// Arrange
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Returns(Task.FromResult(result: true))
|
||||
.Verifiable();
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine.Setup(e => e.FindPartialView(It.IsAny<ActionContext>(), It.IsAny<string>()))
|
||||
.Returns(ViewEngineResult.Found("some-view", view.Object))
|
||||
.Verifiable();
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var result = new ViewViewComponentResult(viewEngine.Object, "some-view", viewData);
|
||||
var viewComponentContext = GetViewComponentContext(view.Object, viewData);
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
|
||||
// Assert
|
||||
viewEngine.Verify();
|
||||
view.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ThrowsIfPartialViewCannotBeFound()
|
||||
{
|
||||
// Arrange
|
||||
var expected = string.Join(Environment.NewLine,
|
||||
"The view 'Components/Object/some-view' was not found. The following locations were searched:",
|
||||
"location1",
|
||||
"location2.");
|
||||
var view = Mock.Of<IView>();
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine.Setup(e => e.FindPartialView(It.IsAny<ActionContext>(), It.IsAny<string>()))
|
||||
.Returns(ViewEngineResult.NotFound("some-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var result = new ViewViewComponentResult(viewEngine.Object, "some-view", viewData);
|
||||
var viewComponentContext = GetViewComponentContext(view, viewData);
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => result.Execute(viewComponentContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_DoesNotWrapThrownExceptionsInAggregateExceptions()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new IndexOutOfRangeException();
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Throws(expected)
|
||||
.Verifiable();
|
||||
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
|
||||
viewEngine.Setup(e => e.FindPartialView(It.IsAny<ActionContext>(), It.IsAny<string>()))
|
||||
.Returns(ViewEngineResult.Found("some-view", view.Object))
|
||||
.Verifiable();
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var result = new ViewViewComponentResult(viewEngine.Object, "some-view", viewData);
|
||||
var viewComponentContext = GetViewComponentContext(view.Object, viewData);
|
||||
|
||||
// Act
|
||||
var actual = Record.Exception(() => result.Execute(viewComponentContext));
|
||||
|
||||
// Assert
|
||||
Assert.Same(expected, actual);
|
||||
view.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_RendersPartialViews()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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 System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using ViewComponentWebSite;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
public class ViewComponentTests
|
||||
{
|
||||
private readonly IServiceProvider _provider = TestHelper.CreateServices("ViewComponentWebSite");
|
||||
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||
|
||||
public static IEnumerable<object[]> ViewViewComponents_AreRenderedCorrectlyData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new[]
|
||||
{
|
||||
"ViewWithAsyncComponents",
|
||||
string.Join(Environment.NewLine,
|
||||
"<test-component>value-from-component value-from-view</test-component>",
|
||||
"ViewWithAsyncComponents InvokeAsync: hello from viewdatacomponent")
|
||||
};
|
||||
|
||||
yield return new[]
|
||||
{
|
||||
"ViewWithSyncComponents",
|
||||
string.Join(Environment.NewLine,
|
||||
"<test-component>value-from-component value-from-view</test-component>",
|
||||
"ViewWithSyncComponents Invoke: hello from viewdatacomponent")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ViewViewComponents_AreRenderedCorrectlyData))]
|
||||
public async Task ViewViewComponents_AreRenderedCorrectly(string actionName, string expected)
|
||||
{
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var body = await client.GetStringAsync("http://localhost/Home/" + actionName);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, body.Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,9 +21,11 @@
|
|||
"RoutingWebSite": "1.0.0",
|
||||
"RazorWebSite": "1.0.0",
|
||||
"RazorInstrumentationWebsite": "1.0.0",
|
||||
"ValueProvidersSite": "1.0.0",
|
||||
"XmlSerializerWebSite": "1.0.0",
|
||||
"TagHelpersWebSite": "1.0.0",
|
||||
"UrlHelperWebSite": "1.0.0",
|
||||
"ValueProvidersSite": "1.0.0",
|
||||
"ViewComponentWebSite": "1.0.0",
|
||||
"XmlSerializerWebSite": "1.0.0",
|
||||
"WebApiCompatShimWebSite": "1.0.0",
|
||||
|
||||
"Microsoft.AspNet.TestHost": "1.0.0-*",
|
||||
|
|
@ -34,7 +36,6 @@
|
|||
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
|
||||
"Microsoft.Framework.Logging": "1.0.0-*",
|
||||
"Microsoft.Framework.Runtime.Interfaces": "1.0.0-*",
|
||||
"TagHelpersWebSite": "1.0.0",
|
||||
"Xunit.KRunner": "1.0.0-*"
|
||||
},
|
||||
"commands": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace ViewComponentWebSite
|
||||
{
|
||||
public class HomeController
|
||||
{
|
||||
public ViewResult ViewWithAsyncComponents()
|
||||
{
|
||||
return new ViewResult();
|
||||
}
|
||||
|
||||
public ViewResult ViewWithSyncComponents()
|
||||
{
|
||||
return new ViewResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ViewComponentWebSite
|
||||
{
|
||||
public class SampleModel
|
||||
{
|
||||
public string Prop1 { get; set; }
|
||||
|
||||
public string Prop2 { get; set; }
|
||||
|
||||
public Task<string> GetValueAsync()
|
||||
{
|
||||
return Task.FromResult(Prop1 + " " + Prop2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace ViewComponentWebSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
var configuration = app.GetTestConfiguration();
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddMvc(configuration);
|
||||
});
|
||||
app.UseMvc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace ViewComponentWebSite
|
||||
{
|
||||
public class TestViewComponent : ViewComponent
|
||||
{
|
||||
public IViewComponentResult Invoke(string valueFromView)
|
||||
{
|
||||
var model = new SampleModel
|
||||
{
|
||||
Prop1 = "value-from-component",
|
||||
Prop2 = valueFromView
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="__ToolsVersion__" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>24b59501-5f37-4129-96e6-f02ec34c7e2c</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace ViewComponentWebSite
|
||||
{
|
||||
[ViewComponent(Name = "ViewData")]
|
||||
public class ViewDataComponent : ViewComponent
|
||||
{
|
||||
public ViewViewComponentResult Invoke()
|
||||
{
|
||||
ViewData["value-from-component"] = nameof(Invoke) + ": hello from viewdatacomponent";
|
||||
return View("ComponentThatReadsViewData");
|
||||
}
|
||||
|
||||
public Task<ViewViewComponentResult> InvokeAsync()
|
||||
{
|
||||
ViewData["value-from-component"] = nameof(InvokeAsync) + ": hello from viewdatacomponent";
|
||||
var result = View("ComponentThatReadsViewData");
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
@model SampleModel
|
||||
<test-component>@await Model.GetValueAsync()</test-component>
|
||||
|
|
@ -0,0 +1 @@
|
|||
@ViewData["value-from-view"] @ViewData["value-from-component"]
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@{
|
||||
ViewData["value-from-view"] = ViewContext.ActionDescriptor.Name;
|
||||
}
|
||||
@await Component.InvokeAsync("Test", "value-from-view")
|
||||
@await Component.InvokeAsync("ViewData")
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@{
|
||||
ViewData["value-from-view"] = ViewContext.ActionDescriptor.Name;
|
||||
}
|
||||
@Component.Invoke("Test", "value-from-view")
|
||||
@Component.Invoke("ViewData")
|
||||
|
|
@ -0,0 +1 @@
|
|||
@using ViewComponentWebSite
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0"
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": { },
|
||||
"aspnetcore50": { }
|
||||
},
|
||||
"webroot": "wwwroot"
|
||||
}
|
||||
Loading…
Reference in New Issue