forked from NancyFx/Nancy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUglifiedNancyModule.cs
More file actions
153 lines (118 loc) · 4.66 KB
/
Copy pathUglifiedNancyModule.cs
File metadata and controls
153 lines (118 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
namespace Nancy.Demo.CustomModule
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Nancy.ModelBinding;
using Nancy.Responses.Negotiation;
using Nancy.Routing;
using Nancy.Validation;
using Nancy.ViewEngines;
/// <summary>
/// A custom INancyModule implementation that uses
/// attributes on methods (eugh!) to define routes.
/// Nobody in their right mind would write a web framework
/// that uses attributes for routing ;-)
/// </summary>
public abstract class UglifiedNancyModule : INancyModule
{
public AfterPipeline After { get; set; }
public BeforePipeline Before { get; set; }
public ErrorPipeline OnError { get; set; }
public NancyContext Context { get; set; }
public IResponseFormatter Response { get; set; }
public IModelBinderLocator ModelBinderLocator { get; set; }
public ModelValidationResult ModelValidationResult { get; set; }
public IModelValidatorLocator ValidatorLocator { get; set; }
public Request Request { get; set; }
public IViewFactory ViewFactory { get; set; }
public string ModulePath { get; private set; }
public ViewRenderer View
{
get { return new ViewRenderer(this); }
}
public Negotiator Negotiate
{
get { return new Negotiator(this.Context); }
}
public UglifiedNancyModule()
: this(string.Empty)
{
}
public IEnumerable<Route> Routes
{
get
{
return this.GetRoutes();
}
}
public dynamic Text { get; set; }
private UglifiedNancyModule(string modulePath)
{
this.After = new AfterPipeline();
this.Before = new BeforePipeline();
this.OnError = new ErrorPipeline();
this.ModulePath = modulePath;
}
private IEnumerable<Route> GetRoutes()
{
// Run through all the methods on the class looking
// for our attribute. If we were to do this for a real
// app we'd be checking parameters and return types etc
// but for simplicity we won't bother here.
var routes = new List<Route>();
var type = this.GetType();
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
foreach (var method in methods)
{
var attribute = method.GetCustomAttributes(typeof(NancyRouteAttribute), false).FirstOrDefault() as NancyRouteAttribute;
if (attribute == null)
{
continue;
}
var routeDelegate = WrapFunc((Func<dynamic, dynamic>)Delegate.CreateDelegate(typeof(Func<dynamic, dynamic>), this, method.Name));
var filter = this.GetFilter(method.Name);
var fullPath = String.Concat(this.ModulePath, attribute.Path);
routes.Add(new Route(attribute.Method.ToUpper(), fullPath, filter, routeDelegate));
}
return routes.AsReadOnly();
}
private Func<NancyContext, bool> GetFilter(string routeMethodName)
{
var type = this.GetType();
var method = type.GetMethod(routeMethodName + "Filter", BindingFlags.Public | BindingFlags.Instance);
if (method == null)
{
return null;
}
return (Func<NancyContext, bool>)Delegate.CreateDelegate(typeof(Func<NancyContext, bool>), this, method.Name);
}
/// <summary>
/// Wraps a sync delegate in a delegate that returns a task
/// </summary>
/// <param name="syncFunc">Sync delegate</param>
/// <returns>Task wrapped version</returns>
private static Func<dynamic, CancellationToken, Task<dynamic>> WrapFunc(Func<object, object> syncFunc)
{
return (p, ct) =>
{
var tcs = new TaskCompletionSource<dynamic>();
try
{
var result = syncFunc.Invoke(p);
tcs.SetResult(result);
}
catch (Exception e)
{
tcs.SetException(e);
}
return tcs.Task;
};
}
}
}