public PnPSerializationScope(Type schemaTemplateType) { // Save the scope information this._baseSchemaNamespace = schemaTemplateType.Namespace; this._baseSchemaAssemblyName = schemaTemplateType.Assembly.FullName; // Save the previous scope, if any this._previous = Current; // Set the new scope to this Current = this; }
/// <summary> /// Serializes an in-memory ProvisioningTemplate into a Stream (the XML) /// </summary> /// <param name="template">The ProvisioningTemplate to serialize</param> /// <returns>The resulting Stream (the XML)</returns> public Stream ToFormattedTemplate(ProvisioningTemplate template) { if (template == null) { throw new ArgumentNullException(nameof(template)); } using (var scope = new PnPSerializationScope(typeof(TSchemaTemplate))) { var result = new TSchemaTemplate(); Stream output = null; // Process the template to generate the output stream output = ProcessOutputStream(template, result); return(output); } }
/// <summary> /// Deserializes a Stream of bytes (the XML) into a Provisioning Template, based on an optional identifier /// </summary> /// <param name="template">The source Stream of bytes (the XML)</param> /// <param name="identifier">An optional identifier for the template to deserialize</param> /// <returns>The deserialized Provisioning Template</returns> public ProvisioningTemplate ToProvisioningTemplate(Stream template, string identifier) { using (var scope = new PnPSerializationScope(typeof(TSchemaTemplate))) { // Prepare a variable to hold the resulting ProvisioningTemplate instance var result = new ProvisioningTemplate(); // Prepare a variable to hold the single source formatted template // We provide the result instance of ProvisioningTemplate in order // to configure the tenant/hierarchy level items // We get back the XML-based object to use with the other serializers var source = ProcessInputStream(template, identifier, result); // We process the chain of deserialization // with the Provisioning-level serializers DeserializeTemplate(source, result); return(result); } }
/// <summary> /// Deserializes a source Stream (the XML) into a ProvisioningHierarchy /// </summary> /// <param name="hierarchy">The source Stream (the XML)</param> /// <returns>The resulting ProvisioningHierarchy object</returns> public ProvisioningHierarchy ToProvisioningHierarchy(Stream hierarchy) { // Create a copy of the source stream MemoryStream sourceStream = new MemoryStream(); hierarchy.Position = 0; hierarchy.CopyTo(sourceStream); sourceStream.Position = 0; // Check the provided template against the XML schema var validationResult = this.GetValidationResults(sourceStream); if (!validationResult.IsValid) { // TODO: Use resource file throw new ApplicationException("Template is not valid", new AggregateException(validationResult.Exceptions)); } // Prepare the output variable ProvisioningHierarchy resultHierarchy = new ProvisioningHierarchy(); // Determine if the file is a provisioning hierarchy sourceStream.Position = 0; XDocument xml = XDocument.Load(sourceStream); if (xml.Root.Name.LocalName != "Provisioning") { throw new ApplicationException("The provided provisioning file is not a Hierarchy!"); } // Determine the specific formatter needed for the current provisioning file var innerFormatter = XMLPnPSchemaFormatter.GetSpecificFormatter( xml.Root.Name.NamespaceName); // Process all the provisioning templates included in the hierarchy, if any XmlNamespaceManager nsManager = new XmlNamespaceManager(new System.Xml.NameTable()); nsManager.AddNamespace("pnp", xml.Root.Name.NamespaceName); // Start with templates embedded in the provisioning file var templates = xml.XPathSelectElements("/pnp:Provisioning/pnp:Templates/pnp:ProvisioningTemplate", nsManager).ToList(); foreach (var template in templates) { // Save the single template into a MemoryStream MemoryStream templateStream = new MemoryStream(); template.Save(templateStream); templateStream.Position = 0; // Process the single template with the classic technique var provisioningTemplate = innerFormatter.ToProvisioningTemplate(templateStream); // Add the generated template to the resulting hierarchy resultHierarchy.Templates.Add(provisioningTemplate); } // Then process any external file reference var templateFiles = xml.XPathSelectElements("/pnp:Provisioning/pnp:Templates/pnp:ProvisioningTemplateFile", nsManager).ToList(); foreach (var template in templateFiles) { var templateID = template.Attribute("ID")?.Value; var templateFile = template.Attribute("File")?.Value; if (!String.IsNullOrEmpty(templateFile) && !String.IsNullOrEmpty(templateID)) { // Process the single template file with the classic technique var provisioningTemplate = this._provider.GetTemplate(templateFile); provisioningTemplate.Id = templateID; // Add the generated template to the resulting hierarchy resultHierarchy.Templates.Add(provisioningTemplate); } } // And now process the top level children elements // using schema specific serializers using (var scope = new PnPSerializationScope(typeof(TSchemaTemplate))) { // We prepare a dummy template to leverage the existing serialization infrastructure var dummyTemplate = new ProvisioningTemplate { Id = $"DUMMY-{Guid.NewGuid()}" }; resultHierarchy.Templates.Add(dummyTemplate); // Deserialize the whole wrapper Object wrapper = null; var wrapperType = Type.GetType($"{PnPSerializationScope.Current?.BaseSchemaNamespace}.Provisioning, {PnPSerializationScope.Current?.BaseSchemaAssemblyName}", true); XmlSerializer xmlSerializer = new XmlSerializer(wrapperType); using (var reader = xml.Root.CreateReader()) { wrapper = xmlSerializer.Deserialize(reader); } #region Process Provisioning level serializers // Get all serializers to run in automated mode, ordered by DeserializationSequence var serializers = GetSerializersForCurrentContext(SerializerScope.Provisioning, a => a?.DeserializationSequence); // Invoke all the serializers InvokeSerializers(dummyTemplate, wrapper, serializers, SerializationAction.Deserialize); #endregion #region Process Tenant level serializers // Get all serializers to run in automated mode, ordered by DeserializationSequence serializers = GetSerializersForCurrentContext(SerializerScope.Tenant, a => a?.DeserializationSequence); // Invoke all the serializers InvokeSerializers(dummyTemplate, wrapper, serializers, SerializationAction.Deserialize); #endregion #region Process ProvisioningHierarchy level serializers // Get all serializers to run in automated mode, ordered by DeserializationSequence serializers = GetSerializersForCurrentContext(SerializerScope.ProvisioningHierarchy, a => a?.DeserializationSequence); // Invoke all the serializers InvokeSerializers(dummyTemplate, wrapper, serializers, SerializationAction.Deserialize); #endregion // Remove the dummy template from the hierarchy resultHierarchy.Templates.Remove(dummyTemplate); } return(resultHierarchy); }
/// <summary> /// Serializes a ProvisioningHierarchy into a Stream (the XML) /// </summary> /// <param name="hierarchy">The ProvisioningHierarchy to serialize</param> /// <returns>The resulting Stream (the XML)</returns> public Stream ToFormattedHierarchy(ProvisioningHierarchy hierarchy) { if (hierarchy == null) { throw new ArgumentNullException(nameof(hierarchy)); } using (var scope = new PnPSerializationScope(typeof(TSchemaTemplate))) { // We prepare a dummy template to leverage the existing deserialization infrastructure var dummyTemplate = new ProvisioningTemplate { Id = $"DUMMY-{Guid.NewGuid()}" }; hierarchy.Templates.Add(dummyTemplate); // Prepare the output wrapper Type wrapperType; object wrapper, templatesItem; Array templates; ProcessOutputHierarchy(dummyTemplate, out wrapperType, out wrapper, out templates, out templatesItem); // Handle the Sequences, if any // Get all ProvisioningHierarchy-level serializers to run in automated mode, ordered by SerializationSequence var serializers = GetSerializersForCurrentContext(SerializerScope.ProvisioningHierarchy, a => a?.SerializationSequence); // Invoke all the ProvisioningHierarchy-level serializers InvokeSerializers(dummyTemplate, wrapper, serializers, SerializationAction.Serialize); // Remove the dummy template hierarchy.Templates.Remove(dummyTemplate); // Add every single template to the output var provisioningTemplates = Array.CreateInstance(typeof(TSchemaTemplate), hierarchy.Templates.Count); for (int c = 0; c < hierarchy.Templates.Count; c++) { // Prepare variable to hold the output template var outputTemplate = new TSchemaTemplate(); // Serialize the real templates SerializeTemplate(hierarchy.Templates[c], outputTemplate); // Add the serialized template to the output provisioningTemplates.SetValue(outputTemplate, c); } templatesItem.SetPublicInstancePropertyValue("ProvisioningTemplate", provisioningTemplates); templates.SetValue(templatesItem, 0); if (provisioningTemplates.Length > 0) { wrapper.SetPublicInstancePropertyValue("Templates", templates); } // Serialize the XML-based object into a Stream XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add(((IXMLSchemaFormatter)this).NamespacePrefix, ((IXMLSchemaFormatter)this).NamespaceUri); MemoryStream output = new MemoryStream(); XmlSerializer xmlSerializer = new XmlSerializer(wrapperType); if (ns != null) { xmlSerializer.Serialize(output, wrapper, ns); } else { xmlSerializer.Serialize(output, wrapper); } // Re-base the Stream and return it output.Position = 0; return(output); } }