Search code examples
c#orchard-modulesorchardcore

Using a ContentPart to retrieve a settings parameter, save it's value on a ContentItem, and updating the settings parameter


I'm trying to build a module containing a Content Part attachable to a Content Type, so when a new Content Item is created, it retrieves a "last id" int parameter from the settings, adds 1 to it, and saves it both to the new Content Item and the settings parameter.

So, the settings parameter seems to work well, I can access it from the Admin menu, set it's value and save it. Creating the content part works well too, I can add the part to an existing Content Type, create a new Content Item and, when I save it, it enters the registered Driver's UpdateAsync method. And this is when everything goes south. Here's the UpdateAsync method from the ContentPart Driver:

public override async Task<IDisplayResult> UpdateAsync(IncrementalPart model, IUpdateModel updater)
{
    // Create IncrementalId only doesn't exist (IncrementalId is int?)
    if (!model.IncrementalId.HasValue) 
    {
        // Retrieve site settings
        var incrementalSettings = _siteService.GetSiteSettingsAsync()
            .GetAwaiter()
            .GetResult();
        // Get last Assigned Id, increment it, and set it to the model's IncrementalId
        model.IncrementalId = ++incrementalSettings.As<IncrementalSettings>().LastId;
        // Save model
        await updater.TryUpdateModelAsync(
            model,
            Prefix,
            t => t.IncrementalId
        );
        // Update and save the last assigned Id
        incrementalSettings.Alter<IncrementalSettings>(nameof(IncrementalSettings), isett => isett.LastId = model.IncrementalId.GetValueOrDefault());
        await _siteService.UpdateSiteSettingsAsync(incrementalSettings);
    }

    return Edit(model);
}

In the Edit view, this part doesn't have any actual editable input for it, because it shouldn't be possible to manually edit it, it should be created the first time the Content Item is saved with the IncrementalPart on it, and only displayed after that (just a <p> showing the assigned number, with an <input type="hidden" asp-for="IncrementalId" /> on it to preserve the ID on edition).

So here's what I've found. When I try to save the IncrementalId field, it doesn't save anything, and the model's LastId value is null after calling await updater.TryUpdateModelAsync, so when saving back the new LastId field on the settings, fails.

On the other hand, if I try to save the settings before updating the ContentItem part with it's new value, it saves the LastId value ok, but then it breaks out of the UpdateAsync method, so I can't update the IncrementalId value after.

What am I doing wrong? I've based this module in a previous one I made based on an example, which just saved a couple values from the editor and displayed them on the corresponding Content Item page, and it worked fine, the problems start when I add the retrieve/save settings part.

Thanks in advance.

UPDATE: So, I've managed to retrieve a value from the configuration, update it on the model and save it, but, when I try to save the last assigned value back to the settings, it just breaks the execution, when await _siteService.UpdateSiteSettingsAsync(incrementalSettings); is executed, the final return Edit(model); is not.


Solution

  • This sounds like an XY problem, notwithstanding that I think the issue is you want to get the part itself and then alter the fields on that. Here's some code below I use when adding contentItems programmatically.

    var salesPersonPart = salesPersonContentItem.As<Parts.SalesPerson>();
    salesPersonPart.Alter<NumericField> (nameof(Parts.SalesPerson.SalesPersonId), field => field.Value = salesPerson.SalesPersonId.Value);
    

    Edit: Looking at other parts of the source code, re your edit. Looks like something like this will work to update site settings.

            var site = await _siteService.LoadSiteSettingsAsync();
            site.Properties["IncrementalSettings"] = IncrementalSettings.Id;
            await _siteService.UpdateSiteSettingsAsync(site);
    

    The use of UpdateSiteSettingsAsync is scattered all through the source code so have a look of how Orchard Core does it.