February 2019

Volume 34 Number 2

[The Working Programmer]

Coding Naked: Naked Speakers

By Ted Neward | February 2019

Ted NewardIn the last piece, I introduced you to the Naked Objects Framework (NOF), a framework that looks to hide away all of the work around UI and data persistence of objects, leaving developer focus solely on building domain objects the way you were always taught in school, before you learned about MVC and Web APIs and HTTP and SQL and database connection management and dependency injection and all the other things that consume the vast majority of our time and energy. It’s a great idea, if it works, but the last arti­cle didn’t exactly overwhelm with features. In this article, I’ll take a deeper look into what you can define on a class with NOF and how that will translate into UI and database persistence.

Naked Concepts

Before I get too far into the code, though, let’s get comfortable with some of the NOF terminology, because it will provide a certain amount of insight into how the creators and maintainers see the world.

First and foremost, at the center of the whole experience are domain objects—the objects that represent the state and behavior of the system. In NOF, any “plain old C# object” can be a domain object, as long as it follows a few rules so that NOF can provide the support it needs: properties must be virtual; any collection members must be initialized; and NOF recommends against constructors because the object in memory may have a different lifecycle than you’re used to. I’ll talk about this more later.

Not everything fits well into the object paradigm, however. Often there are behaviors that operate on objects, but don’t belong particularly well inside of one. Rather than try and force behaviors into objects in an arbitrary way, NOF provides support for services, which provide behaviors “outside” of objects, such as creating, retrieving or other operations on domain objects. Services can also serve as a gateway to external system services like e-mail servers.

From a user perspective, the UI needs to provide behaviors that users can trigger, and these are collectively called actions, which often correspond to menus in the UI. Actions can be discovered (or “contributed”) from a variety of sources, but most often they’ll be found via Reflection against domain objects or services, and displayed in the UI as seen. You can use custom attributes to tailor much of this discovery and display, when and where necessary, and I’ll examine more of this as I go.

This will all become clearer via code, so … shall we?

Naked Conference

In the MEAN series, I used a simple domain example (speakers delivering talks at a conference) as a backdrop for building code, and it seems reasonable to use the same example here, if for no other reason than to compare apples to apples. As domain models go, it’ll be pretty simple: Speakers consist of first name, last name, age, subjects (C#, VB, Java, JavaScript, TypeScript and C++), and average rating (from zero to five), to start. Later I can add Presentations, which will have a title and description, once you see how to set up relationships between objects, but let’s keep it simple for now.

As mentioned in the last article, I’ll start by using the NOF Template .zip as the seed from which to start, so download that from the link in the NOF GitHub project README (bit.ly/2PMojiQ), unzip it into a freshly minted subdirectory, and open the solution in Visual Studio. Now open the Template.Model project node and delete the Student.cs and ExampleService.cs files; you don’t want to store Students, after all. What you do want to store are Speakers (and later Presentations, but I’ll leave that for refactoring later, just to see how well NakedObjects will support refactoring).

To be clear, I need to do a couple of things to support speakers as a domain type in a Naked Objects project: I need to create the domain type; I need to make sure I have a Repository object to obtain and create them; I need to make sure that a repository is made available to the Naked Objects framework to generate menus from; and, finally, I need (or, to be honest, want) to seed the database with some speakers.

Speaker Objects

Building out the Speaker class is actually the simplest of the four steps. In the Template.Model project, create a Speaker.cs file, and in that file, inside the Template.Model namespace, create a public class called Speaker. Speakers are defined (for the moment) by first name, last name and age, so create three properties for them, but mark them “virtual”; this is so that at runtime, NakedObjects can slip some additional behavior into place (via a subclass) that does the desired magic.

Let’s add a little complexity to Speaker, however. First of all, you often want a non-domain-related identifier for objects stored in a database that can be used as a primary key, without allowing users to use or modify that identifier. In the NakedObjects system, I can flag any property with a “NakedObjectsIgnore” custom attribute so that it won’t show up in the UI, so let’s add an integer “Id” property (again virtual) that’s flagged with this attribute. Additionally, it’s not uncommon to want to create a property that’s “computed”using other data elements, so let’s add a “FullName” read-only property that concatenates first and last name. Because NakedObjects isn’t going to be responsible for editing the UI on this, it doesn’t need to be virtual.

When that’s done, you should be left with something like this:

public class Speaker
{
  [NakedObjectsIgnore]
  public virtual int Id { get; set; }

  public virtual string FirstName { get; set; }
  public virtual string LastName { get; set; }
  public virtual int Age { get; set; }

  [Title]
  public string FullName { get { return FirstName + " " + LastName; } }
}

So far, so good.

Speaker Repository

A repository object, for those not familiar with the pattern, is essentially an object that represents access to the database, providing easy method calls for standard database requests. In the NakedObjects system, a repository object is a form of service, which is an object specifically recognized by NakedObjects as an object that isn’t a domain object but can provide UI elements and behavior on behalf of the system. In this case, the repository will provide some menu items for getting speakers out of the database, sorted (for example) by last name.

In practical terms, a NakedObject service is just another class, but it will have something the Speaker class doesn’t: a reference to an IDomainObjectContainer object, which is an object provided by the NakedObjects framework that in turn provides access to the rest of the system. The list of system services available is given in the NakedObjects documentation, but specifically I’m interested in two elements: the NewTransientInstance method, which will construct a new Speaker object and wire it up against the rest of the NakedObjects infrastructure for use; and the Instances method, which will return the complete set of Speaker objects from the database. Thus, a minimal SpeakerRepository looks like what’s shown in Figure 1.

Figure 1 The SpeakerRepository Class

public class SpeakerRepository
{
  public IDomainObjectContainer Container { set; protected get; }

  public Speaker CreateNewSpeaker()
  {
    // 'Transient' means 'unsaved' - returned to the user
    // for fields to be filled in and the object saved.
    return Container.NewTransientInstance<Speaker>();
  }

  public IQueryable<Speaker> AllSpeakers()
  {
    return Container.Instances<Speaker>();
  }
}

Notice that both the NewTransientInstance and the Instances methods are generic functions, taking the type of object they’re working with as a type parameter to the function call. (This is
necessary because the DomainObjectContainer can and will be used for a variety of different domain object types, not just Speakers.)

A repository that just creates a new Speaker and gets a list of all of them isn’t particularly useful, however; you’ll often want to retrieve objects with certain ones filtered out, or sorted in a particular order. Here’s where the power of LINQ and EntityFramework inside the NakedObjects framework makes its presence felt. Because the AllSpeakers method returns an IQueryable, I can use LINQ methods to filter and/or sort the objects returned, so that if I want to find Speakers by last name, I can simply add that method to the repository class, using LINQ as necessary to filter the results:

public class SpeakerRepository
{
  // ... as before

  public IQueryable<Speaker> FindSpeakerByLastName(string name)
  {
    return AllSpeakers().
      Where(c => c.LastName.ToUpper().Contains(name.ToUpper()));
  }
}

Anything LINQ can do, you can express as a method on the repository.

Speaker Context

Two more bookkeeping details I need to take care of: I need to set up the Entity Framework DbContext that will be used by the NakedObject persistence engine, and I need to hook the Speaker­Repository into the UI so I can have menu items to create new Speakers, find existing Speakers, and so on.

The first is found in the Template.DataBase project, in the ExampleDbContext.cs file (whose name you should feel free to change if it matters to you), in the ExampleDbContext class. As a public property on that class, a DbSet needs to be parameterized to the Speaker type called “Speakers,” like so:

namespace Template.DataBase
{
  public class ExampleDbContext : DbContext
  {
    public ExampleDbContext(string dbName,
      IDatabaseInitializer<ExampleDbContext> initializer) : base(dbName)
    {
      Database.SetInitializer(initializer);
    }

    public DbSet<Speaker> Speakers { get; set; }
  }
}

As more top-level domain object types are added to the system, I’ll need to add more properties here that return a DbSet, but for now, this is all I need.

If you want the database to be seeded with some speakers to start, you need to crack open the Template.SeedData project and find the ExampleDbInitializer.cs file and write the Seed method (which is already defined in that file) to add some Speaker objects to the ExampleDbContext (the object I just refactored in the previous paragraph) via the Speakers DbSet, as shown in Figure 2.

Figure 2 Adding Speaker Objects to the DbContex

public class ExampleDbInitializer : 
  DropCreateDatabaseIfModelChanges<ExampleDbContext>
{
  private ExampleDbContext Context;
  protected override void Seed(ExampleDbContext context)
    {
    this.Context = context;

    Context.Speakers.Add(new Speaker() {
      FirstName = "Ted", LastName = "Neward", Age = 47
    });
  }
}

Note that this is straight Entity Framework code, so any further discussion about how to change the drop/create policy of the data­base would fall into the Entity Framework documentation set.

The last place I need to put code is in the Template.Server project, in the NakedObjectsRunSettings.cs file; this code is a collection of registration “hooks” or “hints” to the NakedObjects system, describing what the NakedObjectsFramework needs to know. For example, if you decide that “Template.Model” is a terrible namespace for the model objects for this conference app, then feel free to change it, so long as the ModelNamespaces of this NakedObjectsRunSettings also reflects the changed name.

With respect to the SpeakerRepository, I need to let Naked­Objects know about it by adding it to the “Services” Type array. If I want the SpeakerRepository methods to be accessible via a menu option, I also need to tell NakedObjects to examine the SpeakerRepository for actions to use as menu items, so I need to include it as part of the array of menu items returned from the MainMenus method, as shown in Figure 3.

Figure 3 NakedObjects Run Settings

public class NakedObjectsRunSettings
{
  // ...

  private static Type[] Services
  {
    get
    {
      return new Type[] {
        typeof(SpeakerRepository)
      };
    }
  }

  // ...

  public static IMenu[] MainMenus(IMenuFactory factory)
  {
    return new IMenu[] {
      factory.NewMenu<SpeakerRepository>(true, "Menu")
    };
  }
}
}

Once these changes are in place, I can fire up the projects, bring up the client and create a few speakers. Notice that the FullName property is displayed, built out of FirstName and LastName, but Id doesn’t appear. Additionally, thanks to the FindSpeakersByLastName method on the SpeakerRepository, I can search for speakers by last name, and if more than one is returned, the client automatically knows how to present a list of them that can be selected for individual work.

Wrapping Up

Notice that at no point in this article did I do anything to the Template. Client project—that’s the point! The UI is constructed out of the domain objects and services, with supplemental information provided by custom attributes (which you’ll see more of in later columns). The persistence is, similarly, built out of the structure and metadata that the framework discovers from your types.

What you’ll need to see, going forward, is how NOF handles more complex domain scenarios—like Speakers having a list of subjects on which they can speak and a collection of Presentations they can deliver—and how it presents a UI for them. In the next article, I’ll look at some of these topics. In the meantime, however ... happy coding!


Ted Neward is a Seattle-based polytechnology consultant, speaker, and mentor. He has written a ton of articles, authored and co-authored a dozen books, and speaks all over the world. Reach him at ted@tedneward.com or read his blog at blogs.tedneward.com.


Discuss this article in the MSDN Magazine forum