[Fixes #393] [Design] Update ViewComponent result apis to be consistent with Controller
1. Updated ViewComponent to exposes similar properties to the existing ones in controller where appropiate. We've left out Resolver for being a bad pattern (just inject the dependency on the constructor or use Context.RequestServices to access it if needed) and Response as although available through the Context property, it shouldn't be used/modified in a ViewComponent. 2. Updated ViewViewComponentResult to follow a similar pattern as ViewResult where the constructor is parameterless and elements like ViewEngine are resolved during execution if the user does not set the associated property on the object. 3. Updated ExecuteAsync in JsonViewComponentResult to remove the unnecessary pragma and async keyword from the signature and to use Task.FromResult(true) instead. 4. Cleaned up ViewViewComponentResult tests.
This commit is contained in:
parent
d2aff42e25
commit
8ce069f56a
|
|
@ -7,29 +7,67 @@ using Microsoft.AspNet.Mvc.Rendering;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IViewComponentResult"/> which writes text when executed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="ContentViewComponentResult"/> always writes HTML encoded text from the
|
||||
/// <see cref="EncodedContent"/> property.
|
||||
///
|
||||
/// When using <see cref="ContentViewComponentResult(string)"/>, the provided content will be HTML
|
||||
/// encoded and stored in <see cref="EncodedContent"/>.
|
||||
///
|
||||
/// To write pre-encoded conent, use <see cref="ContentViewComponentResult(HtmlString)"/>.
|
||||
/// </remarks>
|
||||
public class ContentViewComponentResult : IViewComponentResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="ContentViewComponentResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="content">Content to write. The content be HTML encoded when output.</param>
|
||||
public ContentViewComponentResult([NotNull] string content)
|
||||
{
|
||||
Content = content;
|
||||
EncodedContent = new HtmlString(WebUtility.HtmlEncode(content));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="ContentViewComponentResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="content">
|
||||
/// Content to write. The content is treated as already HTML encoded, and no further encoding
|
||||
/// will be performed.
|
||||
/// </param>
|
||||
public ContentViewComponentResult([NotNull] HtmlString encodedContent)
|
||||
{
|
||||
EncodedContent = encodedContent;
|
||||
Content = WebUtility.HtmlDecode(encodedContent.ToString());
|
||||
}
|
||||
|
||||
public string Content { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the content.
|
||||
/// </summary>
|
||||
public string Content { get; }
|
||||
|
||||
public HtmlString EncodedContent { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the encoded content.
|
||||
/// </summary>
|
||||
public HtmlString EncodedContent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes the <see cref="EncodedContent"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/>.</param>
|
||||
public void Execute([NotNull] ViewComponentContext context)
|
||||
{
|
||||
context.Writer.Write(EncodedContent.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the <see cref="EncodedContent"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/>.</param>
|
||||
/// <returns>A completed <see cref="Task"/>.</returns>
|
||||
public async Task ExecuteAsync([NotNull] ViewComponentContext context)
|
||||
{
|
||||
await context.Writer.WriteAsync(EncodedContent.ToString());
|
||||
|
|
|
|||
|
|
@ -2,29 +2,70 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IViewComponentResult"/> which renders JSON text when executed.
|
||||
/// </summary>
|
||||
public class JsonViewComponentResult : IViewComponentResult
|
||||
{
|
||||
public JsonViewComponentResult([NotNull] object data)
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="JsonViewComponentResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to format as JSON text.</param>
|
||||
public JsonViewComponentResult(object value)
|
||||
{
|
||||
Data = data;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public object Data { get; private set; }
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="JsonViewComponentResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to format as JSON text.</param>
|
||||
/// <param name="formatter">The <see cref="JsonOutputFormatter"/> to use.</param>
|
||||
public JsonViewComponentResult(object value, JsonOutputFormatter formatter)
|
||||
{
|
||||
Value = value;
|
||||
Formatter = formatter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value.
|
||||
/// </summary>
|
||||
public object Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the formatter.
|
||||
/// </summary>
|
||||
public JsonOutputFormatter Formatter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Renders JSON text to the output.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/>.</param>
|
||||
public void Execute([NotNull] ViewComponentContext context)
|
||||
{
|
||||
var formatter = new JsonOutputFormatter();
|
||||
formatter.WriteObject(context.Writer, Data);
|
||||
var formatter = Formatter ?? ResolveFormatter(context);
|
||||
formatter.WriteObject(context.Writer, Value);
|
||||
}
|
||||
|
||||
#pragma warning disable 1998
|
||||
public async Task ExecuteAsync([NotNull] ViewComponentContext context)
|
||||
/// <summary>
|
||||
/// Renders JSON text to the output.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/>.</param>
|
||||
/// <returns>A completed <see cref="Task"/>.</returns>
|
||||
public Task ExecuteAsync([NotNull] ViewComponentContext context)
|
||||
{
|
||||
Execute(context);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
private static JsonOutputFormatter ResolveFormatter(ViewComponentContext context)
|
||||
{
|
||||
var services = context.ViewContext.HttpContext.RequestServices;
|
||||
return services.GetRequiredService<JsonOutputFormatter>();
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,69 @@
|
|||
// 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.Security.Principal;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Routing;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for view components.
|
||||
/// </summary>
|
||||
[ViewComponent]
|
||||
public abstract class ViewComponent
|
||||
{
|
||||
private dynamic _viewBag;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="HttpContext"/>.
|
||||
/// </summary>
|
||||
public HttpContext Context
|
||||
{
|
||||
get { return ViewContext == null ? null : ViewContext.HttpContext; }
|
||||
get
|
||||
{
|
||||
return ViewContext?.HttpContext;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="HttpRequest"/>.
|
||||
/// </summary>
|
||||
public HttpRequest Request
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewContext?.HttpContext?.Request;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IPrincipal"/> for the current user.
|
||||
/// </summary>
|
||||
public IPrincipal User
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewContext?.HttpContext?.User;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="RouteData"/> for the current request.
|
||||
/// </summary>
|
||||
public RouteData RouteData
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewContext?.RouteData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view bag.
|
||||
/// </summary>
|
||||
public dynamic ViewBag
|
||||
{
|
||||
get
|
||||
|
|
@ -29,44 +77,105 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ModelStateDictionary"/>.
|
||||
/// </summary>
|
||||
public ModelStateDictionary ModelState
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewData?.ModelState;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IUrlHelper"/>.
|
||||
/// </summary>
|
||||
[Activate]
|
||||
public IUrlHelper Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ViewContext"/>.
|
||||
/// </summary>
|
||||
[Activate]
|
||||
public ViewContext ViewContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ViewDataDictionary"/>.
|
||||
/// </summary>
|
||||
[Activate]
|
||||
public ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ICompositeViewEngine"/>.
|
||||
/// </summary>
|
||||
[Activate]
|
||||
public ICompositeViewEngine ViewEngine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a result which will render HTML encoded text.
|
||||
/// </summary>
|
||||
/// <param name="content">The content, will be HTML encoded before output.</param>
|
||||
/// <returns>A <see cref="ContentViewComponentResult"/>.</returns>
|
||||
public ContentViewComponentResult Content([NotNull] string content)
|
||||
{
|
||||
return new ContentViewComponentResult(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a result which will render JSON text.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to output in JSON text.</param>
|
||||
/// <returns>A <see cref="JsonViewComponentResult"/>.</returns>
|
||||
public JsonViewComponentResult Json([NotNull] object value)
|
||||
{
|
||||
return new JsonViewComponentResult(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a result which will render the partial view with name <c>"Default"</c>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="ViewViewComponentResult"/>.</returns>
|
||||
public ViewViewComponentResult View()
|
||||
{
|
||||
return View<object>(null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a result which will render the partial view with name <paramref name="viewName"/>.
|
||||
/// </summary>
|
||||
/// <param name="viewName">The name of the partial view to render.</param>
|
||||
/// <returns>A <see cref="ViewViewComponentResult"/>.</returns>
|
||||
public ViewViewComponentResult View(string viewName)
|
||||
{
|
||||
return View<object>(viewName, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a result which will render the partial view with name <c>"Default"</c>.
|
||||
/// </summary>
|
||||
/// <param name="model">The model object for the view.</param>
|
||||
/// <returns>A <see cref="ViewViewComponentResult"/>.</returns>
|
||||
public ViewViewComponentResult View<TModel>(TModel model)
|
||||
{
|
||||
return View(null, model);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a result which will render the partial view with name <paramref name="viewName"/>.
|
||||
/// </summary>
|
||||
/// <param name="viewName">The name of the partial view to render.</param>
|
||||
/// <param name="model">The model object for the view.</param>
|
||||
/// <returns>A <see cref="ViewViewComponentResult"/>.</returns>
|
||||
public ViewViewComponentResult View<TModel>(string viewName, TModel model)
|
||||
{
|
||||
var viewData = new ViewDataDictionary<TModel>(ViewData, model);
|
||||
return new ViewViewComponentResult(ViewEngine, viewName, viewData);
|
||||
return new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = ViewEngine,
|
||||
ViewName = viewName,
|
||||
ViewData = viewData
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
|
|
@ -15,22 +16,25 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
// {0} is the component name, {1} is the view name.
|
||||
private const string ViewPathFormat = "Components/{0}/{1}";
|
||||
private readonly IViewEngine _viewEngine;
|
||||
|
||||
public ViewViewComponentResult([NotNull] IViewEngine viewEngine, string viewName,
|
||||
ViewDataDictionary viewData)
|
||||
{
|
||||
_viewEngine = viewEngine;
|
||||
ViewName = viewName;
|
||||
ViewData = viewData;
|
||||
}
|
||||
|
||||
public string ViewName { get; private set; }
|
||||
|
||||
public ViewDataDictionary ViewData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Locates and renders a view specified by <paramref name="context"/>.
|
||||
/// Gets or sets the view name.
|
||||
/// </summary>
|
||||
public string ViewName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ViewDataDictionary"/>.
|
||||
/// </summary>
|
||||
public ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ViewEngine"/>.
|
||||
/// </summary>
|
||||
public IViewEngine ViewEngine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Locates and renders a view specified by <see cref="ViewName"/>. If <see cref="ViewName"/> is <c>null</c>,
|
||||
/// then the view name searched for is<c>"Default"</c>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/> for the current component execution.</param>
|
||||
/// <remarks>
|
||||
|
|
@ -42,9 +46,17 @@ namespace Microsoft.AspNet.Mvc
|
|||
TaskHelper.WaitAndThrowIfFaulted(task);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Locates and renders a view specified by <see cref="ViewName"/>. If <see cref="ViewName"/> is <c>null</c>,
|
||||
/// then the view name searched for is<c>"Default"</c>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/> for the current component execution.</param>
|
||||
/// <returns>A <see cref="Task"/> which will complete when view rendering is completed.</returns>
|
||||
public async Task ExecuteAsync([NotNull] ViewComponentContext context)
|
||||
{
|
||||
var viewEngine = ViewEngine ?? ResolveViewEngine(context);
|
||||
var viewData = ViewData ?? context.ViewContext.ViewData;
|
||||
|
||||
string qualifiedViewName;
|
||||
if (ViewName != null && ViewName.Length > 0 && ViewName[0] == '/')
|
||||
{
|
||||
|
|
@ -71,7 +83,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
ViewName ?? "Default");
|
||||
}
|
||||
|
||||
var view = FindView(context.ViewContext, qualifiedViewName);
|
||||
var view = FindView(context.ViewContext, viewEngine, qualifiedViewName);
|
||||
|
||||
var childViewContext = new ViewContext(
|
||||
context.ViewContext,
|
||||
|
|
@ -85,11 +97,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
private IView FindView(ActionContext context, string viewName)
|
||||
private static IView FindView(ActionContext context, IViewEngine viewEngine, string viewName)
|
||||
{
|
||||
return _viewEngine.FindPartialView(context, viewName)
|
||||
.EnsureSuccessful()
|
||||
.View;
|
||||
return viewEngine.FindPartialView(context, viewName).EnsureSuccessful().View;
|
||||
}
|
||||
|
||||
private static IViewEngine ResolveViewEngine(ViewComponentContext context)
|
||||
{
|
||||
return context.ViewContext.HttpContext.RequestServices.GetRequiredService<ICompositeViewEngine>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
||||
serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of<ICompositeViewEngine>());
|
||||
serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of<IUrlHelper>());
|
||||
var viewContext = GetViewContext(serviceProvider.Object);
|
||||
|
||||
// Act
|
||||
|
|
@ -46,6 +47,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
||||
serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of<ICompositeViewEngine>());
|
||||
serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of<IUrlHelper>());
|
||||
var viewContext = GetViewContext(serviceProvider.Object);
|
||||
|
||||
// Act
|
||||
|
|
@ -66,6 +68,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
||||
serviceProvider.Setup(p => p.GetService(typeof(MyService))).Returns(myTestService);
|
||||
serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine))).Returns(Mock.Of<ICompositeViewEngine>());
|
||||
serviceProvider.Setup(p => p.GetService(typeof(IUrlHelper))).Returns(Mock.Of<IUrlHelper>());
|
||||
var viewContext = GetViewContext(serviceProvider.Object);
|
||||
var instance = new TestViewComponentWithCustomDataType();
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
// Assert
|
||||
Assert.IsType<JsonViewComponentResult>(actualResult);
|
||||
Assert.Same(testData, actualResult.Data);
|
||||
Assert.Same(testData, actualResult.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
// 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.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.PipelineCore;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ContentViewComponentResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void Execute_WritesData_Encoded()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new MemoryStream();
|
||||
var result = new ContentViewComponentResult("<Test />");
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(Mock.Of<IView>(), buffer);
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
buffer.Position = 0;
|
||||
|
||||
// Assert
|
||||
Assert.Equal("<Test />", result.EncodedContent.ToString());
|
||||
Assert.Equal("<Test />", new StreamReader(buffer).ReadToEnd());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_WritesData_PreEncoded()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new MemoryStream();
|
||||
var viewComponentContext = GetViewComponentContext(Mock.Of<IView>(), buffer);
|
||||
|
||||
var result = new ContentViewComponentResult(new HtmlString("<Test />"));
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
buffer.Position = 0;
|
||||
|
||||
// Assert
|
||||
Assert.Equal("<Test />", result.Content);
|
||||
Assert.Equal("<Test />", new StreamReader(buffer).ReadToEnd());
|
||||
}
|
||||
|
||||
private static ViewComponentContext GetViewComponentContext(IView view, Stream stream)
|
||||
{
|
||||
var actionContext = new ActionContext(new RouteContext(new DefaultHttpContext()), new ActionDescriptor());
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, TextWriter.Null);
|
||||
var writer = new StreamWriter(stream) { AutoFlush = true };
|
||||
var viewComponentContext = new ViewComponentContext(typeof(object).GetTypeInfo(), viewContext, writer);
|
||||
return viewComponentContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
// 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.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.PipelineCore;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.DependencyInjection.Fallback;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class JsonViewComponentResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void Execute_SerializesData_UsingSpecifiedFormatter()
|
||||
{
|
||||
// Arrange
|
||||
var view = Mock.Of<IView>();
|
||||
var buffer = new MemoryStream();
|
||||
var viewComponentContext = GetViewComponentContext(view, buffer);
|
||||
|
||||
var expectedFormatter = new JsonOutputFormatter();
|
||||
var result = new JsonViewComponentResult(1, expectedFormatter);
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
buffer.Position = 0;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedFormatter, result.Formatter);
|
||||
Assert.Equal("1", new StreamReader(buffer).ReadToEnd());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_FallsbackToServices_WhenNoJsonFormatterIsProvided()
|
||||
{
|
||||
// Arrange
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
|
||||
serviceProvider
|
||||
.Setup(p => p.GetService(typeof(JsonOutputFormatter)))
|
||||
.Returns(new JsonOutputFormatter())
|
||||
.Verifiable();
|
||||
|
||||
var buffer = new MemoryStream();
|
||||
|
||||
var result = new JsonViewComponentResult(1);
|
||||
var viewComponentContext = GetViewComponentContext(view, buffer);
|
||||
viewComponentContext.ViewContext.HttpContext.RequestServices = serviceProvider.Object;
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
buffer.Position = 0;
|
||||
|
||||
// Assert
|
||||
Assert.Equal("1", new StreamReader(buffer).ReadToEnd());
|
||||
serviceProvider.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_Throws_IfNoFormatterCanBeResolved()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "TODO: No service for type 'Microsoft.AspNet.Mvc.JsonOutputFormatter'" +
|
||||
" has been registered.";
|
||||
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var serviceProvider = new ServiceCollection().BuildServiceProvider();
|
||||
|
||||
var buffer = new MemoryStream();
|
||||
|
||||
var result = new JsonViewComponentResult(1);
|
||||
var viewComponentContext = GetViewComponentContext(view, buffer);
|
||||
viewComponentContext.ViewContext.HttpContext.RequestServices = serviceProvider;
|
||||
|
||||
// Act
|
||||
var ex = Assert.Throws<Exception>(() => result.Execute(viewComponentContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
private static ViewComponentContext GetViewComponentContext(IView view, Stream stream)
|
||||
{
|
||||
var actionContext = new ActionContext(new RouteContext(new DefaultHttpContext()), new ActionDescriptor());
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, TextWriter.Null);
|
||||
var writer = new StreamWriter(stream) { AutoFlush = true };
|
||||
var viewComponentContext = new ViewComponentContext(typeof(object).GetTypeInfo(), viewContext, writer);
|
||||
return viewComponentContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.PipelineCore;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.DependencyInjection.Fallback;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -24,12 +26,53 @@ namespace Microsoft.AspNet.Mvc
|
|||
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 result = new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view.Object, viewData);
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
|
||||
// Assert
|
||||
viewEngine.Verify();
|
||||
view.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ResolvesView_WithDefaultAsViewName()
|
||||
{
|
||||
// Arrange
|
||||
var view = new Mock<IView>(MockBehavior.Strict);
|
||||
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("Default", view.Object))
|
||||
.Verifiable();
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
|
||||
var result = new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewData = viewData
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view.Object, viewData);
|
||||
|
||||
// Act
|
||||
|
|
@ -48,13 +91,23 @@ namespace Microsoft.AspNet.Mvc
|
|||
"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("Components/Object/some-view", new[] { "location1", "location2" }))
|
||||
.Verifiable();
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var result = new ViewViewComponentResult(viewEngine.Object, "some-view", viewData);
|
||||
|
||||
var result = new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view, viewData);
|
||||
|
||||
// Act and Assert
|
||||
|
|
@ -67,16 +120,26 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
// 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 result = new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view.Object, viewData);
|
||||
|
||||
// Act
|
||||
|
|
@ -92,12 +155,21 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
// Arrange
|
||||
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.Found("some-view", view))
|
||||
.Verifiable();
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var result = new ViewViewComponentResult(viewEngine.Object, "some-view", viewData);
|
||||
|
||||
var result = new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view, viewData);
|
||||
|
||||
// Act
|
||||
|
|
@ -107,26 +179,100 @@ namespace Microsoft.AspNet.Mvc
|
|||
viewEngine.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_ResolvesViewEngineFromServiceProvider_IfNoViewEngineIsExplicitlyProvided()
|
||||
{
|
||||
// Arrange
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>(MockBehavior.Strict);
|
||||
viewEngine.Setup(e => e.FindPartialView(It.IsAny<ActionContext>(), It.IsAny<string>()))
|
||||
.Returns(ViewEngineResult.Found("some-view", view))
|
||||
.Verifiable();
|
||||
|
||||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
serviceProvider.Setup(p => p.GetService(typeof(ICompositeViewEngine)))
|
||||
.Returns(viewEngine.Object);
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
|
||||
var result = new ViewViewComponentResult
|
||||
{
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view, viewData);
|
||||
viewComponentContext.ViewContext.HttpContext.RequestServices = serviceProvider.Object;
|
||||
|
||||
// Act
|
||||
await result.ExecuteAsync(viewComponentContext);
|
||||
|
||||
// Assert
|
||||
viewEngine.Verify();
|
||||
serviceProvider.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_ThrowsIfPartialViewCannotBeFound()
|
||||
{
|
||||
// Arrange
|
||||
var expected =
|
||||
@"The view 'Components/Object/some-view' was not found. The following locations were searched:
|
||||
foo
|
||||
bar.";
|
||||
var expected = string.Join(Environment.NewLine,
|
||||
"The view 'Components/Object/some-view' was not found. The following locations were searched:",
|
||||
"view-location1",
|
||||
"view-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("Components/Object/some-view", new[] { "foo", "bar" }))
|
||||
.Returns(ViewEngineResult.NotFound(
|
||||
"Components/Object/some-view",
|
||||
new[] { "view-location1", "view-location2" }))
|
||||
.Verifiable();
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var result = new ViewViewComponentResult(viewEngine.Object, "some-view", viewData);
|
||||
|
||||
var result = new ViewViewComponentResult
|
||||
{
|
||||
ViewEngine = viewEngine.Object,
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view, viewData);
|
||||
|
||||
// Act and Assert
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
async () => await result.ExecuteAsync(viewComponentContext));
|
||||
() => result.ExecuteAsync(viewComponentContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_Throws_IfNoViewEngineCanBeResolved()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "TODO: No service for type 'Microsoft.AspNet.Mvc.Rendering.ICompositeViewEngine'" +
|
||||
" has been registered.";
|
||||
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var serviceProvider = new ServiceCollection().BuildServiceProvider();
|
||||
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
|
||||
var result = new ViewViewComponentResult
|
||||
{
|
||||
ViewName = "some-view",
|
||||
ViewData = viewData
|
||||
};
|
||||
|
||||
var viewComponentContext = GetViewComponentContext(view, viewData);
|
||||
viewComponentContext.ViewContext.HttpContext.RequestServices = serviceProvider;
|
||||
|
||||
// Act and Assert
|
||||
var ex = await Assert.ThrowsAsync<Exception>(
|
||||
() => result.ExecuteAsync(viewComponentContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue