Getting EPiServer FileManager into Relate+ clubs
Having the possibility to upload files into EPiServer Community Clubs has internally been a highly requested feature on our Intranet site. Since the EPiServer.FileManger that you see in our Demo templates are based on EPiServer CMS pages and files stored into the current page folder that will not work for Community clubs that are not based on pages.
Well after some discussion with my colleagues the solution was quite simple; Combine how EPiServer Blog uploads file with the Workroom File Manager web control.
First of create an ClubFile page type and add it to your Relate+ project. Then from EPiServer Demo Templates add/take:
- EPiServer.FileManger Web control
- The usercontrols in EPiServer.Templates.Demo.FileManager
- FileManager and extensions images under Templates/Demo/Styles/Default/images
- Stylesheet specific for Filemanager in styles.css (File manager control, Toolbar buttons, Documents)
- File Manager language texts from demo_en.xml in lang folder.
- Lastly, the EPiCheckBox class which is in /Templates/Demo/Workroom/Core/EPiCheckBox.cs
In Web config you register the File Manager Web control,
1: <configSections>
2: ...
3: <sectionGroup name="episerverModules">
4: <section name="episerver.FileManager" type="EPiServer.Demo.FileManager.Configuration.FileManagerSection, EPiServer.Demo.FileManager"/>
5: </sectionGroup>
6: ...
1: <episerverModules>
2: <episerver.FileManager configSource="Templates\FileManager\views.config" />
3: </episerverModules>
Still in web.config, but in Pages declaration, add
1: <pages validateRequest="false" enableEventValidation="false">
2: <controls>
3: ...
4: <add tagPrefix="FileManager" namespace="EPiServer.Demo.FileManager.WebControls" assembly="EPiServer.Demo.FileManager"/>
5: <add tagPrefix="EPiServer" namespace="EPiServer.Templates.RelatePlus.Classes" assembly="EPiServer.Templates.RelatePlus" />
6: ...
I choose to copy the EPiCheckBox class and changed the namespace to EPiServer.Templates.RelatePlus.Classes.
EPiServer Blog uploads its files into Global Files folder if not reconfigured in web.config. There it creates a xmlrpc folder and from there the tree structure is; PageID, Year, Month, Day.
My strategy was similar. The File Manager requests a RootFolder Path, so instead of a xmlrpc folder I defined a “ClubFiles” folder and beneath it a folder for each club based on ClubId, but I skipped the date folders. Similar to blogs which worked with PageID.
The code then,
1: /// <summary>
2: /// Gets or sets the file folder root.
3: /// </summary>
4: /// <value>Path to root folder for files.</value>
5: public string FileFolderRoot
6: {
7: get
8: {
9: if (String.IsNullOrEmpty(_fileFolderRoot))
10: {
11: _fileFolderRoot = GetVPPFolder();
12: }
13: return _fileFolderRoot;
14: }
15: }
16: private string GetVPPFolder()
17: {
18: // stolen from how episerver.blogs handle file uploads, changed blog page id to use club id
19: string path = "";
20: UnifiedDirectory vdir;
21: VirtualPathUnifiedProvider provider = GetClubProvider(out vdir);
22:
23: path =
24: VirtualPathUtility.AppendTrailingSlash(VirtualPathUtility.Combine(vdir.VirtualPath,
25: Master.CurrentClub.ID.ToString()));
26: UnifiedDirectory clubdir = null;
27: if (!(provider.DirectoryExists(path)))
28: {
29: clubdir = ((UnifiedDirectory)vdir).CreateSubdirectory((Master.CurrentClub.ID.ToString()));
30: }
31: else
32: {
33: clubdir = (UnifiedDirectory)provider.GetDirectory(path);
34: }
35: return clubdir.VirtualPath;
36: }
37:
38: private VirtualPathUnifiedProvider GetClubProvider(out UnifiedDirectory vdir)
39: {
40: const string vppProviderName = "SiteGlobalFiles";
41: const string clubfiles = "clubFiles";
42: VirtualPathUnifiedProvider provider = (VirtualPathUnifiedProvider)VirtualPathHandler.GetProvider(vppProviderName);
43:
44: if (provider.DirectoryExists(provider.VirtualPathRoot + clubfiles))
45: {
46: vdir = (UnifiedDirectory)provider.GetDirectory(provider.VirtualPathRoot + clubfiles);
47: }
48: else
49: {
50: vdir = (UnifiedDirectory)provider.GetDirectory(provider.VirtualPathRoot);
51: vdir = vdir.CreateSubdirectory(clubfiles);
52: }
53: return provider;
54: }
Alright, Lets create an ClubFiles.aspx PageType in our RelatePlus project and set the MasterPageFile to ClubMasterPage. Add the RelatePlus NoClubAccess usercontrol and the File Manager webcontrol,
1: <%@ Page Language="C#" AutoEventWireup="false" CodeBehind="ClubFiles.aspx.cs" Inherits="EPiServer.Templates.RelatePlus.Pages.ClubFiles"
2: MasterPageFile="~/Templates/RelatePlus/MasterPages/ClubMasterPage.master" %>
3:
4: <%@ MasterType VirtualPath="~/Templates/RelatePlus/MasterPages/ClubMasterPage.master" %>
5: <%@ Register TagPrefix="RelatePlus" TagName="NoClubAccess" Src="~/Templates/RelatePlus/UserControls/ClubUserControls/NoClubAccess.ascx" %>
6: <asp:Content ID="leftContent" runat="server" ContentPlaceHolderID="plhLeftContentArea">
7: <RelatePlus:NoClubAccess ID="ucNoClubAccess" Visible="false" runat="server" />
8: <FileManager:FileManagerControl ID="FileManagerControl" runat="server" RootVirtualPath="<%# FileFolderRoot %>" />
9: </asp:Content>
In the code behind, we add the methods described above and databind the FileManagerControl:
1: protected override void OnLoad(EventArgs e)
2: {
3: // Call base
4: base.OnLoad(e);
5:
6: // Set view options
7: if (Master.IsClubAccessable)
8: {
9:
10: if (!IsPostBack)
11: {
12: FileManagerControl.DataBind();
13:
14: if (FileManagerControl.CurrentVirtualDirectory == null)
15: {
16: GetVPPFolder();
17: }
18: }
19: }
20: else
21: {
22: ucNoClubAccess.Visible = true;
23: }
24: }
Fixing the Bread Crumb
The File Manager is built for EPiServer CMS Pages and the bread crumb control expects the files to be in the page’s directory, where it gets the page owner and displays the Page Name. Well this will not work for Community clubs, so we need to change it to get the Club Name of that folder.
My current solution is a quick hack where it tries to Parse the Folder name, which is the club id and then get that club. Anyhow, in the usercontrol HeadingContent we modify the method AppendBreadCrumbs to:
1: /// <summary>
2: /// Appends the cookie crumb links to the control supplied as targetControl.
3: /// </summary>
4: /// <param name="currentDirectory">The current directory.</param>
5: /// <param name="targetControl">The target control to append cookie crumb links to.</param>
6: private void AppendBreadCrumbs(UnifiedDirectory currentDirectory, Control targetControl)
7: {
8: if (currentDirectory == null || FileManager.RootVirtualPath == currentDirectory.VirtualPath)
9: {
10: // Reset the link enumeration when we reach the topmost directory.
11: _linkId = 0;
12: }
13: else
14: {
15: // Append cookie crumb for the parent directory before adding for the current directory.
16: AppendBreadCrumbs(currentDirectory.Parent, targetControl);
17: Literal slash = new Literal();
18: slash.Text = " / ";
19: targetControl.Controls.Add(slash);
20: }
21:
22: string directoryName = currentDirectory.Name;
23: if (currentDirectory.Parent != null)
24: {
25: int clubID;
26: // a hack to make it work. Will try parse all folders
27: if (int.TryParse(currentDirectory.Name, out clubID))
28: {
29: Club currentClub = ClubHandler.GetClub(clubID);
30:
31: if (currentClub != null)
32: {
33: directoryName = currentClub.Name;
34: }
35: }
36: }
37:
38: LinkButton b = new LinkButton();
39: b.ID = "link" + _linkId++;
40: b.Text = directoryName;
41: b.CommandArgument = currentDirectory.VirtualPath;
42: b.CommandName = FileManagerCommandName.SelectFolder;
43: b.Command += new CommandEventHandler(RaiseCommand);
44: targetControl.Controls.Add(b);
45: }
Then the “final” solution looks like this,
And in Admin mode, File Management:
Then you’re done. Now check in your code, get a cup of coffee and let the GUI dude fix the layout stuff.
Something that I haven’t done yet but I should is to create my own Virtual path provider. Inherit from EPiServers VPP, override the QueryAccess method and check that the access rights of the files match the current users club access rights. Might be a different blog post.
By the way, I haven’t tested this on live site yet and might have forgotten something. Comments and feedback is appreciated.
Great Post!
/ Bevan
I just tried this out and it works great! The only detail I can think of that you didn't mention was that you need to add a reference to the EPiServer.Demo.Filemanager dll.
Other than that, awesome! Thanks for writing this post :)
I've had a very very strange effect from setting up this example.
I've got EPiServer Relate+ 2.0, EPiServer CMS 6.0 and was using the 6.0 demo templates.
Uncommenting the code-behind for the ClubFiles.aspx file DELETED files from the bin directory on-rebuild! Files that were disappearing included but were not limited to - nhibernate.dlll and the microsoft enterprise library DLLs.
I reverted my repository to re-add these files after uncommenting the code, and everything works as it should.
If anybody else has a problem with getting this example working, check your bin directory closely!
Really good article. Just added FileManager from CMS 6 demo templates to Relate 2 R2 Successfully after little tweaking.
There more detailed article about this. I recommend this article if you want to try fileManager with Relate:
http://world.episerver.com/Blogs/Jeff-Wallace/Dates/2009/12/Getting-EPiServer-FileManager-into-Relate-Clubs--Verbose-Version/