Page 20 - MSDN Magazine, May 2019
P. 20

sure that the two Repository types are also listed in the Services method in the same file.
Fundamentally, a Talk is given by a Speaker and is on a given Topic. I’m going to ignore the more complicated scenario when a Talk is given by two Speakers, or if a Talk will cross multiple Topics, to keep it simple for the time being. Thus, for the first step, let’s add Talks to the Speaker:
private ICollection<Talk> _talks = new List<Talk>(); public virtual ICollection<Talk> Talks
{
get { return _talks; }
set { _talks = value; } }
If you build and run the project, you’ll see “Talks” show up as a collection (table) in the UI, but it will be empty. I could, of course, add some Talks in SeedData, but in general, Speakers need to be able to add Talks to their profiles.
Naked Actions
This can be done by adding an action to the Speaker class: A method that will appear, “magically,” as a selectable item in the “Actions” menu when a Speaker object is in the display. Like properties, actions are discovered via the magic of Reflection, so all that needs to happen is to create a public method on the Speaker class:
public class Speaker {
// ...
public void SayHello() {
}
}
Now, when built and run, after bringing up a Speaker, the “Actions” menu is displayed and inside of it, “SayHello” appears. Currently it does nothing; it would be nice, as a starting point, to at least put a message back to the user. In the NOF world, this is done by making use of a service, an object whose purpose is to provide some additional functionality that doesn’t belong to a particular domain object. In the case of general “messages back to the user,” this is provided by a generic service, defined by NOF itself in the IDomainObjectContainer interface. I need an instance of one of these in order to do anything, however, and NOF uses dependency injection to provide one on demand: Declare a property on the Speaker class of type IDomainObjectContainer, and NOF will make sure each instance has one:
public class Speaker {
public TalkRepository TalkRepository { set; protected get; } public IDomainObjectContainer Container { set; protected get; }
Figure 2 Creating a List of Topics
The Container object has an “InformUser” method used to convey general messages back to the user, so using it from the Say- Hello action is as simple as:
public class Speaker {
// ...
public void SayHello() {
Container.InformUser("Hello!"); }
NOF needs to be able to inject “hooks” into each domain object in order to work its magic.
But I started with a desire to allow the user to add a Talk to a given Speaker’s repertoire; specifically, I need to capture the title of the talk, the abstract (or description, because “abstract” is a reserved word in C#), and the Topic to which this Talk belongs. Calling this method
“EnterNewTalk,” then, I have the following implementation:
public void EnterNewTalk(string title, string description, Topic topic)
{
var talk = Container.NewTransientInstance<Talk>(); talk.Title = title;
talk.Abstract = description;
talk.Speaker = this;
Container.Persist<Talk>(ref talk); _talks.Add(talk);
}
Several things are happening here, so let’s unpack. First, I use the IDomainObjectContainer to create a transient (non-persisted) instance of the Talk. This is necessary because NOF needs to be able to inject “hooks” into each domain object in order to work its magic. (This is why all properties must be virtual, so that NOF can manage the UI-to-object synchronization, for example.) Then, the Talk’s properties are set, and the Container is used again to Persist the talk; if this isn’t done, the Talk isn’t a persistent object and won’t be stored when I add the Talk to the Speaker’s list of Talks.
It’s fair to ask, however, how the user specified this information to the EnterNewTalk method itself. Once again, the wonders of Reflection are at work: NOF dug the parameter names and types out of the method parameters, and constructed a dialog to capture those items, including the Topic itself. Remember when Topic was annotated with “Bounded”? That instructed NOF to build the list of Topics in this dialog to be a dropdown list, making it incredibly easy to select a topic from the list. (It should be easy to infer at this point that as I add Topics to the system, they’ll all be added to this dropdown list without any additional work required.)
Now, it’s reasonable to suggest that creating Talks should be something supported by the TalkRepository, not on the Speaker class itself, and, as you can see in Figure 3, it’s an easy refactor to do.
What’s more, by doing this, the “Talks” menu will be automatically adorned with a new menu item, “CreateTalk,” which will—again, through the magic of Reflection—automatically create a dialog to enter the data necessary to create a Talk. Speakers, of course, can’t just be typed in, so NOF will make that a “droppable” field, meaning that NOF will expect a Speaker object to be dragged-and-dropped
}
protected override void Seed(ConferenceDbContext context) {
this.Context = context;
Context.Topics.Add(new Topic() { Name = "C#", Description = "A classical O-O language on the CLR" });
Context.Topics.Add(new Topic() { Name = "VB", Description = "A classical O-O language on the CLR" });
Context.Topics.Add(new Topic() { Name = "F#",
Description = "An O-O/functional hybrid language on the CLR" });
Context.Topics.Add(new Topic() { Name = "ECMAScript", Description = "A dynamic language for browsers and servers" });
Context.SaveChanges();
// ... }
14 msdn magazine
The Working Programmer


































































































   18   19   20   21   22