-
Notifications
You must be signed in to change notification settings - Fork 26
Feat/methods to access xsd #1668
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/methods-to-access-xsd
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project> | ||
| <!-- | ||
| This props file is included in the Altinn.App.Api nuget package and will | ||
| apply to the App projects when they reference said nuget package. | ||
| --> | ||
| <PropertyGroup> | ||
| <IsAltinnApp>true</IsAltinnApp> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <!-- | ||
| This props file is included in the build/ path of the Altinn.App.Api nuget package | ||
| but the Rosly analyzer is included transitively, for example in unit test projects or similar. | ||
| We only need to do app-based analysis on actual app projects, so this let's us distinguish | ||
| in the Roslyn Analyzer code. | ||
| --> | ||
| <CompilerVisibleProperty Include="IsAltinnApp" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <!-- | ||
| We include config files as addition files so that they are more easily referenced | ||
| in analyzers and source generators. | ||
| --> | ||
| <AdditionalFiles Include="config/**" /> | ||
| <AdditionalFiles Include="ui/**/*.json" /> | ||
| </ItemGroup> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| using System.Xml; | ||
| using System.Xml.Schema; | ||
| using Altinn.App.Core.Helpers; | ||
| using Altinn.App.Core.Helpers.Serialization; | ||
| using Altinn.App.Core.Internal.App; | ||
| using Altinn.App.Core.Models; | ||
| using Altinn.App.Core.Models.Validation; | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace Altinn.App.Core.Features.Validation.Default; | ||
|
|
||
| /// <summary> | ||
| /// Validates form data against the XSD schema for the data model, if it exists | ||
| /// </summary> | ||
| public class XsdValidator : IValidator | ||
| { | ||
| private readonly ILogger<XsdValidator> _logger; | ||
| private readonly IAppResources _appResourceService; | ||
| private readonly IAppMetadata _appMetadata; | ||
| private readonly ModelSerializationService _modelSerializationService; | ||
|
|
||
| /// <summary> | ||
| /// Constructor for the expression validator | ||
| /// </summary> | ||
| public XsdValidator( | ||
| ILogger<XsdValidator> logger, | ||
| IAppResources appResourceService, | ||
| IAppMetadata appMetadata, | ||
| ModelSerializationService modelSerializationService | ||
| ) | ||
| { | ||
| _logger = logger; | ||
| _appResourceService = appResourceService; | ||
| _appMetadata = appMetadata; | ||
| _modelSerializationService = modelSerializationService; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// We implement <see cref="ShouldRunForTask"/> instead | ||
| /// </summary> | ||
| public string TaskId => "*"; | ||
|
|
||
| /// <summary> | ||
| /// Only run for tasks that specifies a layout set | ||
| /// </summary> | ||
| public bool ShouldRunForTask(string taskId) => | ||
| _appMetadata | ||
| .GetApplicationMetadata() | ||
| .Result.DataTypes.Exists(dt => dt.TaskId == taskId && dt.AppLogic?.ClassRef is not null); | ||
|
|
||
| /// <inheritdoc /> | ||
| public string ValidationSource => "Xsd"; | ||
|
|
||
| /// <inheritdoc /> | ||
| public bool NoIncrementalValidation => true; | ||
|
|
||
| /// <summary> | ||
| /// This is not used for incremental validation | ||
| /// </summary> | ||
| public Task<bool> HasRelevantChanges( | ||
| IInstanceDataAccessor dataAccessor, | ||
| string taskId, | ||
| DataElementChanges changes | ||
| ) => Task.FromResult(true); | ||
|
|
||
| /// <inheritdoc /> | ||
| public async Task<List<ValidationIssue>> Validate( | ||
| IInstanceDataAccessor dataAccessor, | ||
| string taskId, | ||
| string? language | ||
| ) | ||
| { | ||
| var validationIssues = new List<ValidationIssue>(); | ||
| foreach (var (dataType, dataElement) in dataAccessor.GetDataElementsForTask(taskId)) | ||
| { | ||
| var schema = _appResourceService.GetXsdSchema(dataType.Id); | ||
| if (schema is null) | ||
| { | ||
| _logger.LogInformation( | ||
| "No XSD schema found for data type {DataTypeId}, skipping XSD validation", | ||
| dataType.Id | ||
| ); | ||
| continue; | ||
| } | ||
| var formData = await dataAccessor.GetFormData(dataElement); | ||
| ObjectUtils.RemoveAltinnRowId(formData); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bør vi fjerne altinnRowId her, eller bare kreve at den legges til som optional i xsd? Det er nok flere forskjeller, men dette er jo det eneste eksemplet (jeg har sett det har blitt klaget på) der xsd validering og data annotations gir ulikt resultat, men kanskje dere har andre grunner for å gjøre dette?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I testing, så arresterer validatoren deg om du har rowId og det ikke er i Xsd. |
||
|
|
||
| var serializedFormData = _modelSerializationService.SerializeToXml(formData); | ||
| var parsedSchema = new XmlSchemaSet(); | ||
| using (var xsdReader = XmlReader.Create(new StringReader(schema))) | ||
| { | ||
| parsedSchema.Add(null, xsdReader); | ||
| } | ||
| var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema, Schemas = parsedSchema }; | ||
| settings.ValidationEventHandler += (sender, e) => | ||
| { | ||
| validationIssues.Add( | ||
| new ValidationIssue() | ||
| { | ||
| Code = "Xsd", | ||
| CustomTextKey = "backend.xsd_validation", | ||
| DataElementId = dataElement.Id, | ||
| Severity = ValidationIssueSeverity.Error, | ||
| CustomTextParameters = new Dictionary<string, string>() | ||
| { | ||
| { "schema", dataType.Id }, | ||
| { "message", e.Message }, | ||
| }, | ||
| } | ||
| ); | ||
| }; | ||
|
|
||
| using var xmlStream = new MemoryStream(serializedFormData.ToArray(), writable: false); | ||
| using var reader = XmlReader.Create(xmlStream, settings); | ||
| while (reader.Read()) { } | ||
| } | ||
|
|
||
| return validationIssues; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bør det være standard å ha både DataAnnotationValidator og XsdValidator, eller bør aktivering av XsdValidation være et alternativ til dataAnnotations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jeg kan ikke si noe veldig konsekvent, men kan dele vår erfaring med disse typene validering.
Vi har opplevd at en god del innsendinger har blitt godkjent av DataAnnotationValidator, deretter kommet til backend som kjører xsd validering og klager på innsendingen. Så det virker som xsd validering er strengere enn DataAnnotationValidator. Vi kjører alltid xsd datamodeller gjennom altinn studio sitt generer datamodeller-verktøy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jeg har også grublet litt over om xsd validering burde være standard. Jeg føler det finnes et sterkt argument for, og et sterkt argument mot.
For: siden datamodeller kan genereres ut fra Xsd, kan man ofte anta at hvis man har en Xsd med samme navn som en modell, i models mappa, så vil man gjerne validere dataen utfra den xsden. og hvis man utvikler og finner at det skaper problemer, kan man deretter slå av. Ref det jeg nevnte over, med at xsd validering virker som det er strengere. Dette hadde vært "least trust" prinsipp, som noen setter pris på.
Imot: Jeg vet om hvertfall ett prosjekt, som startet i utgangspunktet med datamodell generert ut fra Xsd, og deretter gikk over til å bare redigere .cs filene direkte når de gjorde endringer i modellene. Jeg vet ikke hvor vanlig dette er, men slike utviklere vil helst ikke ha denne funksjonaliteten som standard.