/// <summary> /// Parse the extension /// </summary> public bool Parse(Extension fhirExtension, IdentifiedData modelObject) { if (fhirExtension.Value is FhirDateTime dateTime && modelObject is Person person) { person.DateOfBirth = DataTypeConverter.ToDateTimeOffset(dateTime.Value, out var datePrecision)?.Date; person.DateOfBirthPrecision = datePrecision; return(true); } return(false); }
/// <summary> /// Add cache commit /// </summary> public void AddCacheCommit(IdentifiedData data) { if (data.Key.HasValue && !this.m_cacheCommit.ContainsKey(data.Key.Value) && data.Key.HasValue) { this.m_cacheCommit.Add(data.Key.Value, data); } else if (data.Key.HasValue) { this.m_cacheCommit[data.Key.Value] = data; } }
/// <summary> /// Insert data at the specified index /// </summary> public void Insert(int index, IdentifiedData data) { if (data == null) { return; } this.Item.Insert(index, data); if (!String.IsNullOrEmpty(data.Tag)) { this.m_bundleTags.Add(data.Tag); } }
/// <summary> /// Update specified data /// </summary> public override IdentifiedData Update(IdentifiedData data) { // Additional security: User should be admin be editing themselves var securityUser = ApplicationContext.Current.GetService <ISecurityRepositoryService>().GetUser(AuthenticationContext.Current.Principal.Identity); if (securityUser.Key != (data as UserEntity)?.SecurityUserKey) { new PolicyPermission(PermissionState.Unrestricted, PermissionPolicyIdentifiers.UnrestrictedMetadata).Demand(); } return(base.Update(data)); }
/// <summary> /// Re-constitute the data /// </summary> /// <remarks>Basically this will find any refs and fill them in</remarks> private void Reconstitute(IdentifiedData data, HashSet <IdentifiedData> context) { if (context.Contains(data)) { return; } context.Add(data); // Prevent delay loading from EntitySource (we're doing that right now) // Iterate over properties foreach (var pi in data.GetType().GetRuntimeProperties().Where(o => o.GetCustomAttribute <DataIgnoreAttribute>() == null)) { // Is this property not null? If so, we want to iterate object value = pi.GetValue(data); if (value is IList) { foreach (var itm in value as IList) { if (itm is IdentifiedData) { this.Reconstitute(itm as IdentifiedData, context); } } } else if (value is IdentifiedData) { this.Reconstitute(value as IdentifiedData, context); } // Is the pi a delay load? if so then get the key property var keyName = pi.GetCustomAttribute <SerializationReferenceAttribute>()?.RedirectProperty; if (keyName == null || pi.SetMethod == null) { continue; // Skip if there is no delay load or if we can't even set this property } // Now we get the value of the key var keyPi = data.GetType().GetRuntimeProperty(keyName); if (keyPi == null || (keyPi.PropertyType != typeof(Guid) && keyPi.PropertyType != typeof(Guid?))) { continue; // Invalid key link name } // Get the key and find a match var key = (Guid?)keyPi.GetValue(data); var bundleItem = this.Item.Find(o => o.Key == key); if (bundleItem != null) { pi.SetValue(data, bundleItem); } } context.Remove(data); }
/// <summary> /// Save queue data /// </summary> public string SaveQueueData(IdentifiedData data) { #if PERFMON Stopwatch sw = new Stopwatch(); sw.Start(); try { #endif XmlSerializer xsz = null; if (!this.m_serializers.TryGetValue(data.GetType(), out xsz)) { xsz = new XmlSerializer(data.GetType()); lock (this.m_serializers) if (!this.m_serializers.ContainsKey(data.GetType())) { this.m_serializers.Add(data.GetType(), xsz); } } var sqlitePath = ApplicationContext.Current.Configuration.GetConnectionString(ApplicationContext.Current.Configuration.GetSection <DataConfigurationSection>().MessageQueueConnectionStringName).Value; // Create blob path var blobPath = Path.Combine(Path.GetDirectoryName(sqlitePath), "blob"); if (!Directory.Exists(blobPath)) { Directory.CreateDirectory(blobPath); } blobPath = Path.Combine(blobPath, Guid.NewGuid().ToString() + ".dat"); using (FileStream fs = File.Create(blobPath)) using (GZipStream gz = new GZipStream(fs, CompressionMode.Compress)) using (TextWriter tw = new StreamWriter(gz)) xsz.Serialize(tw, data); lock (m_queueCache) if (!this.m_queueCache.ContainsKey(blobPath)) { this.m_queueCache.Add(blobPath, data); } return(Path.GetFileName(blobPath)); #if PERFMON } finally { sw.Stop(); ApplicationContext.Current.PerformanceLog(nameof(SimpleQueueFileProvider), nameof(SaveQueueData), data.GetType().Name, sw.Elapsed); } #endif }
/// <summary> /// Perform a diff using a simple .compare() method /// </summary> /// <remarks>This method only performs a diff on the root object passed and does not cascade to collections</remarks> public Patch Diff(IdentifiedData existing, IdentifiedData updated, params string[] ignoreProperties) { var retVal = new Patch() { Key = Guid.NewGuid(), CreationTime = DateTimeOffset.Now, Operation = this.DiffInternal(existing, updated, null, ignoreProperties), AppliesTo = new PatchTarget(existing) }; this.m_tracer.TraceVerbose("-->> DIFF {0} > {1}\r\n{2}", existing, updated, retVal); return(retVal); }
/// <summary> /// Serialize objects /// </summary> private HashEntry[] SerializeObject(IdentifiedData data) { XmlSerializer xsz = XmlModelSerializerFactory.Current.CreateSerializer(data.GetType()); HashEntry[] retVal = new HashEntry[3]; retVal[0] = new HashEntry("type", data.GetType().AssemblyQualifiedName); retVal[1] = new HashEntry("loadState", (int)data.LoadState); using (var sw = new StringWriter()) { xsz.Serialize(sw, data); retVal[2] = new HashEntry("value", sw.ToString()); } return(retVal); }
/// <summary> /// Add the specified item to the memory cache /// </summary> public void Add(IdentifiedData data) { var exist = MemoryCache.Current.TryGetEntry(data.Key); MemoryCache.Current.AddUpdateEntry(data); if (exist != null) { this.Updated?.Invoke(this, new DataCacheEventArgs(data)); } else { this.Added?.Invoke(this, new DataCacheEventArgs(data)); } }
/// <summary> /// Get Queue Data /// </summary> public IdentifiedData GetQueueData(string pathSpec, Type typeSpec) { #if PERFMON Stopwatch sw = new Stopwatch(); sw.Start(); try { #endif XmlSerializer xsz = null; if (!this.m_serializers.TryGetValue(typeSpec, out xsz)) { xsz = new XmlSerializer(typeSpec); lock (this.m_serializers) if (!this.m_serializers.ContainsKey(typeSpec)) { this.m_serializers.Add(typeSpec, xsz); } } var sqlitePath = ApplicationContext.Current.Configuration.GetConnectionString(ApplicationContext.Current.Configuration.GetSection <DataConfigurationSection>().MessageQueueConnectionStringName).Value; // Create blob path var blobPath = Path.Combine(Path.GetDirectoryName(sqlitePath), "blob"); if (!Directory.Exists(blobPath)) { Directory.CreateDirectory(blobPath); } blobPath = Path.Combine(blobPath, pathSpec); IdentifiedData cached = null; if (!this.m_queueCache.TryGetValue(blobPath, out cached)) { using (FileStream fs = File.OpenRead(blobPath)) using (GZipStream gz = new GZipStream(fs, CompressionMode.Decompress)) using (TextReader tr = new StreamReader(gz)) return(xsz.Deserialize(tr) as IdentifiedData); } return(cached); #if PERFMON } finally { sw.Stop(); ApplicationContext.Current.PerformanceLog(nameof(SimpleQueueFileProvider), nameof(GetQueueData), typeSpec.Name, sw.Elapsed); } #endif }
/// <summary> /// Excludes the specified properties from the result /// </summary> internal static void ExcludeProperties(IdentifiedData returnValue, NameValueCollection qp, Stack <Guid> keyStack = null) { // Set the stack if (keyStack == null) { keyStack = new Stack <Guid>(); } else if (keyStack.Contains(returnValue.Key.Value)) { return; } keyStack.Push(returnValue.Key.Value); try { // Expand property? if (!qp.ContainsKey("_exclude")) { return; } else { foreach (var property in qp["_exclude"]) { PropertyInfo keyPi = returnValue.GetType().GetProperties().SingleOrDefault(o => o.GetCustomAttributes <XmlElementAttribute>().FirstOrDefault()?.ElementName == property); if (keyPi == null) { continue; } // Get the backing property PropertyInfo excludeProp = returnValue.GetType().GetProperties().SingleOrDefault(o => o.GetCustomAttributes <SerializationReferenceAttribute>().FirstOrDefault()?.RedirectProperty == keyPi.Name); if (excludeProp != null && excludeProp.CanWrite) { excludeProp.SetValue(returnValue, null); } else if (keyPi.CanWrite) { keyPi.SetValue(returnValue, null); } } } } finally { keyStack.Pop(); } }
/// <summary> /// Will layout the object in a referentially proper way /// </summary> private static void LayoutObject(IdentifiedData obj, DatasetInstall dsOutput, bool insert = false) { // Add myself if (!insert) { dsOutput.Action.Add(new DataUpdate() { Element = obj, InsertIfNotExists = true }); } else { dsOutput.Action.Insert(0, new DataUpdate() { Element = obj, InsertIfNotExists = true }); } // Iterate properties foreach (var prop in obj.GetType().GetRuntimeProperties()) { var sra = prop.GetCustomAttribute <SerializationReferenceAttribute>(); var value = prop.GetValue(obj); // Value is list if (value is IList && prop.GetCustomAttribute <XmlElementAttribute>() != null) { foreach (var v in (value as IList)) { LayoutObject(v as IdentifiedData, dsOutput, true); } } else if (value == null && sra != null) // No XmlElement .. hmm we might have to insert this stuff { value = OpenIZ.Core.Model.ExtensionMethods.LoadProperty(obj, prop.Name); } if (value is IdentifiedData) { dsOutput.Action.Insert(0, new DataUpdate() { Element = value as IdentifiedData, InsertIfNotExists = true }); } } }
/// <summary> /// Add an object to the REDIS cache /// </summary> /// <remarks> /// Serlializes <paramref name="data"/> into XML and then persists the /// result in a configured REDIS cache. /// </remarks> public void Add(IdentifiedData data) { try { // We want to add only those when the connection is present if (this.m_connection == null || data == null || !data.Key.HasValue || (data as BaseEntityData)?.ObsoletionTime.HasValue == true || this.m_nonCached.Contains(data.GetType())) { this.m_tracer.TraceVerbose("Skipping caching of {0} (OBS:{1}, NCC:{2})", data, (data as BaseEntityData)?.ObsoletionTime.HasValue == true, this.m_nonCached.Contains(data.GetType())); return; } // Only add data which is an entity, act, or relationship //if (data is Act || data is Entity || data is ActRelationship || data is ActParticipation || data is EntityRelationship || data is Concept) //{ // Add var redisDb = this.m_connection.GetDatabase(RedisCacheConstants.CacheDatabaseId); redisDb.HashSet(data.Key.Value.ToString(), this.SerializeObject(data)); redisDb.KeyExpire(data.Key.Value.ToString(), this.m_configuration.TTL); this.EnsureCacheConsistency(new DataCacheEventArgs(data)); if (this.m_configuration.PublishChanges) { var existing = redisDb.KeyExists(data.Key.Value.ToString()); #if DEBUG this.m_tracer.TraceVerbose("HashSet {0} (EXIST: {1}; @: {2})", data, existing, new System.Diagnostics.StackTrace(true).GetFrame(1)); #endif if (existing) { this.m_connection.GetSubscriber().Publish("oiz.events", $"PUT http://{Environment.MachineName}/cache/{data.Key.Value}"); } else { this.m_connection.GetSubscriber().Publish("oiz.events", $"POST http://{Environment.MachineName}/cache/{data.Key.Value}"); } //} } } catch (Exception e) { this.m_tracer.TraceError("REDIS CACHE ERROR (CACHING SKIPPED): {0}", e); } }
/// <summary> /// Update the specified data in the bundle /// </summary> /// <param name="data"></param> /// <returns></returns> public Bundle Update(Bundle data) { data = this.Validate(data); var persistence = ApplicationContext.Current.GetService <IDataPersistenceService <Bundle> >(); if (persistence == null) { throw new InvalidOperationException("Missing persistence service"); } var breService = ApplicationContext.Current.GetService <IBusinessRulesService <Bundle> >(); // Entry point IdentifiedData old = null; if (data.EntryKey != null) { var type = data.Entry.GetType(); var idps = typeof(IDataPersistenceService <>).MakeGenericType(type); var dataService = ApplicationContext.Current.GetService(idps) as IDataPersistenceService; old = (dataService.Get(data.EntryKey.Value) as IdentifiedData).Clone(); } data = breService?.BeforeUpdate(data) ?? data; data = persistence.Insert(data); data = breService?.AfterUpdate(data); this.DataUpdated?.Invoke(this, new AuditDataEventArgs(data.Item)); // Patch if (old != null) { var diff = ApplicationContext.Current.GetService <IPatchService>()?.Diff(old, data.Entry); if (diff != null) { SynchronizationQueue.Outbound.Enqueue(diff, Synchronization.Model.DataOperationType.Update); } else { SynchronizationQueue.Outbound.Enqueue(data, Synchronization.Model.DataOperationType.Update); } } else { SynchronizationQueue.Outbound.Enqueue(data, Synchronization.Model.DataOperationType.Update); } return(data); }
/// <summary> /// Updates a specific bundle. /// </summary> /// <param name="data">The data to be updated.</param> /// <returns>Returns the updated data.</returns> public IdentifiedData Update(IdentifiedData data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } var bundle = data as Bundle; if (bundle == null) { throw new ArgumentException("Bundle required", nameof(data)); } // Submit return(this.repositoryService.Update(bundle)); }
/// <summary> /// Gets the object id of the specified object from the parent instance if it exists /// </summary> public int?GetParentObjectId(IdentifiedData data) { var idx = this; while (idx != null) { if ((idx.Instance as IdentifiedData)?.Key.HasValue == true && data.Key.HasValue && (idx.Instance as IdentifiedData)?.Key.Value == data.Key.Value || idx.Instance == data) { return(idx.ObjectId); } idx = idx.Parent; } return(null); }
/// <summary> /// Fires the pre map returning whether cancellation is necessary /// </summary> private static object FireMappingToModel(object sender, Guid key, IdentifiedData modelInstance) { ModelMapEventArgs e = new ModelMapEventArgs() { ObjectType = modelInstance.GetType(), ModelObject = modelInstance, Key = key }; MappingToModel?.Invoke(sender, e); if (e.Cancel) { return(e.ModelObject); } else { return(null); } }
/// <summary> /// Obsoletes specified data. /// </summary> /// <param name="data">The data to be obsoleted.</param> public void Obsolete(IdentifiedData data, bool unsafeObsolete = false) { try { if (!(data is Bundle || data is Entity || data is Act || data is EntityRelationship)) // || data is EntityRelationship)) { return; } HdsiServiceClient client = this.GetServiceClient(); //new HdsiServiceClient(ApplicationContext.Current.GetRestClient("hdsi")); client.Client.Credentials = this.GetCredentials(client.Client); client.Client.Responding += (o, e) => this.Responding?.Invoke(o, e); if (client.Client.Credentials == null) { return; } // Force an update if (unsafeObsolete) { client.Client.Requesting += (o, e) => e.AdditionalHeaders["X-SanteDB-Unsafe"] = "true"; } else { client.Client.Requesting += (o, e) => e.AdditionalHeaders["If-Match"] = data.Tag; } var method = typeof(HdsiServiceClient).GetRuntimeMethods().FirstOrDefault(o => o.Name == "Obsolete" && o.GetParameters().Length == 1); method = method.MakeGenericMethod(data.GetType()); this.m_tracer.TraceVerbose("Performing HDSI OBSOLETE {0}", data); var iver = method.Invoke(client, new object[] { data }) as IVersionedEntity; if (iver != null) { this.UpdateToServerCopy(iver, data as IVersionedEntity); } // Indicate that the server has responded this.Responded?.Invoke(this, new IntegrationResultEventArgs(data, iver as IdentifiedData)); } catch (TargetInvocationException e) { throw Activator.CreateInstance(e.InnerException.GetType(), "Error performing action", e) as Exception; } }
/// <summary> /// Invoke the operation /// </summary> public object Invoke(Type scopingType, object scopingKey, ParameterCollection parameters) { if (parameters.TryGet <String>("other", out string bKeyString) && Guid.TryParse(scopingKey.ToString(), out Guid aKey) && Guid.TryParse(bKeyString, out Guid bKey)) { var repository = ApplicationServiceContext.Current.GetService(typeof(IRepositoryService <>).MakeGenericType(scopingType)) as IRepositoryService; if (repository == null) { throw new InvalidOperationException($"Cannot load repository for {scopingType.Name}"); } IdentifiedData objectA = repository.Get(aKey), objectB = repository.Get(bKey); return(this.m_patchService.Diff(objectA, objectB)); } else { throw new ArgumentException("Both A and B parameters must be specified"); } }
public IdentifiedData Create(string resourceType, IdentifiedData body) { this.ThrowIfNotReady(); try { var handler = ResourceHandlerUtil.Current.GetResourceHandler(resourceType); if (handler != null) { var retVal = handler.Create(body, false); var versioned = retVal as IVersionedEntity; WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Created; WebOperationContext.Current.OutgoingResponse.ETag = retVal.Tag; if (versioned != null) { WebOperationContext.Current.OutgoingResponse.Headers.Add(HttpResponseHeader.ContentLocation, String.Format("{0}/{1}/{2}/history/{3}", WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri, resourceType, retVal.Key, versioned.Key)); } else { WebOperationContext.Current.OutgoingResponse.Headers.Add(HttpResponseHeader.ContentLocation, String.Format("{0}/{1}/{2}", WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri, resourceType, retVal.Key)); } return(retVal); } else { throw new FileNotFoundException(resourceType); } } catch (Exception e) { var remoteEndpoint = OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty; this.m_traceSource.TraceEvent(TraceEventType.Error, e.HResult, String.Format("{0} - {1}", remoteEndpoint?.Address, e.ToString())); throw; } }
/// <summary> /// Create a bundle /// </summary> public static Bundle CreateBundle(IdentifiedData resourceRoot, bool followList = true) { if (resourceRoot is Bundle) { return(resourceRoot as Bundle); } Bundle retVal = new Bundle(); retVal.Key = Guid.NewGuid(); retVal.Count = retVal.TotalResults = 1; if (resourceRoot == null) { return(retVal); } retVal.FocalObjects.Add(resourceRoot.Key.Value); retVal.Add(resourceRoot); ProcessModel(resourceRoot, retVal, followList); return(retVal); }
/// <summary> /// Add cache commit /// </summary> public void AddCacheCommit(IdentifiedData data) { try { IdentifiedData existing = null; if (data.Key.HasValue && !this.m_cacheCommit.TryGetValue(data.Key.Value, out existing)) { this.m_cacheCommit.TryAdd(data.Key.Value, data); } else if (data.Key.HasValue && data.LoadState > (existing?.LoadState ?? 0)) { this.m_cacheCommit[data.Key.Value] = data; } } catch (Exception e) { this.m_tracer.TraceEvent(EventLevel.Warning, "Object {0} won't be added to cache: {1}", data, e); } }
/// <summary> /// Create the event data /// </summary> public IEnumerable <ISegment> Create(IdentifiedData data, IGroup context, AssigningAuthority[] exportDomains) { if (data is Entity) { data = (data as Entity).LoadProperty <Act>("CreationAct"); } // Data is null? if (data == null) { return(new ISegment[0]); } // Set event properties var evn = context.GetStructure("EVN") as EVN; var act = data as Act; evn.RecordedDateTime.Time.SetLongDateWithFractionOfSecond(act.CreationTime.DateTime); // Is there a participation for location var location = act.LoadCollection <ActParticipation>("Participations").FirstOrDefault(o => o.ParticipationRoleKey == ActParticipationKey.Location)?.PlayerEntityKey; if (location.HasValue) { evn.EventFacility.UniversalID.Value = location.Value.ToString(); evn.EventFacility.UniversalIDType.Value = "GUID"; } /// Planned event time if (act.MoodConceptKey == ActMoodKeys.Eventoccurrence) { evn.EventOccurred.Time.SetLongDateWithFractionOfSecond(act.ActTime.DateTime); } else if (act.MoodConceptKey == ActMoodKeys.Intent) { evn.DateTimePlannedEvent.Time.SetLongDateWithFractionOfSecond(act.ActTime.DateTime); } evn.EventReasonCode.FromModel(act.LoadProperty <Concept>("ReasonConcept"), EventReasonCodeSystem); evn.EventTypeCode.FromModel(act.LoadProperty <Concept>("TypeConcept"), EventTriggerCodeSystem); return(new ISegment[] { evn }); }
/// <summary> /// Parse the extension /// </summary> public bool Parse(Extension fhirExtension, IdentifiedData modelObject) { if (modelObject is Core.Model.Roles.Patient patient && fhirExtension.Value is CodeableConcept cc) { var isoCode = cc.Coding.FirstOrDefault(o => o.System == "urn:iso:std:iso:3166:1" || o.System == "urn:oid:1.0.3166.1.2.3"); if (isoCode != null) { var country = this.m_placeRepository.Find(o => o.Identifiers.Where(a => a.AuthorityKey == AssigningAuthorityKeys.Iso3166CountryCode).Any(i => i.Value == isoCode.Code) && StatusKeys.ActiveStates.Contains(o.StatusConceptKey.Value)).SingleOrDefault(); if (country != null && !patient.Relationships.Any(c => c.TargetEntityKey == country.Key)) { patient.Relationships.Add(new EntityRelationship(EntityRelationshipTypeKeys.Citizen, country)); return(true); } } } return(false); }
/// <summary> /// Load the related information /// </summary> public TRelated LoadRelated <TRelated>(Guid?objectKey) where TRelated : IdentifiedData, new() { #if DEBUG this.m_tracer.TraceVerbose("Delay loading related object : {0}", objectKey); #endif IdentifiedData value = null; if (objectKey.HasValue && !this.m_loadedObjects.TryGetValue(objectKey.Value, out value)) { value = EntitySource.Current.Provider.Get <TRelated>(objectKey); this.m_loadedObjects.Add(objectKey.Value, value); return((TRelated)value); } else if (value != default(TRelated)) { return((TRelated)value); } else { return(default(TRelated)); } }
public IdentifiedData Create(IdentifiedData data, bool updateIfExists) { var conceptService = ApplicationContext.Current.GetService <IConceptRepositoryService>(); Bundle bundleData = data as Bundle; bundleData?.Reconstitute(); var processData = bundleData?.Entry ?? data; if (processData is Bundle) { throw new InvalidOperationException("Bundle must have entry of type Concept"); } if (processData is Concept) { return(updateIfExists ? conceptService.SaveConcept(processData as Concept) : conceptService.InsertConcept(processData as Concept)); } throw new ArgumentException("Invalid persistence type"); }
/// <summary> /// Perform an update /// </summary> public virtual IdentifiedData Update(IdentifiedData data) { Bundle bundleData = data as Bundle; bundleData?.Reconstitute(); var processData = bundleData?.Entry ?? data; if (processData is Bundle) { throw new InvalidOperationException(string.Format("Bundle must have entry of type {0}", typeof(TResource).Name)); } else if (processData is TResource) { var entityData = data as TResource; return(this.m_repository.Save(entityData)); } else { throw new ArgumentException("Invalid persistence type"); } }
/// <summary> /// Add the specified item to the memory cache /// </summary> public void Add(IdentifiedData data) { // if the data is null, continue if (data == null || !data.Key.HasValue || (data as BaseEntityData)?.ObsoletionTime.HasValue == true || this.m_nonCached.Contains(data.GetType())) { return; } var exist = MemoryCache.Current.TryGetEntry(data.Key); MemoryCache.Current.AddUpdateEntry(data); if (exist != null) { this.Updated?.Invoke(this, new DataCacheEventArgs(data)); } else { this.Added?.Invoke(this, new DataCacheEventArgs(data)); } }
/// <summary> /// Build removal query /// </summary> private PatchOperation BuildRemoveQuery(String path, IdentifiedData c) { PatchOperation retval = new PatchOperation(PatchOperationType.Remove, path, null); var simpleAtt = c.GetType().GetCustomAttribute <SimpleValueAttribute>(); if (c.Key.HasValue && simpleAtt == null) { retval.Path += ".id"; retval.Value = c.Key; } else { var classAtt = c.GetType().GetCustomAttribute <ClassifierAttribute>(); Object cvalue = c; // Build path var serializationName = ""; while (classAtt != null && c != null) { var pi = cvalue.GetType().GetRuntimeProperty(classAtt.ClassifierProperty); var redirectProperty = pi.GetCustomAttribute <SerializationReferenceAttribute>(); // Prefer the key over the type if (redirectProperty != null) { pi = cvalue.GetType().GetRuntimeProperty(redirectProperty.RedirectProperty); } serializationName += "." + pi.GetCustomAttribute <JsonPropertyAttribute>()?.PropertyName; cvalue = pi.GetValue(cvalue); classAtt = cvalue?.GetType().GetCustomAttribute <ClassifierAttribute>(); } retval.Path += serializationName; retval.Value = cvalue; } return(retval); }
public IdentifiedData Update(IdentifiedData data) { Bundle bundleData = data as Bundle; bundleData?.Reconstitute(); var processData = bundleData?.Entry ?? data; if (processData is Bundle) { throw new InvalidOperationException(string.Format("Bundle must have entry of type {0}", nameof(IdentifierType))); } else if (processData is IdentifierType) { var identifierData = data as IdentifierType; return(this.repository.Save(identifierData)); } else { throw new ArgumentException("Invalid persistence type"); } }