Modify TemplateRenderer to use ThrowIfFaulted instead of Task.Wait
Fixes #782
This commit is contained in:
parent
76ecb73040
commit
9c4df4606f
|
|
@ -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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Internal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Utility methods for dealing with <see cref="Task"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class TaskHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws the first faulting exception for a task which is faulted. It preserves the original stack trace when
|
||||||
|
/// throwing the exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Invoking this method is equivalent to calling Wait() on the <paramref name="task" /> if it is not completed.
|
||||||
|
/// </remarks>
|
||||||
|
public static void ThrowIfFaulted(Task task)
|
||||||
|
{
|
||||||
|
task.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Rendering
|
namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
|
|
@ -99,7 +100,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
using (view as IDisposable)
|
using (view as IDisposable)
|
||||||
{
|
{
|
||||||
var viewContext = new ViewContext(_viewContext, viewEngineResult.View, _viewData, writer);
|
var viewContext = new ViewContext(_viewContext, viewEngineResult.View, _viewData, writer);
|
||||||
viewEngineResult.View.RenderAsync(viewContext).Wait();
|
var renderTask = viewEngineResult.View.RenderAsync(viewContext);
|
||||||
|
TaskHelper.ThrowIfFaulted(renderTask);
|
||||||
return writer.ToString();
|
return writer.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// 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.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Internal
|
||||||
|
{
|
||||||
|
public class TaskHelperTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ThrowIfFaulted_DoesNotThrowIfTaskIsNotFaulted()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var task = Task.FromResult(0);
|
||||||
|
|
||||||
|
// Act and Assert
|
||||||
|
Assert.DoesNotThrow(() => TaskHelper.ThrowIfFaulted(task));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ThrowIfFaulted_ThrowsIfTaskIsFaulted()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var message = "Exception message";
|
||||||
|
var task = CreatingFailingTask(message);
|
||||||
|
|
||||||
|
// Act and Assert
|
||||||
|
var ex = Assert.Throws<Exception>(() => TaskHelper.ThrowIfFaulted(task));
|
||||||
|
Assert.Equal(message, ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ThrowIfFaulted_ThrowsFirstExceptionWhenAggregateTaskFails()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var message = "Exception message";
|
||||||
|
var task = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.WhenAll(CreatingFailingTask(message),
|
||||||
|
CreatingFailingTask("different message"));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act and Assert
|
||||||
|
var ex = Assert.Throws<Exception>(() => TaskHelper.ThrowIfFaulted(task));
|
||||||
|
Assert.Equal(message, ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task CreatingFailingTask(string message)
|
||||||
|
{
|
||||||
|
return Task.Run(() =>
|
||||||
|
{
|
||||||
|
throw new Exception(message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -235,5 +236,29 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(result.ToString());
|
Assert.Empty(result.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DisplayFor_DoesNotWrapExceptionThrowsDuringViewRendering()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedMessage = "my exception message";
|
||||||
|
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Test string", };
|
||||||
|
var view = new Mock<IView>();
|
||||||
|
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||||
|
.Returns(Task.Run(() =>
|
||||||
|
{
|
||||||
|
throw new ArgumentException(expectedMessage);
|
||||||
|
}));
|
||||||
|
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||||
|
viewEngine
|
||||||
|
.Setup(v => v.FindPartialView(It.IsAny<ActionContext>(), It.IsAny<string>()))
|
||||||
|
.Returns(ViewEngineResult.Found("test-view", view.Object));
|
||||||
|
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
|
||||||
|
helper.ViewData["Property1"] = "ViewData string";
|
||||||
|
|
||||||
|
// Act and Assert
|
||||||
|
var ex = Assert.Throws<ArgumentException>(() => helper.DisplayFor(m => m.Property1));
|
||||||
|
Assert.Equal(expectedMessage, ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
|
|
@ -386,5 +387,29 @@ Environment.NewLine;
|
||||||
"<input class=\"text-box single-line\" id=\"Property1\" name=\"Property1\" type=\"text\" value=\"\" />",
|
"<input class=\"text-box single-line\" id=\"Property1\" name=\"Property1\" type=\"text\" value=\"\" />",
|
||||||
result.ToString());
|
result.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EditorFor_DoesNotWrapExceptionThrowsDuringViewRendering()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedMessage = "my exception message";
|
||||||
|
var model = new DefaultTemplatesUtilities.ObjectTemplateModel { Property1 = "Test string", };
|
||||||
|
var view = new Mock<IView>();
|
||||||
|
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||||
|
.Returns(Task.Run(() =>
|
||||||
|
{
|
||||||
|
throw new FormatException(expectedMessage);
|
||||||
|
}));
|
||||||
|
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||||
|
viewEngine
|
||||||
|
.Setup(v => v.FindPartialView(It.IsAny<ActionContext>(), It.IsAny<string>()))
|
||||||
|
.Returns(ViewEngineResult.Found("test-view", view.Object));
|
||||||
|
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model, viewEngine.Object);
|
||||||
|
helper.ViewData["Property1"] = "ViewData string";
|
||||||
|
|
||||||
|
// Act and Assert
|
||||||
|
var ex = Assert.Throws<FormatException>(() => helper.EditorFor(m => m.Property1));
|
||||||
|
Assert.Equal(expectedMessage, ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue