FHIR Chat · Profile validation with CachedResolver · dotnet

Stream: dotnet

Topic: Profile validation with CachedResolver


view this post on Zulip Barbro Vessman (Oct 07 2021 at 13:09):

Hello
I’m using the code below to validate resources. It works.
The IG is in a zip-file that is added to the solution. The R4 specification.zip is added to the solution via the Hl7.Fhir.Specification.R4 NuGet package.
Both zip files are extracted by the MultiResolver/CachedResolver to a temp folder in this location: C:\Users\<username>\AppData\Local\Temp\FhirArtifactCache-2.0.3-Hl7.Fhir.R4.Specification

However, sometimes the temp folders above are emptied. I’m not sure how or why since it happens irregularly. It might happen after having switched between branches, but not always. When folders are empty the profile validation fails with the error “Unable to resolve reference to profile”. Workaround is to remove folders or populating them manually.

Any tips on how to fix this are appreciated.

        // Get the Full IG from zip file
        string currentDir = System.IO.Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\"));
        string fulligzip = Path.Combine(currentDir, "ProfilesForTest\\ITB\\manual_full-ig.zip");

        // Create a resolver for both Full IG and specification.zip
        var specificationsource = ZipSource.CreateValidationSource();
        var zipsource = new ZipSource(fulligzip);

        MultiResolver = new CachedResolver(new MultiResolver(specificationsource, zipsource));

        // Create provider from resolver
        Provider = new StructureDefinitionSummaryProvider(MultiResolver);

        // Create validator with settings and resolver
        var settings = ValidationSettings.CreateDefault();
        settings.ResourceResolver = MultiResolver;
        Validator = new Validator(settings);

    }

    public string JsonProfileCheck(string json, string profileUrl)
    {

        // Validate the resouce
        var mySourceNode = FhirJsonNode.Parse(json);
        var myTypedElement = mySourceNode.ToTypedElement(Provider);
        Hl7.Fhir.Model.OperationOutcome outcome = Validator.Validate(myTypedElement, profileUrl);

        //Debug result
        var result = outcome.ToJson(new FhirJsonSerializationSettings() { Pretty = true });
        var outcomestring = result.ToString();

        return outcomestring;
    }

view this post on Zulip Brian Postlethwaite (Oct 07 2021 at 22:31):

Yes this occurs occasionally, I think it may be occurring on occasion when disk space runs low and windows gets a little aggressive - but I can't be sure.
I haven't been able to work that out either.

view this post on Zulip Barbro Vessman (Oct 08 2021 at 05:49):

OK, thanks for your answer @Brian Postlethwaite

view this post on Zulip Brian Postlethwaite (Oct 08 2021 at 07:32):

The repair step I do is delete the temp folder and retry.

view this post on Zulip Ewout Kramer (Oct 11 2021 at 07:36):

Yes it happens to me too now and then. It's happens so irregularly that I have never bothered to hunt it down - it won't happen in production anyway. I think it has something to do with switching branches, yes, and then maybe two processes trying to unzip the directory at the same time.

Since we're looking at switching to the NPM packages instead of the spec.zip, we hope this problem will disappear all by itself.

view this post on Zulip Brian Postlethwaite (Oct 11 2021 at 21:37):

I've done a Sqlite resolver too.

view this post on Zulip Barbro Vessman (Oct 15 2021 at 08:51):

Thanks both of you :smile:
NPM packages might be something to looking into also for us then

view this post on Zulip Brian Postlethwaite (Feb 10 2022 at 04:27):

This is a dirty hack that I've now put into the start of the app startup to try cleaning things up if there are problems.

        public static void VerifyTempSpecificationFolder()
        {
            try
            {
                // locate the temp folder
                Assembly assembly = typeof(ZipSource).GetTypeInfo().Assembly;
                var versionInfo = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
                var productInfo = assembly.GetCustomAttribute<AssemblyProductAttribute>();
                string specificationArtifactKey = $"FhirArtifactCache-{versionInfo.InformationalVersion}-{productInfo.Product}";
                string cachePath = Path.Combine(Path.GetTempPath(), specificationArtifactKey);
                if (Directory.Exists(cachePath))
                {
                    // ensure that the files are all in there from the zip file
                    var artifacts = new DirectoryInfo(cachePath).EnumerateFiles("*.xml", SearchOption.AllDirectories);
                    if (artifacts.Count() < 11)
                    {
                        // Delete the folder (the next step will re-create it)
                        Directory.Delete(cachePath, true);
                    }
                }
            }
            catch(Exception ex)
            {
                // the sorts of issue that MIGHT come up here are related to permissions/concurrency
                //  - however this is OUR temp folder, so shouldn't happen anyway.
                Console.Error.WriteLine("Unexpected Error resetting suspected corrupt Specification Artifact temp folder");
            }
        }

I'm aware that this is pretty crude, but so is quietly failing.
I'd love if there was a function on the ZipCacher to delete the folder that it creates too so that I don't have to have this gross code outside (this is the internals of the function that calculates the name, as thats private too)


Last updated: Apr 12 2022 at 19:14 UTC