<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://blog.aabech.no/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Lars-Erik's blog</title>
    <link>https://blog.aabech.no/</link>
    <description>Ramblings about Umbraco, .net and JavaScript development. With a sprinkle of other stuff.</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <item>
      <guid isPermaLink="false">1216</guid>
      <link>https://blog.aabech.no/archive/more-efficient-integration-tests-with-umbraco/</link>
      <category>umbraco</category>
      <category>unit testing</category>
      <title>More efficient integration tests with Umbraco</title>
      <description>&lt;h2&gt;TLDR;&lt;/h2&gt;
&lt;p&gt;I made &lt;a href="https://www.nuget.org/packages/Umbraco.Community.Integration.Tests.Extensions"&gt;a package&lt;/a&gt; that removes the &amp;quot;database and Umbraco instance&amp;quot; per fixture constraint from &lt;a href="https://www.nuget.org/packages/Umbraco.Cms.Tests.Integration/"&gt;Umbraco's Integration Test library&lt;/a&gt;. It also enables reuse of seeded database snapshots to avoid executing the same setup / seeding over an over per fixture or test.&lt;/p&gt;
&lt;h2&gt;An itch&lt;/h2&gt;
&lt;p&gt;I've spent way too long waiting for similar setup code for my integration tests the last couple of years. The modern .NET version of &lt;a href="https://www.nuget.org/packages/Umbraco.Cms.Tests.Integration/"&gt;Umbraco's integration test library&lt;/a&gt; is super nice, and real effective with SQLite. But it's got a few constraints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All things Umbraco is instantiated and spun up per test, granted a configurable amount.&lt;/li&gt;
&lt;li&gt;Databases have to be &amp;quot;installed&amp;quot; and seeded for each TestFixture at the least.&lt;/li&gt;
&lt;li&gt;All test fixtures need to inherit from Umbraco's base classes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So we spend a long time waiting for suff, even if it's only the little green box we care about:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1072/initial-umbraco-test-sequence.png" alt="Diagram of the hierarchy of a basic Umbraco integration test" /&gt;&lt;/p&gt;
&lt;p&gt;We're also stuck either juggling a singleton of some sorts and/or stuffing a lot of &amp;quot;units&amp;quot; into the same fixture.&lt;br /&gt;
Any notion of intermediate base classes quickly become a sore spot.&lt;/p&gt;
&lt;h2&gt;An idea&lt;/h2&gt;
&lt;p&gt;I had recently discovered, likely for the n-th time in my life, that NUnit supports namespace scoped setup fixtures. Those live as long as all that other tests in that namespace and deeper. They bring an opportunity to share initial state across several fixtures. I often find it nice to have several fixtures for the same systems under tests because it makes sense to group by use-case rather than tech.&lt;/p&gt;
&lt;p&gt;So I set out to see if I could hack together something that made Umbraco's base tests possible to use as setup fixtures rather than &amp;quot;base&amp;quot; fixtures. As things would have it it was early october, and the &lt;a href="https://candidcontributions.com/"&gt;CanCon gang hosted a virtual hackathon&lt;/a&gt; on a friday. I took the day &amp;quot;off&amp;quot; regular work and gave it a go.&lt;/p&gt;
&lt;h2&gt;Dark magic&lt;/h2&gt;
&lt;p&gt;In the end I've used all the dirty tricks you can imagine in today's .NET landscape. You'll find &lt;a href="https://www.nuget.org/packages/Lib.Harmony"&gt;Lib.Harmony&lt;/a&gt; for messing with Umbraco's tests' IL (Intermediate Language), and there's &lt;a href="https://www.nuget.org/packages/Castle.Core"&gt;Castle DynamicProxy&lt;/a&gt; doing a lot of fooling around with the NUnit test hierarchy. The Harmony bit can likely be removed by making a few slight changes to Umbraco's test core, but I wanted to get this working satisfactory before suggesting such changes.&lt;/p&gt;
&lt;p&gt;The bottom line is that those two tools let us run code before, after or even instead of inherited code. And that in turn enables all the following features.&lt;/p&gt;
&lt;h2&gt;A new way of composing tests&lt;/h2&gt;
&lt;p&gt;With the package I've cooked together we can leave the dark world of peach and purple above in favor of a way greener scenery like such:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1071/improved-umbraco-test-sequence.png" alt="Diagram of the hierarchy of an improved Umbraco integration test suite" /&gt;&lt;/p&gt;
&lt;p&gt;So without further ado, let's dig into how you can get there too.&lt;/p&gt;
&lt;h2&gt;Umbraco's attributes&lt;/h2&gt;
&lt;p&gt;We rely on Umbraco's &lt;code&gt;Tests:Database&lt;/code&gt; config and the &lt;code&gt;[UmbracoTest]&lt;/code&gt; attribute to provide databases (or not). The &lt;code&gt;Database&lt;/code&gt; option works almost as expected, but the four non-none options end up doing the same: they prepare &lt;em&gt;one&lt;/em&gt; db for the lifetime of the setup fixture.&lt;/p&gt;
&lt;h2&gt;[ExtendableSetUpFixture]&lt;/h2&gt;
&lt;p&gt;The first attribute you have to know is &lt;code&gt;[ExtendableSetUpFixture]&lt;/code&gt;. It's sole purpose is to enable the rest of them. Since it's inherited from &lt;code&gt;[SetUpFixture]&lt;/code&gt;, it tells NUnit we won't add any &lt;code&gt;[SetUp]&lt;/code&gt;, &lt;code&gt;[TearDown]&lt;/code&gt; or &lt;code&gt;[Test]&lt;/code&gt; methods in the marked class. But this is the attribute we'll add to any &lt;code&gt;UmbracoIntegrationTest&lt;/code&gt; or &lt;code&gt;UmbracoTestServerTestBase&lt;/code&gt;, and those have a bunch of each. That's why we have...&lt;/p&gt;
&lt;h2&gt;[MakeOneTimeLifecycle]&lt;/h2&gt;
&lt;p&gt;The first attribute in the package that &lt;em&gt;does something&lt;/em&gt;. &lt;code&gt;[MakeOneTimeLifecycle]&lt;/code&gt; lets you mark methods in otherwise not accessible base classes like &lt;code&gt;UmbracoTestBase&lt;/code&gt; to become &lt;code&gt;[OneTimeSetUp]&lt;/code&gt; methods rather than &lt;code&gt;[SetUp]&lt;/code&gt; methods, and &lt;code&gt;[TearDown]&lt;/code&gt; methods becomes &lt;code&gt;[OneTimeTearDown]&lt;/code&gt;.&lt;br /&gt;
Here's an example of what we'd feed it for an &lt;code&gt;UmbracoIntegrationTest&lt;/code&gt; inheritor:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[UmbracoTest(Database=SchemaPerFixture, Boot=true)]
[ExtendableSetUpFixture]
[MakeOneTimeLifecycle(
    setUpNames: [nameof(UmbracoIntegrationTest.Setup), nameof(UmbracoIntegrationTest.SetUp_Logging)],
    tearDownNames: [
        nameof(UmbracoIntegrationTest.TearDown), nameof(UmbracoIntegrationTest.TearDownAsync), 
        nameof(UmbracoIntegrationTest.FixtureTearDown), nameof(UmbracoIntegrationTest.TearDown_Logging)
    ]
)]
public class MyLongLivedUmbracoSetUp : UmbracoIntegrationTest
{
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I found it a bother to write that long attribute all the time, so there's a derived one called:&lt;/p&gt;
&lt;h2&gt;[OneTimeUmbracoSetUp]&lt;/h2&gt;
&lt;p&gt;It makes it slightly less messy by letting us write as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[UmbracoTest(Database=SchemaPerFixture, Boot=true)]
[ExtendableSetUpFixture]
[OneTimeUmbracoSetUp]
public class MyLongLivedUmbracoSetUp : UmbracoIntegrationTest
{
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note however that the current version doesn't come with a 100% compatible one for &lt;code&gt;UmbracoTestServerTestBase&lt;/code&gt; or &lt;code&gt;ManagementApiTest&amp;lt;&amp;gt;&lt;/code&gt;, but it's easy to make one yourself, and they're likely suddenly in the package.&lt;/p&gt;
&lt;p&gt;Now if you're into hacking around the environment and hidden, protected members lurking around in memory, we're quite alike. But when doing professional work that's often not what we're paid for. So even though the above code will start up a perfectly fine Umbraco instance with a SQLite database it doesn't do much good. We need to get at the &lt;code&gt;IServiceProvider&lt;/code&gt; somehow...&lt;/p&gt;
&lt;h2&gt;[InjectionProvider(string)] and [ServiceProvider]&lt;/h2&gt;
&lt;p&gt;There is a limit to how many attributes we'll stick on our setup fixtures, I promise. I complained about intermediate base classes earlier, but a few for attribute consolidation is cool enough. OK, these two are a basic re-usable one and a &amp;quot;defaulted&amp;quot; one. The &lt;code&gt;[InjectionProvider(string)]&lt;/code&gt; attribute stores a reference to a property on the setup fixture that exposes an &lt;code&gt;IServiceProvider&lt;/code&gt; instance. Umbraco's base classes exposea property called &lt;code&gt;Services&lt;/code&gt;, and &lt;code&gt;[ServiceProvider]&lt;/code&gt; is just a derived &lt;code&gt;[InjectionProvider(nameof(Services))]&lt;/code&gt;. To be specific, the service provider reference goes into the test context property bag as a factory method.&lt;br /&gt;
By adding one to our growing tower we're ready to meet our first actual &lt;em&gt;test fixture&lt;/em&gt; enjoying the power of:&lt;/p&gt;
&lt;h2&gt;[Inject(string)]&lt;/h2&gt;
&lt;p&gt;To enjoy the benefits of our stored service provider reference, we must expose an instance method on our &amp;quot;scoped&amp;quot; test fixture that accepts services. We could've used constructor injection, but that's already &amp;quot;in use&amp;quot; by NUnit &lt;code&gt;[TestFixture(args)]&lt;/code&gt; functionality. Once you start composing tests like this package allows, you can get &lt;em&gt;much more value&lt;/em&gt; from things like that. So a void method will have to do. A fresh &amp;quot;standalone&amp;quot; and &amp;quot;scoped&amp;quot; test fixture will look like this:&lt;/p&gt;
&lt;p&gt;using Same.Namespace.As.SetupFixture;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Inject(nameof(Inject))]
public class LookMaImFreeAsABird
{
    IDataTypeService dataTypeService = null!;

    public void Inject(IDataTypeService dataTypeService)
    {
        this.dataTypeService = dataTypeService;
    }

    [Test]
    public void FiddleWithDataTypeA()
    {
        // ...
    }

    [Test]
    public void CreateDataTypeB()
    {
        // ...
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice the beauty of &lt;em&gt;no forced ctors&lt;/em&gt;, &lt;em&gt;no base class&lt;/em&gt; and &lt;em&gt;no overrides&lt;/em&gt; in that class! Not to mention, you can have &lt;em&gt;several&lt;/em&gt; of those!&lt;/p&gt;
&lt;h2&gt;Interlude: Transactions&lt;/h2&gt;
&lt;p&gt;With the above setup the individual fixtures are free to create &lt;code&gt;ICoreScope&lt;/code&gt; instances from Umbraco and commit or dispose them as you wish. Just writing three sentences about it here doesn't really give the method justice. Suffice to say, just give it a go!&lt;br /&gt;
However it won't work when we use &lt;code&gt;UmbracoTestServerTestBase&lt;/code&gt;. There's no way to spread a core scope across threads, and there's not even a way to spread gool old .NET transaction scopes across. I guess you could go full old school and bring DCOM into the picture, but after a lot of failed attempts I finally stumbled over an obvious solution.&lt;/p&gt;
&lt;h2&gt;Snapshots&lt;/h2&gt;
&lt;p&gt;The final itch has taken me the longest, and even longer to stuff into an attribute rather than yet another base class. I must admit it took a desperate (but accurate) final plea with ChatGPT 5.1 to see the obvious solution just lying there to implement. All database engines, or at least the two I've implemented, support some sort of fast backup. &lt;code&gt;VACUUM INTO&lt;/code&gt; in SQLite and &lt;code&gt;CREATE/RESTORE DATABASE AS SNAPSHOT&lt;/code&gt; in SQL Server.&lt;/p&gt;
&lt;p&gt;I had two intermediate base classes for a few weeks, but this last weekend I ran over the goal line:&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;[ReusableDatabase(type, string)]&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;If you configure &lt;code&gt;Tests:Database:DatabaseType&lt;/code&gt; in your &lt;code&gt;appSettings.Tests.Local.json&lt;/code&gt; and set any of the non-none values in the &lt;code&gt;[UmbracoTest]&lt;/code&gt; database parameter, you can also add &lt;code&gt;[ReusableDatabase(typeof(SeedClass), nameof(SeedClass.Configure))]&lt;/code&gt; to get a new type of &lt;code&gt;ITestDatabase&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As of writing it requires a method to be implemented in the setup fixture, or on some supporting type. Its mission is to configure whether the database needs a fresh seed and how to seed the initial data for all the tests. Only if we say so, the database is installed and re-seeded. For all other scopes it's just restored from that initial snapshot.&lt;/p&gt;
&lt;p&gt;The seeding can be done in any way you please. My favorite is importing things using uSync, and that might just become another blog post. For simplicity let's say we're testing variants of property editors based on a datatype we want all tests to start with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[UmbracoTest(
    Database = UmbracoTestOptions.Database.NewSchemaPerTest,
    Boot = true,
    Logger = UmbracoTestOptions.Logger.Console
)]
[ExtendableSetUpFixture]
[OneTimeUmbracoSetUp]
[ServiceProvider]
[ReusableDatabase(nameof(ConfigureSeeding))]
public class ReusedDbAttributeSetUp : UmbracoIntegrationTest
{
    public static void ConfigureSeeding(ReusableTestDatabaseOptions options)
    {
        options.NeedsNewSeed = _ =&amp;gt; Task.FromResult(true);
        options.SeedData = async (services) =&amp;gt;
        {
            await TestContext.Progress.WriteLineAsync(&amp;quot;Creating datatype&amp;quot;);
            await services.GetRequiredService&amp;lt;IDataTypeService&amp;gt;().CreateAsync(
                new DataType
                (
                    new TextboxPropertyEditor
                    (
                        services.GetRequiredService&amp;lt;IDataValueEditorFactory&amp;gt;(),
                        services.GetRequiredService&amp;lt;IIOHelper&amp;gt;()
                    ),
                    services.GetRequiredService&amp;lt;IConfigurationEditorJsonSerializer&amp;gt;()
                )
                {
                    Name = &amp;quot;A seeded textbox&amp;quot;
                },
                Umbraco.Cms.Core.Constants.Security.SuperUserKey
            );
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The method has to be static void. If it's on the setup fixture you can omit the type from the attribute parameters.&lt;br /&gt;
Now all tests within this &amp;quot;scope&amp;quot; will have access to the seeded textbox. Such seeding code might quickly grow out of hand though, and that's why I prefer just importing the content schema from the web project in the same repo as my tests.&lt;/p&gt;
&lt;h2&gt;Which ones to choose&lt;/h2&gt;
&lt;p&gt;As you've hopefully realized by now you can introduce really slim intermediate base classes that set up the initial environment for a bunch of use-cases and scenarios. Leaving your actual test fixtures free to be composed just as you wish, and with all the features of NUnit at your disposal.&lt;/p&gt;
&lt;p&gt;I'm sure you can see that the last setup fixture example above makes for a nice base class to avoid repeating that tower of attributes. The &lt;a href="https://github.com/lars-erik/NUnitCompositionWithUmbraco/tree/main/UmbracoTestsComposition"&gt;repository has a few examples using a few or all of the attributes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The final trick I haven't disclosed above is how to do a &amp;quot;mid-fixture&amp;quot; rollback. The reusable database implementations have a &amp;quot;RestoreSnapshot&amp;quot; method, so in a &lt;code&gt;[TearDown]&lt;/code&gt; you can go:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;await serviceProvider.GetRequiredService&amp;lt;IReusableDatabase&amp;gt;().RestoreSnapshot();&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;That makes it so that whatever test comes next it's unaffected by the changes you've made. This is of course what happens during &lt;code&gt;[OneTimeSetUp]&lt;/code&gt; for any setup fixture using &lt;code&gt;[ReusableDatabase]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you want to try this out, I recommend going with &lt;code&gt;[ReusableDatabase]&lt;/code&gt; (and uSync) for everything that use more than 10ish artifacts like data and content types, not to mention content. Whenever you want to run changes through the Management API, or definitely if you want to test how all your sites' elements look in the Delivery API. It's a no-brainer when you go full integration with &lt;code&gt;UmbracoTestServerTestBase&lt;/code&gt; and more than one HTTP call.&lt;/p&gt;
&lt;p&gt;If all your tests have all they need in a fresh Umbraco database, but they all mutate it so you need cleanup, it'll be blazing fast if you can use &lt;code&gt;ICoreScope&lt;/code&gt; with autocommit off. As long as you don't need to test via HTTP endpoints, this is a better option than restoring the snapshot. Using a snapshot restore between fixtures however is still a nice option to keep around, so I still opt for &lt;code&gt;[ReusableDatabase]&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Want more?&lt;/h2&gt;
&lt;p&gt;I'm definitely going to be in &amp;quot;only fix what breaks for me&amp;quot; mode for a little while, as this was just gonna be a hacktoberfest weekend project. Turned out to take too much of my spare time for one and a half month instead.&lt;/p&gt;
&lt;p&gt;But I honestly believe this'll save some trees if applied well to CI pipelines running all day long.&lt;br /&gt;
And I've gone from 90 sec to 26 sec to execute a full test suite, a lot of which would run for &lt;em&gt;any&lt;/em&gt; filter.&lt;/p&gt;
&lt;p&gt;The package is currently listed as a beta (pre-release) on nuget and if it doesn't crash much I might just promote it to full visibility. It's a bit furry on the edges and has a bit of legacy to it (already), but if you stick the namespaces in the project file and leave the stray base classes alone I think you'll be good.&lt;/p&gt;
&lt;p&gt;All this is to say I'd love for conversation about what it solves and if it could do it better. I'd love even more to throw out a bit of the code because Umbraco suddenly fixed the core two issues. Let me hear from you if you try it out. Feel free to clone the code and mess about, although I reserve the right to refactor the mess myself that beautiful day I get to keep going with this. &lt;/p&gt;
&lt;p&gt;Looking forward to hearing how (and if) you like it. Hope you have a go!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/lars-erik/NUnitCompositionWithUmbraco"&gt;Source repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Umbraco.Community.Integration.Tests.Extensions"&gt;Nuget package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Umbraco.Cms.Tests.Integration/"&gt;Umbraco Cms Tests Integration package&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
      <pubDate>Tue, 25 Nov 2025 07:11:08 Z</pubDate>
      <a10:updated>2025-11-25T07:11:08Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1212</guid>
      <link>https://blog.aabech.no/archive/migrating-umbraco-forms-from-7-to-modern/</link>
      <category>umbraco</category>
      <title>Migrating Umbraco Forms from 7 to modern</title>
      <description>&lt;h3&gt;No migration, no cry&lt;/h3&gt;
&lt;p&gt;There is no uSync Migrations extension for moving forms from 7 to modern.
There isn't even a uSync Forms for V7.
However the serialization format for forms on disk didn't change (much?) from 7 to 8, so we can do a trick. (Thanks to Kevin for the tip)&lt;br /&gt;
We can do 7 to 8, then 8 to modern.&lt;br /&gt;
This applies to files. I have not tried with the forms in database method, but that should be possible to do with database migrations from 7 to 8.&lt;/p&gt;
&lt;h3&gt;7 to 8&lt;/h3&gt;
&lt;p&gt;Create an empty V8 site and install the following nuget packages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UmbracoForms&lt;/li&gt;
&lt;li&gt;uSync.Forms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To &amp;quot;migrate&amp;quot; your forms from 7 to 8 you just copy the files over. 😁&lt;br /&gt;
Your source files should be in &lt;code&gt;/App_Data/UmbracoForms/Data&lt;/code&gt;.&lt;br /&gt;
The target should be the same in a V8 site.&lt;/p&gt;
&lt;p&gt;When your files are copied you're ready to go into the backoffice.&lt;br /&gt;
Go to Settings \ uSync and click Export.&lt;/p&gt;
&lt;p&gt;You should now have uSync files for the forms under &lt;code&gt;/uSync/v8/Forms&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;8 to modern&lt;/h3&gt;
&lt;p&gt;Install uSync.Forms in your modern site.&lt;br /&gt;
Copy your uSync forms files from the V8 site into &lt;code&gt;/uSync/v9/Forms&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The uSync files will have prevalues in a &lt;code&gt;parsedPreValues&lt;/code&gt; field instead of &lt;code&gt;preValues&lt;/code&gt;.&lt;br /&gt;
uSync Forms import in modern does not like this.&lt;br /&gt;
So I made a small powershell script that does the necessary &amp;quot;migration&amp;quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;param(
    $path
)

$files = Get-ChildItem -Path $path -File

$files | % {
    $fileInfo = $_
    $doc = [xml](Get-Content $fileInfo.FullName)
    $pageNode = $doc.DocumentElement.SelectSingleNode(&amp;quot;Pages&amp;quot;)
    $origCData = $pageNode.FirstChild
    $pages = [array]($origCData.InnerText | ConvertFrom-Json)

    $results = $pages | % {
        $page = $_
        $page.fieldSets | % {
            $fieldSet = $_
            $fieldSet.containers | % {
                $container = $_
                $container.fields | % {
                    $field = $_
                    if ($field.parsedPrevalues.Length -gt 0) {
                        $field.preValues = $field.parsedPrevalues
                    }
                    $field.psobject.Properties.Remove(&amp;quot;parsedPreValues&amp;quot;)
                }
            }
        }
    }

    $cdata = $doc.CreateCDataSection((ConvertTo-Json -depth 99 -inputobject $pages))
    $replaced = $pageNode.ReplaceChild($cdata, $origCData)

    $doc.Save($fileInfo.FullName)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I called the script &lt;code&gt;fix-usync-forms.ps1&lt;/code&gt; and we can call it as such:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;./fix-usync-forms.ps1 [path-to-site]/uSync/v9/Forms&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;That's it!&lt;/p&gt;
&lt;p&gt;We can now go into the backoffice in our modern site.&lt;br /&gt;
Go to Settings \ uSync and click &amp;quot;Import&amp;quot; under Forms.&lt;/p&gt;
&lt;h3&gt;Success&lt;/h3&gt;
&lt;p&gt;Now all that's left is porting your potential code and views.&lt;/p&gt;
&lt;p&gt;Happy migrating! 🙃&lt;/p&gt;
</description>
      <pubDate>Wed, 28 Feb 2024 11:58:06 Z</pubDate>
      <a10:updated>2024-02-28T11:58:06Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1167</guid>
      <link>https://blog.aabech.no/archive/search-and-rss-for-our-umbraco-contentlist/</link>
      <category>umbraco</category>
      <title>Search and RSS for our Umbraco ContentList</title>
      <description>&lt;p&gt;The ContentList package have gotten a few new improvements over the last couple of weeks. Here's a rundown on what's new since the &lt;a href="//blog.aabech.no/archive/our-umbraco-community-contentlist-10-beta-released/"&gt;initial release post&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Theme control&lt;/h2&gt;
&lt;p&gt;Often a theme is customized to work well with just one or a few of the data sources. This is especially relevant with the changes described later in this post. Also, a theme might not use bootstrap, and as such not have the same rigid column count structure. Themes have therefore got a new config file you can choose to add to a theme folder: &lt;code&gt;list.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There are two options you can add to the list config file:&lt;/p&gt;
&lt;h3&gt;Compatible sources&lt;/h3&gt;
&lt;p&gt;To specify which data sources a theme goes well with, add a &lt;code&gt;compatibleSources&lt;/code&gt; array:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;compatibleSources&amp;quot;: [
        &amp;quot;ListablesByLuceneDataSource&amp;quot;,
        &amp;quot;ListableByNodeDataSource&amp;quot;,
        &amp;quot;ListableChildrenDataSource&amp;quot;
    ] 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Disable columns setting&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://github.com/lars-erik/Our.Umbraco.ContentList/tree/master/Our.Umbraco.ContentList.Web/Views/Partials/ContentList/FlexTheme"&gt;FlexTheme&lt;/a&gt; example view for instance does its own flexbox styling with varying amounts of columns. For this theme, the columns setting with &amp;quot;mobile&amp;quot;, &amp;quot;tablet&amp;quot; and &amp;quot;desktop&amp;quot; column counts make no sense. &lt;/p&gt;
&lt;p&gt;You can now disable the columns setting as such:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;disableColumnsSetting&amp;quot;: true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Search&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;ListableByLuceneDataSource&lt;/code&gt; have gotten a small brushup. The query setting have gotten its textbox expanded for better UX, and a new parameter called &amp;quot;Fulltext Querystring Parameter&amp;quot; have been added.&lt;/p&gt;
&lt;p&gt;The latter will combine the &amp;quot;query&amp;quot; with a search in all fields for all terms in a phrase extracted from the querystring parameter specified in the setting.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1036/contentlist-search-datasource-settings.png" alt="New parameters in the lucene data source" /&gt;&lt;/p&gt;
&lt;p&gt;There is a &lt;a href="https://github.com/lars-erik/Our.Umbraco.ContentList/tree/master/Our.Umbraco.ContentList.Web/Views/Partials/ContentList/SearchResult"&gt;new sample template for search&lt;/a&gt; where a search box is included in the theme list view. It posts and controls the configured querystring parameter. You can of course also just make a form in your layout posting to a given page with a content list. Or even &lt;a href="https://github.com/lars-erik/Our.Umbraco.ContentList/blob/38a65b9d7f43fec69340ffa31192bd759869fb86/Our.Umbraco.ContentList.Web/Config/grid.editors.config.js#L51"&gt;a grid editor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1037/contentlist-search-output.png" alt="Example output of search data source" /&gt;&lt;/p&gt;
&lt;h2&gt;Rss&lt;/h2&gt;
&lt;p&gt;I didn't want to bundle RSS with the core component, so there's a new package on the block called &lt;code&gt;Our.Umbraco.ContentList.Rss&lt;/code&gt;. By installing it, you get another data source aptly called &amp;quot;Rss&amp;quot;. It's also currently in beta, so remember to add the &lt;code&gt;-pre&lt;/code&gt; option when installing.&lt;/p&gt;
&lt;p&gt;It has one parameter for the URL to the RSS-feed, so I gather it doesn't need that much documentation. &lt;/p&gt;
&lt;p&gt;By specifying some theme settings as described earlier, it should be fairly simple to control both RSS and search themes combined with whatever other creative lists you come up with.&lt;/p&gt;
&lt;p&gt;Hope y'all enjoy and find this stuff useful! Don't be shy, come over to &lt;a href="https://github.com/lars-erik/Our.Umbraco.ContentList"&gt;the github repo&lt;/a&gt; and post issues if you want to discuss, ask questions or (please do) contribute.&lt;/p&gt;
</description>
      <pubDate>Wed, 06 May 2020 13:30:33 Z</pubDate>
      <a10:updated>2020-05-06T13:30:33Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1165</guid>
      <link>https://blog.aabech.no/archive/ourumbracowysiwyggrid-100-beta-released/</link>
      <category>umbraco</category>
      <title>Our.Umbraco.WysiwygGrid 1.0.0 beta released</title>
      <description>&lt;p&gt;A while ago I &lt;a href="/archive/the-state-of-wysiwyg-grid-editing-in-umbraco-a-prototype/"&gt;blogged about the state of WYSIWYG in the Umbraco grid editor&lt;/a&gt;. We're now about to add this script to a second and likely third Umbraco 8 site, so I had to generalize and package up the code.&lt;/p&gt;
&lt;p&gt;There's nothing much to hide or earn from here, so I decided to put it up on github and nuget instead of our internal scm and feeds.&lt;/p&gt;
&lt;p&gt;Hope to see some more community members fiddling with it, if nothing else that it inspires the block editor team to make the backoffice experience more similar to the frontend look and feel.&lt;/p&gt;
&lt;p&gt;A definite change from the previous blogpost is that we favor grid settings over inline styling. By slightly modifying the bootstrap view (we use v4 anyway), we can add multiple classes instead of attributes as is done the original views. As such we can have settings like these:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1035/wysiwyg-grid-settings.png" alt="Example grid settings dialog" /&gt;&lt;/p&gt;
&lt;p&gt;Those will generate extra classes named &lt;code&gt;padding-lots&lt;/code&gt; and &lt;code&gt;theme-inverse&lt;/code&gt;.&lt;br /&gt;
Those classes are added to rows or cells in both the backoffice and the front-end.&lt;br /&gt;
By doing some fancy sass include ninjaing, we can hopefully limit the amount of duplication, while still mimicing the front-end as much as possible in the backoffice.&lt;/p&gt;
&lt;p&gt;There are some samples in the github repo if you're unsure how to get started. The SQLCE database is included with a fairly common test username/password. 😇&lt;/p&gt;
&lt;p&gt;Without further ado, here's the nuget and github links:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/lars-erik/Our.Umbraco.WysiwygGrid"&gt;https://github.com/lars-erik/Our.Umbraco.WysiwygGrid&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://www.nuget.org/packages/Our.Umbraco.WysiwygGrid/1.0.0-beta01"&gt;https://www.nuget.org/packages/Our.Umbraco.WysiwygGrid/1.0.0-beta01&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hope you enjoy it, and as usual, hope for a good discussion or feedback from the community!&lt;/p&gt;
</description>
      <pubDate>Thu, 23 Apr 2020 12:09:36 Z</pubDate>
      <a10:updated>2020-04-23T12:09:36Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1164</guid>
      <link>https://blog.aabech.no/archive/the-state-of-wysiwyg-grid-editing-in-umbraco-a-prototype/</link>
      <category>umbraco</category>
      <title>The state of WYSIWYG grid editing in Umbraco - a prototype</title>
      <description>&lt;h2&gt;The state of the grid&lt;/h2&gt;
&lt;p&gt;Since the grid was launched at the CG talk &amp;quot;The sky is the limit&amp;quot; back in 2015 (i think),
it has been a joy to use for editors, designers and developers alike.
Granted, there's been the other feature that could've gotten more love (configuration and settings), but generally it does the job swell.&lt;br /&gt;
However, it's still just a white canvas with &amp;quot;settings applied&amp;quot;.&lt;br /&gt;
&lt;a href="https://twitter.com/aaantoinee"&gt;Antoine&lt;/a&gt; made &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/lepainter/"&gt;LePainter&lt;/a&gt; back in 2015, but likely didn't get much traction.&lt;br /&gt;
I was just told about it today by &lt;a href="https://twitter.com/callumbwhyte"&gt;Callum&lt;/a&gt;. Shame on me for not watching the package space enough, how embarrasing. 😳&lt;/p&gt;
&lt;p&gt;Anyway...&lt;/p&gt;
&lt;h2&gt;Why should we care&lt;/h2&gt;
&lt;p&gt;Recently, I've been in lots of discussions; near battles IMO; about which CMS to sell to our customers.&lt;br /&gt;
The feedback is that editors wonder why what they see while editing does not match what they see in the front-end.
We do work with another CMS where the backoffice experience has a near 1:1 layout and design with the front-end.
As developers, we tend to think structured data is the better solution. Think nested- and stacked content.
I tend to agree. But in a sales meeting, those arguments are total losing arguments. A competing agency will bury you when they oversell the fancy editing experience. Even though the not-so-apparent technical features of the competing CMS are totally useless.&lt;br /&gt;
And I do agree - the editing experience is what Umbraco likes to sell as well!&lt;/p&gt;
&lt;h2&gt;What can we do?&lt;/h2&gt;
&lt;p&gt;The current HQ efforts are working on the &amp;quot;block based&amp;quot; editor. It's been going on for the better part of a year, but the publicly available information is mostly &lt;a href="https://github.com/umbraco/rfcs/blob/master/cms/0012-rfc-block%20editor.md"&gt;just an RFC with screenshots&lt;/a&gt; looking like stacked / nested content, and that's it. The technical aspects seem super, but there's nothing much (but text) about the general editing experience. Also, and I know this is a hot take, editors DO want to see three columns in the editor when it ends up three columns in the front-end.&lt;/p&gt;
&lt;p&gt;Hopefully, as mentioned in the RFC, it can act as a stepping stone towards the &amp;quot;Grid 2.0&amp;quot; (which we started work on at the retreat &lt;em&gt;two&lt;/em&gt; years ago).&lt;/p&gt;
&lt;p&gt;But as far as I'm concerned, this could just as well end up never happening. The effort is not very visible, Project UniCore 🦄 has (rightly) high priority, and in the mean time we're stuck with Grid 1.0, or maybe, hopefully, a rumored &lt;em&gt;commercial&lt;/em&gt; package called Bento by the eminent &lt;a href="https://twitter.com/pgregorynz"&gt;Peter Gregory&lt;/a&gt; and his colleagues at KØBEN Digital.&lt;/p&gt;
&lt;h2&gt;A prototype&lt;/h2&gt;
&lt;p&gt;So back using Grid 1.0 for projects to be delivered imminently, I've started doing some prototypes for something similar to what LePainter did for early v7 projects.&lt;/p&gt;
&lt;p&gt;I asked the community if it was madness or worth pursuing, and the general feedback is that it's both. Hence this blog post to explore it some more, and hopefully gather some more feedback or at least provide feedback to the block editor team. (Hope they receive it. 😁)&lt;/p&gt;
&lt;p&gt;Here's a quick little preview of what I've been doing so far:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/B6LLiO116jc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2&gt;The issues&lt;/h2&gt;
&lt;p&gt;Actually getting the styling into the grid is &amp;quot;just&amp;quot; a matter of including a few pagefuls of JavaScript and a limited and scoped CSS file in a package.manifest file for the site. Both classes and styles are applied as expected, and with some due dilligence it doesn't look half bad.&lt;/p&gt;
&lt;p&gt;The biggest issue I have is that the cells and controls are styled white, and while styling one have to mind not messing up the GUI text like &amp;quot;Settings applied&amp;quot;.&lt;/p&gt;
&lt;p&gt;I attempted to lessen the opacity of the cells and controls, and it works to a degree. The minute one adds a background image however, the entire thing starts to crumble. How to keep the WYSIWYG experience while still seeing the GUI? One could fantasize about doing an average color sample of the image and toggling between white and black text, maybe? Could be done in a short hacking sprint...&lt;br /&gt;
Could just keep it fairly white like I've done in the prototype.
Could keep just the active rows white. This is where I start struggling. 😳&lt;/p&gt;
&lt;p&gt;To be frank, the biggest problem lies in the fact that the &amp;quot;Add content&amp;quot; button is &lt;em&gt;in&lt;/em&gt; the grid. Other CMSes have drag drop functionality from a menu over to the side. It could possibly still just be white or slightly transparent. The last problem then is all those &amp;quot;settings applied&amp;quot; and empty cells with the other type of &amp;quot;Add content&amp;quot; button.&lt;/p&gt;
&lt;p&gt;I can't help but think this is all within grasp, albeit just out of my limited back-ender reach. 😆&lt;/p&gt;
&lt;h2&gt;The settings dialog issues&lt;/h2&gt;
&lt;p&gt;The settings dialog is a chapter of itself. It's a mystery to me why we still have a concept of individual &amp;quot;prevalue editors&amp;quot; in Umbraco. Property editors have the same model, and can be sneaked in there by just providing a full path.&lt;/p&gt;
&lt;p&gt;However, as experienced when working on &lt;a href="http://blog.aabech.no/archive/our-umbraco-community-contentlist-10-beta-released/"&gt;our ContentList package&lt;/a&gt;, nesting property editors using built-in directives wreaks total havok on the styling. There's some grey background and drop shadows - that I haven't seen being actively used anywhere. It's generally just a mystery, and a huge candidate for backoffice re-work.&lt;/p&gt;
&lt;p&gt;Also, for instance the slider property editor does look a bit weird when used as a setting editor. I do hope that those things will get an overhaul and are made more uniform sooner or later.&lt;/p&gt;
&lt;p&gt;I'll just leave that hanging, since I know (and appreciate) there are several HQ and community efforts going on to clean things up.&lt;/p&gt;
&lt;h2&gt;The code&lt;/h2&gt;
&lt;p&gt;Since I managed to &lt;a href="https://github.com/umbraco/Umbraco-CMS/pull/2639/commits/76c924fbaa3da89d9865d9ec405e6dbb123852e3"&gt;sneak in a few new events in the grid&lt;/a&gt;, making it work was a matter of hooking into the &amp;quot;grid.initialized&amp;quot; event and start watching the model. There might be some performance issues with large grids since it's a deep watch, but with todays computers that might be irrational over engineering to think as well.&lt;/p&gt;
&lt;p&gt;It adds the configured styles as expected.&lt;br /&gt;
For the configuration, it just adds the value of the configuration setting called &amp;quot;class&amp;quot;. If there's more it concats the setting key with the setting value, delimited by a dash.&lt;/p&gt;
&lt;p&gt;You can scrutinize the JavaScript here, or in &lt;a href="https://gist.github.com/lars-erik/9dbf8f4004121c8eb109423b814af34c"&gt;this gist&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;angular.module(&amp;quot;umbraco&amp;quot;).run([&amp;quot;eventsService&amp;quot;, function(eventsService) {
    function findModelScope(scope) {
        if (!scope) {
            return null;
        }
        if (scope.model) {
            return scope;
        }
        return findModelScope(scope.$parent);
    }

    function isProtectedClass(className) {
        return className === &amp;quot;umb-row-inner&amp;quot; ||
            className === &amp;quot;umb-cell-inner&amp;quot; ||
            className.substr(0, 2) === &amp;quot;ng-&amp;quot; ||
            className.substr(0, 2) === &amp;quot;ui-&amp;quot;;
    }

    function addClasses(element, gridItem) {
        function classNameFromConfig(e) {
            if (e === &amp;quot;class&amp;quot;) {
                return gridItem.config[e];
            } else {
                return e + &amp;quot;-&amp;quot; + gridItem.config[e];
            }
        }

        var classes = (element.className || &amp;quot;&amp;quot;).split(/\s+/);
        var newClasses = classes.filter(isProtectedClass);
        var nameClass = (gridItem.name || &amp;quot;&amp;quot;).toLowerCase().replace(&amp;quot; &amp;quot;, &amp;quot;-&amp;quot;);
        var configClasses = Object.keys(gridItem.config || {}).map(classNameFromConfig);
        newClasses.push(nameClass);
        newClasses = newClasses.concat(configClasses);
        element.className = newClasses.join(&amp;quot; &amp;quot;);
    }

    function addStyles(element, gridItem) {
        function styleFromKeyPair(e) {
            return e + &amp;quot;:&amp;quot; + gridItem.styles[e];
        }

        var stylesValues = Object.keys(gridItem.styles || {}).map(styleFromKeyPair);
        element.style = stylesValues.join(&amp;quot;;&amp;quot;);
    }

    eventsService.on(&amp;quot;grid.initialized&amp;quot;,
        function(evt, data) {
            var modelScope = findModelScope(data.scope);
            var model = modelScope.model;
            var jqEl = data.element;
            var el = data.element.get(0);
            jqEl.addClass(&amp;quot;stylized-grid&amp;quot;);

            modelScope.$watch(
                &amp;quot;model&amp;quot;,
                function () {
                    var areaElements = el.getElementsByClassName(&amp;quot;umb-column&amp;quot;);
                    if (areaElements.length === 0) {
                        return;
                    }
                    model.value.sections.forEach(function (area, ai) {
                        var rowElements = areaElements[ai].getElementsByClassName(&amp;quot;umb-row-inner&amp;quot;);
                        area.rows.forEach(function (row, ri) {
                            var rowElement = rowElements[ri];
                            addClasses(rowElement, row);
                            addStyles(rowElement, row);

                            var cellElements = rowElement.getElementsByClassName(&amp;quot;umb-cell-inner&amp;quot;);
                            row.areas.forEach(function(cell, ci) {
                                addClasses(cellElements[ci], cell);
                                addStyles(cellElements[ci], cell);
                            });
                        });
                    });
                },
                true
            );
        });

}]);
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;The CSS&lt;/h2&gt;
&lt;p&gt;To not interfere with any other backoffice styling, the script adds the class &amp;quot;stylized-grid&amp;quot; to the grid container. Here's the (S)CSS I used to make things more transparent:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.umb-grid.stylized-grid { 

    .umb-cell-content {
        background-color: rgba(255, 255, 255, .8);
    }

    .umb-cell-content:hover {
        background-color: rgba(255, 255, 255, 1);
    }

    .umb-cell-content.-has-editors {
        background-color: rgba(255, 255, 255, .8);
    }

    .umb-cell-content.-has-editors:hover {
        background-color: rgba(255, 255, 255, 1);
    }

    .umb-grid-add-more-content {
        background-color: rgba(255, 255, 255, 1);
    }

    .umb-control-bar, .umb-grid-has-config {
        font-family: Lato, Helvetica Neue, Helvetica, Arial, sans-serif !important;
    }

    iframe {
        background-color: transparent;
    }

    @import &amp;quot;../../../Assets/grid&amp;quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The import at the bottom is the sass that styles our individual components in the front-end, and that should be reflected in the backoffice. &lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We'll be diving into deep water and testing this out on a real customer. I'm a bit weary, but we need to get the experience.&lt;/p&gt;
&lt;p&gt;I do hope I've been able to provide some inspiration, and that WYSIWYG editing in Umbraco might get the renaissance (I believe) it deserves.&lt;/p&gt;
&lt;p&gt;Feel free to drop your comments below or ping me on Twitter or Slack!&lt;br /&gt;
Also happy to continue the discussion on our or github, but not sure the best way forward, if any.&lt;/p&gt;
</description>
      <pubDate>Fri, 03 Apr 2020 13:26:14 Z</pubDate>
      <a10:updated>2020-04-03T13:26:14Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1163</guid>
      <link>https://blog.aabech.no/archive/our-umbraco-community-contentlist-10-beta-released/</link>
      <category>Umbraco</category>
      <title>Our Umbraco Community ContentList 1.0 (beta) released</title>
      <description>&lt;p&gt;ContentList is a grid editor we've used internally at MarkedsPartner since 2016. It helps editors and designers insert lists of content in the grid without having to worry about queries, paging or building new templates.&lt;br /&gt;
I've finally been able to upgrade it to Umbraco 8 and polished it a bit. It's still slightly in beta, but there's nothing special but a bit of CSS polish lacking, so it should be fairly safe to use in production. 👼&lt;/p&gt;
&lt;p&gt;There's a whole documentation piece in the readme &lt;a href="https://github.com/lars-erik/Our.Umbraco.ContentList"&gt;over on github&lt;/a&gt;, so I won't bother with a whole lot of prose in this blogpost, but I recorded a half an hour demo (below) showing all the aspects of implementing its use in an Umbraco site.&lt;/p&gt;
&lt;p&gt;There's really not much to do once you get the hang of it, and our editors and staff have been enjoying using it for five years, so I hope you will too.&lt;/p&gt;
&lt;p&gt;Here's the demo, and I really hope to get your feedback here, on github or on youtube.
The first 3-4 minutes show the gist of it, so no need to sit through the full half hour if you're just curious. 👍&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/7O6Es1SNf9s" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;</description>
      <pubDate>Wed, 01 Apr 2020 21:57:27 Z</pubDate>
      <a10:updated>2020-04-01T21:57:27Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1138</guid>
      <link>https://blog.aabech.no/archive/morphing-ucommerce-products/</link>
      <category>umbraco</category>
      <category>ucommerce</category>
      <title>Morphing UCommerce Products</title>
      <description>&lt;h2&gt;The problem&lt;/h2&gt;
&lt;p&gt;Today I had a new but fun challenge with UCommerce. Turns out, as usual, it's a great fit for my whims with architecture.
I was stuck between a rock and a hard place when I was looking at adding a custom pricing algoritm.
I can't go into details, but there's custom client pricing involved of course.
To add to the fun, we're mapping UCommerce products to DTOs for wire transfer. We could aslo have been mapping to view models or something else. To map we're using AutoMapper with quite a few configurations and jumps-through-hoops.&lt;/p&gt;
&lt;p&gt;I had this code (ish):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var products = productRepository.Select().Where(SomePredicate);
var mapped = products.Select(Mapper.Map&amp;lt;ProductDto&amp;gt;);
return mapped;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I immediately thought of a few options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Iterate over the products and change prices here&lt;/li&gt;
&lt;li&gt;Create a Product adapter with additional logic and map from that&lt;/li&gt;
&lt;li&gt;Execute the pricing logic from AutoMapper configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They all seemed weird and out of place though. None seemed like they would be easy to find for the next developer. Not even with unit tests. It just didn't seem right.
Changing data on the entities would mean I'd have to go out of my way to ensure nobody went and saved those products later in the request. Creating an adapter would mean loads of new instances, bloated wrapper classes and weird names.
And finally executing business logic from AutoMapper configuration means I'd been mixing responsibilities en mass.&lt;/p&gt;
&lt;h2&gt;UCommerce &amp;amp; NHibernate to the rescue&lt;/h2&gt;
&lt;p&gt;Luckily I've been using EntityFramework a lot and tried to force it into my Domain Driven Design patterns since it's infancy. I've been through the lot (and I enjoy it). So I kind of know what to expect from an ORM. When using UCommerce I'm stuck with NHibernate, but I haven't really been doing it justice by just leaving it in the background. (And fiddling with Entity Framework - which is just as good!)
Together the two systems are extremely powerful. UCommerce have even documented the possibilities,
though the documentation fails to point out the really juicy benefits.&lt;/p&gt;
&lt;p&gt;We have &lt;code&gt;ProductDefintion&lt;/code&gt;, right? It allows us to set up product types with different properties and variant options. It even supports inheritance. But we're still stuck with the &lt;code&gt;Product&lt;/code&gt; class and its &lt;code&gt;GetProperty()&lt;/code&gt; overrides. In my case, I'd like to have &lt;code&gt;ProductWithFancyPricing&lt;/code&gt; so I could override that &lt;code&gt;GetPrice()&lt;/code&gt; method. If I could have &lt;code&gt;ProductWithFancyPricing&lt;/code&gt; and &lt;code&gt;ProductWithEvenFancierPricing&lt;/code&gt; that would be totally awesome.&lt;/p&gt;
&lt;p&gt;Turns out you can have your cake and eat it too. When properly using an ORM you can exploit OOP like it's supposed to and use polymorphism for varying behavior. It's possible to set up an inheritance tree so the mapper automatically handles creation of different types for you. You've basically got three options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Table per concrete class (type)
&lt;ul&gt;
&lt;li&gt;All classes have a table of their own&lt;/li&gt;
&lt;li&gt;Useful when base classes don't have (much) data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Table per hierarchy
&lt;ul&gt;
&lt;li&gt;One table per base class&lt;/li&gt;
&lt;li&gt;Useful when &lt;em&gt;all&lt;/em&gt; data is on the base class&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Table per subclass
&lt;ul&gt;
&lt;li&gt;One common table for base data&lt;/li&gt;
&lt;li&gt;Individual tables per derived class with only additional data&lt;/li&gt;
&lt;li&gt;Useful when there are some data in both classes. (Think umbracoNode)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my case, I don't need any new data on the derived classes. It's all there in &lt;code&gt;GetProperty()&lt;/code&gt; anyway.
&lt;em&gt;(I will add some getters though. ModelsBuilder, anyone? )&lt;/em&gt;&lt;br /&gt;
So for me it's going to be Table per hierarchy. The rest of the options are all viable for this technique if you have other requirements.
You can &lt;a href="https://docs.ucommerce.net/ucommerce/v7.12/extending-ucommerce/extending-ucommerce-entities.html"&gt;read a bit about it in the UCommerce docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Mapping some product types&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;(I inadvertently wrote document types there. ModelsBuilder, anyone?)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In order to have NHibernate treat products as subclasses with the Table per hierarchy strategy it needs a way to pick the right class for each record. That way is known as discriminator columns. I first thought I could just discriminate by the ProductDefinitionId, but it turns out NHibernate doesn't support discriminating on a column already in use for associations (foreign keys) or other means.&lt;br /&gt;
We have to add a column. I just call it &amp;quot;Discriminator&amp;quot; and make it a varchar.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alter table uCommerce_Product add Discriminator nvarchar(max)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then we need some entities. I added a couple of docu... product types:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ProductWithFancyPricing : UCommerce.EntitiesV2.Product
{
    public override Money GetPrice(PriceGroup priceGroup)
    {
        var price = base.GetPrice(priceGroup);
        if (IsChristmas())
        {
            price = new Money(price.Value * 2, price.Culture, price.Currency);
        }
        return base.GetPrice(priceGroup);
    }
}

public class ProductWithEvenFancierPricing : UCommerce.EntitiesV2.Product
{
    public override Money GetPrice(PriceGroup priceGroup)
    {
        var blackMarket = ObjectFactory.Instance.Resolve&amp;lt;IBlackMarketService&amp;gt;();
        var priceValue = blackMarket.GetPrice(Sku);
        return new Money(priceValue, priceGroup.Currency);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The next thing you need is to tell NHibernate that these are our new product classes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ProductWithFancyPricingMapping : FluentNHibernate.Mapping.SubclassMap&amp;lt;ProductWithFancyPricing&amp;gt;
{
    public ProductWithFancyPricingMapping()
    {
        DiscriminatorValue(&amp;quot;Product with fancy pricing&amp;quot;);
    }
}

public class ProductWithEvenFancierPricingMapping : FluentNHibernate.Mapping.SubclassMap&amp;lt;ProductWithEvenFancierPricing&amp;gt;
{
    public ProductWithEvenFancierPricingMapping()
    {
        DiscriminatorValue(&amp;quot;Product with naughty pricing&amp;quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We also need to subclass UCommerce's mapping for Product in order to tell UCommerce which column to use as the discriminator:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ProductMap : global::UCommerce.EntitiesV2.Maps.ProductMap
{
    public ProductMap()
    {
        DiscriminateSubClassesOnColumn(&amp;quot;Discriminator&amp;quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally we need a class in the same assembly with a tag on it. &lt;a href="https://docs.ucommerce.net/ucommerce/v7.12/extending-ucommerce/save-custom-data-in-the-database.html"&gt;More on that in the UCommerce docs&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class MappingMarker : IContainsNHibernateMappingsTag
{
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To have NHibernate pick the right classes now, we just need to fix the existing products if we have any.
I have called my discriminator values the same as my document types, so I can easily construct a query as such:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;update
    ucommerce_product
set 
    discriminator = case productdefinitionid
        when 10 then 'Product with fancy pricing'
        when 11 then 'Product with naughty pricing'
        else null
    end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now if we go...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var products = productRepository.Select();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...we'll get a bounch of &lt;code&gt;ProductWithFancyPricings&lt;/code&gt; and &lt;code&gt;ProductWithEvenFancierPricing&lt;/code&gt;.
If you have more types, you might get into trouble though. You need to have a discriminator on them all.&lt;/p&gt;
&lt;h2&gt;The final hurdle&lt;/h2&gt;
&lt;p&gt;So that's cool. That's really cool. But there's one hurdle we have to jump over before we can cross the goal line. From very nasty experiences I knew I had to test &lt;em&gt;everything&lt;/em&gt; manually and integrated. So I went and tried to see what happened if I added a product through the UCommerce Admin UI.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;boom&lt;/em&gt; :)&lt;/p&gt;
&lt;p&gt;'Course it didn't work. It actually did, and didn't. Several weird things happened ranging from strange NHibernate mapping exceptions to products getting the discriminator &amp;quot;UCommerce.EntitiesV2.Product&amp;quot;. (Which makes a lot of sense if you think about it)&lt;/p&gt;
&lt;p&gt;The @#¤%&amp;amp; &lt;code&gt;CreateCategoryOrProduct.as[p|c]x&lt;/code&gt; WebForms control is in our way. It instantiates a &lt;code&gt;Product&lt;/code&gt; and saves it. It's completely sealed and unconfigurable. We could overwrite it with a custom one, but that would open another can of worms with regards to upgrading, source control and what-not. Luckily it's going away very very soon in UCommerce V8. (2018?)&lt;/p&gt;
&lt;p&gt;After hacking at it a bit my final resolve was to add a step right after save in the product saving pipeline. Again, UCommerce is so versatile that even when it sucks, it's got a golden workaround right up its arm.
If you're not familiar with UCommerce Pipelines, &lt;a href="https://docs.ucommerce.net/ucommerce/v7.12/extending-ucommerce/create-pipeline-task.html"&gt;go read about it here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's the extra configuration. (In a .config file included from UCommerce's custom.config)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- PRODUCT CLASS FIX --&amp;gt;
&amp;lt;component id=&amp;quot;SaveProduct&amp;quot;
           service=&amp;quot;UCommerce.Pipelines.IPipeline`1[[UCommerce.EntitiesV2.Product, UCommerce]], UCommerce&amp;quot;
           type=&amp;quot;UCommerce.Pipelines.Catalog.ProductPipeline, UCommerce.Pipelines&amp;quot;&amp;gt;
  &amp;lt;parameters&amp;gt;
    &amp;lt;tasks&amp;gt;
      &amp;lt;array&amp;gt;
        &amp;lt;value&amp;gt;${Product.UpdateRevision}&amp;lt;/value&amp;gt;
        &amp;lt;value&amp;gt;${Product.Save}&amp;lt;/value&amp;gt;
        &amp;lt;value&amp;gt;${FixProductClass}&amp;lt;/value&amp;gt;
        &amp;lt;value&amp;gt;${Product.IndexAsync}&amp;lt;/value&amp;gt;
      &amp;lt;/array&amp;gt;
    &amp;lt;/tasks&amp;gt;
  &amp;lt;/parameters&amp;gt;
&amp;lt;/component&amp;gt;

&amp;lt;component id=&amp;quot;FixProductClass&amp;quot;
           service=&amp;quot;UCommerce.Pipelines.IPipelineTask`1[[UCommerce.EntitiesV2.Product, UCommerce]], UCommerce&amp;quot;
           type=&amp;quot;My.Awesome.Site.Persistence.FixProductClassTask, My.Awesome.Site.UCommerce&amp;quot;/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A pipeline task gets a reference to the entity being handled, so we can't just go and replace the entire product with an instance of the right type. But we can fake it and force the database value to be correct after saving.
UCommerce uses NHibernate level 2 cache, so we need to flush that as well, but we'll get to that.&lt;/p&gt;
&lt;p&gt;Forcing the database is fairly easy. We have to resort to good old ADO code, which was actually a joyful little deja-vu experience (although I'm glad it was brief):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class FixProductClassTask : IPipelineTask&amp;lt;Product&amp;gt;
{
    private readonly IStatelessSessionProvider sessionProvider;

    public FixProductClassTask(IStatelessSessionProvider sessionProvider)
    {
        this.sessionProvider = sessionProvider;
    }

    public PipelineExecutionResult Execute(Product subject)
    {
        var command = sessionProvider.GetStatelessSession().Connection.CreateCommand();
        command.CommandText = &amp;quot;UPDATE uCommerce_Product SET Discriminator = @discriminator WHERE ProductId = @productId&amp;quot;;
        command.CommandType = CommandType.Text;
        var discriminatorParam = command.CreateParameter();
        discriminatorParam.ParameterName = &amp;quot;discriminator&amp;quot;;
        discriminatorParam.Value = subject.ProductDefinition.Name;
        var idParam = command.CreateParameter();
        idParam.ParameterName = &amp;quot;productId&amp;quot;;
        idParam.Value = subject.Id;
        command.Parameters.Add(discriminatorParam);
        command.Parameters.Add(idParam);
        command.ExecuteNonQuery();

        // TODO: Clear cache

        return PipelineExecutionResult.Success;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I'm sure a lot of sazzy devs out there could prettify this a bit, but it does the job. Insert a &lt;a href="/archive/kill-switch-weve-got-action/"&gt;switch/case (please don't)&lt;/a&gt; or whatever you fancy if the product definition name isn't what you discriminate by. I'll leave it up to you to choose between strings, ints or even enums for performance vs. readability.&lt;/p&gt;
&lt;p&gt;If you've turned off the level 2 cache, you might be fine with this. Otherwise we'd better &amp;quot;evict&amp;quot; the entity from the cache. We need to do that in order for the cached instance to change type from &lt;code&gt;Product&lt;/code&gt; to &lt;code&gt;ProductWithFancyPricing&lt;/code&gt;. Sadly the NHibernate &lt;code&gt;SessionFactory&lt;/code&gt; in charge of doing this is hidden in an internal static field in UCommerce, so we need to resort to some nasty reflection to do it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ...
command.ExecuteNonQuery();

var fieldInfo = typeof(SessionProvider).GetField(&amp;quot;_factory&amp;quot;, BindingFlags.Static | BindingFlags.NonPublic);
if (fieldInfo == null) throw new Exception(&amp;quot;SessionFactory instance has moved in this UCommerce version. %(&amp;quot;);
var sessionFactory = (ISessionFactory)fieldInfo.GetValue(null);
sessionFactory.Evict(typeof(Product), subject.Id);

return PipelineExecutionResult.Success;
// ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Et voilá! We can now save new products, and they immediately morph into the correct derived type.
(Except for when being saved to RavenDB for the first time, ref. the config).&lt;/p&gt;
&lt;p&gt;I'm now free to go back into the instances and implement however naughty pricing I fancy. \o/&lt;/p&gt;
&lt;h2&gt;Added bonuses&lt;/h2&gt;
&lt;p&gt;I already &lt;a href="https://docs.ucommerce.net/ucommerce/v7.12/extending-ucommerce/save-custom-data-in-the-database.html"&gt;have a custom entity in the database and NHibernate model&lt;/a&gt;. It has two associations to &lt;code&gt;Product&lt;/code&gt;. Had I realized what I had under my fingertips it would already have been collections on my new shiny subclasses.&lt;/p&gt;
&lt;p&gt;I recon you noticed I referenced ModelsBuilder a couple of times. How 'bout having all your properties statically typed on your product instances. How about some interfaces?&lt;/p&gt;
&lt;p&gt;I'm sure you're getting the drift.&lt;/p&gt;
&lt;p&gt;I for one am quite embarrased I didn't think of this before. I've had the knowledge and tools for years. But there you go. We learn something every day. And I love doing it with Umbraco, UCommerce, EntityFramework and apparently now also... NHibernate. :)&lt;/p&gt;
</description>
      <pubDate>Tue, 30 Jan 2018 23:48:27 Z</pubDate>
      <a10:updated>2018-01-30T23:48:27Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1137</guid>
      <link>https://blog.aabech.no/archive/umbraco-unit-testing-workshop-material/</link>
      <category>umbraco</category>
      <category>unit testing</category>
      <title>Umbraco Unit Testing Workshop Material</title>
      <description>&lt;p&gt;For this years Umbraco UK Festival I was honored to be invited to run a unit testing workshop. It's a culmination of my talks and workshops until now, and covers everything you need to get going with testing the Umbraco backoffice, controller logic, external calls and finally front-end UI.&lt;/p&gt;
&lt;p&gt;I know there's demand for this kind of training, and it might be difficult to get to the conferences where it's happening. For those of you, and those who feel bold and confident, I've released the material under the MIT license.&lt;/p&gt;
&lt;p&gt;I can't promise I'll be able to help out if you go at it, but keep an eye out for a conference near you and encourage the organizers to host a workshop. ;)&lt;/p&gt;
&lt;p&gt;You can clone the &amp;quot;workshop-start&amp;quot; branch from Bitbucket. The slides and workbook are included at the root of the repo.&lt;/p&gt;
&lt;p&gt;https://bitbucket.org/bleedo/umbraco-testing-workshop-h2-2017/src/?at=workshop-start&lt;/p&gt;
&lt;p&gt;You'll need&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;node&lt;/li&gt;
&lt;li&gt;npm task runner (visual studio extension)&lt;/li&gt;
&lt;li&gt;razorgenerator (visual studio extension)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy testing!&lt;/p&gt;
</description>
      <pubDate>Thu, 09 Nov 2017 10:09:16 Z</pubDate>
      <a10:updated>2017-11-09T10:09:16Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1136</guid>
      <link>https://blog.aabech.no/archive/automating-umbraco-with-powershell/</link>
      <category>umbraco</category>
      <category>automation</category>
      <title>Automating Umbraco with PowerShell</title>
      <description>&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;This particular example is for warming up a UCommerce site in staging, but the technique can be used for anything you can do in the Umbraco backoffice. Especially with the new REST APIs coming out.&lt;/p&gt;
&lt;p&gt;In this particular case, I've sinned and not created a good test environment for the last few integration bits of a project. It was hard to tune the production behavior of some code without actually running it in production. However, it's running Umbraco 7.5.13 and UCommerce 7.7. It's probably missing the other performance fix too, but the result is that it takes quite a while to warm up everything. So we warm it up in staging and then swap slots to get it fresh, awake and blazing fast into production. &lt;/p&gt;
&lt;h2&gt;Resolve&lt;/h2&gt;
&lt;p&gt;After having done this a few times, I figured I wanted something to do while waiting. What better activity than automating the whole routine so I could do something else instead? (Like automating automation...) Here's a powershell script I ended up with to warm up everything in the backoffice. I'll go through the pieces below.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Param(
    [string]$password
)

$ws = New-Object Microsoft.PowerShell.Commands.WebRequestSession

$body = @{
    &amp;quot;username&amp;quot;=&amp;quot;admin@admin.com&amp;quot;
    &amp;quot;password&amp;quot;=$password
}

$json = $body | ConvertTo-Json

Invoke-RestMethod `
    -Method Post `
    -ContentType &amp;quot;application/json&amp;quot; `
    -Uri &amp;quot;https://customer-staging.azurewebsites.net/umbraco/backoffice/UmbracoApi/Authentication/PostLogin&amp;quot; `
    -WebSession $ws `
    -Body $json

Write-Host &amp;quot;20%&amp;quot;

Invoke-RestMethod -Method Get -Uri &amp;quot;https://customer-staging.azurewebsites.net/umbraco/ucommerce/catalog/editcategory.aspx?id=718&amp;quot; -WebSession $ws

Write-Host &amp;quot;40%&amp;quot;

Invoke-RestMethod -Method Get -Uri &amp;quot;https://customer-staging.azurewebsites.net/umbraco/ucommerce/catalog/editproduct.aspx?id=465&amp;amp;parentcategoryId=718&amp;quot; -WebSession $ws

Write-Host &amp;quot;60%&amp;quot;
Invoke-RestMethod -Method Get -Uri &amp;quot;https://customer-staging.azurewebsites.net/umbraco/ucommerce/settings/orders/editpaymentmethod.aspx?id=8&amp;quot; -WebSession $ws

Write-Host &amp;quot;80%&amp;quot;

Invoke-RestMethod -Method Get -Uri &amp;quot;https://customer-staging.azurewebsites.net/umbraco/ucommerce/settings/orders/editshippingmethod.aspx?id=10&amp;quot; -WebSession $ws
Write-Host &amp;quot;100%&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The effect is that we log into Umbraco using a provided password, and instead of navigating and clicking everything, we fire a request triggering all the caching and JIT compilation for us. Even though I'm using the &lt;code&gt;Invoke-RestMethod&lt;/code&gt; cmdlet, I can do regular web calls. The cmdlet has a sibling called &lt;code&gt;Invoke-WebRequest&lt;/code&gt;, but the rest version is better for posting commands. It's mostly a matter of mental context, but they have a few differences.&lt;/p&gt;
&lt;h2&gt;Log into Umbraco&lt;/h2&gt;
&lt;p&gt;To set up an authorized session with Umbraco, we can call the PostLogin action. It's the same endpoint that is used from the login screen. An authorized session means that we need to get a cookie and pass it with all our requests. In order for each &lt;code&gt;Invoke-RestMethod&lt;/code&gt; to pass this cookie, we can create a &lt;code&gt;WebRequestSession&lt;/code&gt; we pass to each call:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ws = New-Object Microsoft.PowerShell.Commands.WebRequestSession

Invoke-RestMethod -WebSession $ws -Uri &amp;quot;...&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the response brings a cookie, it's kept in the &lt;code&gt;WebRequestSession&lt;/code&gt;, and subsequently passed back with each new request. Just like a browser.&lt;/p&gt;
&lt;p&gt;Then we need some JSON to pass our username and password. You can declare dictionaries of sorts in PowerShell like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$body = @{
    &amp;quot;username&amp;quot;=&amp;quot;admin@admin.com&amp;quot;
    &amp;quot;password&amp;quot;=$password
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then convert it to JSON by piping it to the &lt;code&gt;ConvertTo-Json&lt;/code&gt; cmdlet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$json = $body | ConvertTo-Json
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally we're ready to fire the request off to Umbraco, adding config for HTTP method, ContentType etc.:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Invoke-RestMethod `
    -Method Post `
    -ContentType &amp;quot;application/json&amp;quot; `
    -Uri &amp;quot;https://customer-staging.azurewebsites.net/umbraco/backoffice/UmbracoApi/Authentication/PostLogin&amp;quot; `
    -WebSession $ws `
    -Body $json
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Automate Umbraco&lt;/h2&gt;
&lt;p&gt;For this I just needed to kick off a request to some pages, but posting messages around like rebuilding a grumpy index, running an ad hoc task, even publishing should be just as simple.&lt;/p&gt;
&lt;p&gt;It takes a while, so I added a little status message. I'm sure PowerShell wizards would pack this stuff into better reusable parts.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Write-Host &amp;quot;20%&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now reuse that &lt;code&gt;WebRequestSession&lt;/code&gt; object to fire off new &lt;em&gt;authenticated&lt;/em&gt; requests:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Invoke-RestMethod -WebSession $ws -Method Get -Uri &amp;quot;https://customer-staging.azurewebsites.net/umbraco/ucommerce/catalog/editcategory.aspx?id=718&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Do it everywhere&lt;/h2&gt;
&lt;p&gt;With all the love I can give to UCommerce, I ended up naming the script &lt;code&gt;kick-ucommerce.ps1&lt;/code&gt;. It's like kicking your old belowed car to get it started, after you've polished it. Really!&lt;br /&gt;
Adding my source folder to the path environment variable makes the script available from any shell. Even the Package Manager console in Visual Studio. &lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1034/warmup-ucommerce.png" alt="Warm up UCommerce" /&gt;&lt;/p&gt;
&lt;p&gt;Make a note that the password is a parameter. You do change it more often than you'd like to update the code right? How 'bout automating the process? ;)&lt;/p&gt;
&lt;h2&gt;Smoke test and swap the Azure slot&lt;/h2&gt;
&lt;p&gt;I'll leave the swap-slot script I run after warming up the site here too. The cool thing about warming up with the script is that it'll fail almost immediately on the Umbraco login if anything isn't like it should. So it doubles as a smoke test.&lt;/p&gt;
&lt;p&gt;When everything looks good, I can just go:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;swap-slot -from staging -to production -site customer-x
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here's the &amp;quot;simpleness&amp;quot; of that one. There are fairly good docs on all the Azure cmdlets over on Microsoft's sites. (Ask Google. ;) )&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Param(
    [string]$site,
    [string]$from,
    [string]$to
)

$subscriptionId = &amp;quot;333112F4-4483-449C-A2DA-727E8D2E428D&amp;quot;
$resourcegroupname = &amp;quot;Common-Group&amp;quot;     # Might need to be param

Login-AzureRmAccount -SubscriptionId $subscriptionId

Swap-AzureRmWebAppSlot `
    -SourceSlotName $from `
    -DestinationSlotName $to `
    -Name $site `
    -ResourceGroupName $resourcegroupname
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's it! Now go automate something so you get more time to do fun stuff! :)&lt;/p&gt;
</description>
      <pubDate>Tue, 07 Nov 2017 19:46:14 Z</pubDate>
      <a10:updated>2017-11-07T19:46:14Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1127</guid>
      <link>https://blog.aabech.no/archive/umbracosupport-got-typed-content/</link>
      <category>unit testing</category>
      <category>umbraco</category>
      <title>UmbracoSupport got typed content</title>
      <description>&lt;h2&gt;What's UmbracoSupport?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;UmbracoSupport&lt;/code&gt; is a class I've been introducing to my unit tests over the last year or so.
It allows me to have my own hierarchy for tests, as well as re-using all of Umbraco's own
stubbing code. I've written about it in a post called &lt;a href="/archive/the-basics-of-unit-testing-umbraco-just-got-simpler"&gt;Unit testing Umbraco just got simpler&lt;/a&gt;,
and its gut's code is described in details in &lt;a href="/archive/the-basics-of-unit-testing-umbraco"&gt;The basics of unit testing Umbraco&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;A quick primer on what's already available&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;BaseDatabaseFactoryTest&lt;/code&gt; in &lt;code&gt;Umbraco.Tests&lt;/code&gt; has a method called &lt;code&gt;GetXmlContent&lt;/code&gt;.
It replaces the &lt;code&gt;umbraco.config&lt;/code&gt; file that acts as the cache at runtime.
It makes &lt;code&gt;UmbracoContext.Current.ContentCache&lt;/code&gt; tick in unit tests.
The base tests out of the box has a small flaw though. They can't &amp;quot;popuplate&amp;quot; properties.
All you get is the hierarchy.&lt;/p&gt;
&lt;p&gt;Usually I've injected an &lt;code&gt;IPublishedContentCache&lt;/code&gt; to my controllers. When testing them,
I've created a mock instance of the &lt;code&gt;IPublishedContentCache&lt;/code&gt;. However, all my code has to use
the non-context aware overloads. For instance &lt;code&gt;cache.GetById(umbracoContext, false, id)&lt;/code&gt;.
There's also a whole lot of ugly mocking code going on to set up queries and stubbed content.
How to stub properties on stubbed content is described in &lt;a href="/archive/slides-from-cg16-and-testing-ipublishedcontent-properties/"&gt;Slides from CG 2016 and testing IPublishedContent properties&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;So what's new?&lt;/h2&gt;
&lt;p&gt;As mentioned, I've been throwing around all kinds of ugly stubbing code for content and I've also been tampering with &lt;code&gt;Umbraco.Tests&lt;/code&gt;'s &lt;code&gt;GetXmlContent()&lt;/code&gt; to use the &amp;quot;built-in&amp;quot; content stubs.
It's all been done before in misc. tests in Umbraco. I finally got my s**t together and refactored all my setup spaghetti into a few small helpers on the &lt;code&gt;UmbracoSupport&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;Let's go over them in increasing &amp;quot;integrationness&amp;quot;.&lt;/p&gt;
&lt;h2&gt;Pure hierarchy&lt;/h2&gt;
&lt;p&gt;Your basic hierarchy structure can be set up by simply returning a string from an overload of &lt;code&gt;BaseDatabaseFactoryTest.GetXmlContent&lt;/code&gt;. &lt;code&gt;UmbracoSupport&lt;/code&gt; overloads this method and returns whatever you've set on the &lt;code&gt;UmbracoSupport.ContentCacheXml&lt;/code&gt; property. I recommend using the technique described in &lt;a href="/archive/automating-creation-of-source-data-for-tests"&gt;Automating creating of source data for tests&lt;/a&gt; with this. You can even extend that code to have fixture specific content caches.&lt;/p&gt;
&lt;p&gt;In any case, to make this work, you just need to set the XML in the setup method.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: I've got some probs with the markdown parsing here, imagine the CDATA parts of the XML is correctly written.&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[SetUp]
public void Setup()
{
    umbracoSupport = new UmbracoSupport();
    umbracoSupport.SetupUmbraco();

    // This XML is what the ContentCache will represent
    umbracoSupport.ContentCacheXml = @&amp;quot;
        &amp;lt;?xml version=&amp;quot;&amp;quot;1.0&amp;quot;&amp;quot; encoding=&amp;quot;&amp;quot;utf-8&amp;quot;&amp;quot;?&amp;gt;
        &amp;lt;!DOCTYPE root [
          &amp;lt;!ELEMENT contentBase ANY&amp;gt;
          &amp;lt;!ELEMENT home ANY&amp;gt;
          &amp;lt;!ATTLIST home id ID #REQUIRED&amp;gt;
          &amp;lt;!ELEMENT page ANY&amp;gt;
          &amp;lt;!ATTLIST page id ID #REQUIRED&amp;gt;
        ]&amp;gt;
        &amp;lt;root id=&amp;quot;&amp;quot;-1=&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;gt;
          &amp;lt;home id=&amp;quot;&amp;quot;1103=&amp;quot;&amp;quot;&amp;quot;&amp;quot; key=&amp;quot;&amp;quot;156f1933-e327-4dce-b665-110d62720d03=&amp;quot;&amp;quot;&amp;quot;&amp;quot; parentID=&amp;quot;&amp;quot;-1=&amp;quot;&amp;quot;&amp;quot;&amp;quot; level=&amp;quot;&amp;quot;1=&amp;quot;&amp;quot;&amp;quot;&amp;quot; creatorID=&amp;quot;&amp;quot;0=&amp;quot;&amp;quot;&amp;quot;&amp;quot; sortOrder=&amp;quot;&amp;quot;0=&amp;quot;&amp;quot;&amp;quot;&amp;quot; createDate=&amp;quot;&amp;quot;2017-10-17T20:25:12=&amp;quot;&amp;quot;&amp;quot;&amp;quot; updateDate=&amp;quot;&amp;quot;2017-10-17T20:25:17=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeName=&amp;quot;&amp;quot;Home=&amp;quot;&amp;quot;&amp;quot;&amp;quot; urlName=&amp;quot;&amp;quot;home=&amp;quot;&amp;quot;&amp;quot;&amp;quot; path=&amp;quot;&amp;quot;-1,1103=&amp;quot;&amp;quot;&amp;quot;&amp;quot; isDoc=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeType=&amp;quot;&amp;quot;1093=&amp;quot;&amp;quot;&amp;quot;&amp;quot; creatorName=&amp;quot;&amp;quot;Admin=&amp;quot;&amp;quot;&amp;quot;&amp;quot; writerName=&amp;quot;&amp;quot;Admin=&amp;quot;&amp;quot;&amp;quot;&amp;quot; writerID=&amp;quot;&amp;quot;0=&amp;quot;&amp;quot;&amp;quot;&amp;quot; template=&amp;quot;&amp;quot;1064=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeTypeAlias=&amp;quot;&amp;quot;home=&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;gt;
            &amp;lt;title&amp;gt;Welcome!&amp;lt;/title&amp;gt;
            &amp;lt;excerptCount&amp;gt;4&amp;lt;/excerptCount&amp;gt;
            &amp;lt;page id=&amp;quot;&amp;quot;1122=&amp;quot;&amp;quot;&amp;quot;&amp;quot; key=&amp;quot;&amp;quot;1cb33e0a-400a-4938-9547-b05a35739b8b=&amp;quot;&amp;quot;&amp;quot;&amp;quot; parentID=&amp;quot;&amp;quot;1103=&amp;quot;&amp;quot;&amp;quot;&amp;quot; level=&amp;quot;&amp;quot;2=&amp;quot;&amp;quot;&amp;quot;&amp;quot; creatorID=&amp;quot;&amp;quot;0=&amp;quot;&amp;quot;&amp;quot;&amp;quot; sortOrder=&amp;quot;&amp;quot;0=&amp;quot;&amp;quot;&amp;quot;&amp;quot; createDate=&amp;quot;&amp;quot;2017-10-17T20:25:12=&amp;quot;&amp;quot;&amp;quot;&amp;quot; updateDate=&amp;quot;&amp;quot;2017-10-17T20:25:17=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeName=&amp;quot;&amp;quot;Page=&amp;quot;&amp;quot; 1=&amp;quot;&amp;quot;&amp;quot;&amp;quot; urlName=&amp;quot;&amp;quot;page1=&amp;quot;&amp;quot;&amp;quot;&amp;quot; path=&amp;quot;&amp;quot;-1,1103,1122=&amp;quot;&amp;quot;&amp;quot;&amp;quot; isDoc=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeType=&amp;quot;&amp;quot;1095=&amp;quot;&amp;quot;&amp;quot;&amp;quot; creatorName=&amp;quot;&amp;quot;Admin=&amp;quot;&amp;quot;&amp;quot;&amp;quot; writerName=&amp;quot;&amp;quot;Admin=&amp;quot;&amp;quot;&amp;quot;&amp;quot; writerID=&amp;quot;&amp;quot;0=&amp;quot;&amp;quot;&amp;quot;&amp;quot; template=&amp;quot;&amp;quot;1060=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeTypeAlias=&amp;quot;&amp;quot;page=&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;gt;
              &amp;lt;title&amp;gt;Welcome!&amp;lt;/title&amp;gt;
              &amp;lt;excerpt&amp;gt;[CDATA[Lorem ipsum dolor...]]&amp;lt;/excerpt&amp;gt;
              &amp;lt;body&amp;gt;
                [CDATA[&amp;lt;p&amp;gt;Lorem ipsum dolor...&amp;lt;/p&amp;gt;]]
              &amp;lt;/body&amp;gt;
              &amp;lt;image&amp;gt;123&amp;lt;/image&amp;gt;
            &amp;lt;/page&amp;gt;
            &amp;lt;page id=&amp;quot;&amp;quot;1123=&amp;quot;&amp;quot;&amp;quot;&amp;quot; key=&amp;quot;&amp;quot;242928f6-a1cf-4cd3-ac34-f3ddf3526b2e=&amp;quot;&amp;quot;&amp;quot;&amp;quot; parentID=&amp;quot;&amp;quot;1103=&amp;quot;&amp;quot;&amp;quot;&amp;quot; level=&amp;quot;&amp;quot;2=&amp;quot;&amp;quot;&amp;quot;&amp;quot; creatorID=&amp;quot;&amp;quot;0=&amp;quot;&amp;quot;&amp;quot;&amp;quot; sortOrder=&amp;quot;&amp;quot;1=&amp;quot;&amp;quot;&amp;quot;&amp;quot; createDate=&amp;quot;&amp;quot;2017-10-17T20:25:12=&amp;quot;&amp;quot;&amp;quot;&amp;quot; updateDate=&amp;quot;&amp;quot;2017-10-17T20:25:17=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeName=&amp;quot;&amp;quot;Page=&amp;quot;&amp;quot; 2=&amp;quot;&amp;quot;&amp;quot;&amp;quot; urlName=&amp;quot;&amp;quot;page2=&amp;quot;&amp;quot;&amp;quot;&amp;quot; path=&amp;quot;&amp;quot;-1,1103,1123=&amp;quot;&amp;quot;&amp;quot;&amp;quot; isDoc=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeType=&amp;quot;&amp;quot;1095=&amp;quot;&amp;quot;&amp;quot;&amp;quot; creatorName=&amp;quot;&amp;quot;Admin=&amp;quot;&amp;quot;&amp;quot;&amp;quot; writerName=&amp;quot;&amp;quot;Admin=&amp;quot;&amp;quot;&amp;quot;&amp;quot; writerID=&amp;quot;&amp;quot;0=&amp;quot;&amp;quot;&amp;quot;&amp;quot; template=&amp;quot;&amp;quot;1060=&amp;quot;&amp;quot;&amp;quot;&amp;quot; nodeTypeAlias=&amp;quot;&amp;quot;page=&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;gt;
              &amp;lt;title&amp;gt;More welcome!&amp;lt;/title&amp;gt;
              &amp;lt;excerpt&amp;gt;[CDATA[More lorem ipsum dolor...]]&amp;lt;/excerpt&amp;gt;
              &amp;lt;body&amp;gt;[CDATA[Even more lorem ipsum dolor...]]&amp;lt;/body&amp;gt;
              &amp;lt;image&amp;gt;234&amp;lt;/image&amp;gt;
            &amp;lt;/page&amp;gt;
          &amp;lt;/home&amp;gt;
        &amp;lt;/root&amp;gt;
    &amp;quot;.Trim();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In our tests, we can now query by anything. The returned content has the hierarchy and everything, so we can traverse it with &lt;code&gt;Children()&lt;/code&gt;, &lt;code&gt;Parent()&lt;/code&gt; and whatnot.
The only missing piece is the properties. Here's a test showing that we have everything but the title property of Page 1:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const int Page1Id = 1122;

[Test]
public void Returns_Empty_Documents()
{
    var contentCache = umbracoSupport.UmbracoContext.ContentCache;
    var page1 = contentCache.GetById(Page1Id);

    Assert.That(page1, Is
        .Not.Null
        .And
        .InstanceOf&amp;lt;PublishedContentWithKeyBase&amp;gt;()
        .And
        .Property(&amp;quot;Name&amp;quot;).EqualTo(&amp;quot;Page 1&amp;quot;)
        .And
        .Matches&amp;lt;IPublishedContent&amp;gt;(c =&amp;gt; c[&amp;quot;title&amp;quot;] == null)
        .And
        .Property(&amp;quot;Parent&amp;quot;)
            .Property(&amp;quot;Children&amp;quot;)
                .With.Count.EqualTo(2)
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Don't be discouraged though. This method is excellent for testing URL providers, ContentFinders, Menus, Sitemaps. You name it. I know I've written my fair share of hierarchy traversing code or fancy XPath queries. Unless of course, you need property values.&lt;/p&gt;
&lt;p&gt;Instead of pulling your leg about it, here's how we fix that.&lt;/p&gt;
&lt;h2&gt;Put some meat on the content&lt;/h2&gt;
&lt;p&gt;The reason the properties are not there isn't because they weren't read. It's because the &lt;code&gt;XmlPublishedContent&lt;/code&gt; that we get out ultimately relies on the &lt;code&gt;PublishedContentType&lt;/code&gt; for it's respective document type. Luckily, all Umbraco's services are already stubbed up for us, so we can give it what it needs.&lt;/p&gt;
&lt;p&gt;The gory guts of it is that it needs an &lt;code&gt;IContentType&lt;/code&gt; from the &lt;code&gt;ContentTypeService&lt;/code&gt;. We can easily stub one up with Moq: &lt;code&gt;var contentType = Mock.Of&amp;lt;IContentType&amp;gt;()&lt;/code&gt;. Further, it uses the &lt;code&gt;IContentType.CompositionPropertyTypes&lt;/code&gt; collection to iterate the properties. These &lt;code&gt;PropertyType&lt;/code&gt; instances are actually completely dependency-less, so we can just create some:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Mock.Get(contentType)
    .Setup(t =&amp;gt; t.CompositionPropertyTypes)
    .Returns(new[] {
        new PropertyType(&amp;quot;Umbraco.TinyMCEv3&amp;quot;, DataTypeDatabaseType.Nvarchar, &amp;quot;body&amp;quot;)
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, we set it up on the &lt;code&gt;ContentTypeService&lt;/code&gt; stub:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Mock.Get(umbracoSupport.ServiceContext.ContentTypeService)
    .Setup(s =&amp;gt; s.GetContentType(alias))
    .Returns(contentType);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If only it were so easy. We depend on the &lt;code&gt;BaseWebTest&lt;/code&gt; class from &lt;code&gt;Umbraco.Tests&lt;/code&gt;. It sets up a content type factory that's being used somewhere in the hierarchy. It feeds &lt;code&gt;AutoPublishedContent&lt;/code&gt; instances instead of what we've stubbed up. We need to turn that off. There's a trick here. &lt;code&gt;UmbracoSupport&lt;/code&gt; should now live in an assembly called &lt;code&gt;Umbraco.UnitTests.Adapter&lt;/code&gt;. If you're pre 7.6.4 you need to go with &lt;code&gt;Umbraco.VisualStudio&lt;/code&gt;. This is because the factory we need to reset is internal to Umbraco. By having &lt;code&gt;UmbracoSupport&lt;/code&gt; in an assembly with one of these two names, we're able to do it. (Otherwise, you use reflection.) &lt;em&gt;By no means do this with production code. Just... forget it!&lt;/em&gt;&lt;br /&gt;
This paragraph should also get it's own blog post. :)&lt;/p&gt;
&lt;p&gt;But I digress. Here's the line you need to have the content use the &lt;code&gt;ContentTypeService&lt;/code&gt; to fetch its type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PublishedContentType.GetPublishedContentTypeCallback = null;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It's tempting to leave setup code like this lying around in all our &lt;code&gt;SetUp&lt;/code&gt; methods or even in our &amp;quot;Arrange&amp;quot; sections. I've sinned too much, so those few lines are now part of &lt;code&gt;UmbracoSupport&lt;/code&gt; and can be used to set up multiple types for your fixture or test.&lt;/p&gt;
&lt;p&gt;Here's a test that fetches the same document as before, but can now read properties:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Test]
public void With_DocumentTypes_Setup_Returns_Full_Blown_Documents()
{
    umbracoSupport.SetupContentType(&amp;quot;page&amp;quot;, new[]
    {
        new PropertyType(&amp;quot;textstring&amp;quot;, DataTypeDatabaseType.Nvarchar, &amp;quot;title&amp;quot;),
        new PropertyType(&amp;quot;textarea&amp;quot;, DataTypeDatabaseType.Nvarchar, &amp;quot;excerpt&amp;quot;),
        new PropertyType(&amp;quot;Umbraco.TinyMCEv3&amp;quot;, DataTypeDatabaseType.Nvarchar, &amp;quot;body&amp;quot;),
        new PropertyType(&amp;quot;media&amp;quot;, DataTypeDatabaseType.Integer, &amp;quot;image&amp;quot;)
    });

    var page1 = contentCache.GetById(Page1Id);

    Assert.Multiple(() =&amp;gt;
    {
        Assert.That(page1[&amp;quot;title&amp;quot;], Is.EqualTo(&amp;quot;Welcome!&amp;quot;));
        Assert.That(page1[&amp;quot;excerpt&amp;quot;], Is.EqualTo(&amp;quot;Lorem ipsum dolor...&amp;quot;));
        Assert.That(page1[&amp;quot;body&amp;quot;].ToString(), Is.EqualTo(&amp;quot;&amp;lt;p&amp;gt;Lorem ipsum dolor...&amp;lt;/p&amp;gt;&amp;quot;));
        Assert.That(page1[&amp;quot;image&amp;quot;], Is.EqualTo(123));
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice the .ToString() on the body. It's actually not a string, but some weird dynamic Umbraco thingy. I never saw that type before, but I didn't pursue it in time for this post. I don't want anything to do with it though, so let's storm on to the grand finale.&lt;/p&gt;
&lt;h2&gt;Let's make them strong already!&lt;/h2&gt;
&lt;p&gt;We're finally there. The last piece of the puzzle. Strongly typed content!&lt;/p&gt;
&lt;p&gt;It's managed by two resolvers: &lt;code&gt;PublishedContentModelFactoryResolver&lt;/code&gt; and &lt;code&gt;PropertyValueConvertersResolver&lt;/code&gt;. I won't go into details about those now, but suffice to say all resolvers have to be initialized before &lt;code&gt;BaseWebTest.Initialize&lt;/code&gt; and its ancestors.
I've added an &lt;code&gt;InitializeResolvers&lt;/code&gt; method to the &lt;code&gt;UmbracoSupport&lt;/code&gt; class where these two are initialized. The &lt;code&gt;PublishedContentModelFactoryResolver&lt;/code&gt; is set to a &lt;code&gt;FakeModelFactoryResolver&lt;/code&gt; that lets you register constructors for document type aliases. &lt;a href="https://github.com/lars-erik/umbraco-unit-testing-samples/blob/master/Umbraco.UnitTesting.Adapter/Support/FakeTypedModelFactory.cs"&gt;The code for this is available in my &amp;quot;Umbraco unit testing samples&amp;quot; repo on github&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;To set up property value converters, we also need to do that before registering the resolver. The resolver takes all the converters as constructor arguments. I've added a list of those types as a property on &lt;code&gt;UmbracoSupport&lt;/code&gt;, so we can add &lt;code&gt;IPropertyValueConverter&lt;/code&gt; implementing types before calling &lt;code&gt;UmbracoSupport.SetupUmbraco&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[SetUp]
public void Setup()
{
    umbracoSupport = new UmbracoSupport();

    // Converter types need to be added before setup
    umbracoSupport.ConverterTypes.Add(typeof(TinyMceValueConverter));

    umbracoSupport.SetupUmbraco();

    //...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To register the typed model, there's just one line you can do in your setup, or even in your tests. Here I've refactored out the setup for the content type from earlier, and I register a model type for the document type alias:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private void SetupContentType()
{
    umbracoSupport.SetupContentType(&amp;quot;page&amp;quot;, new[]
    {
        new PropertyType(&amp;quot;textstring&amp;quot;, DataTypeDatabaseType.Nvarchar, &amp;quot;title&amp;quot;),
        new PropertyType(&amp;quot;textarea&amp;quot;, DataTypeDatabaseType.Nvarchar, &amp;quot;excerpt&amp;quot;),
        new PropertyType(&amp;quot;Umbraco.TinyMCEv3&amp;quot;, DataTypeDatabaseType.Nvarchar, &amp;quot;body&amp;quot;),
        new PropertyType(&amp;quot;media&amp;quot;, DataTypeDatabaseType.Integer, &amp;quot;image&amp;quot;)
    });
}

[Test]
public void With_DocumentTypes_And_Models_Setup_Returns_Fully_Functional_Typed_Content()
{
    SetupContentType();

    // Register strongly typed models with the ModelFactory
    umbracoSupport.ModelFactory.Register(&amp;quot;page&amp;quot;, c =&amp;gt; new Page(c));

    var page1 = contentCache.GetById(Page1Id);

    Assert.That(page1, Is
        .InstanceOf&amp;lt;Page&amp;gt;()
        .And.Property(&amp;quot;Body&amp;quot;)
            .Matches&amp;lt;IHtmlString&amp;gt;(s =&amp;gt; 
                s.ToString() == &amp;quot;&amp;lt;p&amp;gt;Lorem ipsum dolor...&amp;lt;/p&amp;gt;&amp;quot;
            )
    );
}

public class Page : PublishedContentModel
{
    public Page(IPublishedContent content) : base((IPublishedContentWithKey)content)
    {
    }

    public string Title =&amp;gt; Content.GetPropertyValue&amp;lt;string&amp;gt;(&amp;quot;title&amp;quot;);
    public string Excerpt =&amp;gt; Content.GetPropertyValue&amp;lt;string&amp;gt;(&amp;quot;excerpt&amp;quot;);
    public IHtmlString Body =&amp;gt; Content.GetPropertyValue&amp;lt;IHtmlString&amp;gt;(&amp;quot;body&amp;quot;);
    public int Image =&amp;gt; Content.GetPropertyValue&amp;lt;int&amp;gt;(&amp;quot;image&amp;quot;);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There you go! There's nothing more to it. Well, there is...&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Page&lt;/code&gt; class here is bundled with the test. If we use a common interface both for our runtime model and our test model, we're safe. But we should really use the runtime models. This means you shouldn't use &lt;em&gt;runtime generated&lt;/em&gt; models. &lt;a href="https://github.com/zpqrtbnk/Zbu.ModelsBuilder/wiki/Install-And-Configure"&gt;Go through the instructions for ModelsBuilder&lt;/a&gt; to have your models compiled and accessible from the tests.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;And although the XML is pretty ugly, you can flush it out into files bundled with your tests. You can also exploit the umbraco.config file and just copy segments from there into your test source files. That way, you spend no time writing the stubs, and the content is cleanly separated from your tests.&lt;/p&gt;
&lt;p&gt;That's &lt;em&gt;really&lt;/em&gt; all there is to it! It is. Now go test a bit, or a byte, or a string, or even a &lt;a href="/archive/testing-views-with-razorgenerator/"&gt;view&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/lars-erik/umbraco-unit-testing-samples/tree/master/Umbraco.UnitTesting.Adapter/Support"&gt;The new version of UmbracoSupport including the fake model factory is available here.&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Tue, 17 Oct 2017 21:18:06 Z</pubDate>
      <a10:updated>2017-10-17T21:18:06Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1070</guid>
      <link>https://blog.aabech.no/archive/building-a-spell-checker-for-search-in-umbraco/</link>
      <category>umbraco</category>
      <category>search</category>
      <category>lucene</category>
      <category>examine</category>
      <title>Building a spell checker for search in Umbraco</title>
      <description>&lt;p&gt;I spent the day building a spell checker for a search UI I've been improving. Turns out it was pretty easy when leaning on &lt;a href="https://lucenenet.apache.org/index.html"&gt;Lucene.Net Contrib&lt;/a&gt;.
I'll show you the gist of it in this article.&lt;/p&gt;
&lt;p&gt;Make sure you have some nice proofed data to work with tough. While writing the tests for my checker, I kept getting silly suggestions and wrong results. Turned out the data itself had quite a few typos. On the bright side, it allowed us to fix the typos.&lt;/p&gt;
&lt;h3&gt;Building a dictionary&lt;/h3&gt;
&lt;p&gt;So the first thing you need to provide spell checking is a dictionary. For my solution I went with using all the words that exists in the site so I wouldn't suggest words that don't have results. We already have something that provides this functionality, namely &lt;a href="https://github.com/Shazwazza/Examine"&gt;Examine&lt;/a&gt;. Examine lets you add indexes with custom indexers, and that's a perfect fit for our needs. This dictionary however only needs one field: word.&lt;/p&gt;
&lt;p&gt;Here's the basic code for an indexer that indexes all the words in a site:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class SpellCheckIndexer : BaseUmbracoIndexer
{
    // May be extended to find words from more types
    protected override IEnumerable&amp;lt;string&amp;gt; SupportedTypes
    {
        get
        {
            yield return IndexTypes.Content;
        }
    }

    protected override void AddDocument(Dictionary&amp;lt;string, string&amp;gt; fields, IndexWriter writer, int nodeId, string type)
    {
        var doc = new Document();
        List&amp;lt;string&amp;gt; cleanValues = new List&amp;lt;string&amp;gt;();

        // This example just cleans HTML, but you could easily clean up json too
        CollectCleanValues(fields, cleanValues);
        var allWords = String.Join(&amp;quot; &amp;quot;, cleanValues);

        // Make sure you don't stem the words. You want the full terms, but no whitespace or punctuation.
        doc.Add(new Field(&amp;quot;word&amp;quot;, allWords, Field.Store.NO, Field.Index.ANALYZED));

        writer.UpdateDocument(new Term(&amp;quot;__id&amp;quot;, nodeId.ToString(CultureInfo.InvariantCulture)), doc);
    }

    protected override IIndexCriteria GetIndexerData(IndexSet indexSet)
    {
        var indexCriteria = indexSet.ToIndexCriteria(DataService);
        return indexCriteria;
    }

    private void CollectCleanValues(Dictionary&amp;lt;string, string&amp;gt; fields, List&amp;lt;string&amp;gt; cleanValues)
    {
        var values = fields.Values;
        foreach (var value in values)
            cleanValues.Add(CleanValue(value));
    }

    private static string CleanValue(string value)
    {
        return HttpUtility.HtmlDecode(value.StripHtml());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To make it actually create an index you have to add it and an IndexSet to Examine's configuration. &lt;/p&gt;
&lt;p&gt;/config/ExamineSettings.config:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Examine&amp;gt;
    &amp;lt;ExamineIndexProviders&amp;gt;
        &amp;lt;providers&amp;gt;

                  &amp;lt;!-- Existing providers... --&amp;gt;

                  &amp;lt;add name=&amp;quot;SpellCheckIndexer&amp;quot; type=&amp;quot;YourAssembly.SpellCheckIndexer, YourAssembly&amp;quot;
                      analyzer=&amp;quot;Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net&amp;quot;
                  /&amp;gt;
        &amp;lt;/providers&amp;gt;
    &amp;lt;/ExamineIndexProviders&amp;gt;
    &amp;lt;!-- Search Providers - configured later --&amp;gt;
&amp;lt;/Examine&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;/config/ExamineIndex.config:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ExamineLuceneIndexSets&amp;gt;
    &amp;lt;IndexSet SetName=&amp;quot;SpellCheckIndexSet&amp;quot; IndexPath=&amp;quot;~/App_Data/TEMP/ExamineIndexes/{machinename}/SpellCheck/&amp;quot;&amp;gt;
        &amp;lt;IndexAttributeFields&amp;gt;
            &amp;lt;add Name=&amp;quot;nodeName&amp;quot;/&amp;gt;
        &amp;lt;/IndexAttributeFields&amp;gt;
        &amp;lt;IndexUserFields&amp;gt;
            &amp;lt;!-- Add the properties you want to extract words from here --&amp;gt;
            &amp;lt;add Name=&amp;quot;body&amp;quot;/&amp;gt;
            &amp;lt;add Name=&amp;quot;summary&amp;quot;/&amp;gt;
            &amp;lt;add Name=&amp;quot;description&amp;quot;/&amp;gt;
        &amp;lt;/IndexUserFields&amp;gt;
    &amp;lt;/IndexSet&amp;gt;
&amp;lt;/ExamineLuceneIndexSets&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we're actually ready to create a word index. Open the backoffice and the developer section. Navigate to the Examine Management tab. You should see the &amp;quot;SpellCheckIndexer&amp;quot;. Click it and select &amp;quot;Index info &amp;amp; tools&amp;quot;. You might already have documents in the index. If so, we're good to go, otherwise click &amp;quot;Rebuild index&amp;quot;. If you want, you can have a look at the data using &lt;a href="http://www.getopt.org/luke/"&gt;Luke&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1003/luke.png" alt="Indexed terms shown with Luke" /&gt;&lt;/p&gt;
&lt;h3&gt;Casting the spell&lt;/h3&gt;
&lt;p&gt;Now we're ready to let the Lucene Contrib &lt;code&gt;SpellChecker&lt;/code&gt; do its magic. It needs to get the dictionary from our index, so let's give it a searcher from Exmine. We'll configure that as a regular searcher in ExamineSettings.config:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ExamineSearchProviders defaultProvider=&amp;quot;ExternalSearcher&amp;quot;&amp;gt;
    &amp;lt;providers&amp;gt;
        &amp;lt;add name=&amp;quot;SpellCheckSearcher&amp;quot;
            type=&amp;quot;UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine&amp;quot;
            analyzer=&amp;quot;Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net&amp;quot;
        /&amp;gt;
    &amp;lt;/providers&amp;gt;
&amp;lt;/ExamineSearchProviders&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we've got everything we need to build the checker. I've written some unit-tests for it, so the constructor takes a &lt;code&gt;BaseLuceneSearcher&lt;/code&gt; as an argument. For testing, I just create one from an index I know exists. For Umbraco I instantiate it as a singleton using the searcher from Examine.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class UmbracoSpellChecker
{
    private static readonly object lockObj = new object();
    private static UmbracoSpellChecker instance;
    public static UmbracoSpellChecker Instance
    {
        get
        {
            lock(lockObj)
            { 
                if (instance == null)
                {
                    instance = new UmbracoSpellChecker((BaseLuceneSearcher)ExamineManager.Instance.SearchProviderCollection[&amp;quot;SpellCheckSearcher&amp;quot;]);
                    instance.EnsureIndexed();
                }
            }
            return instance;
        }
    }

    private readonly BaseLuceneSearcher searchProvider;
    private readonly SpellChecker.Net.Search.Spell.SpellChecker checker;
    private readonly IndexReader indexReader;
    private bool isIndexed;

    public UmbracoSpellChecker(BaseLuceneSearcher searchProvider)
    {
        this.searchProvider = searchProvider;
        var searcher = (IndexSearcher)searchProvider.GetSearcher();
        indexReader = searcher.GetIndexReader();
        checker = new SpellChecker.Net.Search.Spell.SpellChecker(new RAMDirectory(), new JaroWinklerDistance());
    }

    private void EnsureIndexed()
    {
        if (!isIndexed)
        { 
            checker.IndexDictionary(new LuceneDictionary(indexReader, &amp;quot;word&amp;quot;));
            isIndexed = true;
        }
    }

    public string Check(string value)
    {
        EnsureIndexed();

        var existing = indexReader.DocFreq(new Term(&amp;quot;word&amp;quot;, value));
        if (existing &amp;gt; 0)
            return value;

        var suggestions = checker.SuggestSimilar(value, 10, null, &amp;quot;word&amp;quot;, true);

        var jaro = new JaroWinklerDistance();
        var leven = new LevenshteinDistance();
        var ngram = new NGramDistance();

        var metrics = suggestions.Select(s =&amp;gt; new
        {
            word = s,
            freq = indexReader.DocFreq(new Term(&amp;quot;word&amp;quot;, s)),
            jaro = jaro.GetDistance(value, s),
            leven = leven.GetDistance(value, s),
            ngram = ngram.GetDistance(value, s)
        })
        .OrderByDescending(metric =&amp;gt;
            (
                (metric.freq/100f) +
                metric.jaro +
                metric.leven +
                metric.ngram
            )
            / 4f
        )
        .ToList();

        return metrics.Select(m =&amp;gt; m.word).FirstOrDefault();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The constructor keeps a reference to our word index and creates a SpellChecker that will do it's work in memory. When we first search for suggestions, &lt;code&gt;EnsureIndex&lt;/code&gt; passes our word index to the &lt;code&gt;SpellChecker&lt;/code&gt; and lets it create it's magic &amp;quot;back-end&amp;quot;. It could also be on disk, but for this site the performance is good enough to do it live.&lt;/p&gt;
&lt;p&gt;The only suggestion code you actually need in &lt;code&gt;Check&lt;/code&gt; is basically just:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        var suggestion = checker.SuggestSimilar(value, 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It will give you a feasible word if the value has a typo. However, in many cases it's not the one you're after. You can increase the number of suggestions you want to get a few more, but for search suggestions, we really just want one. Changing the &lt;code&gt;StringDistance&lt;/code&gt; algorithm passed to the &lt;code&gt;SpellChecker&lt;/code&gt; also varies the output, so you should experiment with that.&lt;/p&gt;
&lt;p&gt;In my case there was a typo in the source data. I was testing against the Norwegian word for bathtub: &amp;quot;badekar&amp;quot;. My test phrase was &amp;quot;badkear&amp;quot; and I kept getting suggestions for &amp;quot;badkar&amp;quot;. That word snuck in there due to one spelling mistake in one document. So I figured word frequency should trump. But sorting the suggestions by word frequency turned out to be a bad idea. &amp;quot;Baderom&amp;quot;, the Norwegian word for &amp;quot;bathroom&amp;quot;, is more frequent and won over &amp;quot;badekar&amp;quot; that I was after.&lt;/p&gt;
&lt;p&gt;I spun up all the string distance algorithms and put the results, including the document frequency of the terms in Excel. Experimenting a bit showed that the frequency divided by 100 added to the sum of the distance results was a good metric. After ordering by that result and taking the first, my checker is pretty intelligent when providing suggestions.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1004/spellcheck_excel.png" alt="Evaluating algorithm with Excel" /&gt;&lt;/p&gt;
&lt;h3&gt;Getting results&lt;/h3&gt;
&lt;p&gt;Here's a snippet from the search controller that builds up the response model:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var spellChecker = UmbracoSpellChecker.Instance; 
var checkedTerms = phrase.Split(' ').Select(t =&amp;gt; spellChecker.Check(t));
var didYouMean = String.Join(&amp;quot; &amp;quot;, checkedTerms);
result.DidYouMean = didYouMean;

// Uses Lucene's TopScoreDocCollector
var totalHits = GetTotalHits(query);

if (result.DidYouMean != phrase)
{
    if (totalHits == 0)
    {
        query = CreateQuery(result.DidYouMean);
        totalHits = GetTotalHits(query);
        result.Modified = true;
        result.Query = result.DidYouMean;
    }
    else
    {
        result.HasAlternative = true;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When searching for &amp;quot;badkear&amp;quot; now, I get &lt;code&gt;result.Modified == true&lt;/code&gt;. I didn't get any hits for that word, but my spell checker found the word &amp;quot;badekar&amp;quot;. I can happily go search for that and tell my user I modified his search. &amp;quot;Did not find any hits for 'badkear', showing results for 'badekar'.&lt;/p&gt;
&lt;p&gt;When searching for &amp;quot;dujs&amp;quot;, a misspelled version of the Norwegian word for &amp;quot;shower&amp;quot;, I find that we have another typo in our data. I get &lt;code&gt;result.Modified == false&lt;/code&gt;, but &lt;code&gt;result.HasAlternative == true&lt;/code&gt;. My spell checker dutifully asks if I ment &amp;quot;dusj&amp;quot;. &amp;quot;Showing 1 result. Did you mean 'dusj'?&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.aabech.no/media/1005/dujs.png" alt="Did you mean dusj?" /&gt;&lt;/p&gt;
&lt;p&gt;There's a lot more you can do with this to provide even more accurate suggestions. For my purposes however, this was all I needed. Leaning on Lucene Contrib when you need some fancy search functionality will almost always save the day. &lt;/p&gt;
&lt;p&gt;If you want to know more about Lucene, I recommend getting the book called &amp;quot;Lucene in Action&amp;quot;.&lt;/p&gt;
</description>
      <pubDate>Fri, 13 May 2016 13:19:11 Z</pubDate>
      <a10:updated>2016-05-13T13:19:11Z</a10:updated>
    </item>
  </channel>
</rss>