Setting up Visual Studio for Umbraco
Setting up Visual Studio for Umbraco

UMBRACO and MICROSOFT VISUAL STUDIO

Programmazione - Visual Studio Visite: 3662

A quick guide to Umbraco

"Umbraco è un sistema open source di gestione (CMS) per la piattaforma di pubblicazione di contenuti sul World Wide Web, scritta in C# e implementato su infrastruttura Microsoft." (wikipedia)

Umbraco è un buon e versatile CMS che usa la tecnologia Microsoft MVC 4 con il framework .NET 4.5.

L'attuale versione v8.0.2 usa il .NET 4.7.2 con Sql Server supportato dalla versione 2012+.

In questo articolo vedremo qualche consiglio pratico tra cui: multi button controller, come chiamare un controller tramite url, BeginUmbracoForm ed il passaggio dei parametri, ...

Umbraco CMS non è altro che un "Joomla like" ma costruito con la tecnologia Microsoft. A me è sembrato una buona via di mezzo tra Joomla e Drupal. E' sviluppato in C# mediante il paradigma MVC, la versione 7.6 del CMS funziona tranquillamente con il .NET Framework 4.6.2 mentre l'attuale versione v8.0.2 (Maggio 2019) funziona con la versione .NET 4.7.2.

Documentazione

La migliore documentazione su Umbraco la trovate sul sito di Umbraco!!!

our.umbraco.org/documentation

 

Utili link per creare un custom controller

https://our.umbraco.org/documentation/reference/routing/custom-controllers

 

Oppure una partial-views:

https://our.umbraco.org/documentation/reference/templating/mvc/partial-views

 

Se volete creare un template custom un'ottima guida è questa:

http://jondjones.com/how-to-create-a-custom-template-in-umbraco-7/

 

Per accedere al back office di Umbraco (o alla parte amministrativa) dovete usare il seguente link:

http://vostraURL/umbraco

 

Ovviamente se volete estendere e/o sviluppare su Umbraco avete bisogno dell'ambiente di sviluppo Microsoft Visual Studio.

Io ho lavorato con la versione 2013 e con la 2017.

Come configurare il progetto iniziale?

Leggete questa guida

https://live4coding.wordpress.com/2014/07/21/setting-up-umbraco-with-visual-studio/

Ricordatevi che il nome del progetto che create può essere qualunque ma non "umbraco" altrimenti avrete un bellissimo errore in fase di start del web site. L'errore che otterrete è:

unable to load 'Umbraco.Web.UmbracoApplication'.

 

L'installazione di Umbraco sotto ambiente Visual Studio, come potete leggere, nella guida che vi ho consigliato, avviene tramite NuGet. Peccato che da qualche versione a questa parte non potete scegliere la versione di Umbraco da installare ma avete a disposizione solo l'ultima.

Un modo per aggirare questo problema è il seguente:

 

Install-Package UmbracoCms -Version 7.5.9

 

Così facendo potrete installare la versione voluta.

Per capire bene come funziona Umbraco il miglior modo è lavorare con Umbraco.

Cosa bisogna fare se si vuole reinstallare Umbraco da zero su un nuovo database?

Ci sono da fare solo due cose nel file web.config:

 

<connectionStrings>
    <remove name="umbracoDbDSN" />
    <add name="umbracoDbDSN" connectionString="" providerName="" />
</connectionStrings>

 

e poi

 

<appSettings>
    <add key="umbracoConfigurationStatus" value="" />
</appSettings>

 

ovvero bisogna svuotare la connection string e il valore della umbracoConfigurationStatus. Così facendo quando Umbraco parte farà eseguira la procedura di installazione.

 

Umbraco si basa sul paradigma MVC. Vediamo quindi come creare una form contatti:

https://our.umbraco.org/documentation/Getting-Started/Code/Creating-Forms/

Questa guida è abbastanza completa ma andando a testare il tutto io ottenevo l'errore

 

Could not find a Surface controller route in the RouteTable for controller name MembershipController

 

Allora ho scoperto che il metodo del controller è meglio che sia questo:

 

        [HttpPost]
        [ActionName("Submit")]
        public ActionResult Submit(ContactFormViewModel model)
        {
            if (!ModelState.IsValid)
                return CurrentUmbracoPage();
            /// Work with form data here
            return RedirectToCurrentUmbracoPage();
        }    

ovvero meglio specificare la ActionName.

L'uso del controller invece l'ho corretto così:

 

    @using MyUmbracoSite.Controllers;
    @model MyUmbracoSite.Models.ContactFormViewModel


    @using (Html.BeginUmbracoForm<ContactController>("Submit"))
    {
        <div>
            @Html.TextBoxFor(m => m.Name)
        </div>
        <div>
            @Html.TextBoxFor(m => m.Email)
        </div>
        <div>
            @Html.TextAreaFor(m => m.Message)
        </div>

        <div>
            @Html.CheckBoxFor(m => m.Check)
        </div>
        <input type="submit" name="Submit" value="Submit" />
    }

 

In questa maniera tutto funziona perfettamente.

Un'altra utilissima guida per capire il funzionamento dell'MVC di Umbraco è la seguente:

http://jondjones.com/how-to-create-a-log-in-page-with-umbraco-7/

 

Come risolvere l'errore "this document is published but is not in the cache"?

A me questo errore capita quando la cache viene corrotta (ma non ne ho capito il motivo).

Altro errore che viene generato sempre per problemi di cache è il seguente:

"This document is published but its url would collide with content"

Per far ricostruire la cache è sufficiente essere collegati nel back office ed andare al seguente link:

 

http://<my host>/Umbraco/dialogs/republish.aspx?xml=true

 

In questa maniera la cache viene ricostruita e tutto riprende a funzionare.

 

Contenuto Pubblicato?

Cosa fare per verificare se un contenuto è pubblicato o meno?

var node = Umbraco.TypedContent(nodes);
if(node==null)
{
    //contenuto non pubblicato
}
else
{
    //contenuto pubblicato
}

 

MACRO

Le macro sono utilissime per renderizzare in un determinato punto un contenuto.

Se in una vista vogliamo inserire una macro si può fare così:

 

@Umbraco.RenderMacro("NomeMacro", new { NomeParametro = 1 })

 

Se invece abbiamo un contenuto che ha a disposizione un RichText Editor, Umbraco mette a disposizione un pulsante apposito per inserire la macro.

 

Come risolvere l'errore CS0234

Questo è un tipico errore in fase di compilazione/esecuzione del nostro progetto.

Per maggiori dettagli vedete questa guida.

Se il problema dipende da una data libreria io consiglio di aprire la console di NuGet "Package Manager Console" e di reinstallare la libreria. Ad esempio:

Install-Package Microsoft.AspNet.Web.Optimization

 

Impostare i TimeOut

A volte un problema di timeout può generare un errore del tipo:

Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

 

Vediamo come impostare alcuni parametri per evitare questo errore.

Alcuni TimeOut vengono impostati nel file di configurazione web.config.

In particolare abbiamo:

 

<add key="umbracoTimeOutInMinutes" value="20" />

 

TimeOut espresso in secondi. Il valore di default è 20. Scaduto questo timeout l'utente non sarà più loggato.

Io consiglio un più idoneo valore di 40, soprattutto se sul sito gli utenti ci devono lavorare e non solo consultare le informazioni.

Altro TimeOut è


<httpRuntime executionTimeout="99999"  />

 

Numero di secondi per la durata massima della esecuzione della request.

Altro valore che consiglio di usare è

 

<httpRuntime maxRequestLength="102400" />

 

Ovvero la dimensione massima della request. Questo valore è espresso in KB (102400KB=100MB).

Altro utile timeout è

 

Connection Timeout=15

 

Questo valore, espresso in secondi, indica il timeout della connessione verso il database. 15 secondi è il valore di default.

 

Creare un nuovo Media Type: My Slider

Il nostro scopo è semplicissimo: in un determinato punto della nostra Home vogliamo far vedere uno slider di contenuti.

Come si fa?

Allora,  si accede al back office e si va nella sezione Media.  Creiamo un Folder che conterrà i contenuti multimediali del nostro slider.  Creiamo sotto questo folder tutti i contenuti che ci servono, ad esempio contenuti di tipo "My Image Slider".

Se siamo nella sezione Media, dentro un folder possiamo creare oggetti di tipo Media Type (proprio come per i contenuti c'è il Document Type). I Media Type standard sono Folder, Image e File.

Si può creare un nuovo Media Type "My Image Slider"? Certo!

Lo si fa nella sezione Settings, sotto la voce Media Types. Possiamo aggiungere il nostro Media Type con tutti i campi necessari (nella parte Design si mettono i field necessari, nella parte Composition si possono ereditare caratteristiche da altri Media Type). Dato che poi gli oggetti di tipo "My Image Slider" li devo mettere dentro un Folder devo andare nella sezione Permissions del Folder e dire che posso creare dentro un folder oggetto di tipo "My Image Slider".

 

Creato il nuovo Media Type e messi i contenuti cosa si fa? Si deve creare un nuovo Document Type che possa avere questo tipo di contenuti, o modificarne uno esistente. Ad esempio si può aggiungere un nuovo tab chiamato "Slider" che contenga una property che abbia come editor il Media Picker. Usando come edito il Media Picker comparirà la voce Start Node nella quale si potrà specificare il folder dei nostri nuovi media creato prima.

Quindi il nostro Document Type punterà ad un folder che conterrà elementi di tipo "My Image Slider".

 

Ora dobbiamo andare nel nostro contenuto, o crearne uno nuovo, ed associare i dati necessari nel nuovo tab. Vedremo il nuovo tab e potremo scegliere dalla cartella che abbiamo creato quale slider far vedere.

 

Ora è quasi tutto pronto. Possiamo gestire i nuovi dati ma ora li dobbiamo far vedere. Bisogna quindi agire a livello di viste.

Una scelta può essere quella di creare una Macro che chiami la nostro vista che visualizza il nostro nuovo Media Type.

La vista va messa qui: ~/Views/MacroPartials/MyImageSliderHome.cshtml

Notate il nome: MyImageSlider --> indica il tipo di Media Type che viene trattato e Home --> indica dove lo fa vedere.

Alcuni consigli per il codice della vista:

//Ci prendiamo la nostra pagina

var currentPage = Model.Content;

//ci prendiamo il nostro media. "mySlider" indica l'id del field dato nel document type

var mySlider = Umbraco.TypedMedia(Model.Content.GetPropertyValue<int>("mySlider"));

//esempio di come si prendono i parametri del media type

if (mySlider .HasValue("titolo")){
        string titolo = slider.GetPropertyValue<string>("titolo");
}

 

Reinstallare un pacchetto con NuGet

Come si fa a reinstallare un pacchetto tramite NuGet?

Basta aprire da Visual Studio la console di NuGet e digitare il comando:

 

Update-Package –reinstall <package_name>

 

Questo non farà altro che reinstallare ed aggiornare all'ultima versione il pacchetto indicato.

Per una guida più completa fare riferimento al seguente link:

https://docs.nuget.org/ndocs/consume-packages/reinstalling-and-updating-packages

 

Errore 0x80070020

Ricevete questo errore quando avviate la vostra applicazione? Molto probabile che avete attivo un sistema anti-virus o anti-malware che scansione la vostra DLL nel momento in cui la eseguite. Se il vostro sistema non è molto performante allora mentre l'anti-virus fa la scansione blocca la DLL ed il sito web non parte più!

 

Ricavare un nodo e Redirect verso la pagina

Vediamo come si può ricavare un determinato nodo in Umbraco al fine di leggerne una sua proprietà.

Ricaviamo la Root del sito (questa soluzione va bene se applicata ad una vista dove abbiamo il Model):

 

var root = Model.Content.AncestorOrSelf(1);

 

Dalla root ricaviamo una determinata pagina:

 

var miaPagina = root.DescendantOrSelf("miaPagina");

 

miaPagina rappresenta l'ID del document type di pagina che vogliamo ottenere. Attenzione se ce ne sono più di una!

Da qui leggiamo la proprietà che ci serve:


var miaProp = miaPagina.GetPropertyValue<string>("miaProprietà");

 

Un'altro piccolo pezzo di codice molto utile è il seguente:

 

    @foreach (var child in Model.Content.Children)
    {
        Html.RenderPartial(child.DocumentTypeAlias, child);
    }

 

Questo codice gira tutti i contenuti figli della home. Per ogni contenuto viene richiamata la sua Partial View per essere renderizzato.

Si suppone che la vista abbia lo stesso nome del document type.

Vediamo ora come ricavare i nodi da un componente MultiPicker:

 

    var typedMultiNodeTreePicker = Model.Content.GetPropertyValue<IEnumerable<IPublishedContent>>("myAlias");
    if (typedMultiNodeTreePicker!=null)
    {
        foreach (var item in typedMultiNodeTreePicker)
        {
                @item.Name <br />
                @item.Url <br />            
        }
    }

 

In un controller Umbraco per fare la redirect verso una determinata pagina si fa così:

IPublishedContent myPage = UmbracoContext.ContentCache.GetByRoute("/myPath/");
if (myPage != null)
{
    return RedirectToUmbracoPage(myPage);
}


La Redirect alla Root di Umbraco la si fa così:

 

return this.Redirect(Umbraco.TypedContentAtRoot().FirstOrDefault().Url);

 

Questo metodo va bene anche per fare la redirect conoscendo una URL.
 

 

Visualizzare una immagine

Vediamo come si può visualizzare una immagine scelta mediante Medie Picker in Umbraco ed in particolare in una partial view.

        var image = Umbraco.TypedMedia(@MyPage.image); //image è l'id dell'attributo messo nel Document Type
        if(image!=null)
        {
            var imageUrl = image.Url;
            var imageAlt = image.Name;
            

            <img src="/@imageUrl"/>

        }

 

Come cancellare gli utenti in UMBRACO

Gli utenti in Umbraco sono di due tipologie: users e members.

I primi sono utenti del back-office mentre i secondi sono utenti del front-office.

I members possono essere eliminati direttamente dalla pagina di amministrazione presente nel back-office.

Gli  users non possono essere eliminati. Ma perché? Semplicemente perché collegato ad un utente ci stanno alcune informazioni chiave.

Vengono memorizzati gli accessi, le proprietà dei documenti e altro ancora.

L'unica alternativa che abbiamo è cancellare gli utenti direttamente da DB.

Vi mostro come esempio alcune query che possono essere eseguite per ripulire il DB di Umbraco da tutti gli utenti del back-office tranne l'admin:

 

-- Questi nodi vengono riassegnati all'Admin
UPDATE umbracoNode SET nodeUser = 0 WHERE nodeUser > 0
UPDATE cmsDocument SET documentUser = 0 WHERE documentUser > 0
-- Queste informazioni vengono cancellate
DELETE FROM umbracoLog WHERE userId > 0
DELETE FROM umbracoUser2App WHERE [user] > 0
DELETE FROM umbracoUserLogins WHERE userID > 0
DELETE FROM umbracoUser WHERE id > 0

 

Multi button controller

Una problematica molto comune è la seguente: una form con più di un pulsante per la submit. Come si fa?

Ho trovato sul web ua guida perfetta: MVC SurfaceController -Post Action

Usate la soluzione di "Nicholas Westby" che è perfetta e funziona benissimo.

 

Call a controller from a URL

E' possibile impostare una URL in maniera da richiamare la Action di un dato controller?

Certo che si può.

La URL la si deve comporre così:

 

myHost/umbraco/surface/{controllername}/{action}?{parameter}

 

In questo caso il nostro controller deve essere così fatto:

public class MyGestController : Umbraco.Web.Mvc.SurfaceController
{  
        [HttpGet]        
        [ActionName("MyAction")]
        public ActionResult MyAction(OrderProcessModel model)
        {

            ....return umbraco page

        }

}

 

Gestione chiamate Ajax

Vediamo in breve quali sono gli step per fare una chiamata Ajax sotto Umbraco.

1. La chiamata Ajax va abilitata

Nel web.config, nella sezione appSettings ci va la chiave seguente:

 

<add key="UnobtrusiveJavaScriptEnabled" value="true" />

<add key="ClientValidationEnabled" value="true" />

 

2. Caricare gli script

Nel nostro template bisogna far caricare gli script JS necessari:

 

<script src="/path/js/jquery.unobtrusive-ajax.min.js"></script>

 

3. Abilitare il file global.asax che altrimenti non verrà caricato:

 

<%@ Application Codebehind="Global.asax.cs" Inherits="Umbraco.Global" Language="C#" %>
          

come si vede, si fa chiamare la classe Umbraco.Global definita nel file Global.asax.cs come questo:

 

public class Global : UmbracoApplication
    {
        protected override void OnApplicationStarted(object sender, EventArgs e)
        {
            LogHelper.Debug(this.GetType(), "OnApplicationStarted");

            base.OnApplicationStarted(sender, e);
            RouteConfig.RegisterRoutes(RouteTable.Routes);            
        }

 

Questo file serve per chiamare la nostra regola di routing.

 

4. Regola di routing

Nella cartella App_Start si mette il file RouteConfig.cs con leregole di routing:

 

namespace Umbraco.Global
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute(
              name: "Ajax",
              url: "Ajax/{controller}/{action}"
            );
        }
    }
}

 

5. Nella form si mette la chiamata Ajax:

 

<div id="myTarget">

</div>

@using (Ajax.BeginRouteForm("Ajax", new { controller = "MyClass", action = "MyAction" }, new AjaxOptions
    {
        HttpMethod = "POST",
        InsertionMode = InsertionMode.Replace,
        UpdateTargetId = "myTarget",
        OnFailure = "ShowFailure()",
        OnSuccess = "ShowSuccess()"
    }, new { @id = "myFormAjaxId" }))
{

    <input type="submit" value="Submit"  />

}

 

Questa è la form che invoca il nostro controller MyClass e la sua action MyAction. Al ritorno, grazie all'istruzione InsertionMode.Replace, il risultato verrà messo nel div target.

 

Modello nelle pagine

Ci troviamo nella seguente casistica: si chiama una pagina umbraco, questa pagina avrà un suo template e quindi un suo layout.

Se associata alla pagina abbiamo un FORM e quindi un Controller associato, spesso può succedere che al refresh della pagina, a seguito di una chiamata Action, si perde il payout della pagina stessa.

Per bypassare questo problema si deve usare la seguente classe:

 

    public static class ExtensionMethods
    {
        public static void MapModel<T>(this WebViewPage<T> page) where T : class
        {
            var models = page.ViewContext.TempData.Where(item => item.Value is T);

            if (models.Any())
            {
                page.ViewData.Model = (T)models.First().Value;
                page.ViewContext.TempData.Remove(models.First().Key);
            }
        }
    }

 

Questo codice serve a rimettere il modello nella pagina, così facendo non si perde il layout.

 

 

BeginUmbracoForm e passaggi di parametri

Vediamo come invocare il submit di una form Umbraco e passare alla action del controller un parametro:

 

@using (Html.BeginUmbracoForm<MyController>("MyAction", new { myParam = "1",  @class="myClassCss"}))
{               
         <button type="submit" name="Submit" value="Submit">Submit</button>
}

Nel nostro esempio, invochiamo il metodo MyAction del controller MyController che riceve il parametro myParam valorizzato a "1".

Come si può vedere dall'esempio di sopra, vi mostro anche come impostare la class CSS per la vostra form. In questo caso la classe associata si chiama myClassCss.

 

Logging on Umbraco v8

Con la versione 8 di Umbraco sono cambiate molte cose tra cui "come fare il log".

Per loggare si deve usare il seguente codice:

 

using Umbraco.Core.Composing;

...

Current.Logger.Debug(this.GetType(), "my log message");

 

Il Team di Umbraco consiglia/sconsiglia le seguenti modalità di log:

 

//GOOD - Do use :)
Logger.Info<MyApiController>("We are saying hello to {Name}", name);

//BAD - Do not use :(
Logger.Info<MyApiController>($"We are saying hello to {name}");

//BAD - Do not use :(
Logger.Info<MyApiController>("We are saying hello to " + name);

 

Umbraco V8 e Bundle e Route config

Nella versione 8 di Umbraco è cambiata anche la gestione dei BundleConfig e RouteConfig che ora si fanno così:

 

public class ApplicationEventComposer : IComposer
    {
        public void Compose(Composition composition)
        {
            AreaRegistration.RegisterAllAreas();            
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);          
        }
    }

 

ovvero si usano gli oggetti composer per lo scopo.

 

Download Umbraco

Il download di Umbraco lo potete fare direttamente dal sito del produttore qui: umbraco.com/download

 

Ottimizzare Umbraco

Vi lascio una risorsa web molto utile se volete ottimizzare il vostro sito Umbraco: 11+ Tips to optimize Umbraco CMS

 

Buon lavoro!