Skip to content

Commit 8a9daee

Browse files
committed
refactor Razor support, decouple internal for IAppHost, allow adhoc razor generation
1 parent 7c088c9 commit 8a9daee

15 files changed

Lines changed: 1281 additions & 1163 deletions

File tree

src/ServiceStack.Razor/Compilation/RazorPageHost.cs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
using ServiceStack.DataAnnotations;
1717
using ServiceStack.Html;
1818
using ServiceStack.IO;
19+
using ServiceStack.Logging;
1920
using ServiceStack.MiniProfiler;
2021
using ServiceStack.Text;
2122

2223
namespace ServiceStack.Razor.Compilation
2324
{
2425
public class RazorPageHost : RazorEngineHost, IRazorHost
2526
{
27+
private static ILog log = LogManager.GetLogger(typeof(RazorPageHost));
28+
2629
private static readonly IEnumerable<string> _defaultImports = new[] {
2730
"System",
2831
"System.Collections.Generic",
@@ -81,7 +84,7 @@ public RazorPageHost(IVirtualPathProvider pathProvider,
8184
templateTypeName: typeof(HelperResult).FullName,
8285
defineSectionMethodName: "DefineSection",
8386
beginContextMethodName: "BeginContext",
84-
endContextMethodName: "EndContext"
87+
endContextMethodName: "EndContext"
8588
)
8689
{
8790
ResolveUrlMethodName = "Href",
@@ -149,10 +152,16 @@ public GeneratorResults Generate()
149152
return results;
150153
}
151154

152-
public Dictionary<string,string> DebugSourceFiles = new Dictionary<string, string>();
155+
public Dictionary<string, string> DebugSourceFiles = new Dictionary<string, string>();
153156

154157
public Type Compile()
155158
{
159+
Type forceLoadOfRuntimeBinder = typeof(Microsoft.CSharp.RuntimeBinder.Binder);
160+
if (forceLoadOfRuntimeBinder == null)
161+
{
162+
log.Warn("Force load of .NET 4.0+ RuntimeBinder in Microsoft.CSharp.dll");
163+
}
164+
156165
var razorResults = Generate();
157166

158167
var @params = new CompilerParameters
@@ -164,7 +173,6 @@ public Type Compile()
164173
TempFiles = { KeepFiles = true }
165174
};
166175

167-
Type forceLoadOfRuntimeBinder = Type.GetType("Microsoft.CSharp.RuntimeBinder.Binder");
168176
var assemblies = CompilerServices
169177
.GetLoadedAssemblies()
170178
.Where(a => !a.IsDynamic)
@@ -178,16 +186,7 @@ public Type Compile()
178186

179187
OnCodeCompletion();
180188

181-
foreach (string tempFile in @params.TempFiles)
182-
{
183-
if (tempFile.EndsWith(".cs"))
184-
{
185-
var src = System.IO.File.ReadAllText(tempFile);
186-
DebugSourceFiles[DefaultClassName] = src;
187-
}
188-
}
189-
190-
var tempFilesMarkedForDeletion = new TempFileCollection(null);
189+
var tempFilesMarkedForDeletion = new TempFileCollection(null);
191190
@params.TempFiles
192191
.OfType<string>()
193192
.ForEach(file => tempFilesMarkedForDeletion.AddFile(file, false));
@@ -205,10 +204,21 @@ public Type Compile()
205204
.FileName;
206205

207206
var sourceCode = "";
208-
if (System.IO.File.Exists(sourceFile))
207+
if (!string.IsNullOrEmpty(sourceFile) && System.IO.File.Exists(sourceFile))
209208
{
210209
sourceCode = System.IO.File.ReadAllText(sourceFile);
211210
}
211+
else
212+
{
213+
foreach (string tempFile in @params.TempFiles)
214+
{
215+
if (tempFile.EndsWith(".cs"))
216+
{
217+
sourceCode = System.IO.File.ReadAllText(tempFile);
218+
}
219+
}
220+
221+
}
212222
throw new HttpCompileException(results, sourceCode);
213223
}
214224

@@ -342,7 +352,7 @@ protected virtual void ModelDirective()
342352

343353
if (_modelStatementFound)
344354
{
345-
Context.OnError(endModelLocation, String.Format(CultureInfo.CurrentCulture,
355+
Context.OnError(endModelLocation, String.Format(CultureInfo.CurrentCulture,
346356
MvcResources.MvcRazorCodeParser_OnlyOneModelStatementIsAllowed, ModelKeyword));
347357
}
348358

@@ -355,7 +365,7 @@ private SpanCodeGenerator CreateModelCodeGenerator(string model)
355365
{
356366
return new SetModelTypeCodeGenerator(model, GenericTypeFormatString);
357367
}
358-
368+
359369
protected override void LayoutDirective()
360370
{
361371
AssertDirective(SyntaxConstants.CSharp.LayoutKeyword);

src/ServiceStack.Razor/DynamicRequestObject.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,38 @@ namespace ServiceStack.Razor
77
{
88
public class DynamicRequestObject : DynamicDictionary
99
{
10-
public IHttpRequest httpReq { get; set; }
10+
private readonly IHttpRequest httpReq;
11+
private readonly IDictionary<string, object> model;
1112

1213
public DynamicRequestObject() { }
13-
public DynamicRequestObject(IHttpRequest httpReq)
14+
public DynamicRequestObject(IHttpRequest httpReq, object model=null)
1415
{
1516
this.httpReq = httpReq;
17+
if (model != null)
18+
{
19+
this.model = new RouteValueDictionary(model);
20+
}
1621
}
1722

1823
public override bool TryGetMember(GetMemberBinder binder, out object result)
1924
{
25+
if (model != null)
26+
{
27+
if (model.TryGetValue(binder.Name, out result))
28+
{
29+
return true;
30+
}
31+
}
32+
2033
result = httpReq.GetParam(binder.Name);
2134
return result != null || base.TryGetMember(binder, out result);
2235
}
2336
}
2437

2538
public class DynamicDictionary : System.Dynamic.DynamicObject, IViewBag
2639
{
27-
readonly Dictionary<string, object> dictionary = new Dictionary<string, object>();
28-
private RenderingPage page;
40+
protected readonly Dictionary<string, object> dictionary = new Dictionary<string, object>();
41+
private readonly RenderingPage page;
2942

3043
public DynamicDictionary() {}
3144

src/ServiceStack.Razor/Managers/FileSystemWatcherLiveReload.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,7 @@ protected virtual void FileSystemWatcher_Renamed(object sender, RenamedEventArgs
6363
Debugger.Break();
6464
}
6565

66-
var newFile = views.GetVirutalFile(e.FullPath);
67-
if (!views.IsWatchedFile(newFile)) return;
68-
69-
views.TrackRazorPage(newFile);
66+
views.AddRazorPage(e.FullPath);
7067
}
7168
catch (Exception ex)
7269
{
@@ -95,10 +92,7 @@ protected virtual void FileSystemWatcher_Created(object sender, FileSystemEventA
9592
{
9693
try
9794
{
98-
var file = views.GetVirutalFile(e.FullPath);
99-
if (!views.IsWatchedFile(file)) return;
100-
101-
views.TrackRazorPage(file);
95+
views.AddRazorPage(e.FullPath);
10296
}
10397
catch (Exception ex)
10498
{

src/ServiceStack.Razor/Managers/PageResolver.cs

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
using System.Web;
77
using ServiceStack.Common;
88
using ServiceStack.Common.Web;
9-
using ServiceStack.DataAnnotations;
109
using ServiceStack.Html;
1110
using ServiceStack.ServiceHost;
1211
using ServiceStack.Text;
13-
using ServiceStack.WebHost.Endpoints;
1412
using ServiceStack.WebHost.Endpoints.Extensions;
1513
using ServiceStack.WebHost.Endpoints.Support;
1614

1715
namespace ServiceStack.Razor.Managers
1816
{
17+
public delegate string RenderPartialDelegate(string pageName, object model, bool renderHtml, StreamWriter writer = null, HtmlHelper htmlHelper = null, IHttpRequest httpReq = null);
18+
1919
/// <summary>
2020
/// A common hook into ServiceStack and the hosting infrastructure used to resolve requests.
2121
/// </summary>
@@ -25,24 +25,19 @@ public class PageResolver : EndpointHandlerBase, IViewEngine
2525

2626
private static readonly UTF8Encoding UTF8EncodingWithoutBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier:false);
2727

28-
private readonly IAppHost appHost;
2928
private readonly IRazorConfig config;
3029
private readonly ViewManager viewManager;
30+
public RenderPartialDelegate RenderPartialFn { get; set; }
3131

32-
public PageResolver(IAppHost appHost, IRazorConfig config, ViewManager viewManager)
32+
public PageResolver(IRazorConfig config, ViewManager viewManager)
3333
{
3434
this.RequestName = "Razor_PageResolver";
3535

36-
this.appHost = appHost;
37-
3836
this.config = config;
3937
this.viewManager = viewManager;
40-
41-
this.appHost.CatchAllHandlers.Add(OnCatchAll);
42-
this.appHost.ViewEngines.Add(this);
4338
}
4439

45-
private IHttpHandler OnCatchAll(string httpmethod, string pathInfo, string filepath)
40+
public IHttpHandler CatchAllHandler(string httpmethod, string pathInfo, string filepath)
4641
{
4742
//does not have a .cshtml extension
4843
var ext = Path.GetExtension(pathInfo);
@@ -63,7 +58,7 @@ private IHttpHandler OnCatchAll(string httpmethod, string pathInfo, string filep
6358
? pathInfo.Substring(0, pathInfo.Length - config.DefaultPageName.Length)
6459
: pathInfo.WithoutExtension();
6560

66-
var webHostUrl = appHost.Config.WebHostUrl;
61+
var webHostUrl = config.WebHostUrl;
6762
return new RedirectHttpHandler
6863
{
6964
AbsoluteUrl = webHostUrl.IsNullOrEmpty()
@@ -109,29 +104,29 @@ public virtual bool ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes,
109104
return true;
110105
}
111106

112-
public void ResolveAndExecuteRazorPage(IHttpRequest httpReq, IHttpResponse httpRes, object dto, RazorPage razorView=null)
107+
public void ResolveAndExecuteRazorPage(IHttpRequest httpReq, IHttpResponse httpRes, object dto, RazorPage razorPage=null)
113108
{
114109
var viewName = httpReq.GetItem("View") as string;
115-
if (razorView == null && viewName != null)
110+
if (razorPage == null && viewName != null)
116111
{
117-
razorView = this.viewManager.GetRazorViewByName(viewName);
112+
razorPage = this.viewManager.GetRazorViewByName(viewName);
118113
}
119114
else
120115
{
121-
razorView = razorView
116+
razorPage = razorPage
122117
?? this.viewManager.GetRazorViewByName(httpReq.OperationName) //Request DTO
123118
?? this.viewManager.GetRazorView(httpReq, dto); // Response DTO
124119
}
125120

126-
if (razorView == null)
121+
if (razorPage == null)
127122
{
128123
httpRes.StatusCode = (int)HttpStatusCode.NotFound;
129124
return;
130125
}
131126

132127
using (var writer = new StreamWriter(httpRes.OutputStream, UTF8EncodingWithoutBom))
133128
{
134-
var page = CreateRazorPageInstance(httpReq, httpRes, dto, razorView);
129+
var page = CreateRazorPageInstance(httpReq, httpRes, dto, razorPage);
135130

136131
var includeLayout = !(httpReq.GetParam("format") ?? "").Contains("bare");
137132
if (includeLayout)
@@ -147,17 +142,19 @@ public void ResolveAndExecuteRazorPage(IHttpRequest httpReq, IHttpResponse httpR
147142
?? DefaultLayoutName;
148143

149144
var layoutView = this.viewManager.GetRazorViewByName(layout, httpReq, dto);
150-
var layoutPage = CreateRazorPageInstance(httpReq, httpRes, dto, layoutView);
151-
152-
var childBody = ms.ToArray().FromUtf8Bytes();
153-
layoutPage.SetChildPage(page, childBody);
154-
layoutPage.WriteTo(writer);
145+
if (layoutView != null)
146+
{
147+
var layoutPage = CreateRazorPageInstance(httpReq, httpRes, dto, layoutView);
148+
149+
var childBody = ms.ToArray().FromUtf8Bytes();
150+
layoutPage.SetChildPage(page, childBody);
151+
layoutPage.WriteTo(writer);
152+
return;
153+
}
155154
}
156155
}
157-
else
158-
{
159-
page.WriteTo(writer);
160-
}
156+
157+
page.WriteTo(writer);
161158
}
162159
}
163160

@@ -173,9 +170,9 @@ public void EnsureCompiled(RazorPage page, IHttpResponse response)
173170
page.IsValid = true;
174171
}
175172

176-
private IRazorViewPage CreateRazorPageInstance(IHttpRequest request, IHttpResponse response, object dto, RazorPage razorPage)
173+
private IRazorViewPage CreateRazorPageInstance(IHttpRequest httpReq, IHttpResponse httpRes, object dto, RazorPage razorPage)
177174
{
178-
EnsureCompiled(razorPage, response);
175+
EnsureCompiled(razorPage, httpRes);
179176

180177
//don't proceed any further, the background compiler found there was a problem compiling the page, so throw instead
181178
if (razorPage.CompileException != null)
@@ -186,10 +183,10 @@ private IRazorViewPage CreateRazorPageInstance(IHttpRequest request, IHttpRespon
186183
//else, EnsureCompiled() ensures we have a page type to work with so, create an instance of the page
187184
var page = (IRazorViewPage) razorPage.ActivateInstance();
188185

189-
page.Init(viewEngine: this, httpReq: request, httpRes: response);
186+
page.Init(viewEngine: this, httpReq: httpReq, httpRes: httpRes);
190187

191188
//deserialize the model.
192-
PrepareAndSetModel(page, request, dto);
189+
PrepareAndSetModel(page, httpReq, dto);
193190

194191
return page;
195192
}
@@ -200,7 +197,7 @@ private void PrepareAndSetModel(IRazorViewPage page, IHttpRequest httpReq, objec
200197
if (hasModel == null) return;
201198

202199
if (hasModel.ModelType == typeof (DynamicRequestObject))
203-
dto = new DynamicRequestObject(httpReq);
200+
dto = new DynamicRequestObject(httpReq, dto);
204201

205202
var model = dto ?? DeserializeHttpRequest(hasModel.ModelType, httpReq, httpReq.ContentType);
206203

@@ -234,17 +231,17 @@ public virtual string RenderPartial(string pageName, object model, bool renderHt
234231
}
235232
else
236233
{
237-
foreach (var viewEngine in appHost.ViewEngines)
234+
if (RenderPartialFn != null)
235+
{
236+
RenderPartialFn(pageName, model, renderHtml, writer, htmlHelper, httpReq);
237+
}
238+
else
238239
{
239-
if (viewEngine == this || !viewEngine.HasView(pageName, httpReq)) continue;
240-
viewEngine.RenderPartial(pageName, model, renderHtml, writer, htmlHelper);
241-
return null;
240+
writer.Write("<!--No RenderPartialFn, skipping {0}-->".Fmt(pageName));
242241
}
243-
writer.Write("<!--{0} not found-->".Fmt(pageName));
244242
}
245243
return null;
246244
}
247-
248245
}
249246

250247
}

0 commit comments

Comments
 (0)