<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rssdatehelper="urn:rssdatehelper"><channel><title>Attackmonkeys Blog</title><link>http://w.attackmonkey.co.uk</link><pubDate>2017-04-05T08:15:48</pubDate><generator>umbraco</generator><description>This is the technical blog of Tim Payne, freelance web developer and covers topics relating to Web Development, Umbraco, SQL Server and ASP.Net.</description><language>en</language><item><title>The Most Important Skill For Web Developers</title><link>http://w.attackmonkey.co.uk/blog/2017/04/the-most-important-skill-for-web-developers</link><pubDate>Wed, 05 Apr 2017 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2017/04/the-most-important-skill-for-web-developers</guid><category>Web Dev</category><description><![CDATA[ 
<p>Over the years (and it's been quite a few years now) I've come
to realise that one of the most important skills a developer can
have is also probably of the most underrated. The ability to
methodically investigate and get to the bottom of a problem.</p>

<p>The ability to really dig into an issue and try and track down
what's going on is a really important skill for a developer to
have. Often you might be working on something that was written by
someone who no longer works at a company so you have no way of
knowing why something was done, or in some cases how. The issue
might be super obscure, or be very hard to replicate, but if you
can doggedly Sherlock the shit out of your problem, you'll
eventually get to the bottom of the issue.</p>

<p>All to often I've seen people just have a quick look at the
code, stick a question on SO and forget about it, when they could
just spend a bit of time digging into the issue to try and work out
the solution. If nothing else, it'll help you to understand the bit
of code you're working on.</p>

<p>So remember, if you hit a problem, do a bit of
investigating!</p>
]]></description></item><item><title>Adding The Language to the URL</title><link>http://w.attackmonkey.co.uk/blog/2016/11/adding-the-language-to-the-url</link><pubDate>Wed, 23 Nov 2016 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2016/11/adding-the-language-to-the-url</guid><category>Web Dev</category><description><![CDATA[ 
<p>If you're doing a one to one translated language site, you'll
want to be able to switch the language. You could do this by
setting a cookie and reloading the page, but that's crap for SEO,
and means users can't share links to the pages in the different
languages.</p>

<p>Conventional wisdom states that you should include the language
in the URL in some fashion. One option is to include it in the
querystring (don't laugh, I've seen this done in the wild).
DON'T!!! You then have to remember to pass the variable around
everywhere, and it's easy to forget, so the selected language
randomly gets lost, and the user switches language without meaning
to. You can also have different subdomains/domains for each
language, but that's a bit faffy to set up and configure,
especially if you're continually adding new languages.</p>

<p>Ideally, you want to make the language code part of the URL.
I've seen site that add it to END of the URL, like "/my-page/de/",
this is also not great. It makes the URLs harder to hack around.
Take "/about-us/awards/" for example, if you knock off the awards
part, you know you're getting the about us page. If you have the
language at the end, if you don't leave the language on the end
when you hack off the awards part, you get the about us page in
English, not German.</p>

<p>For this reason, you should always include the language at the
START of the URL, that way you can hack around to your heart's
content, and the language will be kept!</p>

<p>If you're using Umbraco, you can do clever things with
UrlProviders and Resolvers to automatically include the language in
the URL without much extra work (I'll blog about this at a later
date).</p>
]]></description></item><item><title>Create a User For Content Changes in Code</title><link>http://w.attackmonkey.co.uk/blog/2016/10/create-a-user-for-content-changes-in-code</link><pubDate>Wed, 05 Oct 2016 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2016/10/create-a-user-for-content-changes-in-code</guid><category>Umbraco</category><description><![CDATA[ 
<p>I've not blogged for a while, and I've decided to doa series of
shorter posts highlighting some useful techniques I've come across
recently. Here's the first one!</p>

<p>In Umbraco, you may often have some task that manipulates
content/media etc via the various service APIs. For example you
might have a scheduled import task that imports pages froma feed,
or a task that pulls in content or modifies content based on things
happening in a thiord party system.</p>

<p>By default, all actions carried out using the services are
flagged against user 0 (the default Admin user). This is fine, but
it means it's hard to tell what changes were made by your tasks,
and which were made by the ACTUAL administrator.</p>

<p>Most ofthe Save and publish methods have an additional parameter
for User ID, which can be the ID of any back office user. The fun
part, is that the user doesn't have to actually be able to access
the back office. So you can create a user, called something like
"Task User" (you could even create a different user for each task
if you wanted), and ythen disable it's Umbraco access with the
check box. Then update all of your code to include the user ID.</p>

<p>So this:</p>

<pre>
Services.ContentService.Publish(myContent);
</pre>

<p>Would become something like this:</p>

<pre>
Services.ContentService.Publish(myContent, TaskHelper.TaskUser);
</pre>

<p>This means you can now pin down in the audit trail if content
issues were caused by actual CMS users, or by one of your
tasks!</p>

<p>Why did I start doing this? One of my clients inherited a site
that had a public page that had a link to call a controller that
deleted ALL of the content of a specific type, that no one new
about until they had a pen test done, and the testers clicked on
the link, deleting a sizeable chunk of important content on the
site. The delete by content type method also permanently deleted
the pages in question (but not the sub-pages). As we didn't know
the page existed, or that the pen test was being run, it took us a
while to track down the culprit. Had we had actions flagged against
a task user, we'd have known straight away where to look!</p>

<p>One thing to note, if you are manipulating content through the
APIs, you should keep it to a minimum to avoid clogging up your
versions table. Only update stuff if you need to. If you do need to
use lots of updates, it's worth installing something like <a
href="https://our.umbraco.org/projects/backoffice-extensions/falm-housekeeping/">
FALM Housekeeping</a>, or <a
href="https://our.umbraco.org/projects/website-utilities/unversion/">
Unversion</a> to keep things under control.</p>
]]></description></item><item><title>Crazy Assed Shit With Contour, or How to Export ALL of Your Records as a Unified CSV</title><link>http://w.attackmonkey.co.uk/blog/2016/03/cas-with-contour</link><pubDate>Thu, 24 Mar 2016 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2016/03/cas-with-contour</guid><category>Umbraco</category><category>Contour</category><description><![CDATA[ 
<p>Recently I was tasked with doing some Crazy Assed Shit™ with
Umbraco Contour. Note, this applies to old school Contour, the
techniques outlined here won't work on Forms, as some of the
required information is no longer in the database.</p>

<p>The client wanted to be able to export ALL of the forms on the
site, merged into one giant CSV file. With the columns across the
top of the spreadsheet. So effectively the output would be
something like:</p>

<p>Form Name, Record ID, Date Submitted, Field 1, Field 2, Field 3,
etc</p>

<p>Now, the requirement also stated that fields with the same
caption should be merged together into one column.</p>

<p>Looking at the APIs, there are two options:</p>

<ul>
<li>Use the library methods. There were three issues with this, one
it returns XML, and two the caption names that are stored in the
XML are only correct at the time of saving. If the field name has
been updated, the caption will be wrong, so you'll end up with
extra columns that shouldn't be there, finally, you have to get the
results one form at a time, so there would be some horrific logic
around grouping the fields.</li>

<li>Use the database driven API methods. This solves the stale
caption names issue, but again you have to grab the results one
form at a time, and the API is REALLY database intensive, which
makes it pretty slow for deaing with large numbers of records at
once.</li>
</ul>

<p>So after scratching my head for a bit to think of a better way
of doing it, preferebly in a single database call, I decided that
you could do the whole thing, in one go (ish), using a <a
href="https://blogs.msdn.microsoft.com/spike/2009/03/03/pivot-tables-in-sql-server-a-simple-sample/">
pivot query</a>. This is a special kind of query that allows you to
turn rows into columns, they're commonly used in Excel and SQL
Server reporting.</p>

<p>The only issue that would cause any problems is that you can't
directly do a pivot query without knowing the column names. They
HAVE to be hard coded into the query. The only way round that is to
use dynamic SQL.</p>

<p>First things first, we're going to create a view that contains
all of the raw data that we need to perform our magic. This will
make the pivot query MUCH easier to read, and it also provides
around a 20% perfomance boost to the final query, as we need to use
the data twice (once to get all the captions, and once to actually
do the pivot query). Create a new view, and use the following
query:</p>

<pre>
SELECT dbo.UFRecordFields.Record, dbo.UFFields.Caption, dbo.UFRecords.Created AS [Date Submitted], dbo.UFRecords.IP, dbo.UFForms.Name AS [Contour Form Name], dbo.UFForms.Id, 
    CASE WHEN UFFields.PreValueProvider != '00000000-0000-0000-0000-000000000000' THEN STUFF
    ((SELECT     ',' + a.Value
        FROM UFPrevalues a LEFT JOIN
        UFRecordDataString b ON CAST(a.Id AS Nvarchar(255)) = b.Value
        WHERE a.Field = UFFields.Id AND b.[Key] = UFRecordFields.[Key] FOR XML PATH('')), 1, 1, '') ELSE COALESCE (CAST(UFRecordDataBit.[Value] AS Nvarchar(255)), 
        CAST(UFRecordDataDateTime.[Value] AS Nvarchar(255)), CAST(UFRecordDataInteger.[Value] AS NVarchar(255)), CAST(UFRecordDataLongString.[Value] AS nvarchar(MAX)), 
        UFRecordDataString.[Value]) END AS FieldValues
FROM dbo.UFRecordFields LEFT OUTER JOIN
    dbo.UFRecordDataBit ON dbo.UFRecordFields.[Key] = dbo.UFRecordDataBit.[Key] LEFT OUTER JOIN
    dbo.UFRecordDataDateTime ON dbo.UFRecordFields.[Key] = dbo.UFRecordDataDateTime.[Key] LEFT OUTER JOIN
    dbo.UFRecordDataInteger ON dbo.UFRecordFields.[Key] = dbo.UFRecordDataInteger.[Key] LEFT OUTER JOIN
    dbo.UFRecordDataLongString ON dbo.UFRecordFields.[Key] = dbo.UFRecordDataLongString.[Key] LEFT OUTER JOIN
    dbo.UFRecordDataString ON dbo.UFRecordFields.[Key] = dbo.UFRecordDataString.[Key] LEFT OUTER JOIN
    dbo.UFFields ON dbo.UFRecordFields.Field = dbo.UFFields.Id LEFT OUTER JOIN
    dbo.UFRecords ON dbo.UFRecords.Id = dbo.UFRecordFields.Record LEFT OUTER JOIN
    dbo.UFForms ON dbo.UFRecords.Form = dbo.UFForms.Id
</pre>

<p>You might get an error about the query, but it should still save
(the error is because one of the functions can't be represented in
the diagram pane if you have it open). Save the view as
"vwContourFieldValues". The resulting view contains ALL of the
submitted field values for every submitted record in the database.
It also concatenates prevalue fields that allow multiple selections
into a single comma separated string.</p>

<p>Now that the view is in place, we can write the SQL to pull out
the pivot table. Basically, we will have to do two things. Firstly,
pull out all of the column names to use in the query, and secondly
build some dynamic SQL to use those column names in the pivot
query.</p>

<p>Here's the code:</p>

<pre>
DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
 
--Get distinct values of the PIVOT Column (Contour Field Captions) 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
    + QUOTENAME(Caption)
    FROM (
        SELECT DISTINCT Caption
        FROM vwContourFieldValues
    ) AS Courses ORDER BY [Caption]

    SET @DynamicPivotQuery = 
        N'SELECT [Contour Form Name], Record, [Date Submitted], IP, 
        ' + @ColumnName + '
            FROM vwContourFieldValues

            PIVOT(MAX(FieldValues) 
            FOR Caption IN (' + @ColumnName + ')) AS PVTTable
            ORDER BY [Contour Form Name] ASC, [Date Submitted] DESC'

            --Execute the Dynamic Pivot Query
            EXEC sp_executesql @DynamicPivotQuery
</pre>

<p>Once you have the query written, you can run it, and it will
list all of the records in the database, with all of the columns,
and all of the records with the same caption will be kept in a
single column. You can then output the results to CSV, so the
client can open it in Excel and do any crazy data mining or
reporting that they desire.</p>

<p>This is a pretty simple example, but you could easily modify the
query to filter the forms by date range, or allow them to choose
the forms that they want to bulk export.</p>

<p>I've tested this query on a site with around 70 forms, and over
150,000 records, and it took just over two minutes to run. Given
the resulting CSV file has something like 200 dynamic columns,
that's not too bad. If you run it on a site where the forms share
more fields, it's MUCH faster. You could probably make this even
faster by using temporary tables, indexed views, or other
performance optiomisations.</p>

<p>As I mentioned at the beginning of this article, the code here
won't work on Forms, as the Forms themselves are no longer stored
in the database. You'd have to do some crazy voodoo involving
getting all the forms, and creating a temporary lookup table with
all the GUID/Caption pairs for every form on the site. I'm not 100%
sure on how you'd get the prevalues back either, as they also don't
appear to be in the database any more.</p>

<p>I may try and figure it out though and post an example of how to
do this in Forms if I work it out.</p>
]]></description></item><item><title>Staying Positive</title><link>http://w.attackmonkey.co.uk/blog/2016/01/staying-positive</link><pubDate>Thu, 21 Jan 2016 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2016/01/staying-positive</guid><category>Life</category><description><![CDATA[ 
<p>In a departure from the usual techy stuff, I'm going to post
about something quite close to my heart. Staying positive. I'm
quite an upbeat and positive person, but that wasn't always the
case. It took borderline work burnout and serious illness to get me
to sort my shit out.</p>

<p>So, a bit of background. Back in early 2005, I'd pretty much
burnt myself out working myself to the bone as the lead programmer
at an ambitious startup, for an extremely demanding boss. I was so
miserable, that I seriously considered sacking off web development
entirely, and retraining to do something completely different (top
of my list was touring road crew, but the missus vetoed that
one).</p>

<p>Several of my self employed friends (none of whom work in web)
inspired me to try my hand at freelance, it was something that I'd
always fancied, but I didn't think I was good enough. After a
couple of months, I'd fallen back in live with web dev, and I
realised it was the toxic working environment that burnt me out,
not the industry. All was good, until I got ill. I had a wracking
cough that just wouldn't quit, and I had no energy. For almost a
year, I was a complete medical mystery, until in 2006, after some
surgical exploration, I was diagnosed with Stage IVB Hodgkins
Lymphoma (an immune system Cancer). As bad new goes, that's up
there with "yup, your house is built on a spooky burial
ground".</p>

<p>It was at this point, I started my journey to being more
positive. 12 months of being a medical mystery is RUBBISH. Had I
been any good at music, I'd have written some killer blues songs.
As I led in bed with the Oncologist explaining my diagnosis, I was
actually happy, I think he thought I'd lost the plot. But actually
finding out that my illness had a name, and could be fought was
enormously liberating. From that point on, I focused on the
positives. Throughout the six months of chemo I had, I remained
positive and upbeat, much more so than I would have imagined
possible. Having a health scare like that really made me focus on
what was actually important. I've learnt a lot from the experience,
and some of the inspiring people that I met along the way.</p>

<p>Right, enough background! Staying positive is all about
realising what's important, what you do and don't have control
over, and looking for the opportunity when things go bad.</p>

<h2>Realising What's Important</h2>

<p>We live in extremely information rich times. Most of us carry
devices around in our pockets that are more powerful than the first
7/8 computers I owned, COMBINED. The entirety of the internet is at
our fingertips, and it's easy to get overloaded with information,
making it hard to focus on what really matters. It works for work
as well as personal stuff. Learn to filter out the stuff that
doesn't matter and focus on the things that do. Stop spending all
your time reading about other people's lives, and concentrate on
your own.</p>

<p>With work it's easy to get caught up in the bigger picture and
get sidetracked. Break your project down into smaller parts so you
can concentrate on the individual pieces and it gets simpler. Also,
learn to filter the important stuff from a client brief. It's
sometimes easy to get really caught up on a feature that's actually
pretty inconsequential.</p>

<h2>Control</h2>

<p>People have a tendency to stress about things they have
absolutely no control over, and worry about some nebulous future
event. I find the trick is to focus on what you're doing <span
class="Apple-style-span">now</span>. It's also important to realise
that there are some things you have very little control over and
just accept it and take charge of the things that you can.</p>

<p>One example of this would be me worrying about relapse. I know
people who have literally lost their mind worrying about getting
ill again after recovering from Cancer. They constantly fret about
every little thing they do, terrified that they're making it more
likely they'll get sick again. I look at it this way, as long as I
avoid anything too stupid (smoking, hanging out in chemical plants
without a mask, swimming in Benzene), I'm probably good. I'd rather
enjoy the extra time I have, than lock myself up an be paralyzed
with fear about being ill again.</p>

<p>You can plan for some eventualities, but accept that sometimes
things happen for no real reason!</p>

<h2>Look for the Opportunity</h2>

<p>One of the things I learnt early on was to look for the
positives in the bad. I got diagnosed with Cancer, I could easily
have collapsed in a weeping heap and spent the next 6 months
rocking backwards and forwards. I admit, I cried a bit, but I also
saw my diagnosis as a positive step on the way to recovery.</p>

<p>Been laid off? Take it as a sign that it's time to move on.
Upskill and move on to better things, don't waste your energy being
bitter and focusing on the past. Project didn't work out as well as
hoped? Look for the bits that DID work and take those away as
something you can use next time.</p>

<h2>Perspective</h2>

<p>Finally, one thing that really helps is to have some
perspective. For the majority of us, what we do isn't life and
death. If a menu doesn't line up perfectly in IE8, no one is going
to die (except maybe the IE devs, as they get hunted down by
disgruntled web devs, one by one). Sure, you should fix it, but
it's not worth getting super stressed over.</p>

<p>Make sure that you take a step back every now and again and have
some you time. As an industry, web dev is close to game dev for the
amount of crazy overtime that's expected, often down to poor
planning or lack of resources. Take a step back every now and again
and do something you want to do for you. Since I hit remission,
I've tried to do at least one thing a year that I've always wanted
to do, and man does it recharge my batteries. I learnt to snowboard
at 30 (and I love it), I taught myself SLR photography and I even
climbed Mount Fuji in Japan (something I've wanted to do since
forever). When I come back from a week on the slopes, my creative
batteries are fully recharged, and I feel amazing. It doesn't even
have to be that exciting, go for regular walks in the countryside,
take up cycling, it all helps :)</p>

<p>I realise that a lot of this is probably obvious to most people,
but it's surprising how many people I come across in &nbsp;web dev
who get burnt out, often for the same reasons each time. I hope
this helps someone, or at least gives them some food for
thought!</p>
]]></description></item><item><title>Running Umbraco Over Reverse Proxy</title><link>http://w.attackmonkey.co.uk/blog/2016/01/running-umbraco-over-reverse-proxy</link><pubDate>Mon, 18 Jan 2016 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2016/01/running-umbraco-over-reverse-proxy</guid><category>Umbraco</category><description><![CDATA[ 
<p>Recently I had to get Umbraco working over a reverse proxy, and
I thought I'd share how I did it, as there's actually a pretty
painless way to get it working!</p>

<p>First up, what is a reverse proxy? A reverse proxy is like a
virtual folder, except that the contents of the virtual folder
resides on another server. Why would you need to do this? Well,
usually, if you need to run Umbraco in a virtual folder in a .Net
site, you could use a normal virtual folder. However, security
considerations might prevent installing the Umbraco site on the
same box as the main site, or the main site might be written in PHP
and hosted on a *nix box for example.</p>

<p>Out of the box, platforms like Apache support reverse proxying
natively through Mod Rewrite. In IIS, you have to use something
called Application Request Routing (ARR), combined with URL
Rewritiung to make it work. These are optional add ons for IIS. If
you're interested, <a
href="https://httpd.apache.org/docs/2.4/rewrite/proxy.html">here's
some information on how to do it with Mod Rewrite</a>, and <a
href="http://www.iis.net/learn/extensions/url-rewrite-module/reverse-proxy-with-url-rewrite-v2-and-application-request-routing">
here's how to set up ARR in IIS</a>.</p>

<p>One of the things that you often have to do with reverse proxied
stuff is to rewrite the content as it's sent back to correct image
paths and links etc. Normally you'd do this with outbound rewrite
rules. It's not too painful for simple sites, but for something
like Umbraco, which is a very complex system, it can be quite
difficult to do without accidentally breaking stuff (you also need
to heavily rewrite the contents of JS and CSS files, which can be
quite slow, and each extra plugin increases the work usually).</p>

<p>So I figured out a much easier way of getting it all to work.
Lets say you have www.mysite.com and you want to reverse proxy the
URL www.mysite.com/blog/ to blog.mysite.com, which is an Umbraco
site on another server. All you need to do is set up the Umbraco
site on blog.mysite.com to run in a virtual folder that matches the
name that you want to use for the reverse proxy, e.g.
blog.mysite.com/blog/. As Virtual folder setups work pretty well
out of the box, this means that you only need an outbound rule for
the blog.mysite.com domain, everything else should just work out of
the box, as it already thinks it's in the /blog/ folder!</p>
]]></description></item><item><title>Making Your Packages Work in a Virtual Directory</title><link>http://w.attackmonkey.co.uk/blog/2016/01/making-your-packages-work-in-a-virtual-directory</link><pubDate>Thu, 14 Jan 2016 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2016/01/making-your-packages-work-in-a-virtual-directory</guid><category>Umbraco</category><category>Package Dev</category><description><![CDATA[ 
<p>Just before Christmas I worked on a couple of projects where we
needed to have Umbraco running in a virtual directory. Out of the
box, Umbraco itself works very well in a virtual directory these
days. The main issue that I ran into was packages that didn't work
correctly when Umbrco was in a virtual folder.</p>

<p>From going through all the affected packages in the projects,
I've compiled a list of things that you can do in your packages to
help ensure that it will run correctly when your site is running in
a virtual folder. So without further ado, here are the top five
things to be aware of:</p>

<h2>1. Paths in your package manifest</h2>

<p>In your package manifest, ensure that your paths start with a ~.
E.g. instead of referencing a script as
"/app_plugins/my_plugin/script.js" use
"~/app_plugins/my_plugin/script.js". Umbraco will then work out the
correct path when it loads in all of the manifests.</p>

<h2>2. Paths in your CSS</h2>

<p>You often see people make their image paths in the CSS relative
to the root of the site. This won't work in a virtual folder, so
make sure all of your image paths are relative to the location of
your CSS file. That way the paths will work, regardless of where
the Umbraco site lives.</p>

<h2>3. Paths in your JS</h2>

<p>Again, it's common to see links to things in the JS file be
rleative to the root, e.g. "/umbraco/surface/mysurface/get". Your
JS will be executing from the /umbraco/ path, so code your paths
accordingly. E.g. in the previous example, you could use
"../umbraco/surface/mysurface/get".</p>

<h2>4. Paths in your templates</h2>

<p>As with paths in your JS, code the paths to images and other
resources in your templates/views as if they're in the /umbraco/
folder. So instead of "/app_plugins/myplugin/images/", use
"../app_plugins/myplugin/images/".</p>

<h2>5. Paths inside your code</h2>

<p>If you're mapping paths inside your code for things like
Controllers and other compiled resources, don't forget the ~ at the
start of the URL! this will then map the path to include the
virtual folder as well.</p>

<p>And that's about it. If you follow those five guidelines, your
package should work on an Umbrco site that's running in a virtual
folder!</p>

<p>&nbsp;</p>
]]></description></item><item><title>Upgrading to 7.3: Part 3 - Switching to Razor</title><link>http://w.attackmonkey.co.uk/blog/2015/12/upgrading-to-73-part-3-switching-to-razor</link><pubDate>Wed, 09 Dec 2015 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2015/12/upgrading-to-73-part-3-switching-to-razor</guid><category>Umbraco</category><description><![CDATA[ 
<p>In <a href="/blog/2015/10/upgrading-to-73-part-2-the-upgrade"
title="Upgrading to 7.3: Part 2 - The Upgrade">part 2</a> of this
series, I talked about upgrading the site to 7.3. At this point we
have a nice shiny site, but all of the additional functionality is
currently in XSLT. The client this is for prefers their sites in
Razor these days, so as an added thing to do, I now have to port
the site over to Razor.</p>

<p>In the back office, all of the old templates were still listed,
but as I hadn't copied the master pages across from the old site
(as we're switching to MVC), they'rer all empty. It was fairly
trivial to then just re-save each of those (which created the
physical view pages in my project), and then adding a Layout file
with the outer page. I copied all the HTML from the old templates,
with a few minor changes. I was able to remove a couple of
templates, and combine a couple of others!</p>

<p>The old site is nearly 5 years old, so pretty much everything is
XSLT/Macros. Razor allows you to move everything into partials and
controllers, so looking at the code, it's possible to do away with
all of the Macros bar the one that allows you to embed a special
corporate video into the Richtext editor.</p>

<p>I went through the site and converted all the old macro based
functionality into Razor. Some of it could just be inlined in the
templates, as it was template specific, the rest was turned into
plain old partials.</p>

<p>A few parts of the code made sense to be surface controllers
(the search, and a user profile page, as well as the login stuff).
THese were pretty easy to port over.</p>

<p>With the XSLT, al ot of the code could just be ported over and
rewritten. Quite a few macros were no longer needed, or could be
combined. By the time I was done, I only had a handful of Partials,
compare to the 20+ Macros on the old version of the site.</p>

<p>Once I'd tested everything to make sure it still worked compared
to the old version of the site, it was time to tidy up. All of the
old Macros and XSLT files were deleted from Umbraco.</p>

<p>At this point, we have a fully upgraded site, now running on the
latest version of Umbraco! As an added bonus, between starting this
and finishing, Umbraco crept up to 7.3.4, but a quick
"Update-Package UmbracoCms" in Nuget in VS sorted that out very
quickly and efficiently!</p>

<p>The site and database can now be deployed, replacing the old
site, and we're good to go!</p>

<p>All in all, the process has been significantly less hassle than
I expected, and I'm really imprressed with how straightforward it
all was. I'd be much less hesitant to recommend upgrading a fairly
straighforward Umbraco site than I might have been previously. I'd
love to hear if anyone else has tried this, and whether your
experiences were as painless as mine!</p>
]]></description></item><item><title>Upgrading to 7.3: Part 2 - The Upgrade</title><link>http://w.attackmonkey.co.uk/blog/2015/10/upgrading-to-73-part-2-the-upgrade</link><pubDate>Tue, 27 Oct 2015 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2015/10/upgrading-to-73-part-2-the-upgrade</guid><category>Umbraco</category><category>Web Dev</category><description><![CDATA[ 
<p>In <a href="/blog/2015/10/upgrading-to-73-part-1-preparation"
title="Upgrading to 7.3: Part 1 - Preparation">part 1 of this
series</a>, I talked about preparing for the site upgrade. In this
part I'm going to talk about how I did the actual Upgrade.</p>

<p>Before we start, I pulled down the site files and a backup of
the Database from the live site. I set both up to run on my local
machine, and did some house keeping first. On this particualr site,
we were removing a section and some of the DocTypes, so I did that
on the old copy first, to make things easier later on. I then took
another backup of the database once I was done (in case anything
wet wrong and I needed to start again).</p>

<p>Next, I set up a new VS.Net project, and installed Umbraco 7.3
using NuGet, along with some essential stuff, like the core
property value converters (also installed from NuGet). Once those
were installed, I opened the web.config file for the newly
installed copy of Umbraco and set the connection string to point to
my old database. I decided against merging in my config values etc
at this point, as I wanted there to be as few errors as
possible.</p>

<p>With baited breath, I ran the website from VS.Net. I got the
Umbraco installer screen, and it flagged that I was running an
upgrade rather than a fresh install, hapy days! I clicked the next
button, aaaaand got a big fat SQL error. The error message that I
got was a bit misleading, as it lists all of the tables etc that
aren't in the core install, and I though that was the problem,
however, after much digging through the log files, it turned out to
be a SQL server permissions issue on the database. I sorted that
out and ran the site again. This time, after a couple of minutes, I
saw the success screen, and it redirected me to the back
office.</p>

<p>I had a click around and everything seemed OK. The two DataTypes
that weren't v7 compatible were showing as labels, but everything
was working. At this point, I backed everything up again, and then
merged in my config files, master templates, scripts, CSS and
images etc. If you're updating from a Web Forms site, don't forget
to change the default rendering engine to Web Forms from MVC in the
umbracoSettings site.</p>

<p>At this point I ran into a couple of issues. the first was that
older versions of Umbraco let you have a - in the alias of
DocTypes, and the newer versions don't. This particular site had a
couple of DocTypes that had - in them, so I had to re-save the
DocTypes and restart the App Pool to get rid of the error that was
being generated. Next was that the EXSLT extensions were removed in
7, so some of my XSLT broke. Not to worry though, <a
href="https://our.umbraco.org/projects/website-utilities/exslt-redux/">
you can get a package for that</a> from the mighty Lee Kelleher. In
this particular instance, I don't care about fixing the XSLT, as
I'm going to replace all the XSLT with Razor.</p>

<p>The only other issue that I had was that there appears to be a
bug in one of the database Migrations that scrambles the order of
some of your DocType properties. But that was easily fixed by
re-ordering the properties on the affected DocTypes and re-saving
them.</p>

<p>Finally, in the Data Types section, I swapped the MNTP pickers
from uComponents (which were now labels) ot the new built in one,
and as they were set to store CSV, that just worked. The other
DataType (Embedded Content) was removed and replaced with Nested
Content. This required a bit of set up, and re-entering the data,
but it only took about an hour.</p>

<p>At this point, I have a (mostly) functional site, upgraded from
4.7.2 to 7.3. It was much less hassle than I was expecting, and it
seems to have worked very well for me. Your mileage may vary, I
suspect that for a much more complex site, you'll have a lot more
issues, especially if you are using quite a few custom
DataTypes.</p>

<p>In part 3, I'm going to cover switching the site over from XSLT
and Master Pages to Views, and tidying everything up, ready to go
up to the live site again.</p>
]]></description></item><item><title>Upgrading to 7.3: Part 1 - Preparation</title><link>http://w.attackmonkey.co.uk/blog/2015/10/upgrading-to-73-part-1-preparation</link><pubDate>Wed, 07 Oct 2015 00:00:00 GMT</pubDate><guid>http://w.attackmonkey.co.uk/blog/2015/10/upgrading-to-73-part-1-preparation</guid><category>Umbraco</category><category>Web Dev</category><description><![CDATA[ 
<p>In my <a href="/blog/2015/10/upgrading-to-73"
title="Upgrading to 7.3">previous article</a>, I talked about how
impressed I was with the Umbraco upgrade process in 7.3. I'm now
much further through the full upgrade, so I'm going to blog about
it, in the hope that it helps others considering doing the
same.</p>

<p>In this part, I'm going to talk about the planning for the
upgrade.</p>

<p>I have a client who has an old 4.7.1 site, and they'd like to
use some functionality that's only present in v7. Previously I was
looking at a full rebuild and re-importing content, but due to the
volume of content (10,000+ pages), I wasn't too keen on this, as
copying content between installs is notoriously fiddly.</p>

<p>So, when Neils announced that the new version would upgrade the
database and it actually worked, I decided to give it a go, as it
could potentially save me a LOT of time.</p>

<p>So, the existing site:</p>

<ul>
<li>Runs on 4.7.1</li>

<li>Has 10,000+ pages</li>

<li>Uses XSLT Macros and MasterPages</li>

<li>Uses a handful of packages, mostly event based stuff
(CustomMenus, AutoFolders etc)</li>

<li>Uses two custom DataTypes (Embedded Content and uComponents
MultiNode tree picker)</li>
</ul>

<p>First up, what do we want to achieve with the upgrade?</p>

<ul>
<li>Upgrade to 7.3</li>

<li>Swap out all of the XSLT/MasterPages for Views/Razor</li>

<li>Remove some unused sections of the site</li>
</ul>

<p>So, what issues are you likely to hit? Firstly, not all of the
packages may have been updated for v7. In this case, we were using
the MultiNode tree picker from uComponents, which isn't available
in v7. This one is pretty straightforward. Make sure the DataType
is set to store as CSV (if it isn't already), and republish all the
pages with the DataType on. That way we can just swap DataType to
the built in v7 Multiple Content Picker after the upgrade, and we
won't lose any data.</p>

<p>Embedded content can be replaced with either Archetype, or
Nested Content. HOWEVER, the data cannot be just swapped over. When
you upgrade Umbraco to v7, any DataTypes that are non-core are
turned into labels, and the values preserved, and the DataTypes are
set to a non-editable control. You could write some custom code to
reformat the data for your new DataType using the API once you've
done the upgrade, but in this case, the DataType was only being
used to display some widget boxes on the home page, and nowhere
else, so re-adding the 8 boxes after we've upgraded is probably
quicker than messing aroud trying to reformat the data.</p>

<p>So, now that we've covered the basic issues we're likely to hit,
what next? I decided to take the following approach to the
upgrade:</p>

<ul>
<li>Take a copy of the database</li>

<li>Remove all the stuff that we don't need on the old version of
the CMS</li>

<li>Backup the database (in case it goes horribly wrong)</li>

<li>Create a new Visual Studio project and install Umbraco 7.3 and
packages through NuGet</li>

<li>Run the Upgrade</li>

<li>Merge in the stuff I needed and then start changing view/macros
etc</li>

<li>Test thoroughly</li>

<li>Deploy</li>

<li>Retire to somewhere hot and drink cocktails with tiny hats</li>
</ul>

<p>So, having done a bit of prep work, we're ready to rock. Watch
out for part 2, where I'll talk about the initial upgrade
process.</p>
]]></description></item></channel></rss>