33 messaggi dal 17 febbraio 2015
Ragazzi ho necessità di una mano da parte vostra...

Sto cercando di capire come gestire la cache lato server in Razor, senza controller e MVC.

In giro ho trovato questo:

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
}


CacheEsempio.cs:


public class IndexModel : PageModel
{
    private readonly IMemoryCache _cache;

    public IndexModel(IMemoryCache cache)
    {
        _cache = cache;
    }
    ...
}



E poi... come continuo?

Grazie in anticipo!
11.645 messaggi dal 09 febbraio 2002
Contributi
Ciao, qual è il tuo obiettivo? Cioè, cosa devi mettere in cache?
Modificato da BrightSoul il 05 ottobre 2018 14.45 -

Enjoy learning and just keep making
33 messaggi dal 17 febbraio 2015
Ciao Moreno!

In pratica ho pensato a tre tipi di cache:

1) dati estratti dal database (dati dei prodotti, impostazioni del sito, ...)

2) blocchi di sezioni html statici (menu e altre piccole sezioni)

3) files, immagini, css lato client.


Credo di essermi imbarcato in un progetto ancora, forse, troppo 'nuovo' puntando al solo C#/Razor, visto che su internet si trovano solamente esempi in MVC. :-(
11.645 messaggi dal 09 febbraio 2002
Contributi
Ciao,
quei tre sono tipi di cache differenti. Il servizio IMemoryCache può assolvere solo al primo, mentre il secondo lo risolvi con il tag helper cache, purché ci sia del codice altrimenti se è solo un "blocco di html statico", non c'è motivo di metterlo in cache.
Infine, per il terzo tipo puoi usare il middleware dei file statici per fargli aggiungere un'intestazione Cache-Control in modo che il browser client sappia per quanto tempo può tenere in cache i file. Leggi qui:
https://docs.microsoft.com/it-it/aspnet/core/fundamentals/static-files?view=aspnetcore-2.1&tabs=aspnetcore2x#set-http-response-headers


visto che su internet si trovano solamente esempi in MVC. :-(

Beh, per usare il IMemoryCache non c'è bisogno di usare né MVC né Razor Pages. E' un servizio che espone dei metodi pubblici che puoi usare ovunque. Prendi per esempio questa pagina della documentazione:
https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-2.1
E' vero che IMemoryCache viene mostrato nell'action di un controller MVC ma, tolto questo guscio esterno, puoi usare i suoi metodi Get, GetOrCreate e così via anche in Razor Pages o in qualsiasi altro punto dell'applicazione.

public class IndexModel : PageModel
{
    private readonly IMemoryCache _cache;

    public IndexModel(IMemoryCache cache)
    {
        _cache = cache;
    }
    ...
}

Questo è corretto. Hai ricevuto il servizio IMemoryCache come parametro del costruttore e ora lo puoi usare dagli altri metodi della Razor Page, tipo OnGet. Nel link alla documentazione che ho postato sopra, infatti, trovi anche un esempio di una Razor Page. Cerca "OnGet" per trovarlo.

Comunque, secondo me gli esempi riportati dalla documentazione sono buoni per iniziare però poi quando l'applicazione cresce rischi di trovarti l'IMemoryCache tra i piedi in ogni razor page, riducendo la leggibilità del suo codice.

Il caching è una responsabilità trasversale e perciò non dovrebbe apparire né in una razor page né in un controller MVC. Supponiamo che tu voglia accedere a un database e cachare i risultati: per prima cosa dovresti creare un tuo servizio IProductRepository che espone dei metodi come GetById e GetAll che ti permetteranno di recuperare i prodotti. Quindi crei un'implementazione concreta come AdoNetProductRepository che conterrà la logica vera e propria di accesso al database. In questo modo sposti la logica di accesso ai dati fuori dalla Razor Page, sia per motivi di riutilizzo del codice e sia perché stabilire la logica di accesso ai dati non è una responsabilità della Razor Page.

Poi, volendo aggiungere anche il caching dei dati, crei un'altra implementazione concreta del servizio IProductRepository chiamata ad esempio CachedProductRepository che wrappa l'AdoNetProductRepository e che non farà altro che invocare i suoi metodi. Quando torna il risultato, se lo mette in cache prima di restituirlo al cliente, in modo che possa lui stesso restituire il risultato alle successive invocazioni. Questo è anche chiamato decorator pattern che ti porta a costruire dei servizi tipo cipolla in cui ogni stato offre una singola funzionalità specifica.

Qui trovi alcuni nostri script sulla cache:
http://tags.aspitalia.com/Cache/

ciao,
Moreno
Modificato da BrightSoul il 05 ottobre 2018 22.53 -
Modificato da BrightSoul il 05 ottobre 2018 22.54 -

Enjoy learning and just keep making
33 messaggi dal 17 febbraio 2015
Ciao Moreno e grazie per la risposta!

In questi giorni ho provato ad modificare un esempio di cahching trovato su internet

C'ho sbattuto la testa per giorni ma non riesco ad "eliminare" il controller in modo da evitare MVC.

In pratica ho fatto come mi hai consigliato: ho estratto dal database, tramite un Reposity, i dati che mi interessano e qui sono:

INDEX.CSHTML:
 @foreach (var item in Model.ProductList)
                            {
                                <tr>
                                    <td onclick="myFunction(this)" class="view-message  dont-show"><h5>@item.Id</h5></td>
                                    <td onclick="myFunction(this)" class="view-message"><h5>@item.Name</h5></td>
                                    <td onclick="myFunction(this)"><h4 style="margin-top: 5px;"><span class="label label-success ">@item.Model</span></h4></td>
                                    <td onclick="myFunction(this)" class="view-message  text-left"><h5>@item.Price</h5></td>
                                    <td>
                                        <form method="post">
                                            <span class="btn-group pull-right" style="margin-top: 5px">
                                                <a class="btn btn-warning btn-xs" asp-page="/Product/Edit" asp-route-id="@item.Id" style="background-color: green; height: 29px; margin-top: -1px;">
                                                    <i class="glyphicon glyphicon-edit"></i>
                                                </a>

                                                <button type="submit" class="btn btn-danger btn-xs" asp-page-handler="Delete" asp-route-id="@item.Id" style="height: 27px; margin-top: 0px;"
                                                        onclick="return confirm('Are you sure to delete this product?');">
                                                    <i class="glyphicon glyphicon-remove"></i>
                                                </button>

                                            </span>
                                        </form>
                                    </td>
                                </tr>
                            }



------------------------------------------

INDEX.CS:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using CacheInMemory.Repository;
using System.Collections.Generic;


namespace CacheInMemory.Pages.Product
{
    public class IndexModel : PageModel
    {
        IProductRepository _productRepository;
        public IndexModel(IProductRepository productRepository)
        {
            _productRepository = productRepository;
        }

        [BindProperty]
        public List<Entity.Product> ProductList { get; set; }

        [BindProperty]
        public Entity.Product Product { get; set; }

        [TempData]
        public string Message { get; set; }
        public void OnGet()
        {
            ProductList = _productRepository.GetList();
        }

        public IActionResult OnPostDelete(int id)
        {
            if (id > 0)
            {
                var count = _productRepository.DeleteProdcut(id);
                if (count > 0)
                {
                    Message = "Product Deleted Successfully !";
                    return RedirectToPage("/Product/Index");
                }
            }

            return Page();

        }
    }
}

Ora, come inserisco questi dati in cache (IMemoryCache)? Ovviamente NON voglio inserire tutto il blocco di codice HTML, ma solo i dati (item.Id, item.Name, ...).
11.645 messaggi dal 09 febbraio 2002
Contributi

In pratica ho fatto come mi hai consigliato: ho estratto dal database, tramite un Repository, i dati che mi interessano e qui sono:

Perfetto, ora la tua razor page è completa, e così anche il tuo repository.
Infatti, quando devi implementare una funzionalità trasversale come il caching, non dovresti modificare né la razor page né il repository stesso. Dovresti invece creare una nuova classe che si frappone tra la razor page e il repository e che ha l'unico scopo di implementare questa funzionalità di caching.
Se non facessi così, potrebbe incasinartisi il codice della razor page (o del repository) perché magari poi ti chiedono di aggiungere il logging, l'autorizzazione e altre responsabilità trasversali.

Qui c'è un articolo che ti mostra proprio come realizzare questa ulteriore classe, il "CachedRepository" che ha due dipendenze: il repository vero e IMemoryCache. Questa nuova classe implementa lei stessa IProductRepository quindi possiede gli stessi metodi del repository vero e proprio. Puoi considerarla come un "wrapper" del repository ma più precisamente si chiama "decorator". E' un pattern.
https://ardalis.com/building-a-cachedrepository-in-aspnet-core

Nel momento in cui devi aggiungere anche il logging, crei un'altra classe e l'avvolgi attorno al CachedRepository, tipo cipolla. Così mantieni classi piccole dalla singola responsabilità.

Nota al fondo:
Ti ho proposto di usare il decorator pattern perché ho trovato un articolo preciso preciso per la tua esigenza. Altrimenti, come in quest'altro post che presenta un caso concettualmente identico al tuo, ho suggerito una strada alternativa che consiste nell'inserire la logica di caching dentro il repository che però non è la strada migliore percorribile per via delle commistione di due reponsabilità: caching e accesso ai dati.
Nel suo caso le due responsabilità erano logging e invio email.

Questo sembra essere un tema ricorrente e purtroppo io ora non ho tempo di preparare un'applicazione dimostrativa che risolva la cosa una volta per tutte. Oltretutto il la dependency injection di ASP.NET Core non ha le funzionalità che servirebbero per implementare il decorator pattern in maniera elegante. Nell'articolo che ti ho linkato prima, il tizio è stato costretto a registrare così i servizi che... per carità, funziona, ma non si può guardare.
services.AddScoped<IReadOnlyRepository<Author>, CachedAuthorRepositoryDecorator>();
services.AddScoped(typeof(EfRepository<>));
services.AddScoped<AuthorRepository>();


ciao,
Moreno
Modificato da BrightSoul il 24 ottobre 2018 21.30 -

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.