Arbeidstilsynet.Common.AltinnApp
2.6.0
dotnet add package Arbeidstilsynet.Common.AltinnApp --version 2.6.0
NuGet\Install-Package Arbeidstilsynet.Common.AltinnApp -Version 2.6.0
<PackageReference Include="Arbeidstilsynet.Common.AltinnApp" Version="2.6.0" />
<PackageVersion Include="Arbeidstilsynet.Common.AltinnApp" Version="2.6.0" />
<PackageReference Include="Arbeidstilsynet.Common.AltinnApp" />
paket add Arbeidstilsynet.Common.AltinnApp --version 2.6.0
#r "nuget: Arbeidstilsynet.Common.AltinnApp, 2.6.0"
#:package Arbeidstilsynet.Common.AltinnApp@2.6.0
#addin nuget:?package=Arbeidstilsynet.Common.AltinnApp&version=2.6.0
#tool nuget:?package=Arbeidstilsynet.Common.AltinnApp&version=2.6.0
Introduction
A collection of common patterns and extensions for cross-cutting concerns in Altinn applications.
📖 Installation
To install the package, you can use the following command in your terminal:
dotnet add package Arbeidstilsynet.Common.AltinnApp
🚀 Features
- Extension Methods for common Altinn operations
- Abstract Data Processors for handling data changes
- Country Code Lookup with country dialing codes and names
- Altinn Options Provider for country dropdowns
- Embedded Resource Utilities for JSON data
🧑💻 Usage
Dependency Injection Setup
Altinn Application Utilities
Add services to your service collection:
public void ConfigureServices(IServiceCollection services)
{
// Add country code lookup functionality
services.AddLandskoder();
// OR add country options for Altinn dropdowns (includes AddLandskoder)
services.AddLandOptions();
}
Structured Data
1. Add the structured data extension to your service collection, specifying the data model and structured data types
// Adds a DataElement to you instance to hold structured data of type TStructuredData
// Content type will be "application/json".
services.AddStructuredData<TDataModel, TStructuredData>((datamodel) =>
{
return new TStructuredData
{
// Property mappings here
};
});
2. Add the data element to your App/config/applicationmetadata.json dataTypes
{
"dataTypes": [
{
"id": "structured-data",
"allowedContentTypes": [
"application/json"
],
"allowedContributors": [
"app:owned"
]
},
/// ...Other data types
]
}
Extension Methods
Instance Extensions
Easily extract common information from Altinn instances:
using Arbeidstilsynet.Common.AltinnApp.Extensions;
public class MyService
{
public void ProcessInstance(Instance instance)
{
// Extract instance GUID
Guid instanceId = instance.GetInstanceGuid();
// Get application name
string appName = instance.GetAppName();
// Get party ID of instance owner
int partyId = instance.GetInstanceOwnerPartyId();
Console.WriteLine($"Processing {appName} instance {instanceId} for party {partyId}");
}
}
DataClient Extensions
Simplified data operations with Altinn instances:
using Arbeidstilsynet.Common.AltinnApp.Extensions;
public class DataService
{
private readonly IDataClient _dataClient;
public DataService(IDataClient dataClient)
{
_dataClient = dataClient;
}
public async Task<MyDataModel?> GetFormData(Instance instance)
{
// Get form data with default data type "structured-data"
return await _dataClient.GetSkjemaData<MyDataModel>(instance);
// Or specify custom data type
return await _dataClient.GetSkjemaData<MyDataModel>(instance, "customDataType");
}
public async Task CleanupAttachments(Instance instance, List<DataElement> unusedAttachments)
{
foreach (var attachment in unusedAttachments)
{
// Delete data element and remove from instance
await _dataClient.DeleteElement(instance, attachment, delay: true);
}
}
}
Assembly Extensions
Load and deserialize embedded JSON resources:
using Arbeidstilsynet.Common.AltinnApp.Extensions;
public class ConfigurationService
{
public Task<MyResourceType> GetResource()
{
var assembly = Assembly.GetExecutingAssembly();
// Load embedded JSON resource and deserialize
return assembly.GetEmbeddedResource<MyResourceType>("resource.json");
}
}
Country Code Lookup
Use the built-in country code lookup service:
public class AddressService
{
private readonly ILandskodeLookup _landskodeLookup;
public AddressService(ILandskodeLookup landskodeLookup)
{
_landskodeLookup = landskodeLookup;
}
public async Task<string> GetCountryInfo(string countryCode)
{
// Look up specific country by ISO code
var country = await _landskodeLookup.GetLandskode("NOR");
if (country != null)
{
return $"{country.Land} ({country.Kode})"; // "Norway (+47)"
}
return "Unknown country";
}
}
Abstract Data Processors
Create data processors that respond to form data changes:
Simple Data Processor
using Arbeidstilsynet.Common.AltinnApp.Abstract.Processing;
public class MyFormDataProcessor : BaseDataProcessor<MyDataModel>
{
private readonly ILogger<MyFormDataProcessor> _logger;
public MyFormDataProcessor(ILogger<MyFormDataProcessor> logger)
{
_logger = logger;
}
protected override async Task ProcessData(MyDataModel current, MyDataModel? previous)
{
if (previous == null)
{
_logger.LogInformation("New form data created");
return;
}
_logger.LogInformation("Form data updated");
// Your custom processing logic here
}
}
Member-Specific Processor
public class EmailChangeProcessor : MemberProcessor<MyDataModel, string>
{
protected override string? AccessMember(MyDataModel dataModel)
{
return dataModel.Email;
}
protected override async Task ProcessMember(
string? currentEmail,
string? previousEmail,
MyDataModel currentDataModel,
MyDataModel previousDataModel)
{
// Your custom logic to handle the changed member
}
}
List Processor
public class AttachmentListProcessor : ListProcessor<MyDataModel, AttachmentInfo>
{
protected override List<AttachmentInfo>? AccessMember(MyDataModel dataModel)
{
return dataModel.Attachments; // Point to the list we want to process
}
protected override async Task ProcessListChange(
List<AttachmentInfo>? currentList,
List<AttachmentInfo>? previousList,
MyDataModel currentDataModel,
MyDataModel previousDataModel)
{
// Process that attachments have been removed or added
}
protected override async Task ProcessItem(
AttachmentInfo currentItem,
AttachmentInfo previousItem,
MyDataModel currentDataModel,
MyDataModel previousDataModel)
{
// Process individual item changes
}
}
Registration of Data Processors
Register your data processors in dependency injection:
public void ConfigureServices(IServiceCollection services)
{
// Register data processors
services.AddTransient<IDataProcessor, MyFormDataProcessor>();
services.AddTransient<IDataProcessor, EmailChangeProcessor>();
services.AddTransient<IDataProcessor, AttachmentListProcessor>();
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Altinn.App.Core (>= 8.10.3)
-
net8.0
- Altinn.App.Core (>= 8.10.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.6.0 | 87 | 3/6/2026 |
| 2.5.0 | 83 | 2/25/2026 |
| 2.4.1 | 105 | 2/18/2026 |
| 2.4.1-beta1 | 87 | 2/18/2026 |
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added <!-- for new features. -->
### Changed <!-- for changes in existing functionality. -->
### Deprecated <!-- for soon-to-be removed features. -->
### Removed <!-- for now removed features. -->
### Fixed <!-- for any bug fixes. -->
### Security <!-- in case of vulnerabilities. -->
## 2.6.0
### Changed
- changed(deps): Applied minor and patch updates to dependencies
## 2.5.0
### Changed
- ListProcessor no longer emits ProcessList -- only ProcessItem, and items are compared using AltinnRowId. If you need to process the list as a whole, you should use MemberProcessor pointing to the list in question.
## 2.4.1
### Changed
- chore: moved package to nuget.org
## 2.4.0
- changed: Differentiate structured data and main content.
- More configurable, though defaults should for most.
- The altinn app will declare which data elemnts are the main content, and structured data, using data values
## 2.3.0
- added: PreSubmitProcessor to make it easier to implement custom pre-submit logic in AltinnApps.
- added: A few more extension methods for `IApplicationClient` and `IDataClient`
## 2.2.0
- added: Option to disable deletion of app datamodel after mapping structured data. This can be useful for testing and some legacy use cases.
## 2.1.0
### Changed
- changed(deps): Applied minor and patch updates to dependencies
## 2.0.0
### Changed
- changed(deps): Major dotnet updated (v10)
## 1.5.1
- added: Option to include error details related to mapping structured data in the validation response. This intended for development environments.
## 1.5.0
- added: Extension to manage DataElements for structured data. It deletes the xml-based DataModel, and replaces it with application/json of a user-provided type.
## 1.4.1
### Changed
- applied new default skjema type `structured-data` as default
## 1.4.0
- added: More customization options for LandOptions
- Custom order function for country list in LandOptions (default is alphabetical by country name)
- Option for using either alpha2 or alpha3 country codes as value in dropdowns (default is alpha3)
## 1.3.0
### Changed
- changed: Moved all AltinnApp logic (from the Altinn package) to this new dedicated package, only intended to be used by AltinnApps.