A Programmable Web Framework John Leidegren
Before time... • 1993 • <HTML><BODY>...</HTML> • Very static
Server-side scripting • IIS/ISAPI/ASP/VBScript/ASP.NET • Apache/CGI/JSP • PHP/PHP4+ • ColdFusion?
The Basic Idea • <% %> not well formatted XML <% • <? ?> processing instruction # server-side scripting and then some • runat=”server” %> • Not in the XHTML specification <html xmlns=”...”> • Mixing view and code != MVC <div id=”Name” runat=”server”>...</div> </html>
The Basic Idea • <% %> not well formatted XML • <? ?> processing instruction • runat=”server” • Not in the XHTML specification • Mixing view and code != MVC <% # server-side scripting and then some %> <html xmlns=”...”> <div id=”Name” runat=”server”>...</div> </html>
Worst Case • Copy-paste • No reusable master • No composability • No static type-checking • PHP • Runtime errors
Trellis A programmable web
Trellis • Tightly integrated into Visual Studio 2008 • A compiler framework • A web framework • A web server • Running on .NET 3.5 (Windows only)
Trellis • Uses infix notation • Uses lambda calculus • Uses some lazy evaluation • Written entirely in C# • A fraction of the server is C++/CLI • A Haskell wannabe
Trellis Technology put to good use
CodeDom Foofulishicness CodeMemberMethod method = new CodeMemberMethod(); method.Name = "Clone"; method.ReturnType = new CodeTypeReference( typeof( Fragment ) ); method.Attributes = MemberAttributes.Public | MemberAttributes.Override; CodeObjectCreateExpression objectCreation = new CodeObjectCreateExpression(); objectCreation.CreateType = new CodeTypeReference( someOtherType.Name ); // should be lazy CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement( objectCreation ); method.Statements.Add( returnStatement );
Extension Methods CodeLiteral cloneLiteral = "Clone"; // implicit conversion CodeMemberMethod cloneMethod = cloneLiteral .AsMethod<Fragment>() .SetAttributes( MemberAttributes.Public | MemberAttributes.Override ) .AddStatement( someOtherType.CreateInstance().Return() );
+ Lambda = LINQ byte[] messageBody = ... // array of bytes int[] xs = messageBody .Select( ( x, i ) => new { Value = x, Index = i } ) // zip .Where( x => x.Value == '=' ) .Select( x => x.Index ) // project .ToArray(); // lazy until evaluated
Generator IEnumerable<char> GetRequestHeaderEnumerator() { int k = 0; while ( k != 0x0d0a0d0a ) // <CR><LF><CR><LF> { k = (k << 8) | ReadByte(); yield return (char)(k & 0x7f); // 7‐bit (ascii clamp) } }
// C# 2.0 StringBuilder x = new StringBuilder(); foreach ( var c in GetRequestHeaderEnumerator() ) { x.Append( c ); } string request = x.ToString(); // C# 3.0 string request = GetRequestHeaderEnumerator() .Aggregate( new StringBuilder(), ( x, c ) => x.Append( c ), x => x.ToString() );
The Trellis Compiler • Standardized XML to reusable fragments • A fragment is reusable code • A fragment can be almost anything • A fragment is compiled into a .NET assembly • A Trellis application is just a .NET assembly
Trellis DEMO
More work • Some things did not make the cut • Input validation • Dynamic compilation • Lean and mean coding style • Replace XML with NHaml • Provide NHaml language support in VS
NHaml what is it? Haml takes your gross, ugly templates and replaces them with veritable Haiku.
NHaml %one %two %three Hey there Compiles to: <one> <two> <three>Hey there</three> </two> </one>
NHaml %head %title My Sample MVC Application %link{ href="../../Content/Sites", rel="stylesheet", type="text/css" } Compiles to: <head> <title>My Sample MVC Application</title> <link href="../../Content/Site.css" rel="stylesheet" type="text/css" /> </head>
Problems • Static type-checking vs. dynamic content • Validation rules • Event handling • Separation of concerns • MVC
Final Thoughts • I love to write code • The IDE is really part of the application framework • Trellis is similar to The ASP.NET MVC Framework • Putting new language technology to good use is great fun!
The End Questions?
Recommend
More recommend