Skip to main content

Posts

URL Segment Customisation with Umbraco 15.4

We had an interesting request for customisation of URL structure come into the team that we developer a solution for for 15.4. You'll find it documented here but I thought it was useful to expand on the particular use case and how we used this feature to meet it in a blog post. The requirement came from SEO optimization, where there was an ask to have a particular URL structure, where the path segments for a given page were different based on whether it was a landing or detail page. To illustrate, they were looking to do something like this: Software /software Business Software /software/business-software HR Software /software/business/hr-software Payroll Software /software/business/hr/payroll-software Recruitment Software /software/business/hr/recruitment-software So taking the "HR Software" page, the URL segment would be "hr-software" when rendering the page itself. But for child page...

Personalisation Groups for Umbraco 14

Nearly a year ago now, I started a series of blog posts looking to migrate a package to Umbraco 14. In hindsight, that was a little premature... both in terms of stability (platform) and ability (my skills with modern front-end). So whilst I made some progress, it was slow going and led to a few occasions of getting stuck. Then the day job called, and priority needed to be getting Umbraco's commercial products ready for Umbraco 14, for which we are almost there. I took a recent "cycle hack" at work to see if I could go back to the personal package, and, based on what I've learnt, get that released for Umbraco 14. Which I've now done. You can find the release candidate for the "Personalisation Groups" package here on NuGet . Am pleased to say it was a lot quicker and easier to make progress coming back to it now. Whilst the package isn't particularly complicated compared to some others in the Umbraco community, it's probably at a useful s...

Codegarden Talk - Building Packages with Umbraco 14

I'm talking at Umbraco's Codegarden this year, sharing some of what I've learnt in migrating our commercial products to Umbraco 14. As I'll mention in the talk, there are a few code samples that I'll probably have to go over a bit quickly, so if anyone is interested in viewing them with a bit more time, or using them for reference, I'll share them here. The slides are available here . And if you want to read what I hopefully managed to say... please see the speaker notes. The talk was recorded, so should be available at some point to on the Umbraco Events app as well as the Umbraco YouTube channel .

Verifying Mock Parameters

Found a use case for a feature of the .NET mocking framework Moq that may not be that well known, and was new to me at least. I had a method under test that - via a number of overloaded extension methods - called an underlying method in the Umbraco CMS. The details aren't really important, but specifically it was the method GetImageUrl on IImageUrlGenerator that I was mocking to return a known output. I was then testing how my method used that result it in it's processing. I could see the method failing when I had a setup like this: But passed with this: So clearly we weren't passing in the Height parameter that I was expecting. One way to solve this would be to get the Umbraco code locally and step into it, but I found another way that I read about on this closed issue for the Moq library. It provides a means of capturing the parameters passed to a mocked method, and then establishing what they are via a breakpoint or logging. That revealed that so...

Upgrading Terraform Resources

One of the projects I currently work on consists of a few components - an API, a worker process, a couple of web applications and a serverless functions app - all of which are deployed to Azure using infrastrure as code defined as Terraform resources . We have recently been upgrading it from .NET 6 to .NET 8 and hit an issue when we tried to update the framework definition of the Azure app service resources defined in Terraform. The attribute in question only accepted up to .NET 6. The reason is that the resource we were using - azurerm_app_service - is now deprecated and replaced with azurerm_windows_web_app (or azurerm_linux_web_app ). It was a similar case for the app service plan ( azurerm_app_service_plan replaced with azurerm_service_plan ) and the functions app ( azurerm_function_app replaced with azurerm_windows_function_app ). Naively, my first thought was to just update our infrastructure configuration to use the newer resources, and deploy that update. However, don...

Adding and Deleting Criteria

This is one of a series of posts looking at migrating Umbraco packages to Umbraco 14 and the new backoffice. Other posts in this series: Introduction Upgrading to Umbraco 14 Preview Creating a Property Editor With Umbraco 14 Adding and Deleting Criteria As of last time I posted in this series, I had a partially working property editor for Personalisation Groups. It could display the information stored against the property, and I'd solved a couple of challenges around retrieving external data and injecting scripts dynaically at runtime. There's not been too much progress since, but I've picked up a few more things along the way that I'll include as a bit of a "grab-bag" in this post. First step to make the data editable was wiring up some button clicks. In angularjs we are used to: <button type="button" ng-click="delete($index)">Delete</button> With Lit, the syntax is: <button type="b...

Creating a Property Editor With Umbraco 14

This is one of a series of posts looking at migrating Umbraco packages to Umbraco 14 and the new backoffice. Other posts in this series: Introduction Upgrading to Umbraco 14 Preview Creating a Property Editor With Umbraco 14 Adding and Deleting Criteria A "Hello World" Property Editor The Umbraco documentation is a good guide for getting started, with details on creating an extension and creating a property editor . Using the scripts provided I created an extension within a folder created in my main package project that I called client-src . npm create vite@latest -- --template lit-ts personalisation-groups cd personalisation-groups npm install npm install -D @umbraco-cms/backoffice@next This sets up some files that make up an extension to the backoffice, using the latest preview release from the Umbraco prereleases feed. Next step as described in the docs is to add a vite.config.ts file. I set mine up to export the built files rather than to t...

Upgrading to Umbraco 14 Preview

This is one of a series of posts looking at migrating Umbraco packages to Umbraco 14 and the new backoffice. Other posts in this series: Introduction Upgrading to Umbraco 14 Preview Creating a Property Editor With Umbraco 14 Adding and Deleting Criteria Prerequisites As indicated in the official documentation , to work with Umbraco 14 it's likely your development machine needs some updates, which was the case for me. You'll need: To be running .NET 8, which is available at the time of writing in a first release candidate . To be on at least the v17.8 latest preview version of Visual Studio. To download and install this you may need to change the channel used by the installer . To install a minimum version of Node.js 18.16. I have Node Version Manager for Windows installed, which is handy tool both for installing new versions and also switching between versions that you may need for different projects. Package Update The package I'm worki...

First Steps with Umbraco 14

Probably the largest change coming in the Umbraco ecosystem is the development of a new backoffice , removing the dependency on the legacy angularjs and moving to a modern front-end stack based on web components and Typescript. Not just for HQ in the work needed to update the CMS itself and associated commercial products. But also for the community, whether that be package developers or custom solution implementors looking to extend the backoffice. It reminds me a little of the time coming up to Umbraco 9, the first version running on modern .NET. There was a lot of collbarative effort and information sharing then, as many people were learning new technology and ways of doing things. I'm hoping the next nine months or so leading up to Umbraco 14 will be a similar experience. Although I'm now working at HQ, I'm in a similar position to many in finding a lot of the change new and something I'm going to need to get up to speed with. Like, I suspect, a number of Umbraco...

Migrating An API from Newtonsoft.Json to System.Text.Json

In some recent work with Umbraco I’ve been looking to migrate an API from using the Newtonsoft.Json serialization library to the newer, Microsoft one, System.Text.Json . The reason for doing this was to align the API we created for Umbraco Forms with the content delivery API available in Umbraco 12. We’re keen to ensure these APIs across Umbraco products are similar both in terms of behaviour but also behind the scenes when it comes to the libraries we are using. As such I had a few updates to make – mostly straightforward, and some that needed a bit more research and development. Deserialization via a Model Binder When a form is submitted, a model binder is referenced in the controller’s action method to deserialize the incoming request to a strongly typed model: Within the model binder we had the following code to deserialize the request into the appropriate type: To convert this it was just necessary to change JsonConvert.DeserializeObject to JsonSerializer.Deser...

Introducing Redis and Azure Cognitive Search to Improve API Performance

Cross-posting a couple of articles written for the Umbraco blog on the introduction of Redis Distributed Cache and Azure Cognitive Search to the Umbraco Marketplace , in order to improve performance and functionality: Introducing Redis Distributed Cache to the Umbraco Marketplace Populating and Querying Azure Cognitive Search in the Umbraco Marketplace

Programmatically Creating a Record With Umbraco Forms

Umbraco Forms is a commercial add-on for Umbraco providing an editor interface for creating and managing forms. These forms can then be hosted on the website for completion by site visitors, with the entries available for view in the Umbraco backoffice. That describes the usual use-case, but it is also possible to create form submissions - known as records - for a form programatically. Posting for future reference, this illustrative example for Forms 10 shows how this is done:

Use PostConfigure For Default Configuration of Collections in ASP.NET

This post contains a couple of topics that came together in a recent update I was making - one a gotcha, and one a solution, that as well as addressing this issue has wider application. In my web application there was some configuration that consisted of a list of elements. This was represented in code with a POCO like this: Which can then be injected using IOptions<MySettings> into the classes that need it. And in configuration, via the appSettings.json file, you can provide the values: So far so good, but now I wanted to set some default values for this configuration. If nothing is provided, I wanted a non-empty list to be used as the default. But if the user has configured something for the setting, then that should be used. I figured I could just do the following, setting an initial collection on the class, which would be use unless overridden by a value provided in configuration: Unfortunately this doesn't work as I expected as was pointed out to me ...

Handling Umbraco Events After Deploy Operations

I had a question from an partner Umbraco raised for me this week, that's available at this forum topic . They had some code running in a notification handler running when dictionary items were saved, and found this wasn't firing when the item was saved following an Umbraco Deploy operation. I responded that this is actually expected behaviour - as Deploy supresses events being fired on individual save and publish events when transferring items. This implementation decision was made I understand for performance reasons. In the back-office, the usual case for a save of an item is one-at-a-time, but with a deployment, there could be hundreds of updates within an operation. However, what if you do want to run some code on the save of some Umbraco data, even if this is happening as part of a Deploy operation? There's an option here using cache refresher notifications. Not all events are suppressed by Umbraco Deploy - some that are batched up and fired after the deploy o...

What Content Broke My Restore?

Just something I want to keep track of... From a support issue with Umbraco Deploy on Umbraco 8, a customer was getting a failure when restoring, which stemmed from a JSON serialization failure when generating the Umbraco Deploy artifact. It was a bulk restore though, so tricky to figure out which content was causing the problem. And as this serialization is happening in the upstream environment being restored from, a local instance and debugging doesn't help. This hacky code dumped in a view was useful to find out:

Cache Busting Back-Office Client-Side Assets With Umbraco 9+

Since I started at Umbraco the link I've shared the most when helping with support issues has been a blog post article by Dennis Adofi titled "Bumping The Client Dependency Version" . It describes the method used to ensure caches are cleared for client-side assets in the back-office for Umbraco versions up to 8. There's a similar setting for Umbraco 9+ which I've recently had to look up a few times. The configuration setting is at: Umbraco : CMS : RuntimeMinification: Version and is set to a numeric value. It's documented here and, as described, uses a similar version number that can be increment manually or via a build process to ensure the same cache busting behaviour. When upgrading Umbraco to a new version of the CMS you don't need to worry about this, as the version running is already used in the hash that is generated for the cache key. But this doesn't take into account package installs, or your own custom extensions to the back-office....

A quick post on view model mapping

I had a question about options for mapping Umbraco content to view models come up today, and given my response in Slack was getting a bit long and I'm sure I'll need to refer to it again, decided to create a post instead. So what follows is a quick summary of the history and options for adopting a pattern of mapping Umbraco content to a strongly typed view model. It's not intended to be fully comprehensive... am just saving my keystrokes . Around the time of Umbraco 6 or 7, some colleagues and I from Zone released Umbraco Mapper , which used a combination of convention and configuration to allow for these mapping operations to be made in code. We used it in a fair few projects and liked the approach, and, judging from some feedback, a number of others from the Umbraco community did too. Just after, though likely in use or development concurrently, was Ditto released by Lee Kelleher and Matt Brailsford. This did a similar job, and it gained a fair bit of traction in...

Using SQL Profiler To Identify Repeated SQL Calls

This week I've been looking into some optimisations for a long-running process that chats to the database. Within the operation, the data isn't expected to change, so it would be reasonable that, where we make repeated calls, we cache the values and re-use them for the duration of the operation. I've been using SQL Profiler to identify them and wanted to blog the method for reference. First, start up SQL Profiler and create a new trace. Connect to the database and define the Events Selection. I kept most things related to data reads and writes: I then ran the application, set a break-point in the code at the point where afterward I was interested in the results, and attached the debugger. On hitting the breakpoint, I started the trace and continued the code execution. When the operation was complete I could stop the trace. To analyse the data, I saved it to a new table in a database I created to store the results in, via File > Save As... > Trace Table ...

Customising the Umbraco Pipeline

The excuse for today's post is I need somewhere to write up some findings from an Umbraco support case I've been looking into. A customer was using an external library that provided middleware that needed to be configured between UseRouting() and UseEndpoints() . Which isn't a problem if you have full control over the contents of the StartUp.cs class, but it's not so easy when Umbraco is doing some of this setup for you. Thanks to Benjamin Carleski from the Umbraco community who figured this out and shared it in this forum conversation . Nothing is really different from his answer on setting up CORS, but in this post I can more easily and permanently share the sample code. Assuming we have a library that requires a typical "Add..." addition in the ConfigureServices method and "Use..." in the Configure method of Startup.cs . First we need a pipeline filter class: Then a class responsible for inserting this filter in the pipeline: An...

Pushing Updates to a PR

This is unashamedly a "note to self" post... something I occasionally need to do, and always need to ask about or look-up. As a maintainer of an open-source project on GitHub, an incoming PR from a contributor's fork that needs some minor changes before merging can be dealt with by committing changes directly to the branch on the fork, if the contributor has allowed edits from maintainers . To checkout the branch locally: git fetch origin pull/[pr id]/head:[branch name] git checkout [branch name After making changes, to push them back to the branch on the fork: git remote add [remote name] addremote [fork url] git push [remote name] [branch name]