diff --git a/src/ServiceStack/HttpHandlerFactory.cs b/src/ServiceStack/HttpHandlerFactory.cs index b0ebe4e04e1..50511c643c4 100644 --- a/src/ServiceStack/HttpHandlerFactory.cs +++ b/src/ServiceStack/HttpHandlerFactory.cs @@ -290,13 +290,7 @@ public static IHttpHandler GetHandlerForPathInfo(IHttpRequest httpReq, string fi : ForbiddenHttpHandler; } - if (appHost.Config.FallbackRestPath != null) - { - restPath = appHost.Config.FallbackRestPath(httpReq); - if (restPath != null) - return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType }; - } - + // Check for PagedBasedRouting before wildcard Fallback Service foreach (var httpHandlerResolver in appHost.FallbackHandlersArray) { var httpHandler = httpHandlerResolver(httpMethod, pathInfo, filePath); @@ -304,6 +298,13 @@ public static IHttpHandler GetHandlerForPathInfo(IHttpRequest httpReq, string fi return httpHandler; } + if (appHost.Config.FallbackRestPath != null) + { + restPath = appHost.Config.FallbackRestPath(httpReq); + if (restPath != null) + return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType }; + } + return null; } diff --git a/src/ServiceStack/TemplateBootstrapFilters.cs b/src/ServiceStack/TemplateBootstrapFilters.cs index 75c54e5dcde..4a25936436b 100644 --- a/src/ServiceStack/TemplateBootstrapFilters.cs +++ b/src/ServiceStack/TemplateBootstrapFilters.cs @@ -222,7 +222,7 @@ public IRawString formControl(TemplateScopeContext scope, object inputAttrs, str var cls = inline ? " custom-control-inline" : ""; sbInput.AppendLine($"
"); var inputId = name + "-" + kvp.Key; - var selected = selectedValues.Contains(formValue) || selectedValues.Contains(kvp.Key) ? " checked" : ""; + var selected = kvp.Key == formValue || selectedValues.Contains(kvp.Key) ? " checked" : ""; sbInput.AppendLine($" "); sbInput.AppendLine($" "); sbInput.AppendLine("
"); diff --git a/src/ServiceStack/TemplatePagesFeature.cs b/src/ServiceStack/TemplatePagesFeature.cs index 7958b143439..4c312632b05 100644 --- a/src/ServiceStack/TemplatePagesFeature.cs +++ b/src/ServiceStack/TemplatePagesFeature.cs @@ -447,6 +447,21 @@ public async Task ProcessRequestAsync(IRequest req, object dto, Stream out } } + TemplatePage layoutPage = null; + var layoutName = req.GetItem(Keywords.Template) as string; + Dictionary args = null; + + if (codePage == null && viewPage == null && explicitView != null) + { + if (PageBasedRoutingHandler(req.Verb, explicitView, null) is TemplatePageHandler pageHandler) + { + viewPage = pageHandler.Page; + args = pageHandler.Args; + if (layoutName == null) + layoutPage = pageHandler.LayoutPage; + } + } + if (codePage == null && viewPage == null) return false; @@ -455,14 +470,13 @@ public async Task ProcessRequestAsync(IRequest req, object dto, Stream out else await viewPage.Init(); - var layoutName = req.GetItem(Keywords.Template) as string; - var layoutPage = codePage != null + layoutPage = layoutPage ?? (codePage != null ? Pages.ResolveLayoutPage(codePage, layoutName) - : Pages.ResolveLayoutPage(viewPage, layoutName); - + : Pages.ResolveLayoutPage(viewPage, layoutName)); + var handler = codePage != null ? (HttpAsyncTaskHandler)new TemplateCodePageHandler(codePage, layoutPage) { OutputStream = outputStream, Model = dto } - : new TemplatePageHandler(viewPage, layoutPage) { OutputStream = outputStream, Model = dto }; + : new TemplatePageHandler(viewPage, layoutPage) { OutputStream = outputStream, Model = dto, Args = args }; await handler.ProcessRequestAsync(req, req.Response, req.OperationName); @@ -810,8 +824,8 @@ public object Any(TemplatesAdmin request) public class TemplatePageHandler : HttpAsyncTaskHandler { - private TemplatePage page; - private TemplatePage layoutPage; + public TemplatePage Page { get; private set; } + public TemplatePage LayoutPage { get; private set; } public Dictionary Args { get; set; } public object Model { get; set; } public Stream OutputStream { get; set; } @@ -827,21 +841,21 @@ public TemplatePageHandler(string pagePath, string layoutPath=null) public TemplatePageHandler(TemplatePage page, TemplatePage layoutPage = null) { this.RequestName = !string.IsNullOrEmpty(page.VirtualPath) ? page.VirtualPath : nameof(TemplatePageHandler); - this.page = page; - this.layoutPage = layoutPage; + this.Page = page; + this.LayoutPage = layoutPage; } public override async Task ProcessRequestAsync(IRequest httpReq, IResponse httpRes, string operationName) { - if (page == null && pagePath != null) + if (Page == null && pagePath != null) { var pages = httpReq.TryResolve(); - page = pages.GetPage(pagePath) + Page = pages.GetPage(pagePath) ?? throw new FileNotFoundException($"Template Page not found '{pagePath}'"); if (!string.IsNullOrEmpty(layoutPath)) { - layoutPage = pages.GetPage(layoutPath) + LayoutPage = pages.GetPage(layoutPath) ?? throw new FileNotFoundException($"Template Page not found '{layoutPath}'"); } } @@ -857,16 +871,16 @@ public override async Task ProcessRequestAsync(IRequest httpReq, IResponse httpR } } - var pageResult = new PageResult(page) + var pageResult = new PageResult(Page) { Args = args, - LayoutPage = layoutPage, + LayoutPage = LayoutPage, Model = Model, }; try { - httpRes.ContentType = page.Format.ContentType; + httpRes.ContentType = Page.Format.ContentType; if (OutputStream != null) { await pageResult.WriteToAsync(OutputStream); @@ -900,7 +914,7 @@ public override async Task ProcessRequestAsync(IRequest httpReq, IResponse httpR } catch (Exception ex) { - await page.Format.OnViewException(pageResult, httpReq, ex); + await Page.Format.OnViewException(pageResult, httpReq, ex); } } } @@ -911,6 +925,8 @@ public class TemplateCodePageHandler : HttpAsyncTaskHandler private readonly TemplatePage layoutPage; public object Model { get; set; } public Stream OutputStream { get; set; } + + public Dictionary Args { get; set; } public TemplateCodePageHandler(TemplateCodePage page, TemplatePage layoutPage = null) { @@ -933,6 +949,14 @@ public override async Task ProcessRequestAsync(IRequest httpReq, IResponse httpR Model = Model, }; + if (Args != null) + { + foreach (var entry in Args) + { + result.Args[entry.Key] = entry.Value; + } + } + try { httpRes.ContentType = page.Format.ContentType; diff --git a/tests/CheckWebCore/wwwroot/_layout.html b/tests/CheckWebCore/wwwroot/_layout.html index c608c7ae211..42f56e63065 100644 --- a/tests/CheckWebCore/wwwroot/_layout.html +++ b/tests/CheckWebCore/wwwroot/_layout.html @@ -29,10 +29,10 @@

MyApp

-
+
-

{{ title }}

+ {{#if title}}

{{ title }}

{{/if}} {{ page }}
diff --git a/tests/CheckWebCore/wwwroot/validation/server-js/contacts/edit.html b/tests/CheckWebCore/wwwroot/validation/server-js/contacts/_id/edit.html similarity index 71% rename from tests/CheckWebCore/wwwroot/validation/server-js/contacts/edit.html rename to tests/CheckWebCore/wwwroot/validation/server-js/contacts/_id/edit.html index a90b5ce8760..817c318249c 100644 --- a/tests/CheckWebCore/wwwroot/validation/server-js/contacts/edit.html +++ b/tests/CheckWebCore/wwwroot/validation/server-js/contacts/_id/edit.html @@ -2,13 +2,13 @@ {{ '/validation/server-js/contacts/' | assignTo: continue }} -{{ { Id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} +{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} {{#with response.Result}}

Update Contact

-
+
@@ -35,7 +35,19 @@

Update Contact

- + +
+ {{#each contactGenres}} +
+ x == toString(it))} | htmlAttrs }}> + +
+ {{/each}} +
+
+
+
diff --git a/tests/CheckWebCore/wwwroot/validation/server-js/contacts/index.html b/tests/CheckWebCore/wwwroot/validation/server-js/contacts/index.html index 2b7aefbe179..5392ee4f95f 100644 --- a/tests/CheckWebCore/wwwroot/validation/server-js/contacts/index.html +++ b/tests/CheckWebCore/wwwroot/validation/server-js/contacts/index.html @@ -30,7 +30,18 @@

Add new Contact

- + +
+ {{#each contactGenres}} +
+ + +
+ {{/each}} +
+
+
+
@@ -75,7 +86,7 @@

Add new Contact

function contactRow(contact) { return '' + '' + contact.title + ' ' + contact.name + ' (' + contact.age + ')' + - 'edit' + + 'edit' + '' + ''; } diff --git a/tests/CheckWebCore/wwwroot/validation/server/contacts/edit.html b/tests/CheckWebCore/wwwroot/validation/server/contacts/_id/edit.html similarity index 90% rename from tests/CheckWebCore/wwwroot/validation/server/contacts/edit.html rename to tests/CheckWebCore/wwwroot/validation/server/contacts/_id/edit.html index c472061cab9..958a4745760 100644 --- a/tests/CheckWebCore/wwwroot/validation/server/contacts/edit.html +++ b/tests/CheckWebCore/wwwroot/validation/server/contacts/_id/edit.html @@ -2,7 +2,7 @@ {{ '/validation/server/contacts/' | assignTo: continue }} -{{ { Id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} +{{ { id } | sendToGateway('GetContact', {catchError:'ex'}) | assignTo: response }} {{#with response.Result}}

Update Contact

@@ -10,7 +10,7 @@

Update Contact

{{ 'title,name,color,filmGenres,age' | validationSummary }} - {{ {Id,continue,errorView:"/validation/server/contacts/edit"} | htmlHiddenInputs }} + {{ {continue,errorView:`/validation/server/contacts/${id}/edit`} | htmlHiddenInputs }}
{{ {id:'title',type:'radio',value:Title} | formInput({values:contactTitles,inline:true}) }} diff --git a/tests/CheckWebCore/wwwroot/validation/server/contacts/index.html b/tests/CheckWebCore/wwwroot/validation/server/contacts/index.html index 12508cd91e2..d980d397db7 100644 --- a/tests/CheckWebCore/wwwroot/validation/server/contacts/index.html +++ b/tests/CheckWebCore/wwwroot/validation/server/contacts/index.html @@ -38,7 +38,7 @@

Add new Contact

{{#each response.Results}} {{Title}} {{Name}} ({{Age}}) - edit + edit