LanguageViewLocationExpander.cs
using System ;
using System. Collections. Generic ;
using System. Globalization ;
using System. Threading ;
namespace Microsoft. AspNet. Mvc. Razor
{
public class LanguageViewLocationExpander : IViewLocationExpander
{
private const string ValueKey = "language" ;
private LanguageViewLocationExpanderFormat _format;
public LanguageViewLocationExpander ( )
: this ( LanguageViewLocationExpanderFormat. Suffix)
{
}
public LanguageViewLocationExpander ( LanguageViewLocationExpanderFormat format)
{
_format = format;
}
public void PopulateValues ( ViewLocationExpanderContext context)
{
if ( context == null )
{
throw new ArgumentNullException ( nameof ( context) ) ;
}
#if NET451
context. Values[ ValueKey] = Thread. CurrentThread. CurrentUICulture. Name;
#else
context. Values[ ValueKey] = CultureInfo. CurrentUICulture. Name;
#endif
}
public virtual IEnumerable< string > ExpandViewLocations (
ViewLocationExpanderContext context,
IEnumerable< string > viewLocations)
{
if ( context == null )
{
throw new ArgumentNullException ( nameof ( context) ) ;
}
if ( viewLocations == null )
{
throw new ArgumentNullException ( nameof ( viewLocations) ) ;
}
string value ;
context. Values. TryGetValue ( ValueKey, out value ) ;
if ( ! string . IsNullOrEmpty ( value ) )
{
CultureInfo culture;
try
{
culture = new CultureInfo ( value ) ;
}
catch ( CultureNotFoundException )
{
return viewLocations;
}
return ExpandViewLocationsCore ( viewLocations, culture) ;
}
return viewLocations;
}
private IEnumerable< string > ExpandViewLocationsCore ( IEnumerable< string > viewLocations, CultureInfo cultureInfo)
{
foreach ( var location in viewLocations)
{
var temporaryCultureInfo = cultureInfo;
while ( temporaryCultureInfo != temporaryCultureInfo. Parent)
{
if ( _format == LanguageViewLocationExpanderFormat. SubFolder)
{
yield return location. Replace ( "{0}" , temporaryCultureInfo. Name + "/{0}" ) ;
}
else
{
yield return location. Replace ( "{0}" , "{0}." + temporaryCultureInfo. Name) ;
}
temporaryCultureInfo = temporaryCultureInfo. Parent;
}
yield return location;
}
}
}
}
using Microsoft. AspNet. Mvc. Razor ;
using System. Collections. Generic ;
namespace Host. UI
{
public class CustomViewLocationExpander : IViewLocationExpander
{
public IEnumerable< string > ExpandViewLocations (
ViewLocationExpanderContext context,
IEnumerable< string > viewLocations)
{
yield return "~/UI/{1}/Views/{0}.cshtml" ;
yield return "~/UI/SharedViews/{0}.cshtml" ;
}
public void PopulateValues ( ViewLocationExpanderContext context)
{
}
}
}
CustomViewLocationExpander.cs
using Microsoft. AspNet. Mvc. Razor ;
using System. Collections. Generic ;
namespace Host. UI
{
public class CustomViewLocationExpander : IViewLocationExpander
{
public IEnumerable< string > ExpandViewLocations (
ViewLocationExpanderContext context,
IEnumerable< string > viewLocations)
{
yield return "~/UI/{1}/Views/{0}.cshtml" ;
yield return "~/UI/SharedViews/{0}.cshtml" ;
}
public void PopulateValues ( ViewLocationExpanderContext context)
{
}
}
}
LanguageViewLocationExpander.cs
using System ;
using System. Collections. Generic ;
using Microsoft. AspNet. Mvc ;
using Microsoft. AspNet. Mvc. Razor ;
namespace RazorWebSite
{
public class LanguageViewLocationExpander : IViewLocationExpander
{
private const string ValueKey = "language" ;
private readonly Func< ActionContext, string > _valueFactory;
public LanguageViewLocationExpander ( Func< ActionContext, string > valueFactory)
{
_valueFactory = valueFactory;
}
public void PopulateValues ( ViewLocationExpanderContext context)
{
var value = _valueFactory ( context. ActionContext) ;
if ( ! string . IsNullOrEmpty ( value ) )
{
context. Values[ ValueKey] = value ;
}
}
public virtual IEnumerable< string > ExpandViewLocations ( ViewLocationExpanderContext context,
IEnumerable< string > viewLocations)
{
string value ;
if ( context. Values. TryGetValue ( ValueKey, out value ) )
{
return ExpandViewLocationsCore ( viewLocations, value ) ;
}
return viewLocations;
}
private IEnumerable< string > ExpandViewLocationsCore ( IEnumerable< string > viewLocations,
string value )
{
foreach ( var location in viewLocations)
{
yield return location. Replace ( "{0}" , value + "/{0}" ) ;
yield return location;
}
}
}
}
PagesViewLocationExpander.cs
using Microsoft. AspNet. Mvc. Razor ;
using System. Collections. Generic ;
namespace Odachi. AspNet. MvcPages
{
public class PagesViewLocationExpander : IViewLocationExpander
{
#region IViewLocationExpander
public IEnumerable< string > ExpandViewLocations ( ViewLocationExpanderContext context, IEnumerable< string > viewLocations)
{
return new [ ]
{
"/Areas/{2}/App/{1}/{0}.cshtml" ,
"/Areas/{2}/App/{0}.cshtml" ,
} ;
}
public void PopulateValues ( ViewLocationExpanderContext context)
{
}
#endregion
}
}
BaseViewLocationExpander.cs
namespace University. Module. Mvc. Razor
{
using System. Collections. Generic ;
using System. Linq ;
using Microsoft. AspNet. Mvc. Razor ;
public abstract class BaseViewLocationExpander : IViewLocationExpander
{
#region Fields
protected const string AreaKey = "area" ;
#endregion Fields
#region Constructors
protected BaseViewLocationExpander ( string areaName)
{
CurrentArea = areaName;
}
#endregion Constructors
#region Properties
protected string CurrentArea
{
get ;
}
#endregion Properties
#region Methods
public IEnumerable< string > ExpandViewLocations ( ViewLocationExpanderContext context, IEnumerable< string > viewLocations)
{
var areaName = context. Values[ AreaKey] ;
return CurrentArea != areaName ? viewLocations : GetViewLocation ( context, viewLocations, areaName) ;
}
public void PopulateValues ( ViewLocationExpanderContext context)
{
context. Values[ AreaKey] = context. ActionContext. RouteData. Values. FirstOrDefault ( x => x. Key. Equals ( AreaKey) ) . Value. ToString ( ) ;
}
protected abstract IEnumerable< string > GetViewLocation ( ViewLocationExpanderContext context, IEnumerable< string > viewLocations, string areaName) ;
#endregion Methods
}
}
TenantViewLocationExpander.cs
using Microsoft. AspNet. Http ;
using Microsoft. AspNet. Mvc. Razor ;
using System ;
using System. Collections. Generic ;
using System. Linq ;
using System. Threading. Tasks ;
namespace AspNetMvcSample
{
public class TenantViewLocationExpander : IViewLocationExpander
{
private const string THEME_KEY = "theme" , TENANT_KEY = "tenant" ;
public void PopulateValues ( ViewLocationExpanderContext context)
{
context. Values[ THEME_KEY]
= context. ActionContext. HttpContext. GetTenant < AppTenant> ( ) ?. Theme;
context. Values[ TENANT_KEY]
= context. ActionContext. HttpContext. GetTenant < AppTenant> ( ) ?. Name. Replace ( " " , "-" ) ;
}
public IEnumerable< string > ExpandViewLocations ( ViewLocationExpanderContext context, IEnumerable< string > viewLocations)
{
string theme = null ;
if ( context. Values. TryGetValue ( THEME_KEY, out theme) )
{
IEnumerable< string > themeLocations = new [ ]
{
$"/Themes/ { theme } /{{1}}/{{0}}.cshtml" ,
$"/Themes/ { theme } /Shared/{{0}}.cshtml"
} ;
string tenant;
if ( context. Values. TryGetValue ( TENANT_KEY, out tenant) )
{
themeLocations = ExpandTenantLocations ( tenant, themeLocations) ;
}
viewLocations = themeLocations. Concat ( viewLocations) ;
}
return viewLocations;
}
private IEnumerable< string > ExpandTenantLocations ( string tenant, IEnumerable< string > defaultLocations)
{
foreach ( var location in defaultLocations)
{
yield return location. Replace ( "{0}" , $"{{0}}_ { tenant } " ) ;
yield return location;
}
}
}
}
DefaultViewLocationCacheTest.cs
using System ;
using System. Collections. Generic ;
using Microsoft. AspNet. Http. Internal ;
using Microsoft. AspNet. Mvc. Abstractions ;
using Microsoft. AspNet. Mvc. Routing ;
using Microsoft. AspNet. Routing ;
using Xunit ;
namespace Microsoft. AspNet. Mvc. Razor
{
public class DefaultViewLocationCacheTest
{
public static IEnumerable< object [ ] > CacheEntryData
{
get
{
yield return new [ ] { new ViewLocationExpanderContext ( GetActionContext ( ) , "test" , isPartial : false ) } ;
yield return new [ ] { new ViewLocationExpanderContext ( GetActionContext ( ) , "test" , isPartial : true ) } ;
var areaActionContext = GetActionContext ( "controller2" , "myarea" ) ;
yield return new [ ] { new ViewLocationExpanderContext ( areaActionContext, "test2" , isPartial : false ) } ;
yield return new [ ] { new ViewLocationExpanderContext ( areaActionContext, "test2" , isPartial : true ) } ;
var actionContext = GetActionContext ( "controller3" , "area3" ) ;
var values = new Dictionary< string , string > ( StringComparer. Ordinal)
{
{ "culture" , "fr" } ,
{ "theme" , "sleek" }
} ;
var expanderContext = new ViewLocationExpanderContext ( actionContext, "test3" , isPartial : false )
{
Values = values
} ;
yield return new [ ] { expanderContext } ;
expanderContext = new ViewLocationExpanderContext ( actionContext, "test3" , isPartial : true )
{
Values = values
} ;
yield return new [ ] { expanderContext } ;
}
}
private static DefaultViewLocationCache. ViewLocationCacheKeyComparer CacheKeyComparer =>
DefaultViewLocationCache. ViewLocationCacheKeyComparer. Instance;
[ Theory ]
[ MemberData ( nameof ( CacheEntryData) ) ]
public void Get_ReturnsNoneResultIfItemDoesNotExist ( ViewLocationExpanderContext context)
{
var cache = new DefaultViewLocationCache ( ) ;
var result = cache. Get ( context) ;
Assert. Equal ( result, ViewLocationCacheResult. None) ;
}
[ Theory ]
[ MemberData ( nameof ( CacheEntryData) ) ]
public void InvokingGetAfterSet_ReturnsCachedItem ( ViewLocationExpanderContext context)
{
var cache = new DefaultViewLocationCache ( ) ;
var value = new ViewLocationCacheResult (
Guid. NewGuid ( ) . ToString ( ) ,
new [ ]
{
Guid. NewGuid ( ) . ToString ( ) ,
Guid. NewGuid ( ) . ToString ( )
} ) ;
cache. Set ( context, value ) ;
var result = cache. Get ( context) ;
Assert. Equal ( value , result) ;
result = cache. Get ( context) ;
Assert. Equal ( value , result) ;
}
[ Theory ]
[ InlineData ( "View1" , "View2" ) ]
[ InlineData ( "View1" , "view1" ) ]
public void ViewLocationCacheKeyComparer_EqualsReturnsFalseIfViewNamesAreDifferent (
string viewName1,
string viewName2)
{
var actionContext = GetActionContext ( ) ;
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
actionContext,
viewName1,
isPartial : true ) ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
actionContext,
viewName2,
isPartial : true ) ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. False ( result) ;
Assert. NotEqual ( hash1, hash2) ;
}
[ Theory ]
[ InlineData ( false , true ) ]
[ InlineData ( true , false ) ]
public void ViewLocationCacheKeyComparer_EqualsReturnsFalseIfIsPartialAreDifferent (
bool isPartial1,
bool isPartial2)
{
var actionContext = GetActionContext ( ) ;
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
actionContext,
"View1" ,
isPartial1) ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
actionContext,
"View1" ,
isPartial2) ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. False ( result) ;
Assert. NotEqual ( hash1, hash2) ;
}
[ Theory ]
[ InlineData ( "Controller1" , "Controller2" ) ]
[ InlineData ( "controller1" , "Controller1" ) ]
public void ViewLocationCacheKeyComparer_EqualsReturnsFalseIfIsControllerNamesAreDifferent (
string controller1,
string controller2)
{
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
GetActionContext ( controller1) ,
"View1" ,
isPartial : false ) ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
GetActionContext ( controller2) ,
"View1" ,
isPartial : false ) ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. False ( result) ;
Assert. NotEqual ( hash1, hash2) ;
}
[ Theory ]
[ InlineData ( "area1" , null ) ]
[ InlineData ( "Area1" , "Area2" ) ]
[ InlineData ( "area1" , "aRea1" ) ]
public void ViewLocationCacheKeyComparer_EqualsReturnsFalseIfIsAreaNamesAreDifferent (
string area1,
string area2)
{
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , area1) ,
"View1" ,
isPartial : false ) ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , area2) ,
"View1" ,
isPartial : false ) ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. False ( result) ;
Assert. NotEqual ( hash1, hash2) ;
}
[ Fact ]
public void ViewLocationCacheKeyComparer_EqualsReturnsTrueIfControllerAreaAndViewNamesAreIdentical ( )
{
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. True ( result) ;
Assert. Equal ( hash1, hash2) ;
}
[ Fact ]
public void ViewLocationCacheKeyComparer_EqualsReturnsFalseIfViewLocationExpanderIsNullForEitherKey ( )
{
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext1. Values = new Dictionary< string , string >
{
{ "somekey" , "somevalue" }
} ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. False ( result) ;
Assert. NotEqual ( hash1, hash2) ;
}
[ Fact ]
public void ViewLocationCacheKeyComparer_EqualsReturnsFalseIfExpanderValueCountIsDifferent ( )
{
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext1. Values = new Dictionary< string , string >
{
{ "somekey" , "somevalue" }
} ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext2. Values = new Dictionary< string , string >
{
{ "somekey" , "somevalue" } ,
{ "somekey2" , "somevalue2" } ,
} ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. False ( result) ;
Assert. NotEqual ( hash1, hash2) ;
}
[ Theory ]
[ InlineData ( "key1" , "key2" ) ]
[ InlineData ( "Key1" , "key1" ) ]
public void ViewLocationCacheKeyComparer_EqualsReturnsFalseIfKeysAreDifferent (
string keyName1,
string keyName2)
{
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext1. Values = new Dictionary< string , string >
{
{ keyName1, "somevalue" }
} ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext2. Values = new Dictionary< string , string >
{
{ keyName2, "somevalue" } ,
} ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. False ( result) ;
Assert. NotEqual ( hash1, hash2) ;
}
[ Theory ]
[ InlineData ( "value1" , null ) ]
[ InlineData ( "value1" , "value2" ) ]
[ InlineData ( "value1" , "Value1" ) ]
public void ViewLocationCacheKeyComparer_EqualsReturnsFalseIfValuesAreDifferent (
string value1,
string value2)
{
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext1. Values = new Dictionary< string , string >
{
{ "somekey" , value1 }
} ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext2. Values = new Dictionary< string , string >
{
{ "somekey" , value2 } ,
} ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. False ( result) ;
Assert. NotEqual ( hash1, hash2) ;
}
public void ViewLocationCacheKeyComparer_EqualsReturnsTrueIfValuesAreSame ( )
{
var viewLocationExpanderContext1 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext1. Values = new Dictionary< string , string >
{
{ "somekey1" , "value1" } ,
{ "somekey2" , "value2" } ,
} ;
var viewLocationExpanderContext2 = new ViewLocationExpanderContext (
GetActionContext ( "Controller1" , "Area1" ) ,
"View1" ,
isPartial : false ) ;
viewLocationExpanderContext2. Values = new Dictionary< string , string >
{
{ "somekey2" , "value2" } ,
{ "somekey1" , "value1" } ,
} ;
var key1 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext1,
copyViewExpanderValues : false ) ;
var key2 = DefaultViewLocationCache. GenerateKey (
viewLocationExpanderContext2,
copyViewExpanderValues : false ) ;
var result = CacheKeyComparer. Equals ( key1, key2) ;
var hash1 = CacheKeyComparer. GetHashCode ( key1) ;
var hash2 = CacheKeyComparer. GetHashCode ( key2) ;
Assert. True ( result) ;
Assert. Equal ( hash1, hash2) ;
}
public static ActionContext GetActionContext (
string controller = "mycontroller" ,
string area = null )
{
var routeData = new RouteData ( ) ;
routeData. Values[ "controller" ] = controller;
if ( area != null )
{
routeData. Values[ "area" ] = area;
}
var actionDesciptor = new ActionDescriptor ( ) ;
actionDesciptor. RouteConstraints = new List< RouteDataActionConstraint> ( ) ;
return new ActionContext ( new DefaultHttpContext ( ) , routeData, actionDesciptor) ;
}
private static ActionContext GetActionContextWithActionDescriptor (
IDictionary< string , object > routeValues,
IDictionary< string , string > routesInActionDescriptor,
bool isAttributeRouted)
{
var httpContext = new DefaultHttpContext ( ) ;
var routeData = new RouteData ( ) ;
foreach ( var kvp in routeValues)
{
routeData. Values. Add ( kvp. Key, kvp. Value) ;
}
var actionDescriptor = new ActionDescriptor ( ) ;
if ( isAttributeRouted)
{
actionDescriptor. AttributeRouteInfo = new Routing. AttributeRouteInfo ( ) ;
foreach ( var kvp in routesInActionDescriptor)
{
actionDescriptor. RouteValueDefaults. Add ( kvp. Key, kvp. Value) ;
}
}
else
{
actionDescriptor. RouteConstraints = new List< RouteDataActionConstraint> ( ) ;
foreach ( var kvp in routesInActionDescriptor)
{
actionDescriptor. RouteConstraints. Add ( new RouteDataActionConstraint ( kvp. Key, kvp. Value) ) ;
}
}
return new ActionContext ( httpContext, routeData, actionDescriptor) ;
}
}
}