Commit 0063e84b authored by Shani Elharrar's avatar Shani Elharrar

Modified JsonResponseProvider to handle reference loop by ignoring, Added...

Modified JsonResponseProvider to handle reference loop by ignoring, Added ClassRouter. Bumped version.
parent 3e0b35e6
......@@ -20,10 +20,12 @@ using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Web.UI;
using uhttpsharp;
using uhttpsharp.Handlers;
using uhttpsharp.Headers;
......@@ -31,6 +33,7 @@ using uhttpsharp.Listeners;
using uhttpsharp.ModelBinders;
using uhttpsharp.RequestProviders;
using uhttpsharpdemo.Handlers;
using HttpResponse = System.Web.HttpResponse;
namespace uhttpsharpdemo
{
......@@ -49,6 +52,7 @@ namespace uhttpsharpdemo
//httpServer.Use(new SessionHandler<DateTime>(() => DateTime.Now));
httpServer.Use(new ExceptionHandler());
httpServer.Use(new ClassRouter(new MySuperHandler()));
httpServer.Use(new TimingHandler());
httpServer.Use(new MyHandler());
......@@ -71,16 +75,44 @@ namespace uhttpsharpdemo
}
}
public class MySuperHandler : IHttpRequestHandler
{
public MySuperHandler Child
{
get
{
return new MySuperHandler();
}
}
public Task Handle(IHttpContext context, Func<Task> next)
{
context.Response = uhttpsharp.HttpResponse.CreateWithMessage(HttpResponseCode.Ok, "Hello!", true);
return Task.Factory.GetCompleted();
}
public MySuperHandler this[int index]
{
get
{
return new MySuperHandler();
}
}
}
class MyModel
{
public int MyProperty
{
get; set;
get;
set;
}
public MyModel Model
{
get; set;
get;
set;
}
}
......
......@@ -2,7 +2,7 @@
<package>
<metadata>
<id>uHttpSharp</id>
<version>0.1.4</version>
<version>0.1.4.2</version>
<title>uHttpSharp</title>
<authors>Shani Elharrar, Joe White, Hüseyin Uslu</authors>
<owners>Shani Elharrar, Joe White, Hüseyin Uslu</owners>
......
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace uhttpsharp.Handlers
{
public class ClassRouter : IHttpRequestHandler
{
private static readonly ConcurrentDictionary<Tuple<Type, string>, Func<IHttpRequestHandler, IHttpRequestHandler>>
Routers = new ConcurrentDictionary<Tuple<Type, string>, Func<IHttpRequestHandler, IHttpRequestHandler>>();
private static readonly ConcurrentDictionary<Type, ICollection<string>> PropertySet =
new ConcurrentDictionary<Type, ICollection<string>>();
private static readonly ConcurrentDictionary<Type, Func<IHttpRequestHandler, string, IHttpRequestHandler>>
IndexerRouters = new ConcurrentDictionary<Type, Func<IHttpRequestHandler, string, IHttpRequestHandler>>();
private IHttpRequestHandler _root;
public ClassRouter(IHttpRequestHandler root)
{
_root = root;
}
public Task Handle(IHttpContext context, Func<Task> next)
{
var handler = _root;
foreach (var parameter in context.Request.RequestParameters)
{
var getNextHandler = Routers.GetOrAdd(Tuple.Create(handler.GetType(), parameter), CreateRoute);
if (getNextHandler != null)
{
handler = getNextHandler(handler);
}
else if (!TryGetNextByIndex(parameter, ref handler))
{
return next();
}
// Incase that one of the methods returned null (Indexer / Getter)
if (handler == null)
{
return next();
}
}
return handler.Handle(context, next);
}
private bool TryGetNextByIndex(string parameter, ref IHttpRequestHandler handler)
{
var getNextByIndex = IndexerRouters.GetOrAdd(handler.GetType(), GetIndexerRouter);
if (getNextByIndex == null)
{
return false;
}
handler = getNextByIndex(handler, parameter);
return true;
}
private Func<IHttpRequestHandler, string, IHttpRequestHandler> GetIndexerRouter(Type arg)
{
var indexer = GetIndexer(arg);
if (indexer == null)
{
return null;
}
var parameterType = indexer.GetIndexParameters()[0].ParameterType;
var inputHandler = Expression.Parameter(typeof(IHttpRequestHandler));
var inputObject = Expression.Parameter(typeof(string));
var tryParseMethod = parameterType.GetMethod("TryParse", new[] { typeof(string), parameterType.MakeByRefType() });
Expression body;
if (tryParseMethod == null)
{
var handlerConverted = Expression.Convert(inputHandler, arg);
var objectConverted =
Expression.Convert(
Expression.Call(typeof(Convert).GetMethod("ChangeType", new[] { typeof(object), typeof(Type) }), inputObject,
Expression.Constant(parameterType)), parameterType);
var indexerExpression = Expression.Property(handlerConverted, indexer, objectConverted);
var returnValue = Expression.Convert(indexerExpression, typeof(IHttpRequestHandler));
body = returnValue;
}
else
{
var inputConvertedVar = Expression.Variable(parameterType, "inputObjectConverted");
var handlerConverted = Expression.Convert(inputHandler, arg);
var objectConverted = inputConvertedVar;
var indexerExpression = Expression.Property(handlerConverted, indexer, objectConverted);
var returnValue = Expression.Convert(indexerExpression, typeof(IHttpRequestHandler));
var returnTarget = Expression.Label(typeof(IHttpRequestHandler));
var returnLabel = Expression.Label(returnTarget, Expression.Convert(Expression.Constant(null), typeof(IHttpRequestHandler)));
body =
Expression.Block(
new[] { inputConvertedVar },
Expression.IfThenElse(
Expression.Call(tryParseMethod, inputObject,
inputConvertedVar),
Expression.Return(returnTarget, returnValue),
Expression.Constant(null)
),
returnLabel);
}
return Expression.Lambda<Func<IHttpRequestHandler, string, IHttpRequestHandler>>(body, inputHandler,
inputObject).Compile();
}
private PropertyInfo GetIndexer(Type arg)
{
var indexer = arg.GetProperties()
.SingleOrDefault(p => p.GetIndexParameters().Length == 1 &&
typeof(IHttpRequestHandler).IsAssignableFrom(p.PropertyType));
return indexer;
}
private ICollection<string> GetPropertySet(Type arg)
{
return new HashSet<string>(arg.GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(p => p.Name));
}
private Func<IHttpRequestHandler, IHttpRequestHandler> CreateRoute(Tuple<Type, string> arg)
{
var parameter = Expression.Parameter(typeof(IHttpRequestHandler), "input");
var converted = Expression.Convert(parameter, arg.Item1);
var propertyInfo = arg.Item1.GetProperty(arg.Item2);
if (propertyInfo == null)
{
return null;
}
var property = Expression.Property(converted, propertyInfo);
var propertyConverted = Expression.Convert(property, typeof(IHttpRequestHandler));
return Expression.Lambda<Func<IHttpRequestHandler, IHttpRequestHandler>>(propertyConverted, new[] { parameter }).Compile();
}
}
}
......@@ -10,7 +10,7 @@ namespace uhttpsharp.Handlers
{
var memoryStream = new MemoryStream();
var writer = new JsonTextWriter(new StreamWriter(memoryStream));
var serializer = new JsonSerializer();
var serializer = new JsonSerializer() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, Formatting = Formatting.Indented};
serializer.Serialize(writer, value);
writer.Flush();
return Task.FromResult<IHttpResponse>(new HttpResponse(HttpResponseCode.Ok, "application/json; charset=utf-8", memoryStream, true));
......
......@@ -26,7 +26,7 @@ namespace uhttpsharp.RequestProviders
return null;
}
var httpMethod = HttpMethodProvider.Default.Provide(tokens[0]);
var httpProtocol = tokens[2];
var url = tokens[1];
......@@ -49,6 +49,12 @@ namespace uhttpsharp.RequestProviders
IHttpHeaders headers = new HttpHeaders(headersRaw.ToDictionary(k => k.Key, k => k.Value, StringComparer.InvariantCultureIgnoreCase));
IHttpPost post = await GetPostData(streamReader, headers).ConfigureAwait(false);
string verb;
if (!headers.TryGetByName("_method", out verb))
{
verb = tokens[0];
}
var httpMethod = HttpMethodProvider.Default.Provide(verb);
return new HttpRequest(headers, httpMethod, httpProtocol, uri,
uri.OriginalString.Split(Separators, StringSplitOptions.RemoveEmptyEntries), queryString, post);
}
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.3" targetFramework="net45" />
<package id="Newtonsoft.Json" version="5.0.8" targetFramework="net45" />
<package id="Newtonsoft.Json" version="6.0.1" targetFramework="net45" />
</packages>
\ No newline at end of file
......@@ -39,8 +39,9 @@
<Reference Include="log4net">
<HintPath>..\packages\log4net.2.0.3\lib\net40-full\log4net.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
......@@ -57,6 +58,7 @@
</Compile>
<Compile Include="Clients\ClientSslDecoerator.cs" />
<Compile Include="Clients\IClient.cs" />
<Compile Include="Handlers\ClassRouter.cs" />
<Compile Include="Handlers\FileHandler.cs" />
<Compile Include="Handlers\IResponseProvider.cs" />
<Compile Include="Handlers\IRestController.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment