Example #1
0
        /// <summary>
        /// Portable serialization text is intended to be usable to send complete objects to a web client where we can have client-side JS framework awareness of the format, etc.
        /// We send back extended details including schema details that would not normally be necessary as such, hence the "portability". (Without this, we would need to know the schema ahead of time.)
        /// Options on this method support serializing a subset of properties, among other things that would be relevant when working with client-side logic.
        /// Notably things like row-state are *not* included which differs from some over-wire strategies - we expect to pair use of this method with ApplyChangesFromPortableText() in order to "apply changes" against a re-retrieved set, which has value for security, for example.
        /// The Portable being called out in the name is intended to be more explicit than making an option on the non-Portable function.
        /// </summary>
        /// <param name="mode"></param>
        /// <returns></returns>
        public string GetPortableText(PortableSerializationOptions options = null)
        {
            if (options == null)
            {
                options = new PortableSerializationOptions();
            }

            StringBuilder sb      = new StringBuilder(4096);
            var           actmode = options.Mode.GetValueOrDefault(Globals.PortableJSONMode.GetValueOrDefault(CEF.CurrentServiceScope.Settings.SerializationMode));

            CEF.CurrentServiceScope.ReconcileModifiedState(null);

            using (var jw = new JsonTextWriter(new StringWriter(sb)))
            {
                jw.FloatFormatHandling = FloatFormatHandling.DefaultValue;

                // All contained within an object
                jw.WriteStartObject();

                jw.WritePropertyName("schema");
                jw.WriteStartArray();

                var c = typeof(T).FastGetAllProperties(true, (actmode & SerializationMode.IncludeReadOnlyProps) == 0 ? true : new bool?()).ToList();

                // Use a top x sample of entries in collection to determine if there are any extended properties to serialize
                if (options.IncludeExtended.GetValueOrDefault(Globals.PortableJSONIncludeExtended) && options.ExtendedPropertySampleSize.GetValueOrDefault(Globals.PortableJSONExtendedPropertySampleSize) > 0)
                {
                    foreach (T i in this.Take(options.ExtendedPropertySampleSize.GetValueOrDefault(Globals.PortableJSONExtendedPropertySampleSize)))
                    {
                        c = c.Union(from a in i.AsInfraWrapped().GetAllPreferredTypes() select(a.Key, a.Value, true, true)).ToList();
                    }
                }

                // Explicitly remove audit if needed
                if (options.ExcludeAudit.GetValueOrDefault(Globals.PortableJSONExcludeAudit))
                {
                    if (!string.IsNullOrEmpty(CEF.CurrentAuditService()?.LastUpdatedByField))
                    {
                        var trem = (from a in c where string.Compare(a.name, CEF.CurrentAuditService()?.LastUpdatedByField, true) == 0 select a);

                        if (trem.Any())
                        {
                            c.Remove(trem.First());
                        }
                    }

                    if (!string.IsNullOrEmpty(CEF.CurrentAuditService()?.LastUpdatedDateField))
                    {
                        var trem = (from a in c where string.Compare(a.name, CEF.CurrentAuditService()?.LastUpdatedDateField, true) == 0 select a);

                        if (trem.Any())
                        {
                            c.Remove(trem.First());
                        }
                    }

                    if (!string.IsNullOrEmpty(CEF.CurrentAuditService()?.IsDeletedField))
                    {
                        var trem = (from a in c where string.Compare(a.name, CEF.CurrentAuditService()?.IsDeletedField, true) == 0 select a);

                        if (trem.Any())
                        {
                            c.Remove(trem.First());
                        }
                    }
                }

                // Apply column name filters if needed
                if (options.IncludeColumns != null)
                {
                    c = (from a in c where (from b in options.IncludeColumns where string.Compare(a.name, b, true) == 0 select b).Any() select a).ToList();
                }

                if (options.ExcludeColumns != null)
                {
                    c = (from a in c where !(from b in options.ExcludeColumns where string.Compare(a.name, b, true) == 0 select b).Any() select a).ToList();
                }

                // Get any available key for this type
                var keydef = KeyService.ResolveKeyDefinitionForType(typeof(T));

                List <string> finalName = new List <string>();
                List <Type>   finalType = new List <Type>();

                // Actual schema write based on distinct list of columns and types
                foreach (var prop in (from n in (from a in c select a.name).Distinct() select new { Name = n, Type = (from t in c where string.Compare(t.name, n, true) == 0 orderby(t.type == null ? 1 : 0) select t.type).First() }))
                {
                    var restype = prop.Type;
                    var req     = !(prop.Type.IsGenericType && prop.Type.GetGenericTypeDefinition() == typeof(Nullable <>));

                    if (!req)
                    {
                        restype = Nullable.GetUnderlyingType(prop.Type);
                    }

                    var rp = ValidationService.GetRequiredFor(typeof(T), prop.Name);

                    if (rp.HasValue)
                    {
                        req = rp.Value;
                    }

                    // Ignore non-primative ref types - things like property classes in generated code should interop with the base instance
                    if (restype.IsPrimitive || restype.IsValueType || restype.IsSerializable)
                    {
                        jw.WriteStartObject();
                        jw.WritePropertyName("cn");
                        jw.WriteValue(prop.Name);

                        if ((actmode & SerializationMode.IncludeType) != 0)
                        {
                            jw.WritePropertyName("dt");
                            jw.WriteValue(restype.Name.ToLower().Replace("system.", ""));
                            jw.WritePropertyName("key");
                            jw.WriteValue((from a in keydef where string.Compare(a, prop.Name, true) == 0 select a).Any());
                            jw.WritePropertyName("req");
                            jw.WriteValue(req);

                            // If there's a maxlength setting available, write it
                            var ml = ValidationService.GetMaxLengthFor(typeof(T), prop.Name);

                            if (ml.HasValue)
                            {
                                jw.WritePropertyName("maxlen");
                                jw.WriteValue(ml);
                            }
                        }

                        jw.WriteEndObject();

                        finalName.Add(prop.Name);
                        finalType.Add(restype);
                    }
                }

                // end schema
                jw.WriteEndArray();

                // Start data
                jw.WritePropertyName("rows");
                jw.WriteStartArray();

                var cdates = options.ConvertDates.GetValueOrDefault(Globals.PortableJSONConvertDates);

                IEnumerable <ICEFInfraWrapper> list = this.AllAsInfraWrapped();

                if (options.SortSpec != null)
                {
                    list = list.OrderBy(options.SortSpec);
                }

                if (options.FilterSpec != null)
                {
                    list = list.Where(options.FilterSpec);
                }

                foreach (var iw in list)
                {
                    if ((actmode & SerializationMode.OnlyChanged) == 0 || iw.GetRowState() != ObjectState.Unchanged)
                    {
                        jw.WriteStartArray();

                        for (int i = 0; i < finalName.Count; ++i)
                        {
                            var cv = iw.GetValue(finalName[i]);

                            if (cv == null)
                            {
                                string s = null;
                                jw.WriteValue(s);
                            }
                            else
                            {
                                if (finalType[i] == typeof(DateTime))
                                {
                                    var asdate = Convert.ToDateTime(cv);

                                    if (cdates == DateConversionMode.ToGMTAlways || (cdates == DateConversionMode.ToGMTWhenHasTime && asdate.TimeOfDay.Seconds > 0))
                                    {
                                        asdate = asdate.ToUniversalTime();
                                    }

                                    var d = Convert.ToInt64(asdate.Ticks - 621355968000000000L) / 10000L;
                                    jw.WriteValue(d);
                                }
                                else
                                {
                                    var cvt = cv.GetType();

                                    // For non-primative ref types, need to "flatten" properties
                                    if (cvt.IsValueType || cvt.IsPrimitive || cvt.IsSerializable)
                                    {
                                        jw.WriteValue(cv);
                                    }
                                }
                            }
                        }

                        jw.WriteEndArray();
                    }
                }

                // end data
                jw.WriteEndArray();
                jw.WriteEndObject();
            }

            return(sb.ToString());
        }
Example #2
0
        public IEnumerable <T> GetItemsFromSerializationText <T>(string json, JsonSerializationSettings settings) where T : class, new()
        {
            if (settings == null)
            {
                settings = new JsonSerializationSettings();
            }

            switch (settings.SerializationType)
            {
            case SerializationType.Array:
            {
                var setArray = JArray.Parse(json);

                foreach (var i in setArray.Children())
                {
                    if (i.Type == JTokenType.Object)
                    {
                        yield return(CEF.Deserialize <T>(i.ToString()));
                    }
                }

                break;
            }

            case SerializationType.ObjectWithSchemaType1AndRows:
            {
                // Read schema
                Dictionary <string, Type> schema = new Dictionary <string, Type>();

                var root = JObject.Parse(json);

                // Read schema
                foreach (var propInfo in root.GetValue(settings.SchemaName).ToArray())
                {
                    if (propInfo is JObject jo)
                    {
                        if (jo.Count < 2 || jo.Count > 3)
                        {
                            throw new CEFInvalidOperationException("Invalid JSON format.");
                        }

                        JProperty pn = (from a in jo.Children() let b = a as JProperty where b != null && b.Name.Equals(settings.SchemaFieldNameName) select b).FirstOrDefault();
                        JProperty pt = (from a in jo.Children() let b = a as JProperty where b != null && b.Name.Equals(settings.SchemaFieldTypeName) select b).FirstOrDefault();
                        JProperty pr = (from a in jo.Children() let b = a as JProperty where b != null && b.Name.Equals(settings.SchemaFieldRequiredName) select b).FirstOrDefault();

                        if (pn == null || pt == null)
                        {
                            throw new CEFInvalidOperationException("Invalid JSON format.");
                        }

                        var t     = settings.GetDataType(pt.Value.ToString());
                        var torig = t;

                        // Assume that any property might be omitted/missing which means everything should be considered nullable
                        if (t.IsValueType && !(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable <>)))
                        {
                            t = typeof(Nullable <>).MakeGenericType(t);
                        }

                        var name = pn.Value.ToString();
                        schema[name] = t;

                        // If is required, we add a validation for this
                        if (pr != null && bool.TryParse(pr.Value.ToString(), out bool prv) && prv)
                        {
                            ValidationService.RegisterRequired <T>(torig, name);
                        }
                    }
                }

                // Read objects, using the schema as the "basis" where missing/omitted properties are still carried through
                foreach (var itemInfo in root.GetValue(settings.DataRootName).ToArray())
                {
                    var obj = CEF.Deserialize <T>(itemInfo.ToString());
                    var iw  = obj.AsInfraWrapped();

                    // We need to apply property type settings after-the-fact
                    var allProp = iw.GetAllValues();

                    foreach (var propInfo in schema)
                    {
                        var existingInfo = (from a in allProp where a.Key == propInfo.Key select(propInfo.Value, a.Value));

                        if (existingInfo.Any())
                        {
                            iw.SetValue(propInfo.Key, existingInfo.First().Item2, existingInfo.First().Item1);
                        }
                        else
                        {
                            iw.SetValue(propInfo.Key, null, propInfo.Value);
                        }
                    }

                    yield return(obj);
                }

                break;
            }
            }
        }