Академический Документы
Профессиональный Документы
Культура Документы
1 Visual Studio Snippets and Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.2.2 Installing N2CMS NuGet Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.2.3 Configuring the Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.2.4 Deciding Where to Store Attachments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.3 Prepare for Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.3.1 Install a New Instance of N2 Dinamico MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.3.2 Install a New Instance of N2 MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.3.3 Install a New Instance of N2 WebForms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.3.4 Integrate N2 into an Existing MVC Site . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.3.5 Integrate N2 into an Existing WebForms Site . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.4 Deploying N2 to a web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.5 The N2 Installation Wizard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.6 Contributing Code back to N2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.1 Site and Language Roots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.2 Creating and Editing Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.2.1 Edit mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.2.2 Linking to Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.2.3 Organize Parts mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.2.4 Using the Rich Text Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.3 Managing Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.3.1 Securing Non-ContentItem Pages with N2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.4 Search Engine Optimization (SEO) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.5 Importing and Exporting Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.6 Troubleshooting Runtime Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.6.1 Common Runtime Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.6.2 File Upload Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.6.3 Proxy Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.6.4 Routing Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Developer Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.1 The Domain Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.1.1 Editors via Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.1.2 Your First ContentItem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.2 Creating and Updating Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.3 Page Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.3.1 Creating a ContentPage controller in ASP.NET MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.3.2 Creating a Content Page Template in WebForms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.3.3 Dinamico Page Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.4 Master Pages and Zones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.5 Theming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.6 Part Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.6.1 Built-in Parts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.6.2 Defining Zones within Parts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.6.3 Dinamico Part Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.6.4 MVC Part Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.6.5 Overriding Part Rendering with Adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.6.6 Template-First Definitions (MVC Razor) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.6.7 WebForms Part Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.7 Editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.7.1 Built-in Editor Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.7.2 Creating Custom Editors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.7.3 Organizing Editors with Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.8 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.9 Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.10 Links and Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.11 Finding Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.12 Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 3 5 6 8 8 10 11 11 11 11 12 12 13 13 14 15 17 18 20 21 22 24 27 28 29 29 29 29 30 30 31 31 31 33 35 35 37 37 39 41 43 43 44 44 45 45 45 45 48 48 49 51 51 52 55 57 57 59 59 62
1.3.13 Filtering Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.14 Extending the Administration System with UI Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.15 Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.16 Extending web.config . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.17 Permissions and Roles, Programmatically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4 Additional Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.1 Getting Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63 65 67 68 68 69 69
n2cms Home
This is the home of the n2cms space. To help you on your way, we've inserted some of our favourite macros on this home page. As you start creating pages, blogging and commenting you'll see the macros below fill up with all the activity in your space.
Recently Updated
Managing Permissions
Getting Started
N2 is a lightweight CMS framework. With just a few strokes of your keyboard a wonderful strongly typed model emerges complete with a management UI. You can spend the rest of your day building the best site imaginable.
"It's so .NET!"
Unlike most CMS'es you build the model of the data that needs to be managed using C# or VB code in Visual Studio. The type below is picked up by the N2 engine at runtime and made available to be edited. The code uses an open API with multiple built-in options and unlimited customization options.
[PageDefinition(TemplateUrl = "~/my/pageitemtemplate.aspx")] public class PageItem : N2.ContentItem { [EditableFreeTextArea] public virtual string Text { get; set; } }
"I never thought getting the data out again could be so easy"
N2 CMS knows not to mess with YOUR HTML. For web-forms it provides a nice data binding controls, and for ASP.NET MVC routes to your controller and provides easy access to data.
Binds a control to the current page's text property: <asp:Literal Text="<%$ CurrentItem: Text %>" runat="server" /> Provides create, read, update, delete access to content through ASP.NET the databinding API: <n2:ItemDataSource ID="Level1Items" runat="server" Path="/" /> <asp:DataGrid DataSourceID="Level1Items" runat="server" /> Renders non-page items added to the "RightColumn" zone: <n2:Zone ZoneName="RightColumn" runat="server" /> Outputs content using the default control (a literal in this case): <n2:Display PropertyName="Text" runat="server" />
public void DoSomeStuffWithSomeItems(DateTime minDate, DateTime maxDate) { IList<ContentItem> items = N2.Find.Items .Where.Created.Between(minDate, maxDate) .And.SavedBy.Eq("admin") .OrderBy.Published.Desc .Select(); foreach (ContentItem item in items) DoSomethingWith(item); }
Virtually no administration or configuration is required. To further simplify usage you can create plug ins.
Contents Links
N2CMS Home page http://n2cms.com N2CMS Community page http://n2cms.codeplex.com N2CMS Github repository (code access) http://github.com/n2cms/n2cms
Server Requirements
Operating System
Any OS capable of running .NET framework such as: Windows XP Windows 2003 Windows Vista, Windows 7, Windows 8 Windows 2008/R2 IIS 6 or newer ASP.NET Development Server WebMatrix .NET Framework 3.5 SP1 .NET Framework 4.0 Windows XP and Windows Server 2003 (and Windows Server 2003 R2) do not support .NET Framework 4.5.
Web Servers
N2CMS has been tested successfully on the Visual Studio embedded web server, IIS, and IIS Express.
.NET Framework
N2CMS 1.5 can run on .NET 2.0. We recommend that you run N2CMS on the latest version of the .NET framework possible.
Databases
Supported databases include: SQL Server 2008 * SQL Server 2008 Express * SQL Server 2005 * SQL Server 2005 Express * SQL Server 2000 SqlCe MySQL * SQLite * Firebird Jet DB2 Oracle9i Oracle10g
* A connection string example for these database engines can be found in web.config.
Shared Hosting
Some users report no problems running in shared hosting under medium trust, others have had problems. N2CMS has been tested on unmodified medium trust. Its recommended you ask the hosting provider before you buy a long-term plan. Note that N2CMS can be somewhat RAM intensive, and requires a minimum of 64 MB of RAM dedicated to your website. More RAM may be needed depending on the plugins you require or the amount of traffic your website receives. Plug-ins such as site search can also increase the memory requirement.
Nuget-based environment
You want the easiest integration of N2 in an exisitng project. The Nuget framework will download and install all required dependencies into an existing Visual Studio project. You always want to have the most recent code, or you want to use one of the sample template projects. The Git-based environment contains both the WebForms and MVC template packs, sample data, plus the N2 Core and all dependency binaries. This is a great way to get started with N2, particularly if you don't already have a project started. You can use one of the existing projects as a basis for your new N2-based site: WebForms Templates Pack ASP.NET MVC Templates Pack ASP.NET MVC "Dinamico" Templates Pack (uses the Razor engine)
Git-based environment
Updating N2CMS
After you've installed N2CMS in one of these ways, you will want to update it from time to time to take advantage of the latest features, security patches, and other updates. If you opted to use the Nuget deployment model, the Nuget packages will be updated periodically, and you can update using the built-in Nuget update mechanism to update your local instance of N2CMS. If you chose the Git deployment model, you can use git pull to get the latest updates in your own Git repository.
Installation Instructions
Example: Dinamico Template Pack
For the NOZIP option:
Install-Package -Source C:\N2Packages -Name n2cms.dinamico Install-Package -Source C:\N2Packages -Name n2cms.management.nozip
Install-Package -Source C:\N2Packages -Name n2cms.dinamico Install-Package -Source C:\N2Packages -Name n2cms.management.zip
Database Connection
If this is a clean installation, you will need to install the database.
Upgrading
You can upgrade just the management pack. The N2CMS libraries will be updated automatically if required. You can also upgrade the template packs. Run the relevant Install-Package command as listed above.
OR
<!-- Please not that you need to configure another database and remove \bin\system.data.sqlite.dll if you run in medium trust --> <add name="N2CMS" connectionString="Data Source=|DataDirectory|\n2.sqlite.db;Version=3;New=True;" providerName="System.Data.SQLite" />
Then replace the connection string tag with one that corresponds to the database engine you want to use. Database Engine SQLite Connection String <add name="N2CMS" connectionString="Data Source=|DataDirectory|\n2.db;Version=3;New=True;" providerName="System.Data.SQLite"/> <add name="N2CMS" connectionString="Server=(local);Database=N2_Templates;Integrate d Security=SSPI"/> <add name="N2CMS" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\N2.mdf; Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient"/>
<add name="N2CMS" connectionString="Data Source=SQLServer2000;Database=SQLDatabase2000;User Id=SqlUser2000;Password=SqlPassword2000;Network Library=DBMSSOCN;" providerName="System.Data.SqlClient"/> <add name="N2CMS" connectionString="Data Source=MySQLServer;Database=MySQLDatabase;User Id=MySQLUser;Password=MySQLPassword;" providerName="MySql.Data.MySqlClient"/>
MySQL
N2 supports several kinds of databases. To configure another database open web.config in the sites root directory and find the <connectionStrings> section. Remove the existing connection string and update the most relevant template to your databases settings.
[N2.Web.Controls(typeof(Models.HomePage))] public class HomeController : Controller { public ActionResult Index() { ViewData["Message"] = "Welcome to ASP.NET MVC!"; return View(); } }
Web.config Entries
{content needs to be written}
{content needs to be written} Caveat: more memory used by the ZIP DLL.
Set a password for your new site. Leave the checkbox selected (you can change this later in web.config if you wish) Click on help me install a database for a new site Log in using the username admin and password you just wrote. Continue to create tables. Now is the good time to update the connection string to another database if you dont want to use SQLite. If you are installing N2 in an existing database, the N2 setup wizard will drop any tables that have conflicting names with N2's tables. We recommend that you install N2 in its own database. On step 2. Content Package go to Manually insert nodes and insert a Root Page (fallback) and HomePage and click Add two separate nodes.
On the finishing touches click on disable installation. This will make this installation wizard unavailable. To re-enable it, set allowInstallation to true in web.config (this is needed for upgrade).
customers, or your organizations' needs, we encourage you to commit useful portions of what you create back to the community, so that others can benefit from your work. Think of the time that N2CMS saves you! Your contributions will help our thousands of users in turn.
Github
Official development of N2CMS takes place on Github.
Adding files and Committing Sending a Pull Request Updating Your Fork from Official Branches
Description SourceTree provides rich Git functionality with a slightly more complex user interface. Highly recommended. Github's own official GUI client, available for Windows and Mac.
Setting up SourceTree
First, you need to fork the repository on Github per the instructions above. 1. click Clone/New in the toolbar. Under Source Path / URL, enter the URL to your fork of the N2CMS repository (see above). 2. specify the destination path on your PC where you want to save the source code 3. click Clone and SourceTree will set up your own copy of the repository. Now, you need to add a remote for the official n2cms branches, so that you can pull changes from there. 1. make sure that your n2cms clone is open in SourceTree (double-click the item in the repository list on the left) 2. right-click Remotes and click New Remote
3. In the New Remote dialog, fill in the required properties a. Remote name: github-n2cms b. URL / Path: git@github.com:n2cms/n2cms.git 4. Click OK to save the Remote 5. You can now fetch and pull (which is equivalent to fetch+merge) changes from the official Github repository into your own local copy. When you've done that, you can push those changes to your Github fork copy as well.
Management
Signing in to N2
You'll need a username and password to log on to N2CMS. When you have this, visit ~/n2 (e.g. www.yourdomain.com/n2) to enter your credentials.
Manage user accounts Manage site-wide settings Manage page-level access permissions Perform bulk operations, such as import/export
Figure 1. the management UI N2CMS does not currently support website templates that contain frame-breaking scripts.
In this section
Signing in to N2 For N2CMS 2.5 and earlier For N2CMS 2.5 and later (with UI refresh)
Continue reading
(StartPage) ... (LanguageIntersection) my_other_website (StartPage) en-us (StartPage) es-es (StartPage) ... (Trash) (Upload) Your content pages for each site/language combination go under the respective StartPage.
Hostname (DNS)
You can assign a hostname to a language intersection (or a start page located directly under the Root node) by using the Site configuration menu. Depending on which template pack you are using, you can also configure custom HTTP 404 and 500 error pages by pointing to a node in your content tree. These custom 404/500 pages can even use parts like any other content page! Fill in the Site host name (DNS) field with the domain you want to map. If you leave this field blank (this is the default), then all domains will map to that site.
Template/Theme
You can also customize the template or theme that this virtual site inherits by customizing the Site Theme option. The changes are applied immediately when you Save.
Example Screenshot
n2_host.config file
The n2_host.config file maps hosts to root and start pages. URLs are generated relative to the StartPage specified in the startPageID attribute.
<?xml version="1.0" encoding="UTF-8"?> <!-- This is stored in a separate file so that the installation wizard can write to this file without write access to web.config --> <host rootID="1" startPageID="4" multipleSites="true"> <web extension="" /> <vpp> <zips> <add name="n2.management" observedPath="~/N2/" filePath="~/N2/N2.zip"/> </zips> </vpp> </host>
You should check that the rootID and startPageID node point to the correct root and start page node ID. You might need to look into the database to find the IDs of the start page and rootID. These values should be initially set up correctly by the N2CMS setup wizard.
Then, you can select a template for the new page. Usually, you want the template called Content Page. Once you select a template, the page is created and you are taken to Edit mode.
Editing Content
Content editing is done in one of two modes: Edit mode Organize Parts mode When you first create a page, you're taken to Edit mode. Here, you specify the basic attributes of the page: the page title the url of the page (which is usually generated from the title automatically)
Edit mode
In Edit mode, the various properties of the item you are editing are displayed. There are a variety of editor types, all of which are controlled by att ributes on the classes you are editing. For more information on these editor types and how to create your own, see the Editors topic in the documentation.
Editing a page
Now we are accessing the site's edit interface (/edit) and are editing the start page. Remember we defined a property named Text? Remember that we gave that property an attribute: EditableFreeTextArea? That attribute is interpreted by the N2 engine and a html editor is displayed when we edit the page without the need to write a single form.
While we're still remembering what we discussed in the previous chapter. The TextPage class was also decorated with an attribute: [Defi nition]. The attribute tells N2 what type of page is called when we are editing. In this GalleryItem we're creating a new item.
Linking to Content
In this section... Page-to-Page Navigation Single Links Video: Creating an inline hyperlink Dynamically Linking to Content Items File Downloads
Page-to-Page Navigation
Single Links
There are a few ways that users can download files. You can choose from embedded hyperlinks, or two parts that Method How to Use Screenshot
1. Drag and drop a Hyperlink part from the Organize Parts toolbox into the page. 2. Select a page in your site. You can click on the Browse (hyperlink icon) button to pop up a dialog that allows you to select any page from the site content tree. 3. Fill out the properties of the hyperlink (noting the link URL property) 4. Click Save to save the hyperlink to the document. a. You need to click Save again to save your changes to the overall page. For more information, read about the Hyperlink content part.
Inline hyperlink
1. In any rich text editor, highlight text and click on the Hyperlink button (red circles in the screenshot). 2. Fill in the properties of the link. You can use the Browse Server button to select another page in your website or enter any URL manually. 3. Click Save to write the hyperlink to the document. a. You need to click Save again to save your changes to the overall page. b. Finally, click Save and Publish to publish the document.
1. Drag and drop a Selection part from the Organize Parts toolbox into the page. 2. Mark the checkbox next to each item you want to include in the selection (see screenshot) For more information, read about the Selection Content Part.
File Downloads
How to Use 1. Drag and drop a File Download List from the Organize Parts toolbox into the page. 2. Select the directory on your server (e.g. /upload/...) and specify a file mask (e.g. *.jpg for all file names ending in .jpg) 3. Decide how you want the files to be sorted.
Screenshot
1. Drag and drop a Hyperlink part from the Organize Parts toolbox into the page. 2. Select the file that the user should download. You can click on the Browse ( hyperlink icon) button to pop up a dialog that allows you to select any file from the upload directory. For more information, read about the Hyperlink content part.
1. In any rich text editor, highlight text and click on the Hyperlink button (red circles in the screenshot). 2. Fill in the properties of the link. You can use the Browse Server button to select a file to be downloaded.
what the page is going to look like after editing is complete. There is also a visual tool for editing the parts on a page. On the N2 toolbar, click the Organize Parts icon. When you mouse over any part, a handle is shown. You can click and drag the part up or down in its current zone, or to a different zone on the page. Note that parts can restrict what zones they participate in, and only valid target zones are displayed in the drag and drop interface. Again, changes are saved immediately. You can also add new parts by clicking on the ways: Description 1. Click Edit in the top toolbar and then choose Organize. Add icon in the Edit Mode interface, or by entering Organize Parts mode in one of two
Screenshot
2. Expand the toolbar (fig. a) if it's not expanded already, and then click the Organize Parts icon (fig. b) when the tray opens.
(a)
(b)
Zoned Parts
Other parts can be dragged and dropped into areas called "Zones" on the page. When you enter "Organize Parts" mode on a page, the available zones are highlighted in green when you begin dragging a Part into the page. The available zones are also shown in the Edit form on the right-hand side.
System Requirements
The following web browsers are supported: Internet Explorer 9 or higher, Google Chrome, Mozilla Firefox 3 or higher
Styles
Please note that the styles displayed in the Rich Text Editor may not look the same in the editor as they will appear on the web site. Click Save to save your changes and you can preview the results live. You can always return to the editor if you want to make additional changes.
Extended Functionality
The extended functionality can be accessed by clicking on the Show/Hide Toolbars option all the way on the left of the editor.
Hyperlinks
To insert a hyperlink, use the Insert/Edit link button. The Insert/Edit link button will be disabled if there is no text selected. After you click the Insert/Edit Link button, the Insert/Edit Link Dialog will be shown. Click the Browse button to select the link target from the site hierarchy. Alternatively, you can type any web URL into the box to link to that location. Click Insert when you are finished to create the link. The Unlink butto n (directly to the right of the Insert/Edit Link button) can be used to remove a hyperlink (the underlying text will remain).
Managing Permissions
Editing Page Permission Managing Roles Available roles can be managed from TODO
SHA1
See Also
Permissions and Roles, Programmatically
[NullReferenceException: Object reference not set to an instance of an object.] N2.Edit.FileSystem.Directory1.Reload() in c:\Projekt\OSS\github\n2cms\n2cms\src\Mvc\MvcTemplates\N2\Files\FileSystem\Directory.a spx.cs:44 N2.Edit.FileSystem.Directory1.OnInit(EventArgs e) in c:\Projekt\OSS\github\n2cms\n2cms\src\Mvc\MvcTemplates\N2\Files\FileSystem\Directory.a spx.cs:35 System.Web.UI.Control.InitRecursive(Control namingContainer) +140 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +480
127.0.0.1
n2site.enferno.local
n2site
Create the site in IIS manager, bind it to your name like n2site, and map the root to your project folder. Change project setting to Use Local IIS Server and set the project url to http://n2site This workaround does not work on Windows Azure. When using N2 on Windows Azure you must use / as the root of your N2 site.
Developer Fundamentals
CMS Framework vs. Templates
The framework is represented by N2.dll, N2.Security.dll and N2.Management.dll as well as all files below the /N2/ folder. These reflect upon the application to create a UI where the sites structure and content is managed. The framework provides tools the application can use to create a navigable web site. The application references N2.dll and uses API:s in the N2 namespace to model content items so they can be managed from the management UI. The application contains the external shape of the site including master pages, style sheets and application logic. The application is developed with ASP.NET MVC or WebForms, either way they use the same version of the N2 CMS framework.
Its also possible to inject or replace services in N2 to bend the CMS behavior beyond recognition.
Pages that are outside a start page, e.g. pages in trash can also be accessed but not via a friendly url. Pages handled by an MVC controller are accessed via an url that corresponds to /{controller}/{action}/?page={id}. Pages that are handled by a webforms page are accessible via /{path-to-aspx-template}?page={id}.
Controller:
And the following incoming URL: /news/n2-cms-2-1-1-released This URL is based on each pages name and the names of the ancestors leading up to the start page. In this case the page N2 CMS 2.1.1 released is placed below the page News which is directly below the start page. When a request arrives routes are asked in order if they can handle it. Since the URL maps to a content item the ContentRoute will respond with route data containing controller and referencing to the item. Path segments immediately after a path leading to a controller are mapped as actions if there is a corresponding method on the controller. E.g. if there was an action Comment on the ContentPages controller the following url would lead to that action: /news/n2-cms-2-1-1-released/comment The following URL would also lead to this item and would be generated for pages that arent within a start page (e.g. if they have been thrown in the trash): /ContentPages/Index/?page=123
Figure 1. Editors are exposed via attributes on the properties defined in ContentItems.
Since TextPage inherits from N2.ContentItem (in this case a bit down the inheritance chain) it is treated by the N2 engine as a content type and made available for editing through the edit interface. Take a quick look at that Text property before you move on. It has an interesting attribute that's used by the N2 engine to determine what kind of editor should be used to edit that property.
Since it's the EditableCheckbox attribute a textarea is displayed when you edit this page. The parameters are just the name displayed in edit and the order of this property. There are a number of built-in "editable" attributes. For more information, see the Editors chapter in the user guide. Note the call to GetDetail in the getter. GetDetail gets values from a content detail collection and SetDetail updates the same value. Any serializable class is supported. The content detail collection contains all custom properties.
using N2.Details; using N2.Integrity; using N2.Definitions; using System; public class TextPage : ContentItem { }
By default, N2 inherits a few properties and methods from ContentItem. Here are a few of particular interest (don't worry about the details for now): public virtual DateTime Created { get; set; } public virtual string IconUrl { get; } public virtual bool IsPage { get; } public virtual IList<T> GetChildren<T>() where T : ContentItem public virtual IList<T> GetChildren<T>(string zoneName) where T : ContentItem public virtual string TemplateUrl { get; } public virtual string Title { get; set; } public virtual DateTime Updated { get; set; } public virtual string Url { get; } public virtual int VersionIndex { get; set; } Note that none of these methods are abstract. Thus, you can see that N2 does a lot of the work for you. N2 takes care of versioning, managing URLs (though you can customize them), children, templates, modification and creation times, and more. Also note that all of these methods and properties are virtual; thus, you can override any of them in your own subclass to completely customize N2 to your exact needs. We won't do any customization right now, but we did want to point out this highly flexible engineering model.
Make it a Page
In N2, every piece of content -- whether it's a page, part, or data entity -- is a ContentItem. Therefore, we need to let N2 know that we actually want to create a page. Pages in N2 implement the IPage interface, which is simply a marker interface. In other words, IPage doesn't actually define any methods or properties. Note: At this point we've basically built AbstractPage, which is a base class for all pages used in the Webforms template pack.
[FileAttachment, EditableFileUploadAttribute("Image", 90, ContainerName = Tabs.Content, CssClass = "main")] public virtual string Image { get { return (string)(GetDetail("Image") ?? string.Empty); } set { SetDetail("Image", value, string.Empty); } }
Figure 1. Editors are exposed via attributes on the properties defined in ContentItems.
Since TextPage inherits from N2.ContentItem (in this case a bit down the inheritance chain) it is treated by the N2 engine as a content type and made available for editing through the edit interface. Take a quick look at that Text property before you move on. It has an interesting attribute that's used by the N2 engine to determine what kind of editor should be used to edit that property.
[PageDefinition("TutorialPage")] [WithEditableTitle, WithEditableName] public class TutorialPage : ContentItem { [EditableFreeTextArea("Text", 100)] public virtual string Text { get { return (string)(GetDetail("Text") ?? string.Empty); } set { SetDetail("Text", value, string.Empty); } } }
Ever since N2 CMS 2.1 its possible to get rid of the bulky getters and setters:
[PageDefinition("TutorialPage")] [WithEditableTitle, WithEditableName] public class TutorialPage : ContentItem { [EditableFreeTextArea("Text", 100)] public virtual string Text { get; set; } }
A common pattern is using an abstract base class for re-use across multiple types:
[WithEditableTitle, WithEditableName] public abstract class ContentPageBase : ContentItem { [EditableFreeTextArea("Text", 100)] public virtual string Text { get; set; } } [PageDefinition("Tutorial Page")] public class TutorialPage : ContentPageBase { } [PageDefinition("Example Page")] public class ExamplePage : ContentPageBase { }
Both TutorialPage and ExamplePage will have an editable title, name and text. When developing an ASP.NET MVC application the content item doesnt know which template will use it (the controller defines which content item it controls). When using WebForms however, TemplateUrl is used:
/// <summary> /// This is WebForms' style of content item declaration. /// </summary> [PageDefinition("WebForm Page", TemplateUrl = "~/Path/To/My/Template.aspx")] public class WebFormPage : ContentPageBase { }
The item template includes a content page class. Take note of these traits shared by most content items: 1. Its attributed by [PageDefinition] 2. It inherits from N2.ContentItem Its enriched by attributes with an editable title, name (url segment), and free text A content controller is also generated. It shares some traits in common with most content controllers: 1. It [Controls] a type of content item (the one that was generated). 2. It inherits from ContentController<T>. The generic argument gives strongly typed access to CurrentItem 3. It has an Index action. There is no view yet, but this is easy enough to generate. Right-click in the Index action method, and Add View
Create a strongly typed view by setting the view data class to the generated model class. The view uses all regions from the master page. Usually MainContent is enough and the others can be removed. Tweaking the view a bit will reveal content managed from the UI:
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server"> <%= Html.DisplayContent("Title") %> <%= Html.DisplayContent("Text") %> </asp:Content>
A quick compile (F6 in visual studio) makes the page available in the management UI.
A content item class and a page template is generated. Content item class:
foo
Page template:
bar
Note that the page template (in the code-behind) inherits from ContentPage<T>. Compiling (F6 by default) makes the page available in the N2 management UI.
Creating a View
The basic idea is to be able to create multilpe views with different editors by only adding a view. This is a step aside from a fully strongly typed model. The idea is to to add cshtml files with code like this:
@{ Content.Define(re => { re.Title = "News page"; re.DefaultValue("Visible", false); re.RestrictParents("Container"); re.Sort(N2.Definitions.SortBy.PublishedDescending); }); }
engine.RegisterViewTemplates<Controllers.ContentPagesController>()
which builds up a template definition conneted to the ContentPage type. The filename is stored in as TemplateKey and is used to find the correct view to render.
Part Types
Overview
TODO
Built-in parts
WebForms ASPX Pages
N2 CMS provides a number of web controls for creating UI with WebForms: <n2:ControlPanel renders the control panel <n2:Display displays content from the current page <n2:HasValue a placeholder that is displayed when a property has a value <n2:Repeater - a repeater with support for no results <n2:SlidingCurtain creates a sliding box around the control panel <n2:Tree creates a tree structure <n2:Zone renders parts in a zone <n2:ItemDataSource binds items to grids and repeaters and navigation controls There are also a number of base classes which helps accessing the current item and integrate witch caching: ContentPage a page base class with access to the current page ContentPage<T> - a page base class with strongly typed access to the current page ContentUserControl a user control base class with access to the current page ContentUserControl<TPage> - a base class with strongly typed access to the current page ContentUserControl<TPage, TPart> - a base class used for parts with access to page and part Look at the WebForms template pack for examples on how to use these controls and base classes. This project provides more web controls and TemplatePage<T> and TemplateUesrControl<T> with additional functionality.
Html.CurrentPage Html.CurrentPage<T> Html.CurrentItem Html.CurrentItem<T> Html.Detail Html.DisplayContent Html.RenderDisplay Html.DroppableZone Html.ActionLink Html.Zone Html.RenderZone Example:
<% using (Html.BeginAsyncAction("lazy", new { partial = true })){ %> <%= Html.ActionLink("Loading expensive content", Html.CurrentPage(), "lazy", ... <% } %>
The example shows a link while the lazy action is being retrieved asynchronously from the client.
The template-first system of defining content assumes the location [ThemeRoot]/Default/Views/[Controller]/*.cshtml, where [ThemeRoot] and [Controller] is configurable during startup.
Change [PageDefinition] to [PartDefinition] and remove the attributes [WithEditableTitle] and [WithEditableName]on the TutorialPart class. Move it to the Models.Parts namespace:
namespace N2.Templates.Mvc.Models.Parts { [PartDefinition("TutorialPart")] public class TutorialPart : ContentItem { [EditableFreeTextArea("Text", 100)] public virtual string Text { get; set; } } }
Change TutorialpartController to use the correct namespace and make it return a PartialView:
[Controls(typeof(Models.Parts.TutorialPart))] public class TutorialPartController: ContentController<Models.Parts.TutorialPart> { public override ActionResult Index() { // Right-click and Add View.. return PartialView(CurrentItem); } }
Right-click in the action, Add View, check Create a partial view (.ascx), and Add
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<N2.Templates.Mvc.Models.Parts.TutorialPart>" %> <div style="border: solid 10px red"> <%= Model.Text %> </div>
Compile and Voila! Choose Organize parts on a page and drag TutorialPart onto a zone.
Example Adapter [Adapts(typeof(NewsList))] public class NewsListAdapter : MvcAdapter { public override void RenderTemplate(System.Web.Mvc.HtmlHelper html, N2.ContentItem model) { html.ViewContext.Writer.Write( /** write HTML here **/ ); } }
The base type is defined as a model of type M decorated with [PartDefinition] and there is a controller with [Controls(typeof(M))].
namespace Dinamico.Controllers { [Controls(typeof(Models.ContentPart))] public class ContentPartsController : ContentController<Models.ContentPart> { public override ActionResult Index() { return PartialView((string)CurrentItem.TemplateKey, CurrentItem); } } } namespace Dinamico.Models { /// <summary> /// This part model is the base of several "template first" definitions /// located in /dinamico/default/views/contentparts/ /// </summary> [PartDefinition] [WithEditableTemplateSelection(ContainerName = Defaults.Containers.Metadata)] public class ContentPart : PartModelBase { } }
Sample: Raw HTML part @model Dinamico.Models.ContentPart @{ Content.Define(a => { a.Title = "Raw HTML"; a.Image("/N2/Resources/Icons/Html.png"); a.Text("HTML").Configure(txt => { txt.Columns = 60; txt.Rows = 10; txt.TextMode = System.Web.UI.WebControls.TextBoxMode.MultiLine; }); }); } @if (Content.Has.HTML) { <div>@Html.Raw(Content.Data.HTML)</div> }
Use the n2propfta template to add a free text area snippet. Give the property the name Text. Edit TutorialPart.ascx and add a display control:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TutorialPart.ascx.cs" Inherits="N2.UI.TutorialPart" %> <div style="border:solid 10px red"> <n2:Display runat="server" propertyname="Text" /> </div>
Compile and Voila! select Organize parts and drag TutorialPartItem into a zone to see it in action.
Editors
Built-in Editor Types
Defining editors
Editors are defined using attributes on content item classes or properties. WithEditableChild Adds an edit for form a child item resolved by its name WithEditableDateRange Adds a date range editor WithEditableName Adds editing of the items name (url segment) WithEditablePublishedRange Adds editing of the items publishing range WithEditableTitle Adds editing of the item title EditableCheckBox Adds editing of a Boolean property EditableChildren Adds editing of a collection of children EditableDate Adds editing of a date EditableEnum Adds editing of an enum EditableFileUpload Adds file upload and store a link to the uploaded file EditableFreeTextArea Adds a WYSIWYG editor EditableImage Adds an image picker EditableImageSize Adds an image size drop down EditableItem Adds an editable child item EditableLanguagesDropDown Adds a drop down with languages EditableLink Adds a link picker EditableTextBox Adds a text box EditableUrl Adds an text box with link picker EditableUserControl Adds a custom user control This is an example of a content item with too many editors defined:
[WithEditableChild] [WithEditableDateRange] [WithEditableName] [WithEditablePublishedRange] [WithEditableTitle] public abstract class ContentPageBase : ContentItem { [EditableCheckBox] [EditableChildren] [EditableDate] [EditableEnum] [EditableFileUpload] [EditableFreeTextArea] [EditableImage] [EditableImageSize] [EditableItem] [EditableLanguagesDropDown] [EditableLink] [EditableTextBox] [EditableUrl] [EditableUserControl] public virtual string Text { get; set; } }
using N2.Details; using System.Web.UI; namespace VanillaApplication.Models { public class EditablePageDropDownAttribute : AbstractEditableAttribute { protected override Control AddEditor(Control container) { throw new NotImplementedException(); } public override void UpdateEditor(N2.ContentItem item, Control editor) { throw new NotImplementedException(); } public override bool UpdateItem(N2.ContentItem item, Control editor) { throw new NotImplementedException(); } } }
Implement AddEditor:
protected override Control AddEditor(Control container) { // here we create the editor control and add it to the page DropDownList list = new DropDownList(); list.ID = Name; list.DataTextField = "Title"; list.DataValueField = "ID"; list.DataSource = N2.Find.Items .Where.AncestralTrail.NotLike("Trash%") // exclude trash .MaxResults(1000) // keep a reasonable result size .Filters(new AccessFilter()) // don't reveal secrets .Select(); list.DataBind(); container.Controls.Add(list); return list; }
Now the available pages show up find but we need to persist what the manager selects:
public override void UpdateEditor(N2.ContentItem item, Control editor) { // here we update the editor control to reflect what was saved ContentItem selectedItem = item[Name] as ContentItem; if (selectedItem != null) { DropDownList list = editor as DropDownList; list.SelectedValue = selectedItem.ID.ToString(); } } public override bool UpdateItem(N2.ContentItem item, Control editor) { // here we update the item from dropdown selection DropDownList list = editor as DropDownList; int selectedID = int.Parse(list.SelectedValue); ContentItem previouslySelected = item[Name] as ContentItem; if (previouslySelected != null && previouslySelected.ID == selectedID) // no change return false; item[Name] = Engine.Persister.Get(selectedID); return true; }
public class HomePage : PageBase { [EditablePageDropDown] public virtual ContentItem AboutPage { get; set; } [EditablePageDropDown] public virtual ContentItem CookiePage { get; set; } }
[TabContainer("content", "Content", 0)] [WithEditableName(ContainerName = "content"), WithEditableTitle(ContainerName = "content")] public abstract class PageBase : N2.ContentItem { [EditableFreeTextArea(ContainerName = "content")] public virtual string Text { get; set; } }
[N2.PageDefinition] [TabContainer("advanced", "Advanced", 10)] public class HomePage : PageBase { [EditableImage(ContainerName = "content")] public virtual string ImageUrl { get; set; } [EditablePageDropDown(ContainerName = "advanced")] public virtual ContentItem AboutPage { get; set; } [EditablePageDropDown(ContainerName = "advanced")] public virtual ContentItem CookiePage { get; set; } }
Adds image picker to the Content tab defined in the base class, and an Advanced tab with two drop down editors. The advanced tab is sorted after the content since its sortOrder property is greater (10 > 0). This is the previously defined editor interface:
Nesting Containers
Its also possible to nest containers:
[TabContainer("content", "Content", 0)] [FieldSetContainer("meta", "Meta attributes", 0, ContainerName = "content", SortOrder = 100)] [WithEditableName(ContainerName = "content")] [WithEditableTitle(ContainerName = "content")] public abstract class PageBase : N2.ContentItem { [EditableFreeTextArea(ContainerName = "content")] public virtual string Text { get; set; } [EditableTextBox(ContainerName = "meta")] public virtual string MetaDescription { get; set; } [EditableTextBox(ContainerName = "meta")] public virtual string MetaKeywords { get; set; } }
Built-in Containers
These are the built-in containers: [ExpandableContainer] [FieldSetContainer] [Separator] [TabContainer] To build your own extend from N2.Definitions.EditorContainerAttribute.
Inheritance Constraints
Its possible to use attributes to define which types of items can be created below another type, and who can create.
[WithEditableName, WithEditableTitle] public abstract class PageBase : N2.ContentItem { [EditableFreeTextArea] public virtual string Text { get; set; } }
[N2.PageDefinition] [RestrictParents(typeof(HomePage))] // allow sections immediately below home page [ItemAuthorizedRoles("Administrators")] // only admins can create this page public class SectionPage : PageBase { }
RestrictChildren make so only the referenced types can be created below. By default all types are allowed.
[N2.PageDefinition] [RestrictParents(typeof(NewsContainer))] // allow only below news container public class NewsPage : PageBase, ICommentable { }
Removing RestrictParents would make it possible to create this type below other types than NewsContainer.
[N2.PageDefinition] [RestrictParents(typeof(PageBase))] // allowed below any page inheriting from PageBase public class TextPage : PageBase, ICommentable { }
[PartDefinition] // allowed in any zone on any page public class FooterPart : ContentItem { }
Zone Restrictions
By default all parts are allowed in any zone. Its optional to define on the pages which zones are available. The benefit of declaring with [AvailableZone] is that parts can be added from the management UI without using drag and drop.
Polymorphic Restrictions
Base classes can use and be referenced for restrictions.
[PartDefinition] [RestrictParents(typeof(ICommentable))] // allowed only below commentable items [AllowedZones("Comments")] // allowed only in comments zone public class CommentPart : ContentItem { }
This part can only be created below types implementing ICommentable. Additionally only the zone Comments is allowed.
Enforced Sorting
To sort the children of a certain page the [SortChildren] attribute is used:
Children are sorted whenever one child is saved. When applying the attribute to already saved content one page must be published again in order for changes to take effect.
The finder fluent API (N2.Find.Items) Traversing the content tree (N2.Find.StartPage.GetChildren()) LINQ (using N2.Linq; Engine.QueryItems()) Using NHibernate query options (hql, criteria, raw SQL, LINQ)
public ActionResult QueryForProperty() { ViewData["foundItmes"] = FindRecentlyPublishedWithFinder(); ViewData["traversedItmes"] = FindRecentlyPublishedWithTraversion(); ViewData["linqedItems"] = FindRecentlyPublishedWithLINQ(); ViewData["hqledItems"] = FindRecentlyPublishedItemsWithNHHql(); ViewData["criteriaItems"] = FindRecentlyPublishedItemsWithNHCriteria(); ViewData["nhlinqedItems"] = FindRecentlyPublishedItemsWithNHLINQ(); return View(); }
The MVC action above invokes multiple ways of finding content which will be analyzed in further detail below.
private IEnumerable<ContentItem> FindRecentlyPublishedWithFinder() { // this will create a hql expression behind the scenes and run it var recentlyPublishedItems = N2.Find.Items .Where.Published.Gt(DateTime.Now.AddMonths(-1)) .Filters(new AccessFilter()) .Select(); return recentlyPublishedItems; }
private IEnumerable<ContentItem> FindRecentlyPublishedWithTraversion() { // this will force all contnet items in the database into memory var recentlyPublishedItems = Find.EnumerateTree(Find.RootItem) .Where(ci => ci.Published > DateTime.Now.AddMonths(-1)) .Where(new AccessFilter().Match) .ToList(); return recentlyPublishedItems; }
This is example usage of traversing the complete content hierarchy using a helper method. This method will force all content to be loaded into server memory and isnt optimal when there is a lot of content.
private IEnumerable<ContentItem> FindRecentlyPublishedWithLINQ() { // the linq support is not fully functional in N2 2.1 beta var recentlyPublishedItems = Engine.QueryItems() .Where(ci => ci.Published > DateTime.Now.AddMonths(-1)) .Where(new AccessFilter().Match) .ToList(); return recentlyPublishedItems; }
This example uses the N2 LINQ wrapper around NH LINQ for finding items.
private IEnumerable<ContentItem> FindRecentlyPublishedItemsWithNHHql() { // use NHibernate hql api for querying // will include previous versions by default var recentlyPublishedItems = Engine.Resolve<ISessionProvider>().OpenSession.Session .CreateQuery("from ContentItem ci where ci.Published > :minDate") .SetParameter("minDate", DateTime.Now.AddMonths(-1)) .Enumerable<ContentItem>() .Where(new AccessFilter().Match) .ToList(); return recentlyPublishedItems; }
This example falls back to the NHibernate hql API for querying. The results are not filtered for previous versions In this case. This is used behind the hood when using the N2 finder API.
private IEnumerable<ContentItem> FindRecentlyPublishedItemsWithNHCriteria() { // use NHibernate criteria api for querying // will include previous versions by default var recentlyPublishedItems = Engine.Resolve<ISessionProvider>().OpenSession.Session .CreateCriteria<ContentItem>("ci") .Add(NHibernate.Criterion.Expression.Gt("Published", DateTime.Now.AddMonths(-1))) .List<ContentItem>() .Where(new AccessFilter().Match) .ToList(); return recentlyPublishedItems; }
This example uses the NHibernate Criteria API for querying. The results are not filtered for previous versions.
private IEnumerable<ContentItem> FindRecentlyPublishedItemsWithNHLINQ() { // use NHibernate linq api for querying // will include previous versions by default var recentlyPublishedItems = Engine.Resolve<ISessionProvider>().OpenSession.Session .Query<ContentItem>() .Where(ci => ci.Published > DateTime.Now.AddMonths(-1)) .Where(new AccessFilter().Match) .ToList(); return recentlyPublishedItems; }
This example uses the NHibernate LINQ API for querying. The results are not filtered for previous versions. This is used behind the hood when using the N2 LINQ API.
Finding details
Details are stored in a separate detail table. Querying for details means asking the database to do a sub-select.
private object FindTextContainsWithFinder() { // this will cause a sub-select var itemsWithSomestring = N2.Find.Items .Where.Detail("Text").Like("%somestring%") .Filters(new AccessFilter()) .Select(); return itemsWithSomestring; }
Caching
URL to Item Mapping Cache
By default url-to-item mapping is enabled. Second level cache (generic database entity cache) and output cache can be enabled via configuration. The caches are invalidated when content is changed. Enable output cache for any controller implementing ContentController<> and any page implementing ContentPage<>:
<n2 xmlns="http://n2cms.com/schemas/configuration/v3"> <host rootID="1" startPageID="2"> <!-- output cache caches the rendered page and is invalidated when a page is published --> <outputCache enabled="true" duration="10"/> </host> <engine/> <database /> <edit/> </n2>
<n2 xmlns="http://n2cms.com/schemas/configuration/v3"> <host rootID="1" startPageID="2"> <web> <!-- Disable url caching will make the system traverse children for each request --> <urls enableCaching="false" /> </web> </host> <engine/> <database /> <edit/> </n2>
<n2 xmlns="http://n2cms.com/schemas/configuration/v3"> <host rootID="1" startPageID="2"/> <engine/> <!-- Other cache providers are also available --> <database caching="true" cacheProviderClass="NHibernate.Caches.SysCache2.SysCacheProvider, NHibernate.Caches.SysCache2"/> <edit/> </n2>
NHibernate Caching
TODO
Filtering Content
A very common operation is filtering of lists. To simplify this there is a concept of filters. These are the filters available by default: Filter Type AccessFilter CompositeFilter Description removes items not authorized by the user is composed of other filters, removes items not authorized by all of these is composed of a page, visible, published and access filter skip and takes a number of items, needs to be reset after each use encapsulates an action that does the filtering removes duplicates, needs to be reset after each use contains another filter which behavior is inversed doesn't filter allows only pages (not parts) removes anything not structured below a parent
removes unpublished and expired items removes items not deriving from a certain type removes non-visible items removes items not in a given zone
Examples
Example, filtering found items:
private IEnumerable<ContentItem> FindRecentlyPublishedWithFinder() { var recentlyPublishedItems = N2.Find.Items .Where.Published.Gt(DateTime.Now.AddMonths(-1)) .Filters(new AccessFilter()) .Select(); return recentlyPublishedItems; }
The GetChildren method without parameters uses AccessFilter. When filtering children remember to include an access filter. Example, filtering out child pages that are accessible:
public ActionResult FilteringChildPages() { ViewData["childPages"] = CurrentPage.GetChildren( new CompositeFilter( new AccessFilter(), new PageFilter())); return View(); }
The filter can also be invoked directly. Calling filter will remove entries from the list.
public ActionResult FilteringLists() { var children = CurrentPage.GetChildren(); var filter = new PublishedFilter(); // filtering a list will remove entries from the list filter.Filter(children); return View(); }
Without changing the list, its possible to call Pipe which returns the matching items.
public ActionResult PipingEnumerations() { var children = CurrentPage.GetChildren(); var filter = new PublishedFilter(); // piping will return a filtered enumeration without changing the input var filteredChildren = filter.Pipe(children); return View(); }
Toolbar Plugins
To register an interface into the management UI you add an attribute to your page, e.g.:
[ToolbarPlugin("EDIT", "edit", "{ManagementUrl}/Content/Edit.aspx?{Selection.SelectedQueryKey}={selected}", ToolbarArea.Preview, Targets.Preview, "{ManagementUrl}/Resources/icons/page_edit.png", 50, ToolTip = "edit", GlobalResourceClassName = "Toolbar", RequiredPermission = Permission.Write)]
IPlugin
UI Plug-ins are classes that are decorated by an attribute that implements the N2.Plugin.IPlugin interface. This interface provides a Name and a SortOrder for the plug-in. It identifies the Type that is being Decorated by the attribute and it provides a method for checking if a User IsAuthorized to use this plug-in. The classes for the UI plug-in system are held in N2 assembly under the N2.Plugin namespace.
Finding UI Plug-ins
There is a service identified by the IPluginFinder interface that returns a list of all the UI plug-ins in the system that have been found. The default implementation of this service is the N2.Plugin.PluginFinder class. UI Plug-ins can be excluded from being found by adding elements to the interfacePlugins element in web.config: N2 framework services can find and use UI plug-ins by calling into the IPluginFinder. For example in the Control Panel there is this method.
protected virtual void AddPluginsControlPanelState(state) { var pluginPanel = new Panel(); pluginPanel.CssClass = "plugins"; Controls.AddPluginPanel(); ContentItem start = Engine.Resolve<IUrlParser>().StartPage; ContentItem root = Engine.Persister.Repository.LoadEngine.Resolve<IHost>(.CurrentSite.RootItemID); foreach (IControlPanelPlugin plugin in Engine.Resolve<IPluginFinder>(.GetPlugins<IControlPanelPlugin>)) { var span = new HtmlGenericControl("span"; span.Attributes"class" = "control"; pluginPanel.Controls.Addspan; plugin.AddTo(span, new PluginContext(CurrentItem, null, start, root, state, Engine.ManagementPaths)); } }
This code has not been checked, would someone please review it and update this article? Thanks!
Here, the IPluginFinder is used to get all the control panel UI plug-ins, decorated by attributes deriving from IControlPanelPlugin. Each are then added to the pluginPanel control.
Control Panel
Pages that are decorated with attributes that implement the IControlPanelPlugin interface are added to the control panel. There are three of these attributes built in to N2 CMS: ControlPanelLinkAttribute, Control PanelDrapPluginAttribute and ControlPanelSeparatorAttribute. ControlPanelLinkAttribute adds a link to the control panel. ControlPanelSeparatorAttribute adds a separator to the control panel. ControlPanelDragPluginAttribute adds a link to the control panel that is shown only if there is a zone on the page being viewed.
Toolbar
The ToolbarPluginAttribute is used to decorate toolbar buttons that should appear in the toolbars of the administration area. The attribute defines things like the URL to which the button should link, a URL to an icon for the button, the frame and toolbar area in which the button should appear.
Navigation Pane
Pages that are decorated with attributes that derive from NavigationPluginAttribute are added to the right click context menu on the navigation
page. There are two built-in attributes in N2 CMS: The NavigationLinkPluginAttribute adds a link to the decorated page in the context menu and NavigationSeparatorPluginAttribute adds a separator in the context menu.
Edit Toolbar
Pages that are decorated with the EditToolbarPluginAttribute appear in a toolbar on the Edit page of the administration
Other Plug-ins
In this section a selection of other plug-ins are described.
Scheduling
N2 has a scheduling service that executes work items on a scheduled basis. This functionality can be found in the N2.Plugin.Scheduling namespace of the N2 assembly. Types that derive from ScheduledAction and decorated with the ScheduleExecutionAttribute are plug-ins that the Scheduler can find and execute. The scheduler uses a service called Heart that provides a regular beat event. When the beat event is triggered the Scheduler checks to see if any ScheduledAction plug-ins are due to be executed by interrogating their Interval, LastExecuted and Repeat properties.
Services
Inversion of Control
In software engineering, inversion of control (IoC) is a programming technique, expressed here in terms of object-oriented programming, in which object coupling is bound at run timeby an assembler object and is typically not known at compile time usi ng static analysis. N2 performs inversion of control to allow developers to abstractly extend the framework with their own implementations. Custom implementations can replace and extend those provided by the framework in a plugin-like fashion.
Services
Services are the basic extension points of the N2 framework. They are singletons instantiated at application start-up.
[Service] [Service(typeof(IContentItemRepository), Configuration = "xml")] [Service(typeof(IRepository<ContentItem>), Configuration = "xml", Replaces = typeof(ContentItemRepository))] class HtmlContentRepository : IContentItemRepository {
Service Constructors
N2CMS will automatically resolve constructor parameters and pass in instances of the relevant items. If you're modifying built-in N2 classes, take care not to create dependency cycles here or you'll end up with stack overflow as N2 recursively tries to instantiate these dependencies for you.
Install-Package N2CMS.IoC.Windsor3
1. Add a project reference to N2.IoC.Windsor3 2. Modify the <engine> tag in web.config file as follows:
Manual
1. Copy the following DLL files to your project ~/bin directory: N2.IoC.Windsor3.dll N2.IoC.Windsor3.pdb 2. Modify the web.config as in the Project Reference section above.
Roles.RemoveUserFromRole(SelectedUserName, item.Value);
System.Web.Security.Membership.UpdateUser(SelectedU ser);
This in turn uses something called ItemBridge to persist the standard .NET Membership objects as regular ContentItems.
See Also
Managing users and permissions
Additional Resources
File ckeditor_placeholder_4.1.zip SqlFileStorage.zip N2EditablePropertyGrid.zip N2CMS_TheLittleHandbook.pdf Modified
Download All
Getting Support
Free Community Support
Free community support is provided for issues with N2CMS, and for feature requests on a best-effort basis with no SLA. All community solutions are licensed under the LGPL unless otherwise specified. For bugs and feature requests, please file an issue at Github and a member of the community will eventually try to address a fix. The bug tracker is located at https://github.com/n2cms/n2cms/issues If you are trying to extend N2CMS with the intention of contributing your code back to the N2CMS project, please provide the source code of your
project and we can try to help you debug it. The code must be licensed under LGPL or a compatible license. The solution will be made available to the community, and may be incorporated into the main N2CMS distribution or template libraries in whole or in part.
Commercial Support
If you have a requirement for a project that isnt open-source, or if you need a solution more quickly, various N2 community members offer consulting services at market rates. Please contact those members directly for additional information.