Saturday, February 28, 2009

Intergrate Yet Another Forum 1.9.3RC2 with Umbraco 4

Since Umbraco doesn't have a integrated forum package yet I tried to integrate the latest version of YAF.

Here are the steps that I took and the issues that I encountered.

Preparing Umbraco

  1. Download and install Umbraco4 with Runway to keep it simple
  2. In Umbraco you create new documenttype called Forum and a matching template
  3. Add properties to this documenttype. I only added a title property for this tutorial.
  4. Add the forum documenttype to the allowed childnode types of the Runway homepage
  5. Change the Forum template so it uses the Runway master template
  6. Create a forum page and publish it.
  7. Go to the member section and create 2 Membergroups : Registered Users and Adminstrators
  8. Create a Membertype Registered user
  9. Create a user of the type Registered user and add it to the Admistrators group
  10. Modify the master template by adding code snippet 1 to the Runwaymaster template just before the ContentPlaceHolder
  11. Go to your website and login using the user you just created and confirm that it works

Preparing YAF

  1. Download and unzip YAF to a folder YAF under your Umbraco root
  2. Backup your Umbraco web.config
  3. Copy all the file is in the YAF bin folder to the Umbraco bin folder. If you got to your Umbraco backend UI now you see that it stops working. We solve that in the next step
  4. Open up the Umbraco web.config and add code snippet 2 to it at the bottom before the closing configuration tag. Now the Umbraco backend UI should work again. If not check the version of the AjaxToolkit.dll from the Umbraco zip file and the YAF zip file and change the version numbers in the code snippet
  5. Copy the App_Code folder from the YAF directory to the Umbraco App_Code folder
  6. UPDATE 23/03/2009 : Open up the file App_Code/YAF/Forum.cs and add this.Init += new EventHandler( Forum_Init );  to the constructor (public Forum()). Also add code snippet 9 to this file.
  7. Next open up the web.config and copy/paste code snippet 3 in to the appSettings section. These are the settings from the YAF app.config file with the needed modifications. If you run the forum page in a subdirectory like <yourwebsite>/blabla/forum.aspx you will have to change the baseUrl property to match this directory.
  8. Modify the appSetting umbracoReservedPaths to <add key="umbracoReservedPaths" value="/umbraco,/install/,/yaf/" />
  9. Add code snippet 4 to the Umbraco web.config in the configuration section. Modify the connectionstring so it connects to your YAF database. In this case I will use the Umbraco database.
  10. Add <add name="YafInitModule" type="YAF.Classes.Base.YafInitModule, YAF.Classes.Base"/> to HttpModules section of your Umbraco web.config
  11. Replace the pages section in the Umbraco web.config with code snippet 5
  12. Add code snippet 6 to the Umbraco web.config in the system.web section
  13. UPDATE 23/03/2009 : Add code snippet 8 to the file config/UrlRewriting.config
  14. Delete the bin and App_Code folder from the YAF directory

Install YAF

  1. Open up a browers and call <yourwebsite>/yaf/install/default.aspx
  2. In the first step enter the a password
  3. In step 2 install full text search if your database supports it
  4. In step 3 configure your forum with a existing user. Use the user we created during the setup of umbraco.
  5. In step 4 click finish. This will redirect to the homepage of your website

Using YAF in umbraco

  1. In Umbraco open up your forum masterpage and add <yaf:Forum id="yafForum" runat="server"/> between the asp:Content tags
  2. If you visit your forum page on the website you will see a ugly error. This is caused by a "bug????" in the Umbraco Membership Provider. To override this error create a file called YAFUmbracoMembership.cs in the App_Code folder of Umbraco. Copy code snippet 7 into this file.
  3. Change your Umbraco web.config so that the membership Provider uses Dawoe.Providers.YAFUmbracoMembership
  4. Change the Umbraco web.config so that profile is enabled.
  5. Open up the forum page again and voila !!! YAF integrated in Umbraco. Try to login and you will see that it works.
  6. Also try to create a new user in umbraco and Login in with that one.

Known issues

  1. Registering through the forum doesn't work. No workaround yet. Disable it for now in the YAF hostsettings.

If somebody finds other issues and/or solutions please report them and I'll update this post.

Code snippets

Code snippet 1 :

<asp:LoginView id="loginView" runat="server">
    <AnonymousTemplate>
        <asp:Login id="login" runat="server" />
    </AnonymousTemplate>
    <LoggedInTemplate>
        <asp:LoginStatus id="loginStatus" runat="server"/>
    </LoggedInTemplate>
</asp:LoginView>

Code snippet 2 :

 <!-- Ajaxtoolkit bindings -->
<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
            <assemblyIdentity name="AjaxControlToolkit" publicKeyToken="28f01b0e84b6d53e"/>
            <publisherPolicy apply="no"/>
            <bindingRedirect oldVersion="1.0.10920.32880" newVersion="1.0.20229.26329"/>
        </dependentAssembly>
        <dependentAssembly>
            <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31BF3856AD364E35"/>
            <publisherPolicy apply="no"/>
            <bindingRedirect oldVersion="3.5.0.0" newVersion="1.0.61025.0"/>
        </dependentAssembly>
    </assemblyBinding>
</runtime>

Code snippet 3 :

<add key="configPassword" value="" />
<add key="BoardID" value="1" />
<add key="EnableURLRewriting" value="false" />
<add key="databaseObjectQualifier" value="yaf_" />
<add key="databaseOwner" value="dbo" />
<add key="providerExceptionXML" value="ProviderExceptions.xml" />
<add key="UploadDir" value="~/yaf/upload/" />
<add key="ProviderKeyType" value="System.Int32" /> 
<add key="root" value="/yaf" />  
<add key="BaseUrl" value="~/yaf" />
<add key="BaseUrlOverrideDomain" value="false" />   

Code snippet 4 :

<connectionStrings>
    <add name="yafnet" connectionString="server=.\sqlexpress;database=umbraco;user id=umbracoUser;password=umbraco" />
</connectionStrings>

Code snippet 5 :

<pages validateRequest="false" smartNavigation="false">
    <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add tagPrefix="umbraco" namespace="umbraco.presentation.templateControls" assembly="umbraco" />
        <add tagPrefix="ajaxToolkit" namespace="AjaxControlToolkit" assembly="AjaxControlToolkit"/>
        <add tagPrefix="YAF" namespace="YAF.Classes.UI" assembly="YAF.Classes.UI" />
        <add tagPrefix="YAF" namespace="YAF.Classes.Utils" assembly="YAF.Classes.Utils" />
        <add tagPrefix="YAF" namespace="YAF.Classes.Data" assembly="YAF.Classes.Data" />
        <add tagPrefix="YAF" namespace="YAF.Controls" assembly="YAF.Controls" />
        <add tagPrefix="YAF" namespace="YAF.Controls.Statistics" assembly="YAF.Controls" />                
        <add tagPrefix="YAF" namespace="YAF.Classes" />
        <add tagPrefix="YAF" namespace="YAF"/>
        <add tagPrefix="editor" namespace="YAF.Editor"/>
    </controls>
    <namespaces>
        <add namespace="YAF" />
        <add namespace="YAF.Classes.UI" />
        <add namespace="YAF.Classes.Utils" />
        <add namespace="YAF.Controls" />
        <add namespace="YAF.Classes.Data" />
    </namespaces>
</pages>

Code snippet 6 :

<profile enabled="false" defaultProvider="YafProfileProvider" inherits="YAF.Classes.Utils.YafUserProfile">
    <providers>
        <clear/>
        <add connectionStringName="yafnet" applicationName="YetAnotherForum" name="YafProfileProvider" type="YAF.Providers.Profile.YafProfileProvider"/>
    </providers>
</profile>

Code snippet 7 :

namespace Dawoe.Providers
{
    public class YAFUmbracoMembership : umbraco.providers.members.UmbracoMembershipProvider
    {
        public override string ApplicationName
        {
            get
            {
                return base.ApplicationName;
            }
            set
            {
                // Do nothing because umbraco doesn't allow empty applicationnames or applicationnames with a lenght greater than 0
            }
        }
    }
}

Code snippet 8 :

<add name="YafFramehelperRewrite" virtualUrl="framehelper.aspx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/yaf/framehelper.aspx?$1" ignoreCase="true" />
<add name="YafAdvancedRewrite" virtualUrl="advanced.aspx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/yaf/advanced.aspx?$1" ignoreCase="true" />
<add name="YafErrorRewrite" virtualUrl="error.aspx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/yaf/error.aspx?$1" ignoreCase="true" />
<add name="YafResourceRewrite" virtualUrl="resource.ashx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/yaf/resource.ashx?$1" ignoreCase="true" />
<add name="YafRewrite" virtualUrl="/yaf/forum.aspx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/forum.aspx?$1" ignoreCase="true" />

Code snippet 9 :

private void Forum_Init(object sender, EventArgs e)
{
    try {
        ((umbraco.UmbracoDefault)this.Page).ValidateRequest = false;
        }
    catch {
        // catch error when page isn't called with umbraco master page
        }
}