Scott Hanselman

Exploring ASP.NET Web Pages - A fully-featured MiniBlog using just Razor

April 16, '14 Comments [35] Posted in ASP.NET | Open Source
Sponsored By

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:

Nice Editing Experience

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Wednesday, April 16, 2014 6:26:29 AM UTC
saw it, loved it, forked it
Wednesday, April 16, 2014 7:12:08 AM UTC
This is pretty cool. I really like Web Pages and am surprised more people don't use it to create simple web sites. It beats WebForms and MVC when it comes to simplicity and learning curve.
ed
Wednesday, April 16, 2014 7:22:31 AM UTC
scott , fantastic. any idea if Mads is thinking of providing some guide lines on how to migrate from Wordpress to miniblog ?
Wednesday, April 16, 2014 8:16:45 AM UTC
@Lohith: There is a side project "MiniBlogFormatter" which converts the Wordpress/DasBlog Exports to the MiniBlogFormatter "Format" https://github.com/madskristensen/MiniBlogFormatter
Wednesday, April 16, 2014 8:17:45 AM UTC
That is more than just nice :)

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?
Wednesday, April 16, 2014 8:27:31 AM UTC
I migrated from Blogengine.net to miniblog a while ago and the performance is impressive.
Wednesday, April 16, 2014 9:04:12 AM UTC
Web Pages and Razor are fast and super light weight. I used it to build Career Voyage and it has performed flawlessly for the past year with over 4 million page views by 50K+ users. Its the hidden gem of the ASP.NET stack!!
Wednesday, April 16, 2014 10:17:02 AM UTC
Razor Pages are awesome. I used them along with Webmatrix to write my own 'blog engine' called BlogMatrix.

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
Wednesday, April 16, 2014 10:26:03 AM UTC
I've just tried connecting Writer to MiniBlog, but its coming back saying it cant find the template and asking me to choose which blogging platform it is. Anyone else have this, or know which URL its after?

James.
James
Wednesday, April 16, 2014 10:53:00 AM UTC
After looking some more, to get Writer to 'see' the blog.

The Remote Posting Url was "http://blogaddress/metaweblog"
James
Wednesday, April 16, 2014 11:13:26 AM UTC
That is sweet! Hard to beat Mads, but a blog engine to watch is sblog. The author doesn't seem to have much love yet. But it beats the others I've played around with.
Dave
Wednesday, April 16, 2014 11:26:49 AM UTC
Too bad I didn't hear about it before starting my blog this winter, the Razor engine is great to work with. Wordpress has a lot of features, but it's overkill for many projects.
Wednesday, April 16, 2014 12:53:39 PM UTC
Scott,

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?
Wednesday, April 16, 2014 1:18:19 PM UTC
Razor, WebPages, ASP, ASP MVC, LightSwitch, WebMatrix, etc. etc.

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...
FrustratedConsumer
Wednesday, April 16, 2014 1:48:36 PM UTC
Highly interested in building with this tool to support some podcasting I plan to do. Will be grabbing the bits tonight. Does it support LESS/SASS?
John Dunagan
Wednesday, April 16, 2014 2:12:54 PM UTC
@John: It doesn't look like it natively, but given how simple the .js/.css minifier handler looks, I'm sure you could wire up your own LESS/SASS handler to get that support. https://github.com/madskristensen/MiniBlog/blob/master/Website/app_code/handlers/MinifyHandler.cs
Wednesday, April 16, 2014 2:45:29 PM UTC
I migrated from Blogger to MiniBlog a few months ago. I was about to write something myself (something lightweight and built with MVC). But then I found MiniBlog and it's been a perfect fit. I like that it works with Windows Live Writer.
Wednesday, April 16, 2014 3:58:44 PM UTC
@John,

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.
Wednesday, April 16, 2014 4:15:42 PM UTC
Great article. I like it.
Hadrich Mohamed
Wednesday, April 16, 2014 4:17:32 PM UTC
@Andrew,

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 ;)
Wednesday, April 16, 2014 4:24:44 PM UTC
@Sebastien,

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.

:-)
Wednesday, April 16, 2014 5:23:49 PM UTC
Checkout MvcPages, MVC without routes and controllers, or WebPages with Model Binding, Model Validation, Editor/Display Templates, strongly-typed HTML helpers, TempData, etc.
Wednesday, April 16, 2014 9:26:26 PM UTC
Can I just drop in the BlogEngine.Net XML file(Posts) into MiniBlog?
Wednesday, April 16, 2014 10:49:02 PM UTC
I also love to use plain .cshtml files for 'general' html pages that need a few small server side commands embedded and using Razor instead of the WebForms syntax is definitely way nicer.

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.
Thursday, April 17, 2014 8:43:40 AM UTC
I get

The page cannot be displayed because an internal server error has occurred.

While trying to create a new post. anything wrong ?
Thursday, April 17, 2014 9:45:07 AM UTC
I also get an error when creating a new post on the following line in PostHandler ProcessRequest:


if (!context.User.Identity.IsAuthenticated || Blog.MatchesUniqueId(context))
throw new HttpException(403, "No access"); //this is thrown
Rik
Thursday, April 17, 2014 6:38:41 PM UTC
ASP.NET Web Pages sound very cool. So, how do I add ASP.NET Web Pages to an existing MVC application that uses .net 4.5?
Steve G.
Thursday, April 17, 2014 10:46:56 PM UTC
I'm having the same trouble James was. I am brand new to blogging, just downloaded the code and published directly to azure. When attempting to connect WLW to the site, I'm told by WLW that it can't automatically detect my blog settings and I need to select one from the list (upon which miniBlog is *not* on said list) and to provide the "Remote Posting URL" whatever that is.
Can someone lend a little guidance here for a newby?

Thanks!
Fred Weller
Thursday, April 17, 2014 11:27:46 PM UTC
Figured it out! For WLW, select "Metaweblog API" from the drop down and then add "metaweblog" to the end of your url for the Remote Posting URL e.g. "http://mynewblog.azurewebsites.net/metaweblog" and then WLW should pick it up.
Fred Weller
Friday, April 18, 2014 8:33:31 AM UTC
great Ideas i l like .........<3
Saturday, April 19, 2014 5:25:09 AM UTC
I don't understand the continuing preference for XML-like config files. You said the config is truly minimal, but compare this:


<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!
tyrsius
Sunday, April 20, 2014 7:29:42 PM UTC
I would like to install MiniBlog as a component of my existing ASP.NET MVC Web Application. I have asked about this on StackOverflow here.

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.
Sunday, April 20, 2014 10:15:30 PM UTC
It's pretty awesome, I would only add markdown support since it has nice built in code highlighting.
Friday, May 02, 2014 5:14:04 AM UTC
MiniBlog with Ghost Editor: link.
Andrei Vasilev
Monday, July 14, 2014 2:44:04 AM UTC
It's really very nice idea.I liked these pretty ideas about ASP.NET.If you want to get more knowledge about ASP.NET you can visit myasp.net.
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.