.NET and Open Source: better together

RTur.net

  • Join Us on Facebook!
  • Follow Us on Twitter!
  • LinkedIn
  • Subcribe to Our RSS Feed

Building Widgets for BlogEngine.NET 3.3

Version 3.3 dropped user controls from BlogEngine and new widgets use Razor views instead. To start developing new widget, open source code in Visual Studio, navigate to BlogEngine.NET/Custom/Widgets in the solution explorer and add "Example" folder. If you run application and go to admin/custom/widgets, you'll see "Example" widget added to available widgets. You can even drag it to widget zone and save changes.

But because we don't have any code to support this widget, in the website you'll see an error instead of actual widget. It explains what file BlogEngine is looking for - "widget.cshtml" in that newly created folder.

So go back to Visual Studio and add widget.cshtml file. Here is a code for it:

@{
    var title = Model.Title;
}
<div class="widget tagcloud">
    <h4 class="widget-header">@title</h4>
    <div class="widget-content">
        This is an example. Widget ID is @Model.Id
    </div>
</div>

Few things to understand in this code. It is very simple standard Razor view and BlogEngine passes Model object into the view as one would expect. This is very simple object indeed, it has only 2 properties: Title and Id. If you save your code and reload website, you should see your widget in the sidebar in all glory.

The title is the name of your folder, in this case "Example". The Id created when you drag-and-dropped widget into widget zone. With XML provider, it added line to the widget zone file under app_data/datastore/widgets. With database provider, it would update a record in the table. So there is no mystery here.

Even with this little knowledge, you already can do some useful things. For example, most social sites provide some kind of code widgets you can copy/paste in your blog as HTML - you could add this code to widget.cshtml and be done. Also, BlogEngine exposes many useful objects and events and they all available to you in the server-side code block. The code below shows how you can easily output number of posts and blog title pulling data from server-side code.

@{
    var title = Model.Title;
    var postCnt = BlogEngine.Core.Post.ApplicablePosts.Count;
    var blogName = BlogEngine.Core.BlogSettings.Instance.Name;
}
<div class="widget tagcloud">
    <h4 class="widget-header">@title</h4>
    <div class="widget-content">
        <p>Posts in the blog: @postCnt</p>
        <p>Blog title: @blogName</p>
    </div>
</div>

Here what you should see in the browser now:

This lets you create many simple widgets, but often you would want to provide customization. For this, your widget needs settings. Currently, if you click on pencil icon in the widget admin, it will only let you change title. To add settings page, we need to add "edit.cshtml" to the Example folder. The name follows convention and is what BlogEngine expects to find. So in Visual Studio, add "edit.cshtml" with code as below:

<!DOCTYPE html>
<html>
<body class="widget-edit">
    <div class="widget-edit-commentlist">
        <form method="post">
            <div class="form-group">
                <label>Example setting</label>
                <input type="text" class="form-control" id="txt1" name="txt1" value="" />
            </div>
            <button type="submit" class="btn btn-success">@Resources.labels.save</button>
        </form>
    </div>
</body>
</html>

Now if you open settings page in admin, this will look like this:

So we got our setting, but it is kinda ugly. To fix, we need to include some styles:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="~/Content/bootstrap.min.css">
    <link rel="stylesheet" href="~/Content/font-awesome.min.css">
    <link rel="stylesheet" href="~/admin/themes/standard/css/styles.css">
</head>

And it looks much better now.

With visuals in place, next thing is to be able save this setting and read it back. Modify edit.cshtml to look like code below:

@using BlogEngine.NET.Custom.Widgets
@{
    var exampleSetting = "This is an example";
    var widgetId = Request.QueryString["id"];
    var settings = Common.GetSettings(widgetId);
    if (IsPost)
    {
        settings["examplesetting"] = Request.Form["txt1"];
        Common.SaveSettings(settings, widgetId);
        @:<script type="text/javascript">window.parent.toastr.success("Completed");</script>
    }
    if (settings != null && settings.Count > 0)
    {
        exampleSetting = settings["examplesetting"];
    }
}
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="~/Content/bootstrap.min.css">
    <link rel="stylesheet" href="~/Content/font-awesome.min.css">
    <link rel="stylesheet" href="~/admin/themes/standard/css/styles.css">
</head>
<body class="widget-edit">
    <div class="widget-edit-commentlist">
        <form method="post">
            <div class="form-group">
                <label>Example setting</label>
                <input type="text" class="form-control" id="txt1" name="txt1" value="@exampleSetting" />
            </div>
            <button type="submit" class="btn btn-success">@Resources.labels.save</button>
        </form>
    </div>
</body>
</html>

There few things to explain in this code. First of, we included custom/widgets namespace and introduced local variable "exampleSetting". This variable represents value we want to be able type in the textbox and save. We need to know widget ID to be able to save and retrieve settings for this widget, and ID always passed into edit page by BlogEngine  as query string (line #4), so we use it to get settings object (line #5). This object provided by BlogEngine, and we don't care where and how it saves our value as long as we can save and get it back.

Before we save settings, widget will be using declared in the line #3 as default. But if I click "save" button, the code in the "if (IsPost)" block will be executed (lines 8-10). This will take value fro texbox, save it and display confirmation message.

And I can use code similar to above to use this setting in my Example widget:

@using BlogEngine.NET.Custom.Widgets
@{
    var exempleSetting = "Default value";
    var settings = Common.GetSettings(Model.Id);
    if (settings != null && settings.Count > 0)
    {
        exempleSetting = settings["examplesetting"];
    }
}
<div class="widget example">
    <h4 class="widget-header">@Model.Title</h4>
    <div class="widget-content">
        <p>Setting value: @exempleSetting</p>
    </div>
</div>

Which suppose to produce output in the browser similar to the picture below.

The widget settings allows to save multiple values and use them to customize your widget with anything it needs, like width, height, number of items, color and so on.

This is the first tutorial on widgets to get you started. Next time we can check things like input validation and publishing to the gallery.

Example.zip (1.04 kb)

BlogEngine.NET 3.2 Released

The year wouldn't be complete without it :) It took a lot longer then I hoped, for variety of reasons, but finally went live. New version is much more pleasant to use, it is improved and simplified in many ways. Besides new design, it went through lots of code changes which may not be obvious and this is what I want briefly explain here.

The state of affairs

The project was built in ASP.NET 2.0 time and this shows. It is heavily server-side, with WebForms and user controls on the front end. Obviously, not an optimal these days. During long run, project grew by including lots of code from many people. This is great, but it gets less consistent, harder to maintain with less interest from developers who usually interested in very latest tech to sharpen their skills. To keep it alive and well, we have to push tech side to keep up with time. And this was one of the biggest reasons for 3.2 release.

The 3.2 update

3.2 followed the previous releases modernization path - all new development focused on client side using HTML5/JavaScript and refactoring server-side code trying to get rid from dependencies on WebForms with user controls etc. Currently admin panel almost completely based on HTML templates with AngularJs calling Web API services, with back-end following repository pattern. This all can be easily ported to MVC style application if needed. There was no focus on new features, yet some added, like Facebook comments, along with many improvements to web gallery, editor, file manager, settings and so on.

Future direction

There are two opposite ways to go when you need to bring old code base to the latest tech. You can start from scratch and move your way up, adding features. It seems simpler and cleaner - unless you tried it before. If you did, you know it takes ten times more effort you thought it would and won't guarantee your code will be much better. Inevitably, you'll be reinventing lots of wheels with various success and find yourself diving into old code and borrowing a lot. I don't like this. 

The other way is to re-think your code and start pushing it to better state piece by piece. Split it into components and modernize them one by one. That seems like a lot more work, but it is not. In fact, I believe with "real" product this is the only way - you don't disrupt your customers and do migration behind the scene as much as possible. In case with BlogEngine, we can switch URL rewrite to routing. Then get rid of user controls in widgets, modernizing entire widgets framework. Then take care of themes removing remaining user controls. At this point, it is MVC ready. And MVC project can eventually start taking advantage of new features in MVC5, like platform portability, code editor independence and so on. I know it is not as exiting as jumping right into new environment, but this is where it is going, and I'm ok with that. In fact, in my experience this is the most practical skill developer needs to master.

Post Paging Extension

Reading this thread on Codeplex I was going to write that no such functionality exists but probably easy to add. But then I though just how easy it really would be? So I fired up Visual Studio and about half an hour later I got functioning plugin that does exactly what requested. And this is why I like BlogEngine - it is insanely easy to customize. At least, when you get used to it because documentation admittedly sucks. More...

Boldy Updated to Version 3.1.1

We getting really close to BlogEngine 3.2 release and I'm mostly switching to integration tasks, checking how it works with external code, like themes, plugins etc. As an exercise I decided to refresh my old Boldy theme and make it work with very latest code. To make things simpler, I took layouts from new standard theme and applied Boldy styles on top of it. The result you can see here on this blog, install from gallery if you running BlogEngine.NET blog or check out code at GitHub.

Also, if you running BlogEngine.NET, I would really encourage download latest version and try it out with your blog to make sure it works smoothly and we didn't miss anything specific to your environment. There were lots of changes to the core base, not just UI, and we would love to catch errors before we go live.

Adding Twitter and Facebook Share Buttons to The Post

There are plenty services and plugins that let you add social share buttons, downside is they usually trying to be all things for all people. So you can end up with complex solution to a very simple problem. For example, I just want Twitter and Facebook share buttons and not really interesting in anything else. I want it to be as light, clean and simple as possible. How hard it is to do it manually? Fortunately, not that difficult and I'll try to describe how to do it in this post. More...

Multiple Blogs vs Multiple Users

BlogEngine supported multiple users as far back as I can remember. But what people really wanted was multiple blogs on the single application install. So that hosting company, for example, can install application and provide free blog to everyone buying hosting space. Having multiple users not helping here, it just not the same. And at some point BlogEngine went all in and added multiple blogs feature. It did it by allowing basically replicate entire blog structure as many times as needed, including membership, in every child blog. So right now we have multiple blogs, each with multiple users, custom roles and elaborate access right permissions for every user. This is nuts. More...

Crazy Fun Times

In application where you publish things, published time seems simple. I write post at 12 pm, hit “publish” and all I want is my post saved with that 12 pm time-stamp. How hard it can be, right? Wrong, which I found the hard way trying to fix issues with publish time in relatively simple application. So I made this cheat sheet, or rather note, to help straighten things up. More...

Drag and Drop Widgets with Bootstrap

Just a little concept for the next BE release. Really want to get rid of editing on live site and move all under admin. Why put it here and not just stick in the Github repository or Plunker? Because blog supposed to be center of your digital Universe and if not then something is wrong with it and it needs to be fixed. Blog, not the Universe - that is out of scope. Maybe next year. More...

Sneak peek on BlogEngine 2015

There has been a lot of activity lately on BlogEngine.NET development that went under the radar, so I want to clear things up a little. Because code moved from Codeplex to Github without much publicity, people don't see any changes in a while and assume project is dead done. This is exaggeration :) New release is under active development and coming along in a month or so. It is a bit of ironic that auto-update added in the previous version supposed to allow small quick releases, but somehow we ended up with another monster update. Old habits die hard, I guess. Anyways, here are some highlights on the coming features, some already implemented and some planned or in the works. More...

Entity Framework 7 Getting Started

If you are new to Entity Framework, especially to all new EF7, best way to start is to look at this code from sample application. It shows all you need to know to get rolling: connecting to database, creating a table, inserting and selecting data all in one simple console app. You can run it in the new shiny Visual Studio 2015 with break points on any line that you want to verify and literally walk step by step understanding the process. Which is: More...