Website Development Based on ASP.NET Core and Platformus CMS

  • Tutorial
In this article I want to introduce you to Platformus CMS - a young website content management system (10th alpha at the time of writing), built on the base of no less young ASP.NET Core and ExtCore framework. We will not examine architecture and other technical details in detail now, but restrict ourselves to mentioning a few interesting facts and then immediately try CMS'ka in business - create a small test project based on it.

Some interesting facts

Platformus is a free, open source content management system. It is cross-platform, modular and expandable. The data in it are presented in the form of objects that are described by classes. Multilingualism is supported.

Written by CMS in C #. Thanks to the capabilities of ASP.NET Core, it can work equally well on Windows, Linux, and Mac. The executable environment itself, which is necessary for the operation of any application on the .NET Core, can be either installed separately or integrated directly into the application itself. As a web server, IIS or Kestrel can be used (in the second case, the application becomes a web server for itself and can work independently or be built into a container like IIS or Nginx). As a data warehouse, Microsoft SQL Server, SQLite and PostgreSQL are currently supported. Given all of the above, we can get a configuration that doesn’t require anything third-party at all — copy, run and use it (it can be convenient for testing, for example).

(There are dozens of screenshots in the article.)

Getting down

If you have not worked with ASP.NET Core, then there are links to everything you need for this.

So, download the archive with the 10th alpha of the Platformus via a direct link (~ 9 MB). Unpack it. (As an option, in order not to perform all the actions described in the article yourself, you can download a ready-made demo, there is a link to it at the end of the article.)

To start the application, you need to run 2 commands on the command line (we assume that you are currently working in Windows- environment):

cd путь к распакованному архиву
dotnet webapplication.dll

The result should be something like this:

Now open the browser and go to http: // localhost: 5000 / :

The platform works! Let's start filling our website, for which we’ll go to the backend (admin) by clicking on the corresponding link on the stub page:

Data structure description

As I mentioned above, the data in the Platformus is represented as objects. For example, any page is an object. If you need to display a list of news on a page, then each news will also be a separate object, optionally, with its own separate page (objects are autonomous and embedded).

Objects are described by classes. Each class, in turn, is described by members of the class, representing the properties or relationships of objects of this class, and data sources. By default, the database already has two classes: Base Page and Page. The first is abstract and contains such basic page properties as the headline, META-description and META-keywords, grouped in the SEO tab. Most autonomous objects need these properties, therefore, in order not to duplicate them in each class, it is enough to inherit the corresponding classes from Base Page. The second class represents a regular page with HTML content. It is inherited from Base Page and has one additional property - Content. Here's what the default class list looks like:


As an example that can demonstrate the many features of CMS, let's add a news section to our website. Each news will be tagged and have its own page with detailed information. First, create the News Page class:

Since each news page should have a title, META-description and META-keywords, we will inherit our class from Base Page by selecting it in the Parent class drop-down list. Next, we indicate the name of our class in the singular and plural. Adding the word Page is not necessary, but perhaps more clearly. We set the Is standalone flag, which means that objects of this class will be autonomous (that is, they will have their own URLs). And finally, we indicate the name of the default view for future objects of our class. Click Save. Our News Page class has been created and added to the list:

Now we will create another class - Tag. This time, the objects will be inline, so we do not select the parent class, and we do not set the Is standalone flag. Also, there is no need to specify a default view name:

Class members

Now define the members of the News Page class. We click on the Members link in the corresponding line and go to the empty list (class members inherited from Base Page are not displayed here):

Class members are of two types - properties and relationships.

The property value is plain text edited by various editors, depending on the data type of the property. For example, there is single-line text, multi-line text, HTML, or an image (in the latter case, the property value is the image URL). The property can optionally be localized (i.e. its value differs depending on the culture (language)). In this case, when editing the properties for each culture, a separate editor is displayed. You can also display the values ​​of key properties in the list of objects of the corresponding class.

The relationship value is another object or other objects of the specified class. Also, if one object of one class can be associated with only one object of another class (for example, an article can be included in only one category), you can group these "child" objects relative to their "parent". This may seem a bit confusing. At the end of the article there is a link to an example on GitHub, where this technique is used.

First of all, we will describe the Name property - the name of the news:

On the General tab, we indicate the code, name and position of the class member. Using the code, we will then receive the value of the properties (but not the links!) Of the object, the name is displayed in the property or link editor, and the position determines the order of these editors.

On the Property tab, we specify the data type of our property. For the title, select Single line plain text - a single-line plain text. Set the flag Is property localizable, because the name of the news will be different for different cultures. Also, since the name is a key property, set the Is property visible in list flag so that the value of this property appears in the list of objects of the News Page class.

Since we are describing a property, not a relationship, we don’t access the Relation tab. Click Save, our new class member has been added.

Now we similarly describe the Preview property - a shortened news text that will be displayed in the news list. Since there will be more text in the preview than in the title, we will select Multiline plain text as the property data type and this time we will not set the Is property visible in list flag. Further, in the same way, we add a property with the main content of the news - Content. We’ll select the Html data type to be able to conveniently format the content.

The last property that I would like to add is an illustration for the news. Everything is exactly the same as with other properties, but select Image as the data type and do not set the Is property localizable flag, because the illustration here does not depend on the current culture.

Now let's add a link to the Tag class for our class so that you can specify tags for news:

On the General tab, everything is familiar. This time we go to the Relation tab:

in the Relation class drop-down list, select the class whose objects will be attached to objects of the News Page class.

Everything, now everything is ready. It should turn out something like this:

Similarly, we describe the only property of the Tag class - Name. (Recall that the flags Is property localizable and Is property visible in list must be set.)

Data sources

Although we described the relationship between the News Page and Tag, anchored objects of the Tag class will not be loaded with the corresponding object of the News Page class. For this to happen, we need to add something else to the News Page class, the data source. Data sources determine which objects are loaded with the current object and how. For example, if there are links between a news object and several tag objects, then using data sources, relying on links, we can load all news tags and all tag news. Also, we can load objects even if there is no connection with the current one. For example, to display news on the main page. All data sources are described by C # classes that implement the IDataSource interface, and we can add new such classes. For example, you can add a data source, which will display the latest 100 news with a breakdown of 10 per page. Or a data source that displays the most popular products of the online store. Conveniently, as a result, all data is grouped in a single object, which is a model for its presentation. This is quite in the spirit of MVC.

So, back to the list of our classes and click on the link Data sources in the class line News Page. Add a new data source:

Save and get the following list:

Content Filling

Well, now you can proceed directly to filling our website with content. We turn to the Objects section:

All objects are divided into 2 groups - standalone and embedded. Inside these groups, they are displayed by class. Since the objects of the News Page class need the objects of the Tag class, we will start filling with the last:

Let's create our first object:

As you can see, the page for editing the object is very simple and contains only 2 fields: View name (for embedded objects, you can fill it out and hardcode later in the parent view, if there is no need to be able to change the view in the future from the backend) and Name. The Name property we described in our Tag class. Let's create some tags, it worked out like this:

Finally, let's move on to our news. Create an object of the News Page class. There are already more

fields : For properties of the Image data type, images are downloaded using such a loader-trimmer (currently manipulating images in ASP.NET Core is not yet supported, therefore, real cropping on the server does not occur, the image is saved as is, entirely, regardless of the selected area):

And this is how the communication editor looks like, the choice of tags in our case:

Let's create some more news to make it clearer, and try to test what we ended up with. We ’ll go to one of the URLs of our news, after adding a culture identifier in front of it: http: // localhost: 5000 / en / news / 2016-olympic-games. And ... we get the 500th error. If you look at the console, it becomes obvious that we did not create a NewsPage view for our object:

Views and final customization

Let's try to create a presentation for the news page. Let's go to the \ Views \ Default folder of our application. Here we will see the only view of Page.cshtml (our main page). We copy it, call it a copy of NewsPage.cshtml and open it for editing in any text editor:

The data type of the view model is dynamic, but we all know that in reality it will be an object of the C # class ObjectViewModel containing data of our object of the News Page class .

Access to the property values ​​of an object is performed as follows:


Access to objects in data sources is as follows:


We modify our view, for example, in this way (of course, it would be better not to describe the markup needed to display the tag right here, but to make a separate _Tag partial view for this; we did this for simplification and visibility):

Now we refresh the page in the browser and see this result:

That's great, everything works! It remains only to bring the list of news to the main. To do this, add the following data source to the Page class:

As you can see, the C # class of the data source is different from the one we used before. This is a more generalized data source that does not take into account the relationships between objects. Also, pay attention to the Parameters field. Here is the identifier of the class whose objects you want to load. In the current version of the Platform, this is not entirely elegant, without any visual selector.

Now let's move on to editing the object of the main page, remove all unnecessary content. (The content may not be changed, but it is necessary to open it for editing and then save the object after adding the data source to its class, otherwise this information will not be pulled into the cached object and will not be accessible to the view.)

Now we will open the Page.cshtml view for editing and change it approximately as follows:

Here is what we will get now if we go to the main page of our website in a browser:

Everything is ready! Of course, it would be right to add here, at least, a menu or feedback form, but it is very simple to do this (see the link below), so we will not focus on this.


I think the first question that you need to answer yourself before you start developing the next CMS is “Why?”. If you don’t go into details, then at least there are not many CMS on ASP.NET Core yet, but I really like this platform and I believe in its future.

I sincerely hope that you were interested, and also that I will receive criticism, ideas, food for thought for further improvement of the product - we are only at the beginning of the way. Thanks!

I did not upload the code of this particular project on GitHub, because it is very similar to another example that you can download and see so as not to do everything manually.

Also popular now: