4

In my web application, I am able to map component fields to the View model fields. However still I am not clear about couple of points in view model mapping.

  1. Why RegisterViewModel needs to be called (for example RegisterViewModel("ABCView", typeof(ABCViewModel))). While building the PageModel/EntityModel object, can not binder build the object with only sementic mapping? Sementic mappings specifies which schema maps to which View model entity , and which field in view model maps to which field in the component. Is this information not sufficient to built the model.

  2. If Register View model is called with view name and View model Type, then system already knows which component template was chosen while building the page, which view this template refers to, and what is the view model for the view in discussion, then based on this information can not the entity model be built up? Why is sementic mapping needed in this case?

May be I am not understanding the complete picture? Please help me understand.

Thanks

2 Answers 2

2

With RegisterViewModel(viewName, viewModelType), you associate a View with a (Strongly Typed) View Model.

You could argue that this association is already done in the Razor View itself. That is correct and DXA.NET can even infer those associations by compiling all Views, but this adds considerably to the web app startup time. That is why explicit View (Model) registration was introduced in DXA.NET 1.1.

The View Model type mapping flow is as follows:

  • CM Pages and Component Presentations have Page Templates and Component Templates, respectively.
  • DXA-based Page/Component Templates define a Page/Entity View name (in their metadata)
  • DXA-based Page/Entity Views are associated with Page/Entity View Models (through View Model registration)
  • This is how DXA can determine Page/Entity View Model types when building a Strongly Typed View Model for a CM Page containing Component Presentations (or for a separately published Dynamic Component Presentation)

So, you see that Semantic Mapping is not involved at all in resolving the View Model types. There is one (advanced) View Model type mapping scenario where the Semantic Mapping is used: so-called polymorphic mapping of linked Components.

If you are mapping a linked Component to an embedded Entity Model, the model mapping already knows the type of the embedded Entity Model (from the Model’s property type), but it is possible to let this be an (abstract) base class and let the model mapping instantiate a concrete subclass. This is called polymorphic mapping and the model mapping logic uses the Semantic Mapping between CM Schemas and Entity Model types to determine which concrete subclass to instantiate.

For example, you see that the Core Module’s Teaser.Media property is of type MediaItem, which is an abstract base class. The model mapping will instantiate one of the concrete subclasses (Image, YouTubeVideo or Download), depending on the CM Schema of the linked Component.

Oh, and back to your question why DXA doesn’t use the Semantic Mapping to resolve all Entity Model types: there can be multiple Entity Model types for a single CM Schema. DXA needs to resolve both an Entity View and an Entity View Model type and the View is the most specific. That is why DXA-based Component Templates are associated with a View (which implies a View Model type).

4
  • Thanks Rick for the detailed answer. It makes things clear. I understand that registerviewmodel helps in creating mapping for views to view model, and DXA framework already knows which view is being used so in turn it knows which view model it needs to map to. And then Sementic mapping can help in polymorphic mapping or if not all fields needs to be mapped. Just one additional question, then what is the purpose of the RenderViewModel overload that just accepts the modeltype and no view name in it. Please help me understand that as well.
    – Rites
    Commented Mar 27, 2020 at 13:44
  • 1
    The RegisterViewModel(viewModelType) overload is used to register embedded Entity Models; it is essential to make polymorhpic mapping work. Commented Mar 27, 2020 at 13:47
  • in case of polymorhpic mapping then it should be like this: RegisterViewModel("Viewname",TypeOf(AbstractBaseType));RegisterViewModel(TypeOf(ConcreteType1BasedonAbstractBaseType));RegisterViewModel(TypeOf(ConcreteType2BasedonAbstractBaseType)); And then DXA framework with the help of sementic mapping would see which concrete type object to built up.
    – Rites
    Commented Mar 27, 2020 at 14:06
  • You actually don’t need the first call; embedded View Model types are not associated with a View through View Model registration (there’s nothing in CM that specifies a View name for linked Components). Conversely, an embedded Entity Model type can specify a View name by overriding GetDefaultView(). In this manner, it is still possible to render embedded Entity Models using @Html.DxaEntity() Commented Mar 27, 2020 at 15:02
0

Scenario 1

I wasn't involved in the decisions on this, but I suspect that one reason that the RegisterViewModel("ABCView", typeof(ABCViewModel))) instruction is needed is because there may be more than one ViewModel that applies to a specific schema and we need to know the relationship between the View and the ViewModel.

For example, an Article Schema may have three fields: Field A, Field B and Field C. Depending on what the specific View does, you may then have two ViewModels that are annotated to work with this Schema:

  • ViewModelOne uses Field A and Field B from the Article Schema and also supplements this with some additional information (e.g. from a separate product system). This works with ViewX.
  • ViewModelTwo uses Field A and Field C from the Article Schema and contains additional information about these (e.g. it holds additional information about the image in Field C). This works with ViewY.

In this scenario, even through you have semantic mapping on the ViewModel (telling it which schema it relates to), you still need the following to identify which ViewModel to use with which View:

RegisterViewModel("ViewX", typeof(ViewModelOne))); //Relates to the Article Schema
RegisterViewModel("ViewY", typeof(ViewModelTwo))); //Also relates to the Article Schema

Scenario 2

Another possible reason (although I've never tested this scenario and am not 100% sure it would work!) is that each Component Template can be associated with more than one Schema and each of these schemas may have a different ViewModel.

For example, we may have a Notification Banner Component Template that has a NotificationBannerView View and is associated with two Schemas: News Article and Press Release.

Each of these Schemas may have a different ViewModel: NewsViewModel and PressReleaseViewModel. In this scenario, you need the RegisterViewModel commands to be as follows:

//The framework would know which option to choose of these two based on the schema used.    
RegisterViewModel("NotificationBannerView", typeof(NewsViewModel))); //Used with the 'News Article' Schema
RegisterViewModel("NotificationBannerView", typeof(PressReleaseViewModel))); //Used with the 'Press Release' Schema

(As I say, I've not tested whether the 'plumbing' for this scenario actually works in DXA, but it would be another reason for needing to use the RegisterViewModel command.)

3
  • Update: Looking at the 'View Model type mapping flow' described in Rick's answer, I suspect that Scenario 2 wouldn't actually work. Commented Mar 27, 2020 at 13:25
  • Scenario 2 is possible and will work, but it is the Component Template which determines the View and thus the View Model type. Of course, the selected View Model types will have to be able to map to all allowed CM Schemas, but that’s indeed the idea behind View Model types: there is not a 1:1 association between CM Schema and View Model types. Commented Mar 27, 2020 at 13:40
  • Thanks Jonathan Williams for mentioning the scenarios. I agree with you completely on scenario 1. However in case 2, As you mentioned there is one component template, thus it can only be associated with one view, and this in turn implies that it can have only one view model. And this is exactly the case, where it is beneficial to create a base abstract class which inherits from EntityModel and then view models of each specific schema should inherit from this abstarct base class. And while calling RegisterViewModel one need to pass typeof(AbstractBaseclass) as the viewmodel type.
    – Rites
    Commented Mar 27, 2020 at 13:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.