Make content available in Json
# help-with-umbraco
t
Hi I have a very old Umbraco 7 being used internally. It's not possible to upgrade it but we need all of the data to be available in an Json format. Are there anyways to have the entire site/structure be available in a Json format? Thanks
a
I build this package just for that: https://github.com/limbo-works/Limbo.Umbraco.MigrationsApi/ To get the entire site structure you can call something like
/umbraco/Limbo/Migrations/GetContentAtRoot?maxLevel=999
The endpoint does however only expose property data for the first level of nodes. But children/descendants can be requested specifically - eg.
/umbraco/Limbo/Migrations/GetContentById?id=1234
I've been using this for a handful og migrations along with https://github.com/limbo-works/Limbo.Umbraco.MigrationsClient which essentially is a wrapper for the API.
t
Thank you. I will give this a go
@Anders Bjerner 1. is there a way to have recursive enabled so it can get the children? 2. How can I convert the objects (Legacy Content) into my own models?
a
1) A call like
/umbraco/Limbo/Migrations/GetContentAtRoot?maxLevel=999
would give you the entire site structure. But the returned objects will only contain basic information about each page - not the properties of each page. If you request more information about a specific page - eg.
/umbraco/Limbo/Migrations/GetContentById?id=1234
you will get a larger object, including the properties of the page. 2) I think this depends a lot on your setup. Personally I've used my Limbo.Umbraco.Migrations package for this: https://github.com/limbo-works/Limbo.Umbraco.Migrations The package contains classes representing models for some of Umbraco's property editors - eg. the block list or a media picker: https://github.com/limbo-works/Limbo.Umbraco.Migrations/tree/v1/main/src/Limbo.Umbraco.Migrations/Models When serialized to JSON (using JSON.net), the JSON values should match what Umbraco is saving when you make changes via the backoffice. Unfortunately the package is primarily something I've used internally, so there isn't any documentation. Ideally there should be, but my time has been taken up by other stuff.
t
Ok I think I managed to figure it out, @Anders Bjerner Another weird anomaly I've come across and I'm not sure if I've done something wrong or missed a setting. When I make a call to get the data by content ID using MigrationsApi I get the Json returned in a format. When I install Migrations Client and then call getContentById targeting the same ID the Json is returned in a different format? I was hoping for the same Json from the migrations client? Any reason why?
a
@TigerMan Can you elaborate on this? I'm not sure I understand the issue
t
@Anders Bjerner yes so I install Migrations API and configure it. I make a call to the endpoint ../../GetContentById?id=1 The Json returned is in a particular format. I now install Migrations ClientI on another project. This connects to the API endpoint above but I use the method in MigrationsClient to get the data. When I call the method GetContentById it returns the Json but the format of the returned Json is slightly different if I compare it to the API version. One of the things I noticed in the Migrations Client is the returned Json, at the bottom of the Json returned is an empty jObject. Not sure if this is any clearer?
a
The client class the API, so it should be the same. Do you have an example of your code?
t
I can send it but I don't know if I can post it on discord where it will format correctly. Do you have any other means for me to send it to you? @User
a
t
@Anders Bjerner that's now submitted 👍
a
So You have an Umbraco 7 site where you've installed Limbo.Umbraco.MigrationsApi. Then you have an Umbraco 10 (?) site where you've installed Limbo.Umbraco.MigrationsClient, and set it up to access the Umbraco 7 site. And then you've set up a controller on the new site to expose the data received from the old site.
So do I understand this correctly? And if so, what is the reason for the last part with the controller?
t
@Anders Bjerner It's Umbraco 13. Yes that's correct. I installed the MigrationsClient on Umbraco 13. The controller on Umbraco 13 is simply to call for the required data and to copy the data into Umbraco 13. MigrationsClient was installed to get access to the Json and insert the data as required. All is working except the Json returned in Umbraco 13 doesn't look correct.
a
But what's the purpose of the controller for the U13 site? The purpose of the client package is to provide a way for accessing data on the old site. So when requesting a specific content node, the data received from the API on the old site is parsed into a C# object with some information about the node as well as it's properties. What you do from there is up to you, but the C# models aren't build for being returned in a new API.
Here is an example for getting a page and iterating through it's properties:
Copy code
cshtml
@using Limbo.Umbraco.MigrationsClient
@using Limbo.Umbraco.MigrationsClient.Models.Content
@using Limbo.Umbraco.MigrationsClient.Models.Properties
@using Newtonsoft.Json.Linq
@using Skybrud.Umbraco.GridData.Factories
@using Skybrud.Umbraco.GridData.Models

@inherits UmbracoViewPage

@inject IMigrationsClient MigrationsClient
@inject IGridFactory GridFactory

@{

    LegacyContent content = MigrationsClient.GetContentById(1077);

    <pre>ID: @content.Id</pre>
    <pre>Name: @content.Name</pre>

    <h3>Properties:</h3>

    foreach (ILegacyProperty property in content.Properties) {

        <h3>@property.Alias (@property.EditorAlias)</h3>

        <pre>@property.Value</pre>

        switch (property.EditorAlias) {

            case "Umbraco.Grid":
                object? newValue = ConvertGridValue(property.Value);
                break;

        }

    }

}

@functions {

    public object? ConvertGridValue(JToken value) {
        return value.Type switch {
            JTokenType.Null => null,
            JTokenType.Object => ConvertGridValue(GridFactory.CreateGridModel(null, null, (JObject)value, false)),
            _ => throw new Exception($"Unsupported token type: {value.Type}...")
        };
    }

    public object? ConvertGridValue(GridDataModel value) {
        throw new Exception("YAY");
    }

}
For the solutions that I've migrated, I've used my https://github.com/limbo-works/Limbo.Umbraco.Migrations package. But things quickly start to get complex, and there isn't any documentation, so this isn't necessarily my suggested approach. But with my example, you can check the property editor alias assocaited with each property, and then do something with the property values accordingly.
t
@Anders Bjerner I need to get the data from the old U7 site into the U13 site. The way I thought it was designed was the MigrationsAPI is installed on U7 so it allows the data to be available through an API call. The U13 site then needs to connect to the U7 to retrieve this data so Migrations Client was installed to connect rather than having to create my own HttpClient to retrieve the data and then save the data into U13. The purpose of the controller in U13 was simply to have a way to connect to the U7 API data and then create a set of data and save to U13 as needed
a
I think you're correct except the last line
t
@Anders Bjerner So you mean I need to create my own HttpClient to get the data in the same format U7 shows? It seems the way you have described above the purpose for Migrations Client is to run on the site itself but not use it for any other purpose? Overall if I was to take your project and change it to return the same Json as the one returned in the Migrations API would that be a possibility? The controller on U13 is only temporary to get the data, save the data in U13 and then I won't need that controller once the data is inside U13.
a
The client package is so you don't have to create your own HTTP client. But the client package doesn't expose the data as exposed by the API package - at least not directly. Anyways - I'll try to so create a quick example on how to save a page in the U13 site.
t
That would be super! If possible to tweak the Migrations Client to return the exact same Json as you would from Migrations API then that would be extremely useful
a
Assuming your U7 and U13 site has the same content types and properties, you can import the different properties as-is something like this:
Copy code
cshtml
@using Limbo.Umbraco.MigrationsClient
@using Limbo.Umbraco.MigrationsClient.Models.Content
@using Limbo.Umbraco.MigrationsClient.Models.Properties
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq
@using Umbraco.Cms.Core.Models
@using Umbraco.Cms.Core.Services

@inherits UmbracoViewPage

@inject IContentService ContentService
@inject IMigrationsClient MigrationsClient

@{

    LegacyContent legacy = MigrationsClient.GetContentById(1077);

    <pre>ID: @legacy.Id</pre>
    <pre>Key: @legacy.Key</pre>
    <pre>Name: @legacy.Name</pre>

    <h3>Properties:</h3>

    IContent? content = ContentService.GetById(legacy.Key);

    if (content is null) {
        var parent = legacy.Path.SkipLast().LastOrDefault();
        content = ContentService.Create(legacy.Name, parent?.Id ?? -1, legacy.ContentTypeAlias);
    }

    foreach (ILegacyProperty property in legacy.Properties) {

        <h3>@property.Alias (@property.EditorAlias)</h3>

        <pre>@property.Value</pre>

        switch (property.Value.Type) {

            case JTokenType.Null:
                continue;

            case JTokenType.Array:
            case JTokenType.Object:
                content.SetValue(property.Alias, property.Value.ToString(Formatting.None));
                break;

            case JTokenType.String:
                content.SetValue(property.Alias, property.Value.Value<string>());
                break;

            case JTokenType.Integer:
                content.SetValue(property.Alias, property.Value.Value<int>());
                break;

            default:
                throw new Exception($"Unsupported token type: {property.Value.Type}...");

        }

    }

    ContentService.SaveAndPublish(content);

}
Anyways - to get the data as returned by the API in the U7 site, you can do something like this:
Copy code
cshtml
@using Limbo.Umbraco.MigrationsClient
@using Limbo.Umbraco.MigrationsClient.Models.Content
@using Newtonsoft.Json.Linq

@inherits UmbracoViewPage

@inject IMigrationsClient MigrationsClient

@{

    LegacyContent legacy = MigrationsClient.GetContentById(1077);

    JObject json = legacy.JObject!;

    string jsonString = json.ToString();

    <h3>API response body as JObject</h3>
    <pre>@json</pre>

    <h3>API response body as string</h3>
    <pre>@jsonString</pre>

}
I'm still not sure why you wish to expose this in an API on the U13 site though. I think this may take you down a wrong path
t
Thank you. I will try this out tomorrow. The idea is the U13 is having a new site structure so the nodes won't be the same as the old U7 site. For this all I need is access to the U7 data so I can try and save it to the new node structure in U13. Once I have this data saved there's no need for the controller as it's only a one off to get the data from U7 and into the new node structure in U13
5 Views