Permalink
Browse files

Rejigged RoutingTable

  • Loading branch information...
1 parent 48380d9 commit 73fddcef594bb7ec25236b2945346c441de3a11b @markrendle committed Apr 6, 2012
@@ -17,7 +17,7 @@ internal NinjectContainer(IKernel kernel)
public T Get<T>()
{
- return _kernel.Get<T>();
+ return _kernel.TryGet<T>();
}
}
@@ -1,6 +1,8 @@
namespace Simple.Web.Razor
{
+ using System;
using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.IO;
@@ -23,6 +25,22 @@ public virtual void WriteLiteral(object value)
Trace.Write(value);
}
+ //public virtual void WriteAttribute(object value)
+ //{
+ // Writer.Write(value);
+ // Trace.Write(value);
+ //}
+
+ public virtual void WriteAttribute(string attributeName, AttributePart prefix, AttributePart suffix, params AttributeValue[] values)
+ {
+ WriteLiteral(prefix);
+ for (int i = 0; i < values.Length; i++)
+ {
+ Write(values[i]);
+ }
+ WriteLiteral(suffix);
+ }
+
public virtual void SetModel(object model)
{
@@ -35,6 +53,72 @@ internal protected dynamic Var
}
}
+ public class AttributePart
+ {
+ private readonly object _value;
+ private readonly int _position;
+
+ private AttributePart(object value, int position)
+ {
+ _value = value;
+ _position = position;
+ }
+
+ public static implicit operator AttributePart(Tuple<string,int> source)
+ {
+ return new AttributePart(source.Item1, source.Item2);
+ }
+
+ public static implicit operator AttributePart(Tuple<object,int> source)
+ {
+ return new AttributePart(source.Item1, source.Item2);
+ }
+
+ public override string ToString()
+ {
+ return _value.ToString();
+ }
+
+ public string ToString(IFormatProvider formatProvider)
+ {
+ return Convert.ToString(_value, formatProvider);
+ }
+ }
+
+ public class AttributeValue
+ {
+ private readonly AttributePart _prefix;
+ private readonly AttributePart _value;
+ private readonly bool _literal;
+
+ private AttributeValue(AttributePart prefix, AttributePart value, bool literal)
+ {
+ _prefix = prefix;
+ _value = value;
+ _literal = literal;
+ }
+
+ public static implicit operator AttributeValue(Tuple<Tuple<string, int>, Tuple<object, int>, bool> value)
+ {
+ return new AttributeValue(value.Item1, value.Item2, value.Item3);
+ }
+
+ public static implicit operator AttributeValue(Tuple<Tuple<string, int>, Tuple<string, int>, bool> value)
+ {
+ return new AttributeValue(value.Item1, value.Item2, value.Item3);
+ }
+
+ public override string ToString()
+ {
+ return _prefix.ToString() + _value;
+ }
+
+ public string ToString(IFormatProvider formatProvider)
+ {
+ return _prefix.ToString(formatProvider) + _value.ToString(formatProvider);
+ }
+ }
+
public abstract class SimpleTemplateBase<TModel> : SimpleTemplateBase
{
private TModel _model;
@@ -47,6 +47,8 @@ public MockContext()
public IRequest Request { get; set; }
public IResponse Response { get; set; }
+
+ public IUser User { get; set; }
}
class MockRequest : IRequest
@@ -16,6 +16,14 @@ public void FindsIGetType()
var table = builder.BuildRoutingTable();
Assert.Contains(typeof(GetFoo), table.GetAllTypes());
}
+
+ [Fact]
+ public void FindsIGetTypeWhereIGetIsOnBaseClass()
+ {
+ var builder = new RoutingTableBuilder(typeof (IGet));
+ var table = builder.BuildRoutingTable();
+ Assert.Contains(typeof(Bar), table.GetAllTypes());
+ }
}
[UriTemplate("/foo")]
@@ -44,4 +52,18 @@ public object Output
get { throw new NotImplementedException(); }
}
}
+
+ public abstract class BaseBar : IGet
+ {
+ public Status Get()
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [UriTemplate(("/bar"))]
+ public class Bar : BaseBar
+ {
+
+ }
}
@@ -74,7 +74,6 @@ public void MatchesDynamicUrlWithTrailingValues()
Assert.Equal(expected, actual);
}
-
[Fact]
public void MatchesDynamicUrlWithTrailingValuesAheadOfMultiValue()
{
@@ -86,5 +85,18 @@ public void MatchesDynamicUrlWithTrailingValuesAheadOfMultiValue()
var actual = target.Get("/tests/1/bar", out variables);
Assert.Equal(expected, actual);
}
+
+ [Fact]
+ public void MatchesUrlWhenTwoRegexesHaveSameNumberOfGroups()
+ {
+ var target = new RoutingTable();
+ var expectedFoo = typeof(int);
+ var expectedBar = typeof(string);
+ target.Add("/tests/{Id}/foo", expectedFoo);
+ target.Add("/tests/{Id}/bar", expectedBar);
+ IDictionary<string, string> variables;
+ Assert.Equal(expectedFoo, target.Get("/tests/1/foo", out variables));
+ Assert.Equal(expectedBar, target.Get("/tests/1/bar", out variables));
+ }
}
}
@@ -4,7 +4,7 @@
<s:Boolean x:Key="/Default/Housekeeping/SolutionSettingsUpgraded/IsUpgraded/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Housekeeping/UnitTestingMru/UnitTestSessionPersistentData/=D6FBE422192C450E8EFA1C5073AAEEF5/@KeyIndexDefined">True</s:Boolean>
<s:String x:Key="/Default/Housekeeping/UnitTestingMru/UnitTestSessionPersistentData/=D6FBE422192C450E8EFA1C5073AAEEF5/Name/@EntryValue">RazorHtmlContentTypeHandlerTests</s:String>
- <s:String x:Key="/Default/Housekeeping/UnitTestingMru/UnitTestSessionPersistentData/=D6FBE422192C450E8EFA1C5073AAEEF5/XmlSerializedElements/@EntryValue">&lt;Session&gt;&lt;Elements /&gt;&lt;/Session&gt;</s:String>
+ <s:String x:Key="/Default/Housekeeping/UnitTestingMru/UnitTestSessionPersistentData/=D6FBE422192C450E8EFA1C5073AAEEF5/XmlSerializedElements/@EntryValue">&lt;Session&gt;&lt;Elements&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableBuilderTests" type="XunitTestClassElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableBuilderTests" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestClassElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableBuilderTests.FindsIGetTypeWhereIGetIsOnBaseClass" ParentId="xunit:Simple.Web.Tests.RoutingTableBuilderTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableBuilderTests" methodName="FindsIGetTypeWhereIGetIsOnBaseClass" skipReason="" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests.MatchesDynamicUrlWithOneVariable" ParentId="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" methodName="MatchesDynamicUrlWithOneVariable" skipReason="" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests.MatchesDynamicUrlWithTrailingValues" ParentId="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" methodName="MatchesDynamicUrlWithTrailingValues" skipReason="" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests.MatchesDynamicUrlWithTrailingValuesAheadOfMultiValue" ParentId="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" methodName="MatchesDynamicUrlWithTrailingValuesAheadOfMultiValue" skipReason="" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests.MatchesDynamicUrlWithTwoVariables" ParentId="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" methodName="MatchesDynamicUrlWithTwoVariables" skipReason="" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests.MatchesStaticUrl" ParentId="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" methodName="MatchesStaticUrl" skipReason="" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests.MatchesStaticUrlEndingInSlash" ParentId="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" methodName="MatchesStaticUrlEndingInSlash" skipReason="" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests.MatchesStaticUrlNotEndingInSlash" ParentId="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" methodName="MatchesStaticUrlNotEndingInSlash" skipReason="" /&gt;&lt;UnitTestElement Provider="xUnit" Id="xunit:Simple.Web.Tests.RoutingTableTests.MatchesUrlWhenTwoRegexesHaveSameNumberOfGroups" ParentId="xunit:Simple.Web.Tests.RoutingTableTests" type="XunitTestMethodElement" projectId="29FBE3C3-4CB4-4625-8AA7-C748E1F0D2BA" typeName="Simple.Web.Tests.RoutingTableTests" methodName="MatchesUrlWhenTwoRegexesHaveSameNumberOfGroups" skipReason="" /&gt;&lt;/Elements&gt;&lt;/Session&gt;</s:String>
</wpf:ResourceDictionary>
@@ -86,11 +86,14 @@ static class ExportedTypeHelper
{
public static IEnumerable<Type> FromCurrentAppDomain(Func<Type,bool> predicate)
{
- return AppDomain.CurrentDomain.GetAssemblies()
+ var list = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic)
.Select(assembly =>
assembly.GetExportedTypes().Where(predicate).ToList())
- .SelectMany(exportedTypes => exportedTypes);
+ .SelectMany(exportedTypes => exportedTypes)
+ .ToList();
+
+ return list;
}
}
}
@@ -17,6 +17,8 @@ public EndpointInfo(Type endpointType, string httpMethod)
public EndpointInfo(Type endpointType, IDictionary<string, string> variables, string httpMethod)
{
+ if (endpointType == null) throw new ArgumentNullException("endpointType");
+ if (httpMethod == null) throw new ArgumentNullException("httpMethod");
_endpointType = endpointType;
_variables = variables;
_httpMethod = httpMethod;
@@ -37,6 +39,11 @@ public Type EndpointType
get { return _endpointType; }
}
+ public bool RequiresAuthentication
+ {
+ get { return typeof (IRequireAuthentication).IsAssignableFrom(_endpointType); }
+ }
+
public Type InputType
{
get { return GetInterfaceGenericType(typeof (IInput<>)); }
@@ -0,0 +1,15 @@
+namespace Simple.Web
+{
+ public interface IAuthenticationProvider
+ {
+ IUser GetLoggedInUser(IContext context);
+ }
+
+ class AuthenticationProvider : IAuthenticationProvider
+ {
+ public IUser GetLoggedInUser(IContext context)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}
@@ -2,6 +2,6 @@
{
public interface IRequireAuthentication
{
- IUser CurrentUser { get; set; }
+ IUser CurrentUser { set; }
}
}
View
@@ -9,8 +9,16 @@ namespace Simple.Web
internal class RoutingTable
{
- private readonly Dictionary<string,IList<EndpointTypeInfo>> _staticPaths = new Dictionary<string, IList<EndpointTypeInfo>>();
- private readonly SortedDictionary<Regex, IList<EndpointTypeInfo>> _dynamicPaths = new SortedDictionary<Regex, IList<EndpointTypeInfo>>(new Comparer<Regex>((x,y) => x.GetGroupNames().Length.CompareTo(y.GetGroupNames().Length)));
+ private const int MaximumGroupCount = 64;
+ private readonly Dictionary<string, IList<EndpointTypeInfo>> _staticPaths =
+ new Dictionary<string, IList<EndpointTypeInfo>>(StringComparer.OrdinalIgnoreCase);
+
+ private readonly List<SortedList<Regex, IList<EndpointTypeInfo>>> _dynamicPaths;
+
+ public RoutingTable()
+ {
+ _dynamicPaths = new List<SortedList<Regex, IList<EndpointTypeInfo>>>(GenerateEmptyLists());
+ }
public Type Get(string url, out IDictionary<string,string> variables)
{
@@ -44,21 +52,27 @@ private IEnumerable<EndpointTypeInfo> GetTypesForStatic(string url)
private IEnumerable<EndpointTypeInfo> GetTypesForDynamic(string url, out IDictionary<string, string> variables)
{
- var entry = _dynamicPaths.FirstOrDefault(t => t.Key.IsMatch(url));
- if (entry.Key == null)
+ for (int i = 0; i < MaximumGroupCount; i++)
{
- variables = null;
- return null;
- }
+ if (_dynamicPaths[i].Count == 0) continue;
- variables = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- var match = entry.Key.Match(url);
- foreach (var groupName in entry.Key.GetGroupNames())
- {
- if (groupName == "0") continue;
- variables.Add(groupName, match.Groups[groupName].Value);
+ var entry = _dynamicPaths[i].FirstOrDefault(t => t.Key.IsMatch(url));
+ if (entry.Key == null)
+ {
+ continue;
+ }
+
+ variables = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ var match = entry.Key.Match(url);
+ foreach (var groupName in entry.Key.GetGroupNames())
+ {
+ if (groupName == "0") continue;
+ variables.Add(groupName, match.Groups[groupName].Value);
+ }
+ return entry.Value;
}
- return entry.Value;
+ variables = null;
+ return null;
}
public void Add(string uriTemplate, Type endpointType)
@@ -71,7 +85,7 @@ public void Add(string uriTemplate, EndpointTypeInfo endpointType)
if (uriTemplate.Contains("{"))
{
var regex = new Regex(Regex.Replace(uriTemplate, "{([^}]*)}", "(?<$1>[^/]*)"), RegexOptions.IgnoreCase);
- _dynamicPaths.Add(regex, new[] {endpointType});
+ _dynamicPaths[regex.GetGroupNames().Length].Add(regex, new[] {endpointType});
}
else
{
@@ -90,8 +104,19 @@ public void Add(string uriTemplate, EndpointTypeInfo endpointType)
public IEnumerable<Type> GetAllTypes()
{
return _staticPaths.Values.SelectMany(list => list.Select(eti => eti.EndpointType))
- .Concat(_dynamicPaths.Values.SelectMany(list => list.Select(eti => eti.EndpointType)))
+ .Concat(_dynamicPaths.SelectMany(l => l.Values.SelectMany(t => t)).Select(e => e.EndpointType))
.Distinct();
}
+
+ private static IEnumerable<SortedList<Regex, IList<EndpointTypeInfo>>> GenerateEmptyLists()
+ {
+ var regexTermComparer =
+ new Comparer<Regex>(
+ (regex, regex1) => StringComparer.OrdinalIgnoreCase.Compare(regex.ToString(), regex1.ToString()));
+ for (int i = 0; i < MaximumGroupCount; i++)
+ {
+ yield return new SortedList<Regex, IList<EndpointTypeInfo>>(regexTermComparer);
+ }
+ }
}
}
@@ -62,6 +62,7 @@
<Compile Include="GetRunner.cs" />
<Compile Include="HandlerBase.cs" />
<Compile Include="HeaderCollection.cs" />
+ <Compile Include="IAuthenticationProvider.cs" />
<Compile Include="IConfiguration.cs" />
<Compile Include="IContentTypeHandler.cs" />
<Compile Include="IContext.cs" />
Oops, something went wrong.

0 comments on commit 73fddce

Please sign in to comment.