IUrlHelper and IViewComponentHelper need to be activated

* Removing Init method and using [Activate] to activate IUrlHelper.
* Moving IViewComponentHelper to default injected properties
* Adding functional tests to verify these properties are injected \
  activated

Fixes #789
This commit is contained in:
Pranav K 2014-07-15 18:13:37 -07:00
parent 472e500864
commit 9f8c656b31
15 changed files with 139 additions and 25 deletions

View File

@ -16,7 +16,8 @@ namespace Microsoft.AspNet.Mvc.Razor
ActivateAttributeName = "Microsoft.AspNet.Mvc.ActivateAttribute";
DefaultInjectedProperties = new List<InjectDescriptor>()
{
new InjectDescriptor("Microsoft.AspNet.Mvc.Rendering.IHtmlHelper<TModel>", "Html")
new InjectDescriptor("Microsoft.AspNet.Mvc.Rendering.IHtmlHelper<TModel>", "Html"),
new InjectDescriptor("Microsoft.AspNet.Mvc.IViewComponentHelper", "Component"),
};
}

View File

@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using System.Net;
@ -21,7 +20,8 @@ namespace Microsoft.AspNet.Mvc.Razor
private readonly HashSet<string> _renderedSections = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private bool _renderedBody;
public IViewComponentHelper Component { get; private set; }
[Activate]
public IUrlHelper Url { get; set; }
public HttpContext Context
{
@ -42,8 +42,6 @@ namespace Microsoft.AspNet.Mvc.Razor
protected TextWriter Output { get; set; }
public IUrlHelper Url { get; private set; }
public virtual IPrincipal User
{
get
@ -76,8 +74,6 @@ namespace Microsoft.AspNet.Mvc.Razor
SectionWriters = new Dictionary<string, HelperResult>(StringComparer.OrdinalIgnoreCase);
ViewContext = context;
InitHelpers();
var contentBuilder = new StringBuilder(1024);
using (var bodyWriter = new StringWriter(contentBuilder))
{
@ -112,22 +108,6 @@ namespace Microsoft.AspNet.Mvc.Razor
}
}
private void InitHelpers()
{
Contract.Assert(ViewContext != null);
Contract.Assert(Context != null);
Url = Context.RequestServices.GetService<IUrlHelper>();
Component = Context.RequestServices.GetService<IViewComponentHelper>();
var contextable = Component as ICanHasViewContext;
if (contextable != null)
{
contextable.Contextualize(ViewContext);
}
}
private async Task RenderLayoutAsync(ViewContext context, string bodyContent)
{
var virtualPathFactory = context.HttpContext.RequestServices.GetService<IVirtualPathViewFactory>();

View File

@ -61,5 +61,52 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var body = await result.HttpContext.Response.ReadBodyAsStringAsync();
Assert.Equal(expected, body);
}
[Fact]
public async Task ViewActivator_ActivatesDefaultInjectedProperties()
{
var server = TestServer.Create(_provider, _app);
var client = server.Handler;
var expected = "<label for=\"Hello\">Hello</label> world!";
// Act
var result = await client.GetAsync("http://localhost/View/ConsumeDefaultProperties");
// Assert
var body = await result.HttpContext.Response.ReadBodyAsStringAsync();
Assert.Equal(expected, body.Trim());
}
[Fact]
public async Task ViewActivator_ActivatesAndContextualizesInjectedServices()
{
var server = TestServer.Create(_provider, _app);
var client = server.Handler;
var expected = "4 test-value";
// Act
var result = await client.GetAsync("http://localhost/View/ConsumeInjectedService?test=test-value");
// Assert
var body = await result.HttpContext.Response.ReadBodyAsStringAsync();
Assert.Equal(expected, body.Trim());
}
[Fact]
public async Task ViewActivator_ActivatesServicesFromBaseType()
{
var server = TestServer.Create(_provider, _app);
var client = server.Handler;
var expected =
@"/content/scripts/test.js
/View/ConsumeDefaultProperties";
// Act
var result = await client.GetAsync("http://localhost/View/ConsumeServicesFromBaseType");
// Assert
var body = await result.HttpContext.Response.ReadBodyAsStringAsync();
Assert.Equal(expected, body.Trim());
}
}
}

View File

@ -31,6 +31,8 @@ using MyNamespace
{ get; private set; }
[Microsoft.AspNet.Mvc.ActivateAttribute]
public Microsoft.AspNet.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
[Microsoft.AspNet.Mvc.ActivateAttribute]
public Microsoft.AspNet.Mvc.IViewComponentHelper Component { get; private set; }
#line hidden

View File

@ -37,6 +37,8 @@
#line default
#line hidden
{ get; private set; }
[Microsoft.AspNet.Mvc.ActivateAttribute]
public Microsoft.AspNet.Mvc.IViewComponentHelper Component { get; private set; }
#line hidden

View File

@ -23,6 +23,8 @@
#line hidden
[Microsoft.AspNet.Mvc.ActivateAttribute]
public Microsoft.AspNet.Mvc.Rendering.IHtmlHelper<System.Collections.IEnumerable> Html { get; private set; }
[Microsoft.AspNet.Mvc.ActivateAttribute]
public Microsoft.AspNet.Mvc.IViewComponentHelper Component { get; private set; }
#line hidden

View File

@ -24,12 +24,18 @@
</PropertyGroup>
<ItemGroup>
<Content Include="Project.json" />
<Content Include="Views\View\ConsumeDefaultProperties.cshtml" />
<Content Include="Views\View\ConsumeInjectedService.cshtml" />
<Content Include="Views\View\ConsumeServicesFromBaseType.cshtml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Components\TestComponent.cs" />
<Compile Include="Controllers\CannotBeActivatedController.cs" />
<Compile Include="Controllers\PlainController.cs" />
<Compile Include="Controllers\RegularController.cs" />
<Compile Include="Controllers\ViewController.cs" />
<Compile Include="Services\MyService.cs" />
<Compile Include="Services\ViewService.cs" />
<Compile Include="Startup.cs" />
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />

View File

@ -0,0 +1,13 @@
using Microsoft.AspNet.Mvc;
namespace ActivatorWebSite
{
[ViewComponent(Name = "Test")]
public class TestComponent : ViewComponent
{
public IViewComponentResult Invoke(string content)
{
return Content(content + "!");
}
}
}

View File

@ -0,0 +1,28 @@
// 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 ActivatorWebSite
{
/// <summary>
/// Controller that verifies if view activation works.
/// </summary>
public class ViewController : Controller
{
public ViewResult ConsumeDefaultProperties()
{
return View();
}
public ViewResult ConsumeInjectedService()
{
return View();
}
public ViewResult ConsumeServicesFromBaseType()
{
return View();
}
}
}

View File

@ -1,8 +1,6 @@
// 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;
namespace ActivatorWebSite
{
public class MyService

View File

@ -0,0 +1,26 @@
// 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;
using Microsoft.AspNet.Mvc.Rendering;
namespace ActivatorWebSite
{
/// <summary>
/// A service that needs to be contextualized.
/// </summary>
public class ViewService : ICanHasViewContext
{
private ViewContext _context;
public void Contextualize(ViewContext viewContext)
{
_context = viewContext;
}
public string GetValue()
{
return _context.HttpContext.Request.Query["test"];
}
}
}

View File

@ -19,6 +19,7 @@ namespace ActivatorWebSite
// Add MVC services to the services container
services.AddMvc(configuration);
services.AddInstance(new MyService());
services.AddScoped<ViewService, ViewService>();
});
// Add MVC to the request pipeline

View File

@ -0,0 +1 @@
@Html.Label("Hello") @Component.Invoke("Test", "world")

View File

@ -0,0 +1,5 @@
@using ActivatorWebSite
@inject MyService MyServiceInstance
@inject ViewService ViewServiceInstance
@MyServiceInstance.Random @ViewServiceInstance.GetValue()

View File

@ -0,0 +1,2 @@
@Href("~/content/scripts/test.js")
@Url.Action("ConsumeDefaultProperties")