Exploring ASP.NET Web Pages - A fully-featured MiniBlog using just Razor
ASP.NET "Razor" Web Pages are ASP.NET sites without models, views, controllers, or project files. Some folks say "oh, that's just Classic ASP, or PHP right? Not at all. It's the full power and speed of the .NET CLR, the full syntax of C#, LINQ, along with things like C# dynamics. It's super powerful, and my friend Mads and I are surprised more people don't use them for small things.
In fact, Rob Conery and I did the http://thisdeveloperslife.com web site using just Razor and Rob's "massive" micro-ORM. Later I made http://hanselminutes.com with Web Pages as well.
This blog runs DasBlog, an older ASP.NET 2.0 blogging engine I worked on with Clemens Vasters and a lot of co-contributors, but I'm actively checking on Mads' MiniBlog, a minimal but VERY competent blog engine using Razor Web Pages. Why wouldn't I use something like Ghost? I've thought about it, but MiniBlog is SO minimal and that makes it very attractive.
Here's some things I like about MiniBlog, as both a blog and a learning tool.
Minimal
It's not called Mini for fun. There's a truly minimal packages.config of dependencies:
<packages>
<package id="AjaxMin" version="5.2.5021.15814" targetFramework="net45" />
<package id="Microsoft.AspNet.Razor" version="3.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebPages" version="3.0.0" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="xmlrpcnet" version="3.0.0.266" targetFramework="net45" />
<package id="xmlrpcnet-server" version="3.0.0.266" targetFramework="net45" />
</packages>
Clean use of Handlers for Web Services
Blogs do more than just serve pages, there is also a need for RSS feeds, MetaWeblog Web Services for things like Windows Live Writer, and dynamic minification for JS and CSS.
<handlers>
<add name="CommentHandler" verb="*" type="CommentHandler" path="/comment.ashx"/>
<add name="PostHandler" verb="POST" type="PostHandler" path="/post.ashx"/>
<add name="MetaWebLogHandler" verb="POST,GET" type="MetaWeblogHandler" path="/metaweblog"/>
<add name="FeedHandler" verb="GET" type="FeedHandler" path="/feed/*"/>
<add name="CssHandler" verb="GET" type="MinifyHandler" path="*.css"/>
<add name="JsHandler" verb="GET" type="MinifyHandler" path="*.js"/>
</handlers>
MiniBlog uses .ashx (HttpHanders) and wires them up in web.config. RSS feeds are easily handled with System.ServiceModel.Syndication, even JavaScript and CSS minification. Though MiniBlog is very new, it uses the old but extremely reliable CookComputing.XmlRpc for the MetaWeblog service communication with Windows Live Writer. I
No Database Need
I like apps that can avoid using databases. Sometimes the file system is a fine database. I thought this when we worked on DasBlog, Mads thought it when he made BlogEngine.NET (his original blog engine) and that "no database needed" design tenet continues with MiniBlog. It stores its files in XML, but MiniBlog could just as easily use JSON.
Clean Content-Editable Design Service
I always (exclusively) use Windows Live Writer for my blog posts. WLW is also the preferred way to write posts with MiniBlog. However, if you insist, MiniBlog also has a really nice content-editable scheme with a great toolbar, all in the browser:
When you are viewing a post while logged in as Admin, you click Edit and turn the page into editable content.
editPost = function () {
txtTitle.attr('contentEditable', true);
txtContent.wysiwyg({ hotKeys: {}, activeToolbarClass: "active" });
txtContent.css({ minHeight: "400px" });
txtContent.focus();
btnNew.attr("disabled", true);
btnEdit.attr("disabled", true);
btnSave.removeAttr("disabled");
btnCancel.removeAttr("disabled");
chkPublish.removeAttr("disabled");
showCategoriesForEditing();
toggleSourceView();
$("#tools").fadeIn().css("display", "inline-block");
}
The resulting HTML you write (in a WYSIWYG mode) is converted into XHTML and posted back to MiniBlog:
parsedDOM = ConvertMarkupToValidXhtml(txtContent.html());
$.post("/post.ashx?mode=save", {
id: postId,
isPublished: chkPublish[0].checked,
title: txtTitle.text().trim(),
content: parsedDOM,
categories: getPostCategories(),
})
The JavaScript is surprisingly simple, and gets one thinking about adding basic editing and CMS functions to websites. A design mode would be a daunting task 5 years ago, and with today's JavaScript it's almost trivial.
It even automatically optimizes images you drag and drop into the design surface and upload.
public static string SaveFileToDisk(byte[] bytes, string extension)
{
string relative = "~/posts/files/" + Guid.NewGuid() + "." + extension.Trim('.');
string file = HostingEnvironment.MapPath(relative);
File.WriteAllBytes(file, bytes);
var cruncher = new ImageCruncher.Cruncher();
cruncher.CrunchImages(file);
return VirtualPathUtility.ToAbsolute(relative);
}
The code is fun to read, and you can go check it out at https://github.com/madskristensen/MiniBlog. It supports HTML5 microdata, sitemaps, both RSS and Atom, simple theming, and gets a 100/100 of Google Page Speed.
Sponsor: Big thanks to Red Gate for sponsoring the feed this week. 24% of database devs don’t use source control. Do you? Database source control is now standard. SQL Source Control is an easy way to start - it links your database to any source control system. Try it free!
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
Actually by moving the application logic behind API the only really valuable thing in .NET-based UI is the ability to use the MasterPage (WebForms) or ViewMasterPage (MVC) - to keep all common stuff like general page layout, CSS/JS/etc. links in one place.
I've been meaning to try to do that but just didn't have the time. Anybody tried?
It is highly tailored to my own needs and wasn't really written with others in mind :)
Some of its features:
- Free hosting with GitHub Pages
- Uses git to deploy
- Razor Pages goodieness (layouts, partials etc)
- Responsive design via Twitter bootstrap
- No database
- JSON used for metadata and populates the RSS feed
- 'Compiles' down to pure HTML through the use of wget
- WebMatrix for my GUI editor
Anyway checkout my blog post series (which is using BlogMatrix): BlogMatrix. A Very Simple Blog Engine
Kestrel
James.
The Remote Posting Url was "http://blogaddress/metaweblog"
Do you know if miniblog supports arbitrary standalone pages? I'm currently using Orchard, which is a fine CMS, but arguably overkill for a blog, and I find myself longing for something simpler.
Anyone else on Orchard want to work together on a formatter to export Orchard content to miniblog?
By the time I learn the names and what they do and how they connect, Microsoft renames them all and I have to start all over again!
Sigh...
You can easily use LESS or Sass with MiniBlog if you use Web Essentials or any other VS extension that can compile it. On my blog, which also runs MiniBlog, I've made such modifications. For instance, I don't use the minification HttpHandler, but instead uses Web Essentials for both bundling and minification.
You should ask Brady Gaster (http://bradygaster.com/) who made the switch last year. I think he has some code to do that. See the irony when you start asking for more features like adding pages, but without the overkill ;)
I fully appreciate the irony, and I also appreciate all the hard work you've put into Orchard. It's a tough balance between feature-richness and complexity vs. simplicity.
:-)
However, one reason I don't use .cshtml as much as I should is that it's not automatically configured. For example, when distributing demos or NuGet packages, you can't be assured that .cshtml just runs. You have to specify the <appSettings> keys to specify that WebPages are enabled and worse - you have to specify the version. Plus you may have to add additional NuGet packages to get the right version of WebPages installed. Compared to ASPX which is just there and works that's can be a pain for casual use. I'd love to see .cshtml work the same as ASPX does without required configuraiton.
The page cannot be displayed because an internal server error has occurred.
While trying to create a new post. anything wrong ?
if (!context.User.Identity.IsAuthenticated || Blog.MatchesUniqueId(context))
throw new HttpException(403, "No access"); //this is thrown
Can someone lend a little guidance here for a newby?
Thanks!
<packages>
<package id="AjaxMin" version="5.2.5021.15814" targetFramework="net45" />
<package id="Microsoft.AspNet.Razor" version="3.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebPages" version="3.0.0" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="xmlrpcnet" version="3.0.0.266" targetFramework="net45" />
<package id="xmlrpcnet-server" version="3.0.0.266" targetFramework="net45" />
</packages>
with this:
{
packages: {
'AjaxMin': '5.2.5021.15814',
'Microsoft.AspNet.Razor': '3.0.0'
'Microsoft.AspNet.WebPages': '3.0.0',
'Microsoft.Web.Infrastructure': '1.0.0.0',
'xmlrpcnet': '3.0.0.266',
'xmlrpcnet-server': '3.0.0.266'
},
targetFramework: 'net45'
}
Much better!
How would you integrate MiniBlog as a module of an existing Web App?
My sense is that ASP.NET MVC Areas might be a good approach. I'm not sure, though, how to place an existing Web Site into an Area.
Comments are closed.