-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFigaroViewEngine.cs
131 lines (122 loc) · 5.22 KB
/
FigaroViewEngine.cs
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
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using Figaro;
using Nancy.ViewEngines;
namespace Nancy.Demos.Figaro
{
public class FigaroViewEngine : IViewEngine
{
private readonly FigaroDataContext context;
public FigaroViewEngine(FigaroDataContext dataContext)
{
context = dataContext;
}
public void Initialize(ViewEngineStartupContext viewEngineStartupContext)
{
Console.WriteLine("Figaro view engine initialized.");
}
public Response RenderView(ViewLocationResult viewLocationResult, dynamic model, IRenderContext renderContext)
{
var w = new Stopwatch();
w.Start();
//use the snapshot transaction to ensure we don't interrupt any write operations.
int i = 0;
while (true)
{
using (var tx = context.Manager.CreateTransaction(TransactionType.SnapshotTransaction))
{
try
{
//can't put a using on it so let's make sure it gets disposed
QueryContext qc;
//pull the query from the parameter so we can use below (and wrap/dispose our XmlResults appropriately)
string queryContents;
using (var r = viewLocationResult.Contents.Invoke())
{
queryContents = r.ReadToEnd();
}
//currently our model simply passes in a QueryContext if it's needed
if (model == null)
{
qc = context.Manager.CreateQueryContext(EvaluationType.Eager);
}
else
qc = model as QueryContext;
qc?.SetNamespace("db", FigaroDataContext.META_URI);
qc?.SetNamespace("nancy",context.resolver.Uri.ToString());
//http://xqilla.sourceforge.net/ExtensionFunctions
qc?.SetNamespace("xqilla", "http://xqilla.sourceforge.net/Functions");
var sbResp = new StringBuilder();
if (i == 0)
{
var xp = context.Manager.Prepare(tx, queryContents, qc);
Trace.WriteLine(xp.QueryPlan);
Trace.Flush();
xp.Dispose();
}
i++;
using (var results = context.Manager.Query(tx, queryContents, qc))
{
tx.Commit();
while (results.HasNext())
{
var d = results.NextDocument();
if (d != null)
sbResp.Append(d.GetContentAsTextReader().ReadToEnd());
var v = results.NextValue();
if (v != null)
sbResp.Append(v);
}
}
try
{
return new Response
{
Contents = stream =>
{
using (var sr = new StreamWriter(stream))
{
sr.Write(sbResp.ToString());
sr.Flush();
}
}
};
}
finally
{
qc?.Dispose();
}
}
catch(XQueryException ex)
{
Console.WriteLine($"{ex.GetType()}: {ex.Message}, line {ex.QueryLine}, column {ex.QueryColumn}");
throw;
}
catch (XmlException ex)
{
if (!tx.Committed) tx.Abort();
Console.WriteLine($"{DateTime.Now} {ex.ExceptionCategory} in view engine: {ex.Message}");
Console.WriteLine($"{ex.StackTrace}");
if (i == 9) throw;
Thread.Sleep(100);
}
catch(Exception ex)
{
if (!tx.Committed) tx.Abort();
Console.WriteLine($"{ex.GetType()} in view engine: {ex.Message}");
}
finally
{
w.Stop();
Console.WriteLine($"view rendered in {w.ElapsedMilliseconds} ms ");
}
}
}
}
public IEnumerable<string> Extensions => new[] { "xqy", "xq"/*, "xqm"*/ };
}
}