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.Core;
using Microsoft.AspNet.Mvc.Internal; using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.DependencyInjection;
namespace Microsoft.AspNet.Mvc namespace Microsoft.AspNet.Mvc
{ {
public class ViewResult : ActionResult public class ViewResult : ActionResult
{ {
private const int BufferSize = 1024; 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 string ViewName { get; set; }
public ViewDataDictionary ViewData { get; set; } public ViewDataDictionary ViewData { get; set; }
public IViewEngine ViewEngine { get; set; }
public override async Task ExecuteResultAsync([NotNull] ActionContext context) public override async Task ExecuteResultAsync([NotNull] ActionContext context)
{ {
var viewEngine = ViewEngine ?? context.HttpContext.RequestServices.GetService<IViewEngine>();
var viewName = ViewName ?? context.ActionDescriptor.Name; 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) 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) if (!result.Success)
{ {
var locations = string.Empty; var locations = string.Empty;

View File

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

View File

@ -23,17 +23,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
{ {
// Arrange // Arrange
var expected = new byte[] { 97, 98, 99, 100 }; 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>(); var view = new Mock<IView>();
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>())) view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
.Callback((ViewContext v) => .Callback((ViewContext v) =>
@ -41,11 +31,85 @@ namespace Microsoft.AspNet.Mvc.Core.Test
v.Writer.Write("abcd"); v.Writer.Write("abcd");
}) })
.Returns(Task.FromResult(0)); .Returns(Task.FromResult(0));
var serviceProvider = Mock.Of<IServiceProvider>();
var routeDictionary = new Dictionary<string, object>();
var viewEngine = new Mock<IViewEngine>(); var viewEngine = new Mock<IViewEngine>();
viewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>())) viewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object)); .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 // Act
await viewResult.ExecuteResultAsync(actionContext); await viewResult.ExecuteResultAsync(actionContext);
@ -63,17 +127,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test
{ {
// Arrange // Arrange
var longString = new string('a', writtenLength); 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 routeDictionary = new Dictionary<string, object>();
var actionContext = new ActionContext(context.Object,
new RouteData() { Values = routeDictionary },
new ActionDescriptor());
var view = new Mock<IView>(); var view = new Mock<IView>();
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>())) view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
.Callback((ViewContext v) => .Callback((ViewContext v) =>
@ -81,11 +137,28 @@ namespace Microsoft.AspNet.Mvc.Core.Test
v.Writer.Write(longString); v.Writer.Write(longString);
throw new Exception(); throw new Exception();
}); });
var serviceProvider = Mock.Of<IServiceProvider>();
var viewEngine = new Mock<IViewEngine>(); var viewEngine = new Mock<IViewEngine>();
viewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>())) viewEngine.Setup(v => v.FindView(routeDictionary, It.IsAny<string>()))
.Returns(ViewEngineResult.Found("MyView", view.Object)); .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 // Act
await Record.ExceptionAsync(() => viewResult.ExecuteResultAsync(actionContext)); await Record.ExceptionAsync(() => viewResult.ExecuteResultAsync(actionContext));