Fix for #617 - ViewResult can be constructed without a view engine

We want result types to be constructable without services.
This commit is contained in:
Ryan Nowak 2014-06-27 17:05:09 -07:00
parent 172a5a5500
commit c17d33154f
3 changed files with 110 additions and 43 deletions

View File

@ -8,29 +8,26 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Mvc
{
public class ViewResult : ActionResult
{
private const int BufferSize = 1024;
private readonly IServiceProvider _serviceProvider;
private readonly IViewEngine _viewEngine;
public ViewResult([NotNull] IServiceProvider serviceProvider, [NotNull] IViewEngine viewEngine)
{
_serviceProvider = serviceProvider;
_viewEngine = viewEngine;
}
public string ViewName { get; set; }
public ViewDataDictionary ViewData { get; set; }
public IViewEngine ViewEngine { get; set; }
public override async Task ExecuteResultAsync([NotNull] ActionContext context)
{
var viewEngine = ViewEngine ?? context.HttpContext.RequestServices.GetService<IViewEngine>();
var viewName = ViewName ?? context.ActionDescriptor.Name;
var view = FindView(context.RouteData.Values, viewName);
var view = FindView(viewEngine, context.RouteData.Values, viewName);
using (view as IDisposable)
{
@ -56,9 +53,12 @@ namespace Microsoft.AspNet.Mvc
}
}
private IView FindView([NotNull] IDictionary<string, object> context, [NotNull] string viewName)
private static IView FindView(
[NotNull] IViewEngine viewEngine,
[NotNull] IDictionary<string, object> context,
[NotNull] string viewName)
{
var result = _viewEngine.FindView(context, viewName);
var result = viewEngine.FindView(context, viewName);
if (!result.Success)
{
var locations = string.Empty;

View File

@ -35,12 +35,6 @@ namespace Microsoft.AspNet.Mvc
[Activate]
public ActionContext ActionContext { get; set; }
[Activate]
public IServiceProvider ServiceProvider { get; set; }
[Activate]
public IViewEngine ViewEngine { get; set; }
[Activate]
public IUrlHelper Url { get; set; }
@ -122,7 +116,7 @@ namespace Microsoft.AspNet.Mvc
ViewData.Model = model;
}
return new ViewResult(ServiceProvider, ViewEngine)
return new ViewResult()
{
ViewName = viewName,
ViewData = ViewData,

View File

@ -23,17 +23,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
{
// Arrange
var expected = new byte[] { 97, 98, 99, 100 };
var memoryStream = new MemoryStream();
var response = new Mock<HttpResponse>();
response.SetupGet(r => r.Body)
.Returns(memoryStream);
var context = new Mock<HttpContext>();
context.SetupGet(c => c.Response)
.Returns(response.Object);
var routeDictionary = new Dictionary<string, object>();
var actionContext = new ActionContext(context.Object,
new RouteData() { Values = routeDictionary },
new ActionDescriptor());
var view = new Mock<IView>();
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
.Callback((ViewContext v) =>
@ -41,11 +31,85 @@ namespace Microsoft.AspNet.Mvc.Core.Test
v.Writer.Write("abcd");
})
.Returns(Task.FromResult(0));
var serviceProvider = Mock.Of<IServiceProvider>();
var routeDictionary = new Dictionary<string, object>();
var viewEngine = new Mock<IViewEngine>();
viewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object));
var viewResult = new ViewResult(serviceProvider, viewEngine.Object);
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(sp => sp.GetService(typeof(IViewEngine))).Returns(viewEngine.Object);
var memoryStream = new MemoryStream();
var response = new Mock<HttpResponse>();
response.SetupGet(r => r.Body)
.Returns(memoryStream);
var context = new Mock<HttpContext>();
context.SetupGet(c => c.Response)
.Returns(response.Object);
context.SetupGet(c => c.RequestServices)
.Returns(serviceProvider.Object);
var actionContext = new ActionContext(context.Object,
new RouteData() { Values = routeDictionary },
new ActionDescriptor());
var viewResult = new ViewResult();
// Act
await viewResult.ExecuteResultAsync(actionContext);
// Assert
Assert.Equal(expected, memoryStream.ToArray());
}
[Fact]
public async Task ExecuteResultAsync_UsesProvidedViewEngine()
{
// Arrange
var expected = new byte[] { 97, 98, 99, 100 };
var view = new Mock<IView>();
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
.Callback((ViewContext v) =>
{
v.Writer.Write("abcd");
})
.Returns(Task.FromResult(0));
var routeDictionary = new Dictionary<string, object>();
var goodViewEngine = new Mock<IViewEngine>();
goodViewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object));
var badViewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(sp => sp.GetService(typeof(IViewEngine))).Returns(badViewEngine.Object);
var memoryStream = new MemoryStream();
var response = new Mock<HttpResponse>();
response.SetupGet(r => r.Body)
.Returns(memoryStream);
var context = new Mock<HttpContext>();
context.SetupGet(c => c.Response)
.Returns(response.Object);
context.SetupGet(c => c.RequestServices)
.Returns(serviceProvider.Object);
var actionContext = new ActionContext(context.Object,
new RouteData() { Values = routeDictionary },
new ActionDescriptor());
var viewResult = new ViewResult()
{
ViewEngine = goodViewEngine.Object,
};
// Act
await viewResult.ExecuteResultAsync(actionContext);
@ -63,17 +127,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test
{
// Arrange
var longString = new string('a', writtenLength);
var memoryStream = new MemoryStream();
var response = new Mock<HttpResponse>();
response.SetupGet(r => r.Body)
.Returns(memoryStream);
var context = new Mock<HttpContext>();
context.SetupGet(c => c.Response)
.Returns(response.Object);
var routeDictionary = new Dictionary<string, object>();
var actionContext = new ActionContext(context.Object,
new RouteData() { Values = routeDictionary },
new ActionDescriptor());
var view = new Mock<IView>();
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
.Callback((ViewContext v) =>
@ -81,11 +137,28 @@ namespace Microsoft.AspNet.Mvc.Core.Test
v.Writer.Write(longString);
throw new Exception();
});
var serviceProvider = Mock.Of<IServiceProvider>();
var viewEngine = new Mock<IViewEngine>();
viewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object));
var viewResult = new ViewResult(serviceProvider, viewEngine.Object);
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(sp => sp.GetService(typeof(IViewEngine))).Returns(viewEngine.Object);
var memoryStream = new MemoryStream();
var response = new Mock<HttpResponse>();
response.SetupGet(r => r.Body)
.Returns(memoryStream);
var context = new Mock<HttpContext>();
context.SetupGet(c => c.Response)
.Returns(response.Object);
context.SetupGet(c => c.RequestServices).Returns(serviceProvider.Object);
var actionContext = new ActionContext(context.Object,
new RouteData() { Values = routeDictionary },
new ActionDescriptor());
var viewResult = new ViewResult();
// Act
await Record.ExceptionAsync(() => viewResult.ExecuteResultAsync(actionContext));