NuGet package | Owin.Framework.Pages.Html |
GitHub source | OwinFramework.Pages.Html |
This package contains a Build Engine for modules, pages, layouts, regions and components. If you want the fluent builder to use this build engine you need to add a couple of lines to your startup code similar to:
var fluentBuilder = ninject.Get<IFluentBuilder>(); ninject.Get<OwinFramework.Pages.Html.BuildEngine>().Install(fluentBuilder);
After adding this build engine to the fluent builder you can add web pages to your application by defining modules, pages, layouts, regions and components using classes that are decorated with attributes. The fluent builder will discover these classes and use the attributes to configure these elements.
This package also contains a templating system. You can choose from a variety of template loaders and template parsers to add templates to the name manager, or you can programatically construct templates using a fluent syntax. These templates can be referenced by pages, layouts and regions to define their content. See template overview for more details.
The code below is taken from the getting started walkthrough. It creates a very simple web page that only contains "Hello, world".
[IsPage] [Route("/", Method.Get)] [PageTitle("Getting started with Owin Framework Pages")] [UsesLayout("homePageLayout")] internal class HomePage { } [IsLayout("homePageLayout", "region1")] [RegionHtml("region1", "hello-world", "Hello, world")] internal class HomePageLayout { }
The attributes that you can attach to your classes are defined in OwinFramework.Pages.Core.Attributes.
The attributes that can be applied to pages are:
The attributes that can be applied to layouts are:
The attributes that can be applied to regions are:
The attributes that can be applied to components are:
Templates are a really important concept in building a website. Writing classes and decorating them with attributes to define pages, layouts, regions etc is very powerful and flexible, especially when those classes inherit from the standard implementation and override some of the virtual methods, but this technique has two important drawbacks: All of the website content is compiled into the asemblies which means you need to recompile and redepoly to change anything; Writing html and Javascript as strings that are passed to attribute constructors is ugly, and you don't get any help from the development tool (syntax highlighting and intellisense).
The templating system addresses these two issues by allowing you to place snippets of html, css and Javascript into separate resources then reference them from region and layout elements.
The template system overview contains a lot more information about how to use templates. Note that all of the content of this website is defined in templates.
As well as defining classes and decorating them with attributes as described above, you can also make these classes inherit from the base class and override virtual methods to customize the behavior.
You can use this technique for all types of element. The example below is for a page:
using System; using System.Threading; using System.Threading.Tasks; using OwinFramework.Pages.Core.Attributes; using OwinFramework.Pages.Core.Interfaces.Builder; using OwinFramework.Pages.Core.Interfaces.Runtime; using OwinFramework.Pages.Html.Runtime; namespace Sample1.SamplePages { [Description("<p>This is an example of how to add a semi custom page that inherits from the base Page base class</p>")] [Example("<a href='/pages/semiCustom.html'>/pages/semiCustom.html</a>")] internal class SemiCustomPage : Page { public SemiCustomPage(IPageDependenciesFactory dependenciesFactory) : base(dependenciesFactory) { TitleFunc = context => "Page title"; } public override IWriteResult WriteBodyArea(IRenderContext context) { var html = context.Html; // Save this location in the output buffer var begining = html.CreateInsertionPoint(); // Write a paragraph of text html.WriteElementLine("p", "This is a semi custom page", "class", "normal"); // Use the saved buffer location to write the heading before the paragraph // and do this in a separate thread var task = Task.Factory.StartNew(() => { // Simulate a call to a service or database here Thread.Sleep(10); begining.WriteElementLine("h1", "Semi Custom", "class", "page-heading"); }); // Write a second paragraph of text html.WriteElementLine("p", "My second paragraph of text", "class", "normal"); return WriteResult.WaitFor(task); } public override IWriteResult WriteInPageStyles( ICssWriter writer, Func<ICssWriter, IWriteResult, IWriteResult> childrenWriter) { writer.WriteRule(".normal", "background-color: linen; font-size: 12px;"); writer.WriteRule(".page-heading", "font-size: 16px;"); return base.WriteInPageStyles(writer, childrenWriter); } public override IWriteResult WriteHeadArea(IRenderContext context) { var result = base.WriteHeadArea(context); context.Html.WriteUnclosedElement( "link", "rel", "stylesheet", "href", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"); context.Html.WriteLine(); return result; } } }
As well as defining classes and decorating them with attributes as described above, you can also make these classes implement an interface to fully define the behavior.
You can use this technique for all types of element. The example below is for a page:
using System; using System.Threading.Tasks; using Microsoft.Owin; using OwinFramework.InterfacesV1.Middleware; using OwinFramework.Pages.Core.Attributes; using OwinFramework.Pages.Core.Debug; using OwinFramework.Pages.Core.Enums; using OwinFramework.Pages.Core.Interfaces; using OwinFramework.Pages.Core.Interfaces.Runtime; namespace Sample1.SamplePages { [Description("<p>This is an example of how to add a full custom page that directly implements IPage</p>")] [Option(OptionType.Method, "GET", "<p>Returns the html for this custom page</p>")] [Option(OptionType.Header, "Accept", "text/html")] [Example("<a href='/pages/anything.html'>/pages/anything.html</a>")] internal class FullCustomPage : IPage { public ElementType ElementType { get { return ElementType.Page; } } public string Name { get; set; } public IPackage Package { get; set; } string IRunable.RequiredPermission { get { return null; } set { } } string IRunable.SecureResource { get { return null; } set { } } bool IRunable.AllowAnonymous { get { return true; } set { } } Func<IOwinContext, bool> IRunable.AuthenticationFunc { get { return null; } } Func<IRenderContext, string> IPage.CanonicalUrlFunc { get; set; } string IRunable.CacheCategory { get; set; } CachePriority IRunable.CachePriority { get; set; } public void Initialize() { } public DebugInfo GetDebugInfo(int parentDepth, int childDepth) { return new DebugPage { Name = Name, Instance = this }; } Task IRunable.Run(IOwinContext context, Action<IOwinContext, Func<string>> trace) { context.Response.ContentType = "text/html"; return context.Response.WriteAsync("<html><head><title>Full custom</title></head><body>This is a fully custom page</body></html>"); } } }