Fix for #1192 - Support customizing reflected model through attributes
This adds support for attributes which interact with reflected model. These conventions are applied after all of our built-in constructs so that you can see and modify the results.
This commit is contained in:
parent
6c49d0b40e
commit
d8995a7767
13
Mvc.sln
13
Mvc.sln
|
|
@ -82,6 +82,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UrlHelperWebSite", "test\We
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ApiExplorerWebSite", "test\WebSites\ApiExplorerWebSite\ApiExplorerWebSite.kproj", "{61061528-071E-424E-965A-07BCC2F02672}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ApiExplorerWebSite", "test\WebSites\ApiExplorerWebSite\ApiExplorerWebSite.kproj", "{61061528-071E-424E-965A-07BCC2F02672}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ReflectedModelWebSite", "test\WebSites\ReflectedModelWebSite\ReflectedModelWebSite.kproj", "{C2EF54F8-8886-4260-A322-44F76245F95D}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -422,6 +424,16 @@ Global
|
||||||
{61061528-071E-424E-965A-07BCC2F02672}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
{61061528-071E-424E-965A-07BCC2F02672}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
{61061528-071E-424E-965A-07BCC2F02672}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
{61061528-071E-424E-965A-07BCC2F02672}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{61061528-071E-424E-965A-07BCC2F02672}.Release|x86.ActiveCfg = Release|Any CPU
|
{61061528-071E-424E-965A-07BCC2F02672}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -461,5 +473,6 @@ Global
|
||||||
{96107AC0-18E2-474D-BAB4-2FFF2185FBCD} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
{96107AC0-18E2-474D-BAB4-2FFF2185FBCD} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
{A192E504-2881-41DC-90D1-B7F1DD1134E8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
{61061528-071E-424E-965A-07BCC2F02672} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
{61061528-071E-424E-965A-07BCC2F02672} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
|
{C2EF54F8-8886-4260-A322-44F76245F95D} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// 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 Microsoft.AspNet.Mvc.ReflectedModelBuilder;
|
||||||
|
|
||||||
|
namespace MvcSample.Web
|
||||||
|
{
|
||||||
|
// Adds an auto-generated route-name to each action in the controller
|
||||||
|
public class AutoGenerateRouteNamesAttribute : Attribute, IReflectedControllerModelConvention
|
||||||
|
{
|
||||||
|
public void Apply(ReflectedControllerModel model)
|
||||||
|
{
|
||||||
|
foreach (var action in model.Actions)
|
||||||
|
{
|
||||||
|
if (action.AttributeRouteModel == null)
|
||||||
|
{
|
||||||
|
action.AttributeRouteModel = new ReflectedAttributeRouteModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.AttributeRouteModel.Name == null)
|
||||||
|
{
|
||||||
|
action.AttributeRouteModel.Name = string.Format(
|
||||||
|
"{0}_{1}",
|
||||||
|
model.ControllerName,
|
||||||
|
action.ActionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
namespace MvcSample.Web
|
namespace MvcSample.Web
|
||||||
{
|
{
|
||||||
|
[AutoGenerateRouteNames]
|
||||||
[Route("api/REST")]
|
[Route("api/REST")]
|
||||||
public class SimpleRest : Controller
|
public class SimpleRest : Controller
|
||||||
{
|
{
|
||||||
|
|
@ -23,5 +24,13 @@ namespace MvcSample.Web
|
||||||
{
|
{
|
||||||
return Url.Action(action, controller);
|
return Url.Action(action, controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("Link/{name}")]
|
||||||
|
public string GenerateLinkByName(string name = null)
|
||||||
|
{
|
||||||
|
// This action leverages [AutoGenerateRouteNames]. Try a URL like api/Rest/Link/SimpleRest_ThisIsAGetMethod
|
||||||
|
// which matches the auto-generated name for the ThisIsAGetMethod action.
|
||||||
|
return Url.RouteUrl(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,22 +8,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class ControllerDescriptor
|
public class ControllerDescriptor
|
||||||
{
|
{
|
||||||
public ControllerDescriptor(TypeInfo controllerTypeInfo)
|
public string Name { get; set; }
|
||||||
{
|
|
||||||
if (controllerTypeInfo == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("controllerTypeInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
ControllerTypeInfo = controllerTypeInfo;
|
public TypeInfo ControllerTypeInfo { get; set; }
|
||||||
|
|
||||||
Name = controllerTypeInfo.Name.EndsWith("Controller", StringComparison.Ordinal)
|
|
||||||
? controllerTypeInfo.Name.Substring(0, controllerTypeInfo.Name.Length - "Controller".Length)
|
|
||||||
: controllerTypeInfo.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; private set; }
|
|
||||||
|
|
||||||
public TypeInfo ControllerTypeInfo { get; private set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,19 +31,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private readonly IActionDiscoveryConventions _conventions;
|
private readonly IActionDiscoveryConventions _conventions;
|
||||||
private readonly IReadOnlyList<IFilter> _globalFilters;
|
private readonly IReadOnlyList<IFilter> _globalFilters;
|
||||||
private readonly IEnumerable<IReflectedApplicationModelConvention> _modelConventions;
|
private readonly IEnumerable<IReflectedApplicationModelConvention> _modelConventions;
|
||||||
private readonly IInlineConstraintResolver _constraintResolver;
|
|
||||||
|
|
||||||
public ReflectedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
public ReflectedActionDescriptorProvider(IControllerAssemblyProvider controllerAssemblyProvider,
|
||||||
IActionDiscoveryConventions conventions,
|
IActionDiscoveryConventions conventions,
|
||||||
IGlobalFilterProvider globalFilters,
|
IGlobalFilterProvider globalFilters,
|
||||||
IOptionsAccessor<MvcOptions> optionsAccessor,
|
IOptionsAccessor<MvcOptions> optionsAccessor)
|
||||||
IInlineConstraintResolver constraintResolver)
|
|
||||||
{
|
{
|
||||||
_controllerAssemblyProvider = controllerAssemblyProvider;
|
_controllerAssemblyProvider = controllerAssemblyProvider;
|
||||||
_conventions = conventions;
|
_conventions = conventions;
|
||||||
_globalFilters = globalFilters.Filters;
|
_globalFilters = globalFilters.Filters;
|
||||||
_modelConventions = optionsAccessor.Options.ApplicationModelConventions;
|
_modelConventions = optionsAccessor.Options.ApplicationModelConventions;
|
||||||
_constraintResolver = constraintResolver;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order
|
public int Order
|
||||||
|
|
@ -60,12 +57,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public IEnumerable<ReflectedActionDescriptor> GetDescriptors()
|
public IEnumerable<ReflectedActionDescriptor> GetDescriptors()
|
||||||
{
|
{
|
||||||
var model = BuildModel();
|
var model = BuildModel();
|
||||||
|
ApplyConventions(model);
|
||||||
foreach (var convention in _modelConventions)
|
|
||||||
{
|
|
||||||
convention.OnModelCreated(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Build(model);
|
return Build(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +72,11 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
foreach (var controllerType in controllerTypes)
|
foreach (var controllerType in controllerTypes)
|
||||||
{
|
{
|
||||||
var controllerModel = new ReflectedControllerModel(controllerType);
|
var controllerModel = new ReflectedControllerModel(controllerType)
|
||||||
|
{
|
||||||
|
Application = applicationModel,
|
||||||
|
};
|
||||||
|
|
||||||
applicationModel.Controllers.Add(controllerModel);
|
applicationModel.Controllers.Add(controllerModel);
|
||||||
|
|
||||||
foreach (var methodInfo in controllerType.AsType().GetMethods())
|
foreach (var methodInfo in controllerType.AsType().GetMethods())
|
||||||
|
|
@ -93,10 +89,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
foreach (var actionInfo in actionInfos)
|
foreach (var actionInfo in actionInfos)
|
||||||
{
|
{
|
||||||
var actionModel = new ReflectedActionModel(methodInfo);
|
var actionModel = new ReflectedActionModel(methodInfo)
|
||||||
|
{
|
||||||
|
ActionName = actionInfo.ActionName,
|
||||||
|
Controller = controllerModel,
|
||||||
|
IsActionNameMatchRequired = actionInfo.RequireActionNameMatch,
|
||||||
|
};
|
||||||
|
|
||||||
actionModel.ActionName = actionInfo.ActionName;
|
|
||||||
actionModel.IsActionNameMatchRequired = actionInfo.RequireActionNameMatch;
|
|
||||||
actionModel.HttpMethods.AddRange(actionInfo.HttpMethods ?? Enumerable.Empty<string>());
|
actionModel.HttpMethods.AddRange(actionInfo.HttpMethods ?? Enumerable.Empty<string>());
|
||||||
|
|
||||||
if (actionInfo.AttributeRoute != null)
|
if (actionInfo.AttributeRoute != null)
|
||||||
|
|
@ -107,7 +106,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
foreach (var parameter in methodInfo.GetParameters())
|
foreach (var parameter in methodInfo.GetParameters())
|
||||||
{
|
{
|
||||||
actionModel.Parameters.Add(new ReflectedParameterModel(parameter));
|
actionModel.Parameters.Add(new ReflectedParameterModel(parameter)
|
||||||
|
{
|
||||||
|
Action = actionModel,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
controllerModel.Actions.Add(actionModel);
|
controllerModel.Actions.Add(actionModel);
|
||||||
|
|
@ -118,6 +120,62 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return applicationModel;
|
return applicationModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ApplyConventions(ReflectedApplicationModel model)
|
||||||
|
{
|
||||||
|
// Conventions are applied from the outside-in to allow for scenarios where an action overrides
|
||||||
|
// a controller, etc.
|
||||||
|
foreach (var convention in _modelConventions)
|
||||||
|
{
|
||||||
|
convention.Apply(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
// First apply the conventions from attributes in decreasing order of scope.
|
||||||
|
foreach (var controller in model.Controllers)
|
||||||
|
{
|
||||||
|
// ToArray is needed here to prevent issues with modifying the attributes collection
|
||||||
|
// while iterating it.
|
||||||
|
var controllerConventions =
|
||||||
|
controller.Attributes
|
||||||
|
.OfType<IReflectedControllerModelConvention>()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var controllerConvention in controllerConventions)
|
||||||
|
{
|
||||||
|
controllerConvention.Apply(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var action in controller.Actions)
|
||||||
|
{
|
||||||
|
// ToArray is needed here to prevent issues with modifying the attributes collection
|
||||||
|
// while iterating it.
|
||||||
|
var actionConventions =
|
||||||
|
action.Attributes
|
||||||
|
.OfType<IReflectedActionModelConvention>()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var actionConvention in actionConventions)
|
||||||
|
{
|
||||||
|
actionConvention.Apply(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var parameter in action.Parameters)
|
||||||
|
{
|
||||||
|
// ToArray is needed here to prevent issues with modifying the attributes collection
|
||||||
|
// while iterating it.
|
||||||
|
var parameterConventions =
|
||||||
|
parameter.Attributes
|
||||||
|
.OfType<IReflectedParameterModelConvention>()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var parameterConvention in parameterConventions)
|
||||||
|
{
|
||||||
|
parameterConvention.Apply(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<ReflectedActionDescriptor> Build(ReflectedApplicationModel model)
|
public List<ReflectedActionDescriptor> Build(ReflectedApplicationModel model)
|
||||||
{
|
{
|
||||||
var actions = new List<ReflectedActionDescriptor>();
|
var actions = new List<ReflectedActionDescriptor>();
|
||||||
|
|
@ -132,7 +190,12 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
foreach (var controller in model.Controllers)
|
foreach (var controller in model.Controllers)
|
||||||
{
|
{
|
||||||
var controllerDescriptor = new ControllerDescriptor(controller.ControllerType);
|
var controllerDescriptor = new ControllerDescriptor()
|
||||||
|
{
|
||||||
|
ControllerTypeInfo = controller.ControllerType,
|
||||||
|
Name = controller.ControllerName,
|
||||||
|
};
|
||||||
|
|
||||||
foreach (var action in controller.Actions)
|
foreach (var action in controller.Actions)
|
||||||
{
|
{
|
||||||
// Controllers with multiple [Route] attributes (or user defined implementation of
|
// Controllers with multiple [Route] attributes (or user defined implementation of
|
||||||
|
|
@ -351,7 +414,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
private static void AddApiExplorerInfo(
|
private static void AddApiExplorerInfo(
|
||||||
ReflectedActionDescriptor actionDescriptor,
|
ReflectedActionDescriptor actionDescriptor,
|
||||||
ReflectedActionModel action,
|
ReflectedActionModel action,
|
||||||
ReflectedControllerModel controller)
|
ReflectedControllerModel controller)
|
||||||
{
|
{
|
||||||
var apiExplorerIsVisible = action.ApiExplorerIsVisible ?? controller.ApiExplorerIsVisible ?? false;
|
var apiExplorerIsVisible = action.ApiExplorerIsVisible ?? controller.ApiExplorerIsVisible ?? false;
|
||||||
|
|
@ -360,7 +423,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var apiExplorerActionData = new ApiDescriptionActionData()
|
var apiExplorerActionData = new ApiDescriptionActionData()
|
||||||
{
|
{
|
||||||
GroupName = action.ApiExplorerGroupName ?? controller.ApiExplorerGroupName,
|
GroupName = action.ApiExplorerGroupName ?? controller.ApiExplorerGroupName,
|
||||||
};
|
};
|
||||||
|
|
||||||
actionDescriptor.SetProperty(apiExplorerActionData);
|
actionDescriptor.SetProperty(apiExplorerActionData);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ReflectedModelBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allows customization of the of the <see cref="ReflectedActionModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// To use this interface, create an <see cref="System.Attribute"/> class which implements the interface and
|
||||||
|
/// place it on an action method.
|
||||||
|
///
|
||||||
|
/// <see cref="IReflectedActionModelConvention"/> customizations run after
|
||||||
|
/// <see cref="IReflectedActionModelConvention"/> customications and before
|
||||||
|
/// <see cref="IReflectedParameterModelConvention"/> customizations.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IReflectedActionModelConvention
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called to apply the convention to the <see cref="ReflectedActionModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The <see cref="ReflectedActionModel"/>.</param>
|
||||||
|
void Apply([NotNull] ReflectedActionModel model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,8 +3,22 @@
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ReflectedModelBuilder
|
namespace Microsoft.AspNet.Mvc.ReflectedModelBuilder
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allows customization of the of the <see cref="ReflectedApplicationModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implementaions of this interface can be registered in <see cref="MvcOptions.ApplicationModelConventions"/>
|
||||||
|
/// to customize metadata about the application.
|
||||||
|
///
|
||||||
|
/// <see cref="IReflectedApplicationModelConvention"/> run before other types of customizations to the
|
||||||
|
/// reflected model.
|
||||||
|
/// </remarks>
|
||||||
public interface IReflectedApplicationModelConvention
|
public interface IReflectedApplicationModelConvention
|
||||||
{
|
{
|
||||||
void OnModelCreated([NotNull] ReflectedApplicationModel model);
|
/// <summary>
|
||||||
|
/// Called to apply the convention to the <see cref="ReflectedApplicationModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The <see cref="ReflectedApplicationModel"/>.</param>
|
||||||
|
void Apply([NotNull] ReflectedApplicationModel model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ReflectedModelBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allows customization of the of the <see cref="ReflectedControllerModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// To use this interface, create an <see cref="System.Attribute"/> class which implements the interface and
|
||||||
|
/// place it on a controller class.
|
||||||
|
///
|
||||||
|
/// <see cref="IReflectedControllerModelConvention"/> customizations run after
|
||||||
|
/// <see cref="IReflectedApplicationModelConvention"/> customizations and before
|
||||||
|
/// <see cref="IReflectedActionModelConvention"/> customizations.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IReflectedControllerModelConvention
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called to apply the convention to the <see cref="ReflectedControllerModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The <see cref="ReflectedControllerModel"/>.</param>
|
||||||
|
void Apply([NotNull] ReflectedControllerModel model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ReflectedModelBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allows customization of the of the <see cref="ReflectedControllerModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// To use this interface, create an <see cref="System.Attribute"/> class which implements the interface and
|
||||||
|
/// place it on an action method parameter.
|
||||||
|
///
|
||||||
|
/// <see cref="IReflectedParameterModelConvention"/> customizations run after
|
||||||
|
/// <see cref="IReflectedActionModelConvention"/> customizations.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IReflectedParameterModelConvention
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called to apply the convention to the <see cref="ReflectedParameterModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The <see cref="ReflectedParameterModel"/>.</param>
|
||||||
|
void Apply([NotNull] ReflectedParameterModel model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,6 +51,8 @@ namespace Microsoft.AspNet.Mvc.ReflectedModelBuilder
|
||||||
|
|
||||||
public List<object> Attributes { get; private set; }
|
public List<object> Attributes { get; private set; }
|
||||||
|
|
||||||
|
public ReflectedControllerModel Controller { get; set; }
|
||||||
|
|
||||||
public List<IFilter> Filters { get; private set; }
|
public List<IFilter> Filters { get; private set; }
|
||||||
|
|
||||||
public List<string> HttpMethods { get; private set; }
|
public List<string> HttpMethods { get; private set; }
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ namespace Microsoft.AspNet.Mvc.ReflectedModelBuilder
|
||||||
|
|
||||||
public List<ReflectedActionModel> Actions { get; private set; }
|
public List<ReflectedActionModel> Actions { get; private set; }
|
||||||
|
|
||||||
|
public ReflectedApplicationModel Application { get; set; }
|
||||||
|
|
||||||
public List<object> Attributes { get; private set; }
|
public List<object> Attributes { get; private set; }
|
||||||
|
|
||||||
public string ControllerName { get; set; }
|
public string ControllerName { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ namespace Microsoft.AspNet.Mvc.ReflectedModelBuilder
|
||||||
IsOptional = ParameterInfo.HasDefaultValue;
|
IsOptional = ParameterInfo.HasDefaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReflectedActionModel Action { get; set; }
|
||||||
|
|
||||||
public List<object> Attributes { get; private set; }
|
public List<object> Attributes { get; private set; }
|
||||||
|
|
||||||
public bool IsOptional { get; set; }
|
public bool IsOptional { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -227,8 +227,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
controllerAssemblyProvider,
|
controllerAssemblyProvider,
|
||||||
actionDiscoveryConventions,
|
actionDiscoveryConventions,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor());
|
||||||
Mock.Of<IInlineConstraintResolver>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HttpContext GetHttpContext(string httpMethod)
|
private static HttpContext GetHttpContext(string httpMethod)
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
controllerAssemblyProvider.Object,
|
controllerAssemblyProvider.Object,
|
||||||
actionDiscoveryConventions,
|
actionDiscoveryConventions,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor());
|
||||||
Mock.Of<IInlineConstraintResolver>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HttpContext GetHttpContext(string httpMethod)
|
private static HttpContext GetHttpContext(string httpMethod)
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Routing;
|
|
||||||
using Microsoft.AspNet.Mvc.Description;
|
using Microsoft.AspNet.Mvc.Description;
|
||||||
using Microsoft.AspNet.Mvc.Routing;
|
using Microsoft.AspNet.Mvc.Routing;
|
||||||
|
using Microsoft.AspNet.Mvc.ReflectedModelBuilder;
|
||||||
|
using Microsoft.Framework.OptionsModel;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Test
|
namespace Microsoft.AspNet.Mvc.Test
|
||||||
{
|
{
|
||||||
|
|
@ -1130,6 +1130,56 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
Assert.Equal("Store", action.GetProperty<ApiDescriptionActionData>().GroupName);
|
Assert.Equal("Store", action.GetProperty<ApiDescriptionActionData>().GroupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verifies the sequence of conventions running
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_RunsInOrderOfDecreasingScope()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var sequence = 0;
|
||||||
|
|
||||||
|
var applicationConvention = new Mock<IReflectedApplicationModelConvention>();
|
||||||
|
applicationConvention
|
||||||
|
.Setup(c => c.Apply(It.IsAny<ReflectedApplicationModel>()))
|
||||||
|
.Callback(() => { Assert.Equal(0, sequence++); });
|
||||||
|
|
||||||
|
var controllerConvention = new Mock<IReflectedControllerModelConvention>();
|
||||||
|
controllerConvention
|
||||||
|
.Setup(c => c.Apply(It.IsAny<ReflectedControllerModel>()))
|
||||||
|
.Callback(() => { Assert.Equal(1, sequence++); });
|
||||||
|
|
||||||
|
var actionConvention = new Mock<IReflectedActionModelConvention>();
|
||||||
|
actionConvention
|
||||||
|
.Setup(c => c.Apply(It.IsAny<ReflectedActionModel>()))
|
||||||
|
.Callback(() => { Assert.Equal(2, sequence++); });
|
||||||
|
|
||||||
|
var parameterConvention = new Mock<IReflectedParameterModelConvention>();
|
||||||
|
parameterConvention
|
||||||
|
.Setup(c => c.Apply(It.IsAny<ReflectedParameterModel>()))
|
||||||
|
.Callback(() => { Assert.Equal(3, sequence++); });
|
||||||
|
|
||||||
|
var options = new MockMvcOptionsAccessor();
|
||||||
|
options.Options.ApplicationModelConventions.Add(applicationConvention.Object);
|
||||||
|
|
||||||
|
var provider = GetProvider(typeof(ConventionsController).GetTypeInfo(), options);
|
||||||
|
|
||||||
|
var model = provider.BuildModel();
|
||||||
|
|
||||||
|
var controller = model.Controllers.Single();
|
||||||
|
controller.Attributes.Add(controllerConvention.Object);
|
||||||
|
|
||||||
|
var action = controller.Actions.Single();
|
||||||
|
action.Attributes.Add(actionConvention.Object);
|
||||||
|
|
||||||
|
var parameter = action.Parameters.Single();
|
||||||
|
parameter.Attributes.Add(parameterConvention.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
provider.ApplyConventions(model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(4, sequence);
|
||||||
|
}
|
||||||
|
|
||||||
private ReflectedActionDescriptorProvider GetProvider(
|
private ReflectedActionDescriptorProvider GetProvider(
|
||||||
TypeInfo controllerTypeInfo,
|
TypeInfo controllerTypeInfo,
|
||||||
IEnumerable<IFilter> filters = null)
|
IEnumerable<IFilter> filters = null)
|
||||||
|
|
@ -1145,8 +1195,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
assemblyProvider.Object,
|
assemblyProvider.Object,
|
||||||
conventions,
|
conventions,
|
||||||
new TestGlobalFilterProvider(filters),
|
new TestGlobalFilterProvider(filters),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor());
|
||||||
Mock.Of<IInlineConstraintResolver>());
|
|
||||||
|
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
@ -1165,12 +1214,29 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
assemblyProvider.Object,
|
assemblyProvider.Object,
|
||||||
conventions,
|
conventions,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor());
|
||||||
Mock.Of<IInlineConstraintResolver>());
|
|
||||||
|
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReflectedActionDescriptorProvider GetProvider(
|
||||||
|
TypeInfo type,
|
||||||
|
IOptionsAccessor<MvcOptions> options)
|
||||||
|
{
|
||||||
|
var conventions = new StaticActionDiscoveryConventions(type);
|
||||||
|
|
||||||
|
var assemblyProvider = new Mock<IControllerAssemblyProvider>();
|
||||||
|
assemblyProvider
|
||||||
|
.SetupGet(ap => ap.CandidateAssemblies)
|
||||||
|
.Returns(new Assembly[] { type.Assembly });
|
||||||
|
|
||||||
|
return new ReflectedActionDescriptorProvider(
|
||||||
|
assemblyProvider.Object,
|
||||||
|
conventions,
|
||||||
|
new TestGlobalFilterProvider(),
|
||||||
|
options);
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerable<ActionDescriptor> GetDescriptors(params TypeInfo[] controllerTypeInfos)
|
private IEnumerable<ActionDescriptor> GetDescriptors(params TypeInfo[] controllerTypeInfos)
|
||||||
{
|
{
|
||||||
var conventions = new StaticActionDiscoveryConventions(controllerTypeInfos);
|
var conventions = new StaticActionDiscoveryConventions(controllerTypeInfos);
|
||||||
|
|
@ -1184,8 +1250,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
assemblyProvider.Object,
|
assemblyProvider.Object,
|
||||||
conventions,
|
conventions,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor());
|
||||||
null);
|
|
||||||
|
|
||||||
return provider.GetDescriptors();
|
return provider.GetDescriptors();
|
||||||
}
|
}
|
||||||
|
|
@ -1588,5 +1653,10 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
|
|
||||||
public void Create() { }
|
public void Create() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ConventionsController
|
||||||
|
{
|
||||||
|
public void Create(int productId) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
// 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 Microsoft.AspNet.Builder;
|
||||||
|
using Microsoft.AspNet.TestHost;
|
||||||
|
using Xunit;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
|
{
|
||||||
|
public class ReflectedModelTest
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _services = TestHelper.CreateServices(nameof(ReflectedModelWebSite));
|
||||||
|
private readonly Action<IApplicationBuilder> _app = new ReflectedModelWebSite.Startup().Configure;
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ControllerModel_CustomizedWithAttribute()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_services, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetAsync("http://localhost/CoolController/GetControllerName");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var body = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal("CoolController", body);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ActionModel_CustomizedWithAttribute()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_services, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetAsync("http://localhost/ReflectedActionModel/ActionName");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var body = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal("ActionName", body);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ParameterModel_CustomizedWithAttribute()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_services, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetAsync("http://localhost/ReflectedParameterModel/GetParameterIsOptional");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
var body = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal("True", body);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
"Microsoft.AspNet.PipelineCore": "1.0.0-*",
|
"Microsoft.AspNet.PipelineCore": "1.0.0-*",
|
||||||
"ModelBindingWebSite": "",
|
"ModelBindingWebSite": "",
|
||||||
"MvcSample.Web": "",
|
"MvcSample.Web": "",
|
||||||
|
"ReflectedModelWebSite": "",
|
||||||
"RoutingWebSite": "",
|
"RoutingWebSite": "",
|
||||||
"RazorWebSite": "",
|
"RazorWebSite": "",
|
||||||
"ValueProvidersSite": "",
|
"ValueProvidersSite": "",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ namespace ApiExplorer
|
||||||
_type = type.GetTypeInfo();
|
_type = type.GetTypeInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnModelCreated(ReflectedApplicationModel model)
|
public void Apply(ReflectedApplicationModel model)
|
||||||
{
|
{
|
||||||
foreach (var controller in model.Controllers)
|
foreach (var controller in model.Controllers)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace ApiExplorer
|
||||||
// convention
|
// convention
|
||||||
public class ApiExplorerVisibilityEnabledConvention : IReflectedApplicationModelConvention
|
public class ApiExplorerVisibilityEnabledConvention : IReflectedApplicationModelConvention
|
||||||
{
|
{
|
||||||
public void OnModelCreated(ReflectedApplicationModel model)
|
public void Apply(ReflectedApplicationModel model)
|
||||||
{
|
{
|
||||||
foreach (var controller in model.Controllers)
|
foreach (var controller in model.Controllers)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ namespace AutofacWebSite
|
||||||
{
|
{
|
||||||
public void Configure(IApplicationBuilder app)
|
public void Configure(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
|
var configuration = app.GetTestConfiguration();
|
||||||
|
|
||||||
app.UseServices(services => {
|
app.UseServices(services => {
|
||||||
services.AddMvc();
|
services.AddMvc(configuration);
|
||||||
services.AddTransient<HelloWorldBuilder>();
|
services.AddTransient<HelloWorldBuilder>();
|
||||||
|
|
||||||
var builder = new ContainerBuilder();
|
var builder = new ContainerBuilder();
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||||
"Microsoft.AspNet.Mvc": "",
|
"Microsoft.AspNet.Mvc": "",
|
||||||
|
"Microsoft.AspNet.Mvc.TestConfiguration": "",
|
||||||
"Microsoft.Framework.DependencyInjection.Autofac": "1.0.0-*",
|
"Microsoft.Framework.DependencyInjection.Autofac": "1.0.0-*",
|
||||||
"Autofac": "3.3.0"
|
"Autofac": "3.3.0"
|
||||||
},
|
},
|
||||||
"frameworks" : {
|
"frameworks": {
|
||||||
"aspnet50" : { }
|
"aspnet50": { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// 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 Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.AspNet.Mvc.ReflectedModelBuilder;
|
||||||
|
|
||||||
|
namespace ReflectedModelWebSite
|
||||||
|
{
|
||||||
|
// This controller uses an reflected model attribute to change an action name, and thus
|
||||||
|
// the URL.
|
||||||
|
public class ReflectedActionModelController : Controller
|
||||||
|
{
|
||||||
|
[ActionName2("ActionName")]
|
||||||
|
public string GetActionName()
|
||||||
|
{
|
||||||
|
var actionDescriptor = (ReflectedActionDescriptor)ActionContext.ActionDescriptor;
|
||||||
|
|
||||||
|
return actionDescriptor.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ActionName2Attribute : Attribute, IReflectedActionModelConvention
|
||||||
|
{
|
||||||
|
private readonly string _actionName;
|
||||||
|
|
||||||
|
public ActionName2Attribute(string actionName)
|
||||||
|
{
|
||||||
|
_actionName = actionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Apply(ReflectedActionModel model)
|
||||||
|
{
|
||||||
|
model.ActionName = _actionName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// 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 Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.AspNet.Mvc.ReflectedModelBuilder;
|
||||||
|
|
||||||
|
namespace ReflectedModelWebSite
|
||||||
|
{
|
||||||
|
// This controller uses an reflected model attribute to change the controller name, and thus
|
||||||
|
// the URL.
|
||||||
|
[ControllerName("CoolController")]
|
||||||
|
public class ReflectedControllerModelController : Controller
|
||||||
|
{
|
||||||
|
public string GetControllerName()
|
||||||
|
{
|
||||||
|
var actionDescriptor = (ReflectedActionDescriptor)ActionContext.ActionDescriptor;
|
||||||
|
|
||||||
|
return actionDescriptor.ControllerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ControllerNameAttribute : Attribute, IReflectedControllerModelConvention
|
||||||
|
{
|
||||||
|
private readonly string _controllerName;
|
||||||
|
|
||||||
|
public ControllerNameAttribute(string controllerName)
|
||||||
|
{
|
||||||
|
_controllerName = controllerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Apply(ReflectedControllerModel model)
|
||||||
|
{
|
||||||
|
model.ControllerName = _controllerName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 System;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.AspNet.Mvc.ReflectedModelBuilder;
|
||||||
|
|
||||||
|
namespace ReflectedModelWebSite
|
||||||
|
{
|
||||||
|
// This controller uses an reflected model attribute to change a parameter to optional.
|
||||||
|
public class ReflectedParameterModelController : Controller
|
||||||
|
{
|
||||||
|
public string GetParameterIsOptional([Optional] int? id)
|
||||||
|
{
|
||||||
|
var actionDescriptor = (ReflectedActionDescriptor)ActionContext.ActionDescriptor;
|
||||||
|
|
||||||
|
return actionDescriptor.Parameters[0].IsOptional.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OptionalAttribute : Attribute, IReflectedParameterModelConvention
|
||||||
|
{
|
||||||
|
public void Apply(ReflectedParameterModel model)
|
||||||
|
{
|
||||||
|
model.IsOptional = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>c2ef54f8-8886-4260-a322-44f76245f95d</ProjectGuid>
|
||||||
|
<OutputType>Web</OutputType>
|
||||||
|
<RootNamespace>ReflectedModelWebSite</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="$(OutputType) == 'Console'">
|
||||||
|
<DebuggerFlavor>ConsoleDebugger</DebuggerFlavor>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="$(OutputType) == 'Web'">
|
||||||
|
<DebuggerFlavor>WebDebugger</DebuggerFlavor>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<DevelopmentServerPort>9411</DevelopmentServerPort>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// 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.Builder;
|
||||||
|
using Microsoft.Framework.DependencyInjection;
|
||||||
|
|
||||||
|
namespace ReflectedModelWebSite
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public void Configure(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
var configuration = app.GetTestConfiguration();
|
||||||
|
|
||||||
|
app.UseServices(services =>
|
||||||
|
{
|
||||||
|
services.AddMvc(configuration);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.UseMvc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.AspNet.Mvc": "",
|
||||||
|
"Microsoft.AspNet.Mvc.TestConfiguration": ""
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"aspnet50": { },
|
||||||
|
"aspnetcore50": { }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue