Developer forum

Forum » Dynamicweb 10 » Access product when overriding ProductViewModel

Access product when overriding ProductViewModel

Mario Santos Dynamicweb Employee
Mario Santos
Reply

Hi,

I am trying to extend the ProductViewModel to add more properties to it. We can simply create a custom viewmodel - but how do we know the actual product that is in context?
I need to do a DB check based on a ProductId, ProductVariantId.

I tried something like the following but Id, VariantId, LanguageId are null - properties were not set yet.

public class InolexProductViewModel : Dynamicweb.Ecommerce.ProductCatalog.ProductViewModel
{
    public IList<Entities.ProductPrice> PricesWithWeight { get; set; }
    public Entities.ProductPrice? PriceWithWeight { get; set; }

    public InolexProductViewModel() {
        var productObj = Dynamicweb.Ecommerce.Services.Products.GetProductById(Id, VariantId, LanguageId);
    }

}

BR Mario


Replies

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Hi Mario

InolexProductViewModel’s constructor runs before the Id, VariantId, and LanguageId are populated — so calling
Services.Products.GetProductById(Id, VariantId, LanguageId) inside the constructor won’t work because those values are still null at that stage.

More importantly, you should be very careful to hold or lazily create a Product instance inside a view model.

A ProductViewModel belongs purely to the presentation layer — it’s meant for rendering, binding, or serialization.
If you start pulling in domain objects (like Product) from there, you break separation of concerns and create several serious risks:

  • Hidden database calls during rendering or serialization.

  • Massive circular object graphs if ever serialized to JSON.

  • Hard-to-track performance bottlenecks and caching issues.

Instead of putting that logic inside the view model, use a pattern where the domain object is explicitly fetched when needed.

In general you should avoid doing properties on viewmodels except for very specific situations where you need the property serialized in e.g. the /dwapi. In any other situation you should use an extension method instead.

You can do something like this:

public class InolexProductViewModel : Dynamicweb.Ecommerce.ProductCatalog.ProductViewModel
{
    private Lazy<Product?>? _productLazy;

    private Lazy<Product?> ProductLazy =>
        _productLazy ??= new Lazy<Product?>(() =>
        {
            if (string.IsNullOrEmpty(Id))
                return null;

            return Products.GetProductById(Id, VariantId, LanguageId);
        });

    public Product? GetProduct() => ProductLazy.Value;

    public decimal? GetWeightedPrice()
    {
        var product = GetProduct();
        if (product == null)
            return null;

        var weight = product.Weight > 0 ? product.Weight : 1;
        var price = product.Price.Price ?? 0;
        return price * (decimal)weight;
    }

    public IList<Entities.ProductPrice> GetPricesWithWeight()
    {
        var product = GetProduct();
        if (product == null)
            return Array.Empty<Entities.ProductPrice>();

        return new List<Entities.ProductPrice>
        {
            new Entities.ProductPrice { Weight = product.Weight, Value = product.Price.Price ?? 0 }
        };
    }
}
 
Mario Santos Dynamicweb Employee
Mario Santos
Reply

Hi Nicolai,

Thanks for your feedback. In this case we actually need the values in dwapi. Could you please share an example?

Thanks, Mario

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

An example of what?

My post does contain an example of how to get the product object.

 

You must be logged in to post in the forum