コード例 #1
0
ファイル: EntitySet.cs プロジェクト: sunwei3126/CodexMicroORM
        /// <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());
        }
コード例 #2
0
        private void WriteSerializationText(JsonTextWriter tw, object o, SerializationMode mode, SerializationVisitTracker visits)
        {
            var iw = o.AsInfraWrapped(false);

            if (iw != null)
            {
                tw.WriteStartObject();

                var wot = iw.GetWrappedObject()?.GetType() ?? iw.GetBaseType();

                // We only really want/need to include type info on outermost objects (session scope level only), so reset this for all nested objects
                var nextmode = (SerializationMode)((int)mode & (-1 ^ (int)SerializationMode.IncludeType));

                if ((mode & SerializationMode.IncludeType) != 0)
                {
                    tw.WritePropertyName(Globals.SerializationTypePropertyName);
                    tw.WriteValue(o.GetType().AssemblyQualifiedName);
                }

                // Attempt to push enumerable types to the "end"
                foreach (var kvp in (from a in iw.GetAllValues() orderby a.Value is IEnumerable ? 1 : 0 select a))
                {
                    // If it's enumerable, recurse each item
                    // TODO - better way to detect primitive type like string w/o hardcoding??
                    if (kvp.Value is IEnumerable && kvp.Value.GetType() != typeof(string))
                    {
                        tw.WritePropertyName(kvp.Key);
                        tw.WriteStartArray();

                        var asEnum = (kvp.Value as IEnumerable).GetEnumerator();

                        while (asEnum.MoveNext())
                        {
                            var i = asEnum.Current;

                            // We only need to do this for tracked objects, for now we only do for value types or non-system (TODO)
                            if (i == null || i.GetType().IsValueType || i.GetType().FullName.StartsWith("System."))
                            {
                                tw.WriteValue(i);
                            }
                            else
                            {
                                if ((mode & SerializationMode.SingleLevel) == 0)
                                {
                                    var iw2 = i.AsInfraWrapped();

                                    if (iw2 != null)
                                    {
                                        SaveContents(tw, iw2, nextmode, visits);
                                    }
                                    else
                                    {
                                        if (i.GetType().IsSerializable)
                                        {
                                            tw.WriteValue(i);
                                        }
                                    }
                                }
                            }
                        }

                        tw.WriteEndArray();
                    }
                    else
                    {
                        // If it's a tracked object, recurse
                        if (kvp.Value != null && !kvp.Value.GetType().IsValueType&& CEF.CurrentServiceScope.GetTrackedByWrapperOrTarget(kvp.Value) != null)
                        {
                            if ((mode & SerializationMode.SingleLevel) == 0)
                            {
                                var iw2 = kvp.Value.AsInfraWrapped();

                                if (iw2 != null)
                                {
                                    tw.WritePropertyName(kvp.Key);
                                    SaveContents(tw, iw2, nextmode, visits);
                                }
                            }
                        }
                        else
                        {
                            if ((mode & SerializationMode.ExtendedInfoAsShadowProps) != 0)
                            {
                                var rs = iw.GetRowState();

                                if (rs == ObjectState.Modified || rs == ObjectState.ModifiedPriority)
                                {
                                    var ov = iw.GetOriginalValue(kvp.Key, false);

                                    if (ov != null)
                                    {
                                        tw.WritePropertyName("\\\\" + kvp.Key);
                                        tw.WriteValue(ov);
                                    }
                                }

                                // We write out schema metadata only when see a type for the first time
                                if (!visits.Types.Contains(wot))
                                {
                                    var pb = wot.GetProperty(kvp.Key);

                                    // Preferred data type
                                    var pt = (from a in iw.GetAllPreferredTypes() where a.Key == kvp.Key select a.Value).FirstOrDefault() ?? pb?.PropertyType;

                                    if (pt != null)
                                    {
                                        tw.WritePropertyName("\\+" + kvp.Key);
                                        tw.WriteValue(pt.AssemblyQualifiedName);

                                        // Is writeable
                                        tw.WritePropertyName("\\-" + kvp.Key);
                                        tw.WriteValue(pb?.CanWrite);
                                    }
                                }
                            }

                            if (kvp.Value != null || (mode & SerializationMode.IncludeNull) != 0)
                            {
                                if (((mode & SerializationMode.IncludeReadOnlyProps) != 0) || (wot.GetProperty(kvp.Key)?.CanWrite).GetValueOrDefault(true))
                                {
                                    if (((mode & SerializationMode.OnlyCLRProperties) == 0) || (wot.GetProperty(kvp.Key)?.CanRead).GetValueOrDefault(false))
                                    {
                                        var aud = CEF.CurrentAuditService();

                                        if (aud != null)
                                        {
                                            if (((mode & SerializationMode.OriginalForConcurrency) == 0) || (string.Compare(aud.LastUpdatedDateField, kvp.Key, true) != 0 && string.Compare(aud.IsDeletedField, kvp.Key, true) != 0))
                                            {
                                                if (kvp.Value == null || kvp.Value.GetType().IsSerializable)
                                                {
                                                    tw.WritePropertyName(kvp.Key);
                                                    tw.WriteValue(kvp.Value);
                                                }
                                            }
                                            else
                                            {
                                                // Only need to send original date - do not send isdeleted at all
                                                if (string.Compare(aud.IsDeletedField, kvp.Key, true) != 0)
                                                {
                                                    var rs = iw.GetRowState();

                                                    if (rs != ObjectState.Added && rs != ObjectState.Unlinked)
                                                    {
                                                        var val = iw.GetOriginalValue(kvp.Key, false);

                                                        if (val != null)
                                                        {
                                                            tw.WritePropertyName(kvp.Key);
                                                            tw.WriteValue(val);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if ((mode & SerializationMode.ExtendedInfoAsShadowProps) != 0)
                {
                    tw.WritePropertyName("_ot_");
                    tw.WriteValue(wot.Name);
                }

                // Allows for inclusion of object state, etc.
                iw.FinalizeObjectContents(tw, mode);

                tw.WriteEndObject();
            }
            else
            {
                tw.WriteValue(o);
            }
        }