Archive for tag: Umbraco

Entity Framework Code First Migrations på en Umbraco installation

Arbejder du med kode til en Umbraco installation, som anvender Entity Framework 6 og Code First Migrations, kan det være du kommer i samme situation som mig, hvor Migrations ikke bliver kørt ifm. Web Deploy.

Jeg kunne ikke umiddelbart finde frem til årsagen, men jeg fandt en vej udenom problemet. Det er ikke en perfekt løsning, da den involverer noget manuelt arbejde, men nogle vil påstå, at det er en bedre metode i et produktionssetup, hvor du gerne vil have 100% kontrol over, hvad der sker med din database og hvornår det sker.

Til formålet anvender jeg Package Manager Console, hvor jeg skyder en update-database af mod min produktionsdatabase server og får et script genereret, som jeg så kan fyre af i MSSMS (mod min produktionsdatabase server).

Inden jeg kunne gøre dette, løb jeg dog ind i et par problemer. Det første var at DbProviderFactory skal være til stede i min web.config, for ellers ville update-database kommandoen ikke køre. Dette betyder helt konkret, at flg. skal tilføjes i system.web-sektionen af web.config:

  <system.data>
    <DbProviderFactories>
      <remove invariant="System.Data.SqlClient" />
      <add name="SqlClient Data Provider"
           invariant="System.Data.SqlClient"
           description=".Net Framework Data Provider for SqlServer"
           type="System.Data.SqlClient.SqlClientFactory, System.Data, 
                 Version=2.0.0.0, Culture=neutral, 
                 PublicKeyToken=b77a5c561934e089" />
    </DbProviderFactories>
  </system.data>

Når dette er på plads kan update-kommandoen udføres med flg. format:

update-database -script -projectname <projektet med entity datacontext>
     -connectionstring <connectionstring til produktionsdatabasen>

NB: Det er naturligvis en forudsætning, at du har adgang til din produktionsdatabase server fra din udviklermaskine (hvilket nok i større setups ikke er sandsynligt), da update-database skal læse migrationshistorikken fra databasen, for at vide, hvilke migrationer der skal udføres.

Efter denne kommando er udført, får du, i Visual Studio, et vindue med SQL-koden, som modsvarer migrationen. Denne kode kan så udføres i MSSMS mod produktionsdatabasen og migrationen er dermed gennemført.

Hvis du føler dig rigtig modig, kan du undlade -script parameteren og få udført opdateringen direkte fra PMC'en. Det sparer dig for at skulle udføre scriptet i MSSMS efter det er genereret i PMC, men det fjerner også muligheden for, at kontrollere, hvad migrationsscriptet rent faktisk har tænkt sig, at gøre ved din produktionsdatabase...

Umbraco pre v4 database oprydning

Jeg havde for nylig et site der kørte på Umbraco og som kørte enormt langsomt og fungerede egentlig ikke rigtigt. Jeg undrede mig en del over det, for indholdsmæssigt var det ikke et tungt site (kun få sider - mindre end 100), men et site der havde været i drift i en længere periode. Jeg besluttede mig for at finde ud af hvorfor det ikke fungerede. Her er hvad jeg fandt frem til...

Symptomerne

Sitet kørte som nævnt ikke rigtigt. Helt konkret var det enormt langsomt til at indlæse træstrukturen og det var et held, hvis man fik lov til at oprette nye dokumenter.

Det er klart, at man ikke kan forvente hvad som helst af en 10+ år gammel undskyldning for en server, men jeg havde da også andre Umbraco-sites på denne server, som slet ikke havde problemer med at køre, så jeg mente jo nok dette ikke burde være et problem. Også det faktum, at der var tale om et Umbraco v3.0.6 kunne vække en vis bekymring, men igen, så var der også andre sites i denne version, på samme server, som kørte tilfredsstillende.

Opdagelsen

Efter af have kigget lidt rundt i Umbraco-admin, uden dog at kunne finde noget, der virkede himmelråbende tåbeligt konfigureret, bedrog jeg mig ud i stifinderen, for at se om der kunne være noget der. Første stop web.config, men også her så tingene tilforladelige ud, så heller ikke der synes jeg, der var noget at hente.

Efter lidt stikken og justeren, fandt jeg frem til databasefilerne (data og log) for sitet og til min store overraskelse opdagede jeg, at data-filen fyldte 2.3+ Gb! Det var vist ikke nødvendigt for sådan et lille site, så noget måtte være galt, men hvad!?

Undersøgelsen

Gad vide hvordan sådan en Umbraco database er bygget op? En hel masse tabeller præfikset med cms og umbraco og lidt svær at gennemskue, hvis man ikke har arbejdet indgående med sådan en før (hvilket jeg ikke havde), så Google måtte kunne hjælpe...(?)

Først og fremmest måtte jeg have et overblik over hvormeget data der var i hvilke tabeller. Til dette formål fandt jeg flg. SQL-script, som, om en given database, kunne fortælle mig, hvormange rækker der er i hver tabel, hvormeget tabellens indhold fylder i Kb m.m.

SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows AS RowCounts,
    SUM(a.total_pages) * 8 AS TotalSpaceKB, 
    SUM(a.used_pages) * 8 AS UsedSpaceKB, 
    (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID 
                    AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN 
    sys.schemas s ON t.schema_id = s.schema_id
WHERE 
    t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255 
GROUP BY 
    t.Name, s.Name, p.Rows
ORDER BY 
    t.Name

Efter at have kørt dette script i SSMS, fik jeg en fornemmelse af, at problemet havde med versionering af dokumenterne at gøre. De tabeller som indeholdte markant mere data end forventet, var cmsContentVersion, cmsDocument, cmsPropertyData og umbracoLog. Uden at ville (og kunne) gå i yderligere detaljer om, hvad disse tabeller konkret bruges til, indikerer det i det mindste, at det har noget med versionering at gøre. Spørgsmålet er bare, hvorfor? Der er ikke specielt meget aktivitet i relation til vedligeholdelse af indhold på sitet, så hvorfor er der oprettet så mange rækker i disse tabeller (der var over 500.000 i cmsDocument og cmsContentVersion og over 3.500.000 i cmsPropertyData, ligesom der også var omkring 1.200.000 i umbracoLog...!

Et kig i umbracoLog afslører en periodisk publisering af to specifikke dokumenter, som resulterer i 4 nye rækker i umbracoLog, samt nye 2 eller flere rækker i hver af de andre tabeller, hver gang. Hver gang vil sige, hvert minut 24/7/365 - det bliver til en del rækker med tiden... :-)

Det var naturligvis ikke en optimal situation, så der måtte da være en løsning på dette. Hvorfor blev disse to dokumenter (indholdssider på linje med en masse andre på sitet) publiseret med 1 minuts intervaller og mere vigtigt, hvordan fik jeg det så stoppet!?

"Løsningen"

Derfor måtte jeg finde ud af, hvordan jeg kunne løse dette. Google er min ven(!), men selv venner har sine begrænsninger, så det lykkedes den ikke at fremskaffe en løsning. Den eneste tilnærmelsesvis overkommelige løsning var, at opgradere til en nyere version, hvor dette ikke længere var et problem. Det lader nemlig til at være et bug i nogle versioner (herunder v3.0.6, som dette site jo kører), som bevirker, at der publiseres på denne måde.

Jeg skal erkende, at jeg heller ikke har søgt efter en løsning meget mere end en times tid, da sitet skulle pilles ned indenfor en overskuelig tidshorisont, så det kan være der rent faktisk kan køres et workaround, som løser dette, men jeg er som sagt ikke faldet over det.

Det jeg så gør i stedet, er symptombehandling (when all else fails...). Det indbefatter en periodisk udførsel af et SQL script, som sletter alle versioner op til en bestemt dato (i nedenfor viste script, er det til dagen før den dato hvorpå scriptet udføres) og som ikke er den aktive version. Dette script ser således ud.

DECLARE @createdDate Datetime
SET @createdDate = DateAdd(day, -1, getdate())

DELETE FROM cmsPropertyData WHERE
    versionId NOT IN (
              SELECT versionId 
              FROM cmsDocument 
              WHERE updateDate > @createdDate 
                 OR published = 1 
                 OR newest = 1) AND
    contentNodeId IN (SELECT DISTINCT nodeID FROM cmsDocument)

DELETE FROM cmsContentVersion WHERE
    versionId NOT IN (
              SELECT versionId 
              FROM cmsDocument 
              WHERE updateDate > @createdDate 
                 OR published = 1 
                 OR newest = 1) AND
    ContentId  IN (SELECT DISTINCT nodeID FROM cmsDocument)

DELETE FROM cmsDocument WHERE
    versionId NOT IN (
              SELECT versionId 
              FROM cmsDocument 
              WHERE updateDate > @createdDate 
                 OR published = 1 
                 OR newest = 1) AND
    nodeId IN (SELECT DISTINCT nodeID FROM cmsDocument)

Dette script, når det bliver gemt som en fil og placeret på serveren, kan så, med jævne mellemrum, aktiveres, som en baggrundsopgave på serveren, hvor scriptet kaldes med sqlcmd.

sqlcmd -S myServer\instanceName -i C:\sqlscripts\umbracoCleanup.sql

Konklusion

Nu har jeg i det mindste fået lidt styr på databasevæksten på mit site, selvom jeg ikke synes dette er den optimale løsning (langt fra - det bedste ville jo være, at publiseringen ikke gik i selvsving!). Nogle gange er vi bare nød til, at nøjes med mindre, så vi kan komme videre med det der er rigtig fedt! :-)

 

Et hurtigt brødkrummespor i Umbraco

Efter at have opgraderet til Umbraco 4.7.2 er jeg gået igang med Razor-delen af Umbraco og det er jo indtil videre en fornøjelse (sammenlignet med XSLT/Macro-helvedet). Jeg har ellers ikke haft det store imod at arbejde med XSLT, men hvis det kan blive så meget lettere, så kom bare med det!

Jeg ved det er et simpelt problem, men nedenstående kode smidt ind i en skabelon (inline!) giver et brødkrummespor til den aktuelle side.

<umbraco:Macro runat="server" language="cshtml">                                                       
  @foreach(var ancestor in Model.AncestorsOrSelf()) {
    if(!ancestor.umbracoNaviHide) {
      if(ancestor != Model) {
        <a  href="@ancestor.Url">@ancestor.Name</a>
        @Html.Raw("&gt;")
      }
      else {
        @ancestor.Name
      }
    }
  }
</umbraco:Macro>

Så bliver det vist ikke ret meget simplere! Der er taget højde for at, at visse sider i hierarkiet kan være skjult for menuer og andet. Desuden er den aktuelle side ikke renderet som et link.

Jeg kommer til at bruge mere tid på dette! Nice!

Første forsøg med Umbraco 4.6

Ja, så fik jeg installeret en Umbraco 4.6.1 vha. webPI og det gik overraskende nemt!

Jeg kommer fra installationer af Umbraco 3.0.6 og tidligere og det har været lidt mere hardcore at gå til, men det lader til at der nu også er kommet styr på den del af Umbraco. Nice!