How to Create an XAF Application from Scratch

XAF Team Blog
30 October 2012

In my previous post, I listed all of the Visual Studio templates that speed-up XAF application development. In this next post, I explain how to create a desktop XAF application without using any XAF templates or designers. By taking a closer look at an XAF application, you will see that it is just a regular .NET WinForms application. Although building applications from scratch on a daily basis is not recommended (because templates speed up the development process), I do believe that it is good practice to try building an application from scratch at least once to better understand XAF architecture. I will also demonstrate how to add extra modules, controllers and security in code. In some instances, you may find it easier to type several lines of code, rather than wait for the designer to load and the toolbox to populate. Of course, XAF design-time tools are extremely valuable for beginners, but as you become more proficient in XAF, you may find that in some cases, it is easier to carry out many of the designer-related tasks in code.

Create an XAF Application Project

Let’s begin with the Empty Project template supplied with Visual Studio. The Windows Forms Application template is not suitable for this task because it contains the Form1 class as well as other unneeded references. Start Visual Studio and select FILE | New... | Project in the main menu. In the Templates | Visual C# | Windows category, choose the Empty Project template,  specify project and solution names (e.g., MyXafApplication and MyXafAppplcationSolution) and click OK.

XAF Application From Scratch - Add Empty Project

Open the newly added project properties by right-clicking the project in Solution Explorer and selecting Properties. The project's Output type is Console Application by default. Change it to Windows Application.

XAF Application From Scratch - Project Output Type

At the moment, the project's References list is empty. In the beginning, the following assemblies will be required.

  1. DevExpress.ExpressApp.v12.1.dll - contains the base XAF functionality (e.g., the XafApplication class).
  2. DevExpress.ExpressApp.Win.v12.1.dll - contains the WinForms XAF functionality (e.g., the WinApplication class).
  3. DevExpress.ExpressApp.Xpo.v12.1.dll - provides XPO support. We will use XPO to create and access the application database.
  4. System.dll
  5. System.Data.dll

Now when the initial preparations are complete, we can begin coding. (The XAF team recommends that you use CodeRush to speed-up the coding process). Add a Program.cs file with the following code.

using System;
namespace MyXafAppplication {
static class Program {
[STAThread]
static void Main() {
}
}
}
 

The application is ready to be launched, but it does not do anything yet. We will need to create an instance of the WinForms XAF application, and start it from our Main method, so declare the following MyXafApplication class.

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Win;
using DevExpress.ExpressApp.Xpo;
//...
public class MyXafApplication : WinApplication {
protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
args.ObjectSpaceProvider = new XPObjectSpaceProvider(ConnectionString, Connection);
}
protected override void OnDatabaseVersionMismatch(DatabaseVersionMismatchEventArgs args) {
args.Updater.Update();
args.Handled = true;
}
}
 

In the overridden CreateDefaultObjectSpaceProvider method, state that XPO will be used as the ORM tool - all Object Spaces in the application will be of the XPObjectSpace type. In the overridden OnDatabaseVersionMismatch method, instruct XAF to always update the application database when a version mismatch occurs.

Now we can instantiate, configure and run MyXafApplication. You should at least initialize the ApplicationName and the ConnectionString properties.


static void Main() {
MyXafApplication myXafApplication = new MyXafApplication();
myXafApplication.ApplicationName = "MyXafApplication";
myXafApplication.ConnectionString =
"Integrated Security=SSPI;Pooling=false;Data Source=(local);Initial Catalog=MyXafApplication";
myXafApplication.Setup();
myXafApplication.Start();
}

Although the solution contains a single application project and no module projects, an empty main window is shown, and limited basic functionality (e.g., Model Editor) is available when the application is launched.
 
XAF Application From Scratch - First Run
Note: Since the default XAF application project created from a template implements the WinApplication descendant in a separate file, the Application Designer can be used. In the designer, the ApplicationName and ConnectionString properties can be initialized in the Properties window.

Add a Module Project with a Business Model

Next, Let’s add some functionality to our application. Add another Empty Project and call it MyXafModule. The XAF Module is a class library that contains the ModuleBase descendant class. Reference the DevExpress.ExpressApp.v12.1.dll assembly and add the following MyModule class.

using DevExpress.ExpressApp;
namespace MyXafModule {
public class MyModule : ModuleBase {
}
}
 

Then change the project's output type to Class Library and specify the assembly version, as shown in the image below.

XAF Application From Scratch - Module Project Properties

The asterisk (“*”) instructs Visual Studio to increment the build and revision numbers automatically. This is required for XAF to update the database correctly.

Now we can reference the MyXafModule project in MyXafApplication and add our new module to the application's Modules collection.

using MyXafModule;
// ...
static void Main() {
MyXafApplication myXafApplication = new MyXafApplication();
myXafApplication.ApplicationName = "MyXafApplication";
myXafApplication.ConnectionString =
"Integrated Security=SSPI;Pooling=false;Data Source=(local);Initial Catalog=MyXafApplication";
myXafApplication.Modules.Add(new MyModule());
myXafApplication.Setup();
myXafApplication.Start();
}

Run the application, invoke the Model Editor, and click the Loaded Modules button. Notice that MyModule is included in the list.

XAF Application From Scratch - Module List in the Model Editor

Note that SystemModule and SystemWindowsFormsModule are in the list as well. They were added in the application’s ancestor classes (XafApplication and WinApplication, respectively).

Next, you can define a business model within the module in the usual way - by adding business classes to the module project. For instance, you can add the following Contact class.

using DevExpress.Xpo;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
namespace MyXafModule {
[DefaultClassOptions, ImageName("BO_Contact")]
public class Contact : BaseObject {
public Contact(Session session) : base(session) { }
private string name;
public string Name {
get { return name; }
set { SetPropertyValue("Name", ref name, value); }
}
private string email;
public string Email {
get { return email; }
set { SetPropertyValue("Email", ref email, value); }
}
}
}

To follow our "from scratch" concept, you can add this class without using a special XAF template. Simply choose Add | New Class.... As the ancestor BaseObject class resides within the DevExpress.Persistent.BaseImpl.v12.1.dll assembly, a reference to this assembly is required to compile the code above. Since we are using XPO, the DevExpress.Xpo.v12.1.dll and DevExpress.Data.v12.1.dll references are required as well.

Supply Initial Data

To add several Contact records to the database, let's implement a Module Updater class.

using System;
using System.Collections.Generic;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Updating;
//...
public class MyModuleUpdater : ModuleUpdater {
public MyModuleUpdater(IObjectSpace objectSpace, Version currentDBVersion) :
base(objectSpace, currentDBVersion) { }
public override void UpdateDatabaseAfterUpdateSchema() {
base.UpdateDatabaseAfterUpdateSchema();
Contact contactJane = ObjectSpace.FindObject<Contact>(
new BinaryOperator("Name", "Jane Smith"));
if (contactJane == null) {
contactJane = ObjectSpace.CreateObject<Contact>();
contactJane.Name = "Jane Smith";
contactJane.Email = "jane.smith@example.com";
}
Contact contactJohn = ObjectSpace.FindObject<Contact>(
new BinaryOperator("Name", "John Smith"));
if (contactJohn == null) {
contactJohn = ObjectSpace.CreateObject<Contact>();
contactJohn.Name = "John Smith";
contactJohn.Email = "john.smith@example.com";
}
}
}

The image below illustrates the result.

XAF Application From Scratch - Contact Object

In the current version of XAF (12.1), the ModuleUpdater descendants are automatically collected via the reflection. In the upcoming 12.2 release, we have added an option to explicitly register Module Updater classes that should be used by the module in the overridden GetModuleUpdaters method. This method is recommended to improve performance. Once version 12.2 has been published, download and install it, and modify the MyModule class as follows.

public class MyModule : ModuleBase {
public override IEnumerable<ModuleUpdater> GetModuleUpdaters(IObjectSpace objectSpace, Version versionFromDB) {
return new ModuleUpdater[] { new DatabaseUpdate.Updater(objectSpace, versionFromDB) };
}
}
 

Use Extra Modules

You can plug extra modules supplied with XAF in to your application in the same manner as our custom MyModule. For instance, to enable reporting, reference the DevExpress.ExpressApp.Reports.Win.v12.1.dll assembly and add an instance of the ReportsWindowsFormsModule class to the application's Modules collection.

using DevExpress.ExpressApp.Reports.Win;
//...
static void Main() {
MyXafApplication myXafApplication = new MyXafApplication();
myXafApplication.ApplicationName = "MyXafApplication";
myXafApplication.ConnectionString =
"Integrated Security=SSPI;Pooling=false;Data Source=(local);Initial Catalog=MyXafApplication";
myXafApplication.Modules.Add(new MyModule());
myXafApplication.Modules.Add(new ReportsWindowsFormsModule());
myXafApplication.Setup();
myXafApplication.Start();
}

With a single line of code (demonstrated above), we can design and print reports (see the image below).

XAF Application From Scratch - Reports

Note: In the default XAF application project, the Application Designer is used to populate the modules collection. It is convenient for XAF beginners to browse the toolbox and choose the required modules, but experienced XAF users can accomplish the same task in code more efficiently.

Secure Your Application

To enable the security system, reference the DevExpress.ExpressApp.Security.v12.1.dll assembly, instantiate the Security Strategy and Authentication, and initialize the application's Security property. Additionally, references to the DevExpress.Xpo.v12.1.dll and DevExpress.Persistent.Base.v12.1.dll assemblies that are used by the Security System are required.

using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Security.Strategy;
//...
static void Main() {
MyXafApplication myXafApplication = new MyXafApplication();
myXafApplication.ApplicationName = "MyXafApplication";
myXafApplication.ConnectionString =
"Integrated Security=SSPI;Pooling=false;Data Source=(local);Initial Catalog=MyXafApplication";
AuthenticationActiveDirectory authentication =
new AuthenticationActiveDirectory() { CreateUserAutomatically = true};
myXafApplication.Security =
new SecurityStrategyComplex(typeof(SecuritySystemUser), typeof(SecuritySystemRole), authentication);
myXafApplication.Modules.Add(new MyModule());
myXafApplication.Modules.Add(new ReportsWindowsFormsModule());
myXafApplication.Setup();
myXafApplication.Start();
}

By adding two lines of code, the application is secure! No need to wait for the designer to load and search for the security components in the toolbox. The administrator’s UI is added automatically (see the image below).

XAF Application From Scratch - Security

Add a Controller with an Action

You can easily add a Controller and Action in code, without the use of a template and designer. Let's add the following class to our module project.

using System;
using System.Diagnostics;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.Persistent.Base;
//...
public class SendMessageController : ObjectViewController<ListView, Contact> {
public SendMessageController() {
SimpleAction sendMessageAction = new SimpleAction(this, "SendMessage", PredefinedCategory.View);
sendMessageAction.ImageName = "BO_Contact";
sendMessageAction.SelectionDependencyType = SelectionDependencyType.RequireSingleObject;
sendMessageAction.Execute += delegate(object sender, SimpleActionExecuteEventArgs e) {
string startInfo = String.Format(
"mailto:{0}?body=Hello, {1}!%0A%0A", ViewCurrentObject.Email, ViewCurrentObject.Name);
Process.Start(startInfo);
};
}
}

This Controller invokes the email client to compose a message addressed to the selected contact. Don't forget to declare the Controller as public. Also, note that we use the generic ObjectViewController class here. Passing the target view and object types as generic parameters is a convenient approach. There is no need to initialize the corresponding controller's properties. The Controller's ViewCurrentObject property simplifies access to the current object. Since the target object type (Contact) is known, there is no need to cast the current object value to the Contact type. The image below illustrates the SendMessage Action implemented in the code above.

XAF Application From Scratch - SendMessage Action

Enable the Design-Time Model Editor

A major drawback of our hand-made solution is that the Model Editor, a great tool for browsing and customizing the Application Model, is unavailable. Fortunately, this can be easily remedied. Simply add the Model.DesignedDiffs.xafml file to the MyXafModule project.

XAF Application From Scratch - Add Model.DesignedDiffs.xafml File

The next step is to open this file in an XML editor and add the following code (the Model Editor cannot open the file if it is empty).

<?xml version="1.0" ?>
<Application/>

Once this code has been added, the Model Editor can be used to change the model differences for the MyXafModule module.

XAF Application From Scratch - Design-Time Model Editor

By default, an XAF module uses the ResourcesModelStore model differences storage. As this class name implies, it reads application model customizations from the module assembly’s resource files (*.xafml and *.bo). If the model differences file isn’t built as an embedded resource, it will be ignored. Thus, to apply changes at runtime, change the XAFML file's Build Action property to Embedded Resource.

XAF Application From Scratch - Model.DesignedDiffs.xafml Properties

The Model Editor can be enabled in a similar way for the MyXafApplication project. The required file name for the application project is Model.xafml. The file's Build Action property should be set to Content, and Copy to Output Directory should be set to Copy Always. In WinForms XAF applications, the FileModelStore model differences storage is used, and application-level customizations are loaded from the Model.xafml file located in the application’s working folder.

XAF Application From Scratch - Model..xafml Properties

As a result, we have a fully functional WinForms XAF solution. A discussion of web application implementation has been omitted, since it is not easy to create an ASP.NET XAF application from scratch, due to the volume of code required to create XAF web pages (Default.aspx, Login.aspx, etc.). For the web, you can use the lightweight modules and controllers demonstrated in this article.

Note: You can download the complete source code for this project from our Code Examples.

Free DevExpress Products - Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We'll be happy to follow-up.
No Comments

Please login or register to post comments.