Posts: An explanation of Post code

This is a summary of the main parts used to list, detail, create, edit and delete Post entries via a DTO This type of services that needs a DTO are used then the data class have dependent foreign keys that need to be manipulated before the data class can be written to the database.

The headers contain links to the code on GitHub for you to look at. For most of you the links to the code will be sufficient, but more information is available by clicking on the panel titles.

The Posts Controller

The PostsController (see here for code on GitHub) uses the GenericService's DTO version of the database commands, which are injected into each action as a parameter. The PostsController has List, Detail, Create, Update and Delete actions on the Post data class.

Click on the panel below to get more details about how this works.

PostsController Database Actions

Index Action - List of Posts

Let's look at the Index action in a detail because it has some standard patterns you will see on other actions.

The Index action's job is to produce a list of posts, but using a DTO to combine data from linked tables to produce a user-friendly display. In this case I have listed the code here as its really short:

public ActionResult Index(IListService service)
{
    View(service.GetAll<SimplePostDto>().ToList());
}

Things to note:

  • Notice that the service is injected by DI into the action as a parameter. This is the standard way that all services are created in SampleMvcWebApp. It is explained in more detail in Dependency Injection section.
  • This service has one command, .GetAll<T>(), which returns IQueryable<T>, where T is either a class that is used in EF or a DTO that has inherited from EfGenericDto or EfGenericDtoAsync. In this case the IQueryable result is turned into a List to show in the view.
One stage actions List, Detail and Delete

List, Detail and Delete have only have one stage as there is no setup needed. Detail and Delete do need a reference to the entry to act on, but that normally comes from a list entry or a link.

Two stage actions like Edit and Create

Edit and Create are always a two stage action:

  1. The xxxSetupService is run to get the data to show in a Html Form ready for input or edit by the user.
  2. When the form is Submitted then the main part of the service, either UpdateService or CreateService takes that data and updates the data item. see more about this under Generic Services, two stage services.
Handling errors

In robust applications you should check data as it moves deeping into the system so that bad or bogus is not let through. MVC is the first validation but GenericServices, in conjunction with EF carries out further checks.

In the Create and Edit Actions you will see checks happening at two stages:

  1. Checking that the data that came in from the HttpPost is correct. If it isn't it calls service.ResetDto(dto) which makes sure that any lists used in the UI are refilled before the dto is redisplayed with model errors
  2. After the service has run if raised by the EF validation, then they are returned in the status. In the case of Create or Edit these are then copied into the ModelState of the dto before it is redisplayed. Note that the service internally runs the service.ResetDto(dto) method if it finds an error so that the dto is ready to display.
The SampleMvcWepApps DbContext purposely includes a test inside EF's SaveChanges() method to check that the Tag property Slug is unique to show this in action. Also the Post class (code) is a IValidatableObject with some unusual valdation about sheep and cows (?!) rules to check where errors are reported.

The GenericService methods

In the Controller the ListService (code), DetailService (code), UpdateService (code), CreateService (code) and DeleteService (code) are called. Click on the panel below to get more details about how these work.

GenericService methods

Basic, one stage services, i.e. ListService and DetailService

These services have only one stage, i.e. the production of data. Therefore they are nice and simple.

The CreateService and the UpdateService need two stages.

These services have a setup stage to provide the initial data to display to the user. Therefore there is:

  • A CreateSetupService which has a GetDto<T>() method, where T is either a class that is used in EF or a DTO that has inherited from EfGenericDto or EfGenericDtoAsync.
  • A UpdateSetupService which has a GetOriginal(param object[] keys) method, where you have to supply the primary key, or if multiple keys then they must be in the order that LINQ expects.
The ListService returns IQueryable
This is really important, as the actual SQL command has not been created yet. This means you can use LINQ command like .Take(n) or .Skip(m) to do paging, or apply further filters etc. and they will become part of the SQL request. That is really important for producing efficient database access commands.

The DetailPostDto DTO

The DetailPostDto (code) is at the heart of how the Create and Edit actions allows the user to setup or change a Post's author or tags. It inherits the abstract class EfGenericDto (code) and overrides a few methods to handle the Post's BlogId and Tag Collection.

Click on the panel below to get more details about how these work.

DetailPostDto DTO Actions

Adding UI controls for changing a Post's author and tags

The DetailPostDto adds two lists; a DropDownListType called Bloggers and a MultiSelectListType called UserChosenTags. These two provide the data in a form that the MVC view can use.

The MVC Views, such as Edit then uses two EditorTemplates of the same name, i.e. DropDownListType and MultiSelectListType. The names tell you what they do.

Filling in the UI lists prior to display

The DetailPostDto inherits from the EfGenericDto (code) and overrides the SetupSecondaryData method. This method makes sure that the two lists are filled with the correct data prior to MVC displaying the Create or Edit View.

Updating the Author (BlogId) and Tags

As well as overriding the SetupSecondaryData method in the EfGenericDto CopyDtoToData also overrides the CopyDtoToData method. This method is called every time the DetailPostDto properties are copied back to the Post class.

The DetailPostDto also overrides the CopyDtoToData method. In this new method it has code to obtain the user's choices from the Bloggers and UserChosenTags lists and then updates the properties BlogId and Tags. It then calls the base CopyDtoToData to copy the updated properties back into the Post class prior to EF's SubmitChanges method being called.

Other interesting stuff
  • The property SupportedFunctions has to be overrriden and says what services the DTO can support. See the different setting in DetailPostDto and DetailPostDto
  • When doing a Create or Edit(Update) the CopyDtoToData is called. Only properties that have a public setter, e.g. public int BlogId { get; set; } are copied to the data. This means you can exclude items that either you don't want to change or EF is responsible for setting. (see LastUpdated property in Post class which is filled in by EF.)
  • I would have liked all the references to the data classes and the DTO to be via interfaces as I think this gives better separation of classes, e.g. IxxxService<IPost, IDetailedPostDto> instead of IxxxService<Post, DetailedPostDto>. I did try to get Interfaces to work but EF does not support Interfaces, and using a interface for the DTOs had a few problems too. Nice aim to use interfaces, but I think the classes are simple enough to use direct. (Note: when it comes to running business level actions I do use interfaces for obviosu reasons.)

How DI is used in SampleMvcWebApp

Using DI to inject Action parameters (see MVC module that does this) in a Controller is a short and efficient way of injecting specific services to each action. Also by using Generic DI binding (see example from AutoFac) means that the DI can define all the possible service options quickly in its registration file (see in SampleMvcWebApp)

Click on the panel below to get more details about how these work.

How DI is used in SampleMcvWebpp

How we inject the action Parameter

Many years ago I came across an interesting blog post by by Alex Meyer-Gleaves who is one of the main people involved in AutoFac. In Alex's post he was proposing injecting method via each Action method in a controller rather than the more normal constructor injection.

I thought that was a great idea which solved so many problems so I implemented it, but in a different way to Alex's post. I create a new MVC Model Binder which is assigned in the Default Model Binder in the Global.asax.cs using the command ModelBinders.Binders.DefaultBinder = new DiModelBinder();

... however you can use GenericServices without DI

While we talk a lot about DI the GenericServices framework does NOT rely on DI at all. It just makes creating these services much easier and clearer. So, if you can't use DI then GenericServices may still be useful to you.