<?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">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">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>
  </channel>
</rss>