namespace MFiles.Grpc.Samples.Recipes; /// /// Recipe "vault-structure": object types, the classes of documents with their properties, and /// IDs resolved by alias. /// Arguments: [class alias] [property alias], default "MF.CL.Document" and "MF.PD.Keywords" /// public static class VaultStructure { public static async Task RunAsync(MFilesSettings settings, string[] args) { string classAlias = RecipeHelpers.StringArg(args, 0, "MF.CL.Document")!; string propertyAlias = RecipeHelpers.StringArg(args, 1, "MF.PD.Keywords")!; await using var connection = await MFilesConnection.ConnectAsync(settings, RecipeHelpers.ClientName); // [START vault-structure] // Object types. GetObjectTypes returns the real object types, not the value lists. var objectTypes = new IRPCObjectTypes.IRPCObjectTypesClient(connection.CallInvoker); var types = (await objectTypes.GetObjectTypesAsync(new GetObjectTypesRequest())).ObjectTypes; Console.WriteLine($"Object types: {types.Count}"); foreach (var type in types) Console.WriteLine($" {type.Id} {type.NamePlural}"); // Property definitions and classes. var propertyDefs = new IRPCPropertyDefs.IRPCPropertyDefsClient(connection.CallInvoker); var properties = (await propertyDefs.GetPropertyDefsAsync(new GetPropertyDefsRequest())) .PropertyDefs.ToDictionary(p => p.Id); Console.WriteLine($"Property definitions: {properties.Count}"); var classes = (await propertyDefs.GetObjectClassesAndGroupsAsync(new GetObjectClassesAndGroupsRequest())) .Classes; var documentClasses = classes.Where(c => c.ObjectType == 0).ToList(); Console.WriteLine($"Document classes: {documentClasses.Count}"); foreach (var objectClass in documentClasses) { var info = objectClass.BaseInfo.ItemInfo; // The properties a new object of the class must have, other than built-in ones. var required = objectClass.AssociatedPropertyDefs .Where(p => p.IsRequired) .Select(p => properties.GetValueOrDefault(p.PropertyDef)) .Where(def => def is { IsPredefined: false }) .Select(def => def!.Name); Console.WriteLine($" {info.ObjId.ItemId.InternalId} {info.Name}; " + $"required: {string.Join(", ", required.DefaultIfEmpty("-"))}"); } // [END vault-structure] // [START resolve-alias] // Code that must work in many vaults refers to classes and properties by alias, not ID. // The answer is -1 when no item, or more than one, has the alias. var vault = new IRPCVault.IRPCVaultClient(connection.CallInvoker); var classId = await vault.GetMetadataStructureItemIdByAliasAsync( new GetMetadataStructureItemIdByAliasRequest { ItemType = MetadataStructureItem.ObjectClass, Alias = classAlias, }); var propertyId = await vault.GetMetadataStructureItemIdByAliasAsync( new GetMetadataStructureItemIdByAliasRequest { ItemType = MetadataStructureItem.PropertyDef, Alias = propertyAlias, }); Console.WriteLine($"Class alias {classAlias}: ID {classId.Id}"); Console.WriteLine($"Property alias {propertyAlias}: ID {propertyId.Id}"); // [END resolve-alias] } }