mojoPortal 2.2.8.1 Released

I'm happy to announce the release of mojoPortal 2.2.8.1, available now on the download page.

Bug Fix

The main reason for this release is to fix a bug in the MS SQL version of the blog that was introduced in version 2.2.8.0. I'm surprised it took 5 days for anyone to report this bug, it was causing an error when adding new blog posts and this prevented the friendly url from being created to link to the post. Once it was reported I felt it needed an immediate fix and release. We are on a short release cycle anyway, typically we release every 2-8 weeks but any time a significant bug is confirmed we like to get a fixed release out as soon as possible.

If you are upgrading from 2.2.7.9 or higher, you don't have to upload the ClientScript or Data folders as nothing has changed there. Those are big folders so it should help not having to upload them.

New Stuff

YUI

Even though its only been a week since the last release there are some new things in this release worth mentioning. I've been gradually trying to eliminate the places where we were using ExtJs since they changed the license and we can no longer get upgrades, I'm focusing on YUI and jQuery and MS Ajax for UI enhancements. I previously removed all the use of ExtJs Tabs and implemented YUI tabs. In this release I implemented a YuiGridView, which is an ASP.NET GridView decorated with the YUI DataTable javascript. I had previously implemented a similar ExtJsGridView and was using it in quite a few places in mojoPortal, but now I have replaced all of those with the new YUI version.

Using the Google CDN

We've been shipping all the YUI and jQuery javascript with mojoPortal for a while. YUI is fairly large, its a lot of files and added a lot to the size of our package. Yahoo has had their own CDN (Content Delivery Network) that allowed you to just load the YUI files from the Yahoo servers, but they don't have support for SSL, so in the past it seemed better to include the files within the site, otherwise on secure pages IE users would get the pesky warning about the page having both secure and insecure content. Recently I saw this blog post in the YUI blog mentioning that google is now also hosting YUI on their CDN which does support SSL. So now we can leave out all of that YUI javascript from our package and load it from the google CDN. This is now enabled by default in mojoPortal, though there is a web.config setting that allows you to disable it if you have some reason why you want to host the files yourself, you still can do that, but its up to you to download the latest YUI and configure it in Web.config. We are also loading jQuery from the Google CDN. The only reason I can think of not to use the google CDN is if your site is on a private network and your users don't have internet access. To me that would be a very unusual use case, but in this case you would want to host all the javascript on the server.

WebStore Gets Its First Report

I implemented a Sales Overview report for the WebStore. I debated with myself whether to show you this screen shot, but I generally lean toward transparency so decided to show my own sales on this report. You can see that I'm clearly not making a living selling products yet.

webstore sales report screen shot

For reference, the store opened on July 23, 2008 with only the Buy Me a Beer product. Event Calendar Pro went on sale August 20th, 2008, and Form Wizard Pro went on sale Sept 29, 2008. Sales are currently only a trickle and I have a long way to go to get to my goal of selling 50 units per month, which is the point where I would start to make a decent living. For now I am still living primarily on savings, but I am optimistic about reaching my goals before I run out of savings. I think I need to add iCal import and export to the Event Calendar Pro and I need to add support for multi page forms or surveys in Form Wizard Pro to make them more popular, and having a few more products would be good. However, I still think the main thing is to improve the popularity of mojoPortal since my products only target users of mojoPortal, and to that end I've outlined some things on my road map that I think will help get there. Anyway, the main idea of the screen shot is to show the new report. The tables are using the YUIGridView I mentioned, and the Chart is ZedGraph.

 

Gravatar Joe Audette is the founder of the mojoPortal project and was the primary developer until February 2017.

mojoPortal 2.2.8.0 Released

I'm happy to announce the release of mojoPortal 2.2.8.0, available now on the download page.

Blog Improvements

Refactored the core meta data system to make it easier for features to control the meta data for their own content. Now you have per post control of the meta data in the blog. Its now possible to use html in the excerpts. If you enable excerpts and don't enter an excerpt, we still generate a plain text one for you of the configured length, but you now have the flexibility to specify the content of the excerpt so you can use images and html, but in that case we don't truncate anything so as not to lose any closing tags, so its up to you to determine how much to include in the excerpt.

WebStore Improvements

Also added meta data support for products so you can optimise SEO for product pages. Also products are now indexed into the site search index and can be found using site search.

Site Search Improvements

I added paging to the results. Previously we just brought back up to 200 results and it was up to you to refine your search if you didn't find what you were looking for. Now you can page through all of the results no matter how many there are.

404 Page Not Found Handler

When a user clicks a broken link to your site or types an url incorrectly, they typically get what is known as a 404 page not found error. 404 s the status code that indicates to the browser (or crawler) that the page was not found. Web servers like IIS and apache have a page about the error that is shown to the user by default in that case but its not the most friendly thing. It is possible to customize the 404 page in IIS or apache, but typically we would rather control it from within our application. The prevailing technique for doing this in ASP.NET has been to declare a custom 404 page in Web.config like this:

<customErrors mode="RemoteOnly" defaultRedirect="yourcustomerrorpage.aspx">
<error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>

allowing you to customize the 404 page and make it a little more user friendly. The problem with this technique is that when it does the redirect it never delivers the 404 status code, it provides a friendly experience to the user by redirecting to a page that does exist so no 404 really occurs as far as the browser knows. This is bad for search engine crawlers because they don't see the broken links either and you don't find out about them as you should from google webmaster tools. Its better if you can get reports about the broken links in your site and fix them. So what you really want is a custom 404 page that provides friendly content but still delivers the 404 status code, but redirecting to this page is what will prevent the status. You could set a status code from within your custom 404 page but since you redirected it won't report the correct url because you are now at the error page url not the missing url. Redirecting is not the correct solution, its just easy.

So I implemented an HttpModule to trap exceptions that indicate 404 errors and instead of redirecting I keep the current url and set the response status code to 404 then I make a server side web request to the custom 404 page to get its content and then just write the content into the reponse. So in effect I deliver the content of the custom 404 page but stay on the incorrect url so the status code will indicate that this url was not found. You can see the status code in the screen shot below where I have firebug showing the status of the request.  I've also added the google 404 enhancement javscript to the cutom 404 page, so for example if a user typos the url for the download page (as shown below in the screen shot) as dwnload.aspx instead of download.aspx, google is smart enough to suggest the correct page.

404 page not found handler screen shot

This seems like an ideal solution as the user gets a friendly page with good suggestions and the crawlers get the correct story about broken urls.

Bug Fixes

There were a number of bugs reported in the forums since the last release which have been fixed. There were some problems with the setup scripts for MySql that affected some installations. There were a number of small bugs resulting from the re-organisation of the code. I think most of these are now shaken out and though the last release was a little bumpy the benefits of the new code structure were worth the trouble.

Upgrade Notes

People often complain about having to upload all the files again, but generally this is always the best thing to do to make sure you don't miss any of the new files. We are on short release cycles so it tends to amplify the problem for those who like to upgrade every release. For this release, if you are upgrading from 2.2.7.9, you can skip uploading the ClientScript folder and Data folder as nothing changed there since the last release. Those are 2 big folders, so it will save you some upload time. Be sure and upload all the rest of the files though, and if upgrading from older versions upload all the files.

Lots of other fun stuff going on. I've been prototyping some things in Silverlight that I will blog more on later.

 

 

Gravatar Joe Audette is the founder of the mojoPortal project and was the primary developer until February 2017.

Silverlight + Google Gears = Awesome! at least in Firefox

I spent most of the week prototyping some things in Silverlight. I figured during the holiday week most people out there goofed off on their jobs a lot this week, so rather than work on my roadmap priorities, I decided to have some fun and play with Silverlight.

Some of you who have followed my blog for a while may remember some posts I made in the past about my plans for Site Office as a second plug in model for mojoPortal more geared to line of business apps that need a consistent look and feel rather than the web site kind of look, they need to look like applications. I originally protyped the UI using Dojo and then later re-did it with ExtJs. You can see the ExtJs version if you login to this site (or http://demo.mojoportal.com using admin@admin.com and password admin), then click the Site Office link at the top. You'll see the drag resizable panes that give the idea of where I wanted to go with Site Office as a UI for LOB applications. This prototype has just been sitting there without much attention because of other priorities and also partly because my enthusiasm for ExtJs disappeared when they changed the license from LGPL to GPL. Anyway, even back then I implemented a google gears query tool. Its really the only functioning app in the old Site Office prototype, you can find it by clicking the My Stuff in the left accordian menu in Site Office and then click SQL. For those who don't know, google gears is a client side SQL database built on SQLite and having this database available opens a lot of possibilities in web development for very rich and responsive applications.

Well, now my plan is to scrap the old ExtJs based Site Office prototype and build a better one with Silverlight. I've already got the Google Gears Query Tool re-implemented in Silverlight as shown below:

silverlight google gears query tool ascreenshot

I wrote a nice managed code wrapper around the javscript calls for gears. The only problem is, it doesn't work well in IE 7 for some reason, it works great in Firefox. I've sent an email off to Scott Guthrie at Microsoft in hopes of some help looking into the problem, but for now you can try it out online at http://demo.mojoportal.com/Index.aspx, you can see that I've got the basic layout of Site Office again implemented in Silverlight with the drag re-sizable panes. I plan to build a plug in model that allows you to plugin your own Silverlight applets and let the framework provide stuff thats common across applications. If I can get google gears working well across browsers with Silverlight its really going to be sweet. The code for this is in my svn sandbox and will probably land in trunk sometime next week.

Now using the managed gears wrapper can be seen in this client side business/data class, it looks very much like a server side class but its a client side object populated from a client side database in a very similar fashion to what it would look like in server side code. Notice the parametrized queries to prevent sql injection attacks. This class represents a saved query but it could represent anything.

using System;


namespace mojoPortal.Silverlight.Helpers.Gears
{
   
    public class SavedQuery
    {
        public SavedQuery()
        {}

        private int id = -1;
        private string name = string.Empty;
        private string query = string.Empty;

        public int Id
        {
            get { return id; }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public string Query
        {
            get { return query; }
            set { query = value; }
        }

        public void Save(GearsDb gearsDb)
        {
            if (id == -1) { Create(gearsDb); return; }

            Update(gearsDb);
        }

        private void Create(GearsDb gearsDb)
        {
            if (gearsDb == null) { return; }

            string sqlCommand = "insert into savedqueries (name, query) values (?, ?)";
            object[] parameters = new object[2];
            parameters.SetValue(name, 0);
            parameters.SetValue(query, 1);
            gearsDb.Execute(sqlCommand, parameters);
            id = gearsDb.LastInsertRowId();

        }

        private bool Update(GearsDb gearsDb)
        {
            if (gearsDb == null) { return false; }

            string sqlCommand = "update savedqueries set name = ?, query = ? where id = ?";
            object[] parameters = new object[3];
            parameters.SetValue(name, 0);
            parameters.SetValue(query, 1);
            parameters.SetValue(id, 2);
            gearsDb.Execute(sqlCommand, parameters);
            int rowsAffected = gearsDb.RowsAffected();
            return (rowsAffected > 0);
        }

        public static SavedQuery GetQuery(GearsDb gearsDb, int id)
        {
            if (gearsDb == null) { return null; }
            string sqlCommand = "select * from savedqueries where id = ?";
            object[] parameters = new object[1];
            parameters.SetValue(id, 0);
            GearsResultSet rs = new GearsResultSet(gearsDb.Execute(sqlCommand, parameters));

            SavedQuery query = null;
            if (rs.IsValidRow())
            {
                query = new SavedQuery();
                query.id = Convert.ToInt32(rs.GetFieldValue("id"));
                query.name = rs.GetFieldValue("name").ToString();
                query.query = rs.GetFieldValue("query").ToString();
            }
            rs.Close();

            return query;
        }

        public static SavedQuery GetQuery(GearsDb gearsDb, string name)
        {
            if (gearsDb == null) { return null; }

            string sqlCommand = "select * from savedqueries where name = ?";
            object[] parameters = new object[1];
            parameters.SetValue(name, 0);
            GearsResultSet rs = new GearsResultSet(gearsDb.Execute(sqlCommand, parameters));

            SavedQuery query = null;
            if (rs.IsValidRow())
            {
                query = new SavedQuery();
                query.id = Convert.ToInt32(rs.GetFieldValue("id"));
                query.name = rs.GetFieldValue("name").ToString();
                query.query = rs.GetFieldValue("query").ToString();
            }
            rs.Close();

            return query;
        }

        public static bool Delete(GearsDb gearsDb, int id)
        {
            if (gearsDb == null) { return false; }
            string sqlCommand = "delete from savedqueries where id = ?";
            object[] parameters = new object[1];
            parameters.SetValue(id, 0);
            gearsDb.Execute(sqlCommand, parameters);
            int rowsAffected = gearsDb.RowsAffected();
            return (rowsAffected > 0);

        }

    }
}

Update 2008-12-23

I have narrowed down the problem with IE and use of Google Gears in Silverlight. All the Gears functionality works except for 2 methods. The 2 methods broken in IE are GearsResultSet.GetFieldName(int fieldIndex) and GearsResultSet.GetFieldValue(int fieldIndex). I can get the field value if I know the field name ahead of time using GearsResultSet.GetFieldValue(string fieldName), so for most applications I should still be able to use Gears even in IE because my field names will be known ahead of time. Unfortunately for the query tool we have no way of knowing what fields will be in the result of ad hoc queries. So the query tool will only be useful in Firefox, but for other features I should be able to use gears without any trouble and this is very good news. I also have got a few web services talking to Silverlight, so I'm able to authenticate and get user roles. These services are actually built into the framework so I didn't have to implement them. I am working on some RESTful web services using the WCF REST Starter Kit.
 

Gravatar Joe Audette is the founder of the mojoPortal project and was the primary developer until February 2017.

mojoPortal 2.2.7.9 Released

I'm happy to announce the release of mojoPortal 2.2.7.9, available now on our download page.

New Related Sites Mode

mojoPortal has for a long time had the multiple sites feature which enables you to host multiple sites on a single installation using a single database. The feature was carefully designed to keep the sites and users completely independent so that each site is isolated from the others from a security perspective. But for some scenarios its desirable to host multiple sites but use the same users and roles in all of them. For example, maybe you want to have different versions of your site for different languages bu you want the same users in all of the sites. Or maybe a university wants to create separate sites for different departments but they want the students to have the same sign in credentials in all of them. This is now possible with simple configuration settings as indicated in the documentation. Multiple sites can be configured either based on host names or by folders beneath the root site. With the folder based sites, since they share a common cookie, once the user is signed into any of the sites he is signed into all of them.

New 301 Redirect Manager

When you create pages in mojoPortal, the page gets a friendly url based on its title, like /fun-stuff.aspx would be the url for a page named Fun Stuff. Now if you change the name of the page later it will get a different url, so for example if I change the name to Really Fun Stuff, its going to get a new url /really-fun-stuff.aspx.

Now from an SEO (Search Engine Optimisation) point of view, its not a good idea to be changing your urls willy nilly. If someone bookmarked your old url you don't want it to be broken, or if its already popular in search results, you don't want it to be a broken link. So ideally, you need to have the old page do a 301 redirect to the new page. The 301 status code tells the browser that the page moved permanently. Now mojoPortal will create the 301 redirect for you automatically when you re-name a page or blog post. However, its still not a great idea to be renaming your pages frequently, you should avoid it generally but if you need to its ok to do it. You can also see the 301 redirect mappings and manually manage them from Administration Menu > Advanced Tools > 301 Redirect Manager. You need to be very careful with this feature, you do not want to create circular redirects where 2 urls redirect to each other.

This is the last Release Targeting ASP.NET 2.0

This release as previous ones targets the 2.0 ASP.NET runtime. I requested feedback in my previous post about changing to target the 3.5 ASP.NET runtime and everyone who responded was in favor. I've already changed it in my svn sandbox and will change it in trunk soon. I find that on a machine with VS 2005 I am still able to build and run the solution as long as .NET 3.5 is installed. Using the Mono 2.0 release I could still get it working if I swaped out the Web.config so it used 2.0 version of System.Web.Extensions. Using the latest Mono built from svn I see that the Mono version of System.Web.Extensions has changed to 3.5, but I'm getting an error running it and will have to investigate further.

So the next release will target .NET 3.5. If someone needs a 2.0 build it will be possible for them to change the build target back to 2.0 (in Visual Studio 2008) and rebuild, because I'm not really planning to use 3.5 specific features in the core projects for a while yet. I just need to use the 3.5 version of ScriptManager to support features like Silverlight that I will use in external projects. Just like our other features, the external projects will copy the needed files up to the main Web project so it can work at runtime. This allows us to move forward and take advantage of new things in 3.5 while keeping general compatibility with Mono and 2.0 .NET. Changing the target to 3.5 NET on the core projects only changes the Web.config file and the .csproj file

I'm very excited to start working with Silverlight 2 and RESTful web services using the REST toolkit. I'm just beginning to do exploratory prototyping now but I'm seeing some very cool possibilities.

Gravatar Joe Audette is the founder of the mojoPortal project and was the primary developer until February 2017.

mojoPortal 2.2.7.8 Released

I'm happy to announce the release of mojoPortal 2.2.7.8, available now on the download page.

Important Upgrade Notes

We added a feature to combine and minify the CSS files in the skins. Those using custom skins should modify their skins as described here after upgrading.

This release also contains Oomph, as described in my previous post.

We have a new Croatian language translation thanks to Slaven Brumec.

Other than the above and a few bug fixes and feature tweaks as discussed in the forums since the last release, the main focus of this release is changes to make developers happy as discussed below.

Source Code Project Re-Organization

All of the content features like Blog, forum, Gallery, Maps, etc, have been moved out of the core mojoPortal projects into the mojoPortal.Features.* projects. This makes it possible to build and package a leaner version of mojoPortal without any features except Html Content. I will still continue to make the official mojoPortal releases with all the features, I have no plans to package separate mojoPortal lite packages myself, but the idea is that developers can package their own application with mojoPortal without having to include all the features we have. If you work with the mojoportal-core.sln Visual Studio Solution, it will build without any of the extra features and you can package it with UnLeashIt. If you build the mojoportal-complete.sln solution, post build events will copy the extra features up to the core Web project, so you don't want to do that if you plan to package without those features. Once they are copied up to the Web project UnLeashIt will include them, so you need to keep it clean by not building that solution if you want to package without those features.

As a result of this, features are now basically self contained within folders, like the Blog is in the siteroot/Blog folder and forums are in the siteroot/Forums folder and so on. For backward compatibility I created pages with the old names that will do a 301 redirect to the new pages. I also was careful to make sure friendly urls for existing blog posts would continue to work correctly.

The only thing site owners need to change is if they previously submitted a blog site map to google using siteroot/BlogSiteMap.ashx, you need to change that to siteroot/Blog/BlogSiteMap.ashx

When Should We Target .NET 3.5?

I'd like to gather input and opinions about when we should change the target platform to .NET 3.5. I'm eager to start playing with Silverlight in mojoPortal and it seems to need the 3.5 versions of ScriptManager to host the <asp:Silverlight control

The issues I see are:

  • We need to be careful to keep compatibility with Mono. I think we can move forward with using .NET 3.5 on Windows and continue to build for .NET 2.0 for the MonoDevelop solution. We really won't add non-supported features in the core projects but we need to be able to specify 3.5 settings in Web.config of the core Web project. We already maintain a different Web.config file for Mono packages so this should not be a problem. We can put 3.5 functionality like Silverlight into separate projects and use post build events to deploy them into the main web for runtime as we do with most features. So these projects can be left out of the MonoDevelop Solution until they are supported. In summary I think we can workaround all issues relating to Mono and should be able to move forward while still maintaining Mono compatibility.
  • Hosting - This is the issue I'm not entirely sure of and would appreciate any input. If the next release of mojoPortal for Windows targets the 3.5 runtime is that available at your hosting or will it pose a barrier to upgrade? It seems like most of the big name hosts have .NET 3.5, they don't like to be left behind by the competition.
  • Visual Studio 2005 Issues? - As far as I know VS 2005 can target 3.5 without problems except maybe for Windows Workflow development and it doesn't have some of the built in project templates for 3.5 .NET projects. We already maintain separate VS 2005 solution files so we could leave out any projects if they don't work.

UPDATE:

Forgot to mention that I updated the project road map yesterday.

Gravatar Joe Audette is the founder of the mojoPortal project and was the primary developer until February 2017.