Search code examples
abp-framework

Ho do i pass a model with data from the DB to an ABP.IO Layout Hook?


trying to setup a multi-tenant site using ABP.io framework 3.1.

I am trying to set the <meta keywords (amongst other tags) in the page html head. I am attempting to get the values from a database field for the current tenant so the meta keywords will be specific for the tenant. I tried to follow the sample that is available here: https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface#layout-hooks where they inject a google analytics script code into the head tag.

this is fine, as it is static text, but when i try to load the partial page with a model it throws an error of expecting a different model to that which is passed in.

So far i have the Notification View Componet

Public class MetaKeywordViewComponent : AbpViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync() {
        return View("/Pages/Shared/Components/Head/MetaKeyword.cshtml"); //, meta);
    }
}

and the cshtml page

@using MyCompany.MyProduct.Web.Pages.Shared.Components.Head
@model  MetaKeywordModel 

@if (Model.SiteData.Keywords.Length > 0)
{
    <meta content="@Model.SiteData.Keywords" name="keywords" />
}

and the cshtml.cs file as

 public class MetaKeywordModel : MyProductPageModel
    {
        private readonly ITenantSiteDataAppService _tenantSiteDataAppService;

        public TenantSiteDataDto SiteData { get; private set; }

        public MetaKeywordModel(ITenantSiteDataAppService tenantSiteDataAppService)
        {
            _tenantSiteDataAppService = tenantSiteDataAppService;
        }

        public virtual async Task<ActionResult> OnGetAsync()
        {
            if (CurrentTenant != null)
            {
                SiteData = await _tenantSiteDataAppService.GetSiteDataAsync();
            }

            return Page();
        }
    }

but when i run the program i get the following error.

An unhandled exception has occurred while executing the request.
System.InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'Volo.Abp.AspNetCore.Mvc.UI.Components.LayoutHook.LayoutHookViewModel', but this ViewDataDictionary instance requires a model item of type 'MyCompany.MyProduct.TenantData.Dtos.TenantSiteDataDto'.
 

How do i pass the data from my database into the page to be rendered if i can't use my model?

Any help tips or tricks would be greatly appreciated.

Regards Matty


Solution

  • ViewComponent is different from the razor page.

    See https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-3.1#view-components

    You should inject the service in view component class directly. like:

    public class MetaKeywordViewComponent : AbpViewComponent
    {
        private readonly ITenantSiteDataAppService _tenantSiteDataAppService;
    
        public MetaKeywordViewComponent(ITenantSiteDataAppService tenantSiteDataAppService)
        {
            _tenantSiteDataAppService = tenantSiteDataAppService;
        }
    
        public async Task<IViewComponentResult> InvokeAsync()
        {
            return View("/Pages/Shared/Components/Head/MetaKeyword.cshtml",
                await _tenantSiteDataAppService.GetSiteDataAsync());
        }
    }
    

    In addition, you can refer https://github.com/abpframework/abp/blob/42f37c5ff01ad853a5425d15539d4222cd0dab69/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/PageAlerts/PageAlertsViewComponent.cs