private static bool TestSerializationPolicies(Type type)
        {
            var fullSerializerMembers = fsMetaType
                                        .Get(new fsConfig(), type)
                                        .Properties
                                        .Select(p => p._memberInfo)
                                        .OrderBy(m => m.MetadataToken)
                                        .ToList();

            var odinSerializerMembers = FormatterUtilities.GetSerializableMembers(type, SerializationPolicy.instance)
                                        .OrderBy(m => m.MetadataToken)
                                        .ToList();

            var matches = fullSerializerMembers.SequenceEqual(odinSerializerMembers);

            if (!matches)
            {
                Debug.LogWarning($"Serialization Policy mismatch on {type}: \n\nFull Serializer members:\n{fullSerializerMembers.Select(m => m.Name).ToLineSeparatedString()}\n\nOdin Serializer members:\n{odinSerializerMembers.Select(m => m.Name).ToLineSeparatedString()}\n");
            }

            return(matches);
        }
Beispiel #2
0
        /// <summary>
        /// Generates an AOT DLL, using the given parameters.
        /// </summary>
        public static void GenerateDLL(string dirPath, string assemblyName, List <Type> supportSerializedTypes, bool generateLinkXml = true)
        {
            if (!dirPath.EndsWith("/"))
            {
                dirPath += "/";
            }

            var newDllPath  = dirPath + assemblyName;
            var fullDllPath = newDllPath + ".dll";

            var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName()
            {
                Name = assemblyName
            }, AssemblyBuilderAccess.Save, dirPath);
            var module = assembly.DefineDynamicModule(assemblyName);

            assembly.SetCustomAttribute(new CustomAttributeBuilder(typeof(EmittedAssemblyAttribute).GetConstructor(new Type[0]), new object[0]));

            // The following is a fix for Unity's crappy Mono runtime that doesn't know how to do this sort
            //  of stuff properly
            //
            // We must manually remove the "Default Dynamic Assembly" module that is automatically defined,
            //  otherwise a reference to that non-existent module will be saved into the assembly's IL, and
            //  that will cause a multitude of issues.
            //
            // We do this by forcing there to be only one module - the one we just defined, and we set the
            //   manifest module to be that module as well.
            {
                var modulesField        = assembly.GetType().GetField("modules", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                var manifestModuleField = assembly.GetType().GetField("manifest_module", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                if (modulesField != null)
                {
                    modulesField.SetValue(assembly, new ModuleBuilder[] { module });
                }

                if (manifestModuleField != null)
                {
                    manifestModuleField.SetValue(assembly, module);
                }
            }

            var type = module.DefineType(assemblyName + ".PreventCodeStrippingViaReferences", TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic);

            CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(typeof(PreserveAttribute).GetConstructor(Type.EmptyTypes), new object[0]);

            type.SetCustomAttribute(attributeBuilder);

            var staticConstructor = type.DefineTypeInitializer();
            var il = staticConstructor.GetILGenerator();

            HashSet <Type> seenTypes = new HashSet <Type>();

            //var endPoint = il.DefineLabel();
            //il.Emit(OpCodes.Br, endPoint);

            foreach (var serializedType in supportSerializedTypes)
            {
                if (serializedType == null)
                {
                    continue;
                }

                if (serializedType.IsAbstract || serializedType.IsInterface)
                {
                    Debug.LogError("Skipping type '" + serializedType.GetNiceFullName() + "'! Type is abstract or an interface.");
                    continue;
                }

                if (serializedType.IsGenericType && (serializedType.IsGenericTypeDefinition || !serializedType.IsFullyConstructedGenericType()))
                {
                    Debug.LogError("Skipping type '" + serializedType.GetNiceFullName() + "'! Type is a generic type definition, or its arguments contain generic parameters; type must be a fully constructed generic type.");
                    continue;
                }

                if (seenTypes.Contains(serializedType))
                {
                    continue;
                }

                seenTypes.Add(serializedType);

                // Reference serialized type
                {
                    if (serializedType.IsValueType)
                    {
                        var local = il.DeclareLocal(serializedType);

                        il.Emit(OpCodes.Ldloca, local);
                        il.Emit(OpCodes.Initobj, serializedType);
                    }
                    else
                    {
                        var constructor = serializedType.GetConstructor(Type.EmptyTypes);

                        if (constructor != null)
                        {
                            il.Emit(OpCodes.Newobj, constructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }
                }

                // Reference and/or create formatter type
                if (!FormatterUtilities.IsPrimitiveType(serializedType) && !typeof(UnityEngine.Object).IsAssignableFrom(serializedType))
                {
                    var actualFormatter = FormatterLocator.GetFormatter(serializedType, SerializationPolicies.Unity);

                    if (actualFormatter.GetType().IsDefined <EmittedFormatterAttribute>())
                    {
                        //TODO: Make emitted formatter code compatible with IL2CPP
                        //// Emit an actual AOT formatter into the generated assembly

                        //if (this.emitAOTFormatters)
                        //{
                        //    var emittedFormatter = FormatterEmitter.EmitAOTFormatter(typeEntry.Type, module, SerializationPolicies.Unity);
                        //    var emittedFormatterConstructor = emittedFormatter.GetConstructor(Type.EmptyTypes);

                        //    il.Emit(OpCodes.Newobj, emittedFormatterConstructor);
                        //    il.Emit(OpCodes.Pop);
                        //}
                    }

                    var formatters = FormatterLocator.GetAllCompatiblePredefinedFormatters(serializedType, SerializationPolicies.Unity);

                    foreach (var formatter in formatters)
                    {
                        // Reference the pre-existing formatter

                        var formatterConstructor = formatter.GetType().GetConstructor(Type.EmptyTypes);

                        if (formatterConstructor != null)
                        {
                            il.Emit(OpCodes.Newobj, formatterConstructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }

                    //// Make sure we have a proper reflection formatter variant if all else goes wrong
                    //il.Emit(OpCodes.Newobj, typeof(ReflectionFormatter<>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes));
                    //il.Emit(OpCodes.Pop);
                }

                ConstructorInfo serializerConstructor;

                // Reference serializer variant
                if (serializedType.IsEnum)
                {
                    serializerConstructor = typeof(EnumSerializer <>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes);
                }
                else
                {
                    serializerConstructor = typeof(ComplexTypeSerializer <>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes);
                }

                il.Emit(OpCodes.Newobj, serializerConstructor);
                il.Emit(OpCodes.Pop);
            }

            //il.MarkLabel(endPoint);
            il.Emit(OpCodes.Ret);

            type.CreateType();

            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            if (File.Exists(fullDllPath))
            {
                File.Delete(fullDllPath);
            }

            if (File.Exists(fullDllPath + ".meta"))
            {
                File.Delete(fullDllPath + ".meta");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            assembly.Save(assemblyName);

            File.Move(newDllPath, fullDllPath);

            if (generateLinkXml)
            {
                File.WriteAllText(dirPath + "link.xml",
                                  @"<linker>
       <assembly fullname=""" + assemblyName + @""" preserve=""all""/>
</linker>");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            var pluginImporter = PluginImporter.GetAtPath(fullDllPath) as PluginImporter;

            if (pluginImporter != null)
            {
                //pluginImporter.ClearSettings();

                pluginImporter.SetCompatibleWithEditor(false);
                pluginImporter.SetCompatibleWithAnyPlatform(true);

                // Disable for all standalones
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux64, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinuxUniversal, false);

                // StandaloneOSXUniversal (<= 2017.2) / StandaloneOSX (>= 2017.3)
                pluginImporter.SetCompatibleWithPlatform((BuildTarget)2, false);

                if (!UnityVersion.IsVersionOrGreater(2017, 3))
                {
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)4, false);        // StandaloneOSXIntel
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)27, false);       // StandaloneOSXIntel64
                }

                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false);
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false);

                //pluginImporter.SetCompatibleWithPlatform(BuildTarget.Android, false);

                pluginImporter.SaveAndReimport();
            }

            AssetDatabase.SaveAssets();
        }
Beispiel #3
0
        /// <summary>
        /// Generates an AOT DLL, using the given parameters.
        /// </summary>
        public static void GenerateDLL(string dirPath, string assemblyName, List <Type> supportSerializedTypes, bool generateLinkXml = true)
        {
            #if UNITY_EDITOR && NET_4_6
            if (!dirPath.EndsWith("/"))
            {
                dirPath += "/";
            }

            var newDllPath  = dirPath + assemblyName;
            var fullDllPath = newDllPath + ".dll";

            var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName()
            {
                Name = assemblyName
            }, AssemblyBuilderAccess.Save, dirPath);
            var module = assembly.DefineDynamicModule(assemblyName);

            assembly.SetCustomAttribute(new CustomAttributeBuilder(typeof(EmittedAssemblyAttribute).GetConstructor(new Type[0]), new object[0]));

            // VRChat Edit: Add the UnityAPICompatibilityVersion Attribute for the current version of Unity to skip API Updating.
            #if UNITY_2019
            assembly.SetCustomAttribute(new CustomAttributeBuilder(
                                            typeof(UnityAPICompatibilityVersionAttribute).GetConstructor(new[] { typeof(string), typeof(bool) }),
                                            new object[] { Application.unityVersion, true })
                                        );
            #else
            assembly.SetCustomAttribute(new CustomAttributeBuilder(
                                            typeof(UnityAPICompatibilityVersionAttribute).GetConstructor(new[] { typeof(string) }),
                                            new object[] { Application.unityVersion })
                                        );
            #endif

            // The following is a fix for Unity's crappy Mono runtime that doesn't know how to do this sort
            //  of stuff properly
            //
            // We must manually remove the "Default Dynamic Assembly" module that is automatically defined,
            //  otherwise a reference to that non-existent module will be saved into the assembly's IL, and
            //  that will cause a multitude of issues.
            //
            // We do this by forcing there to be only one module - the one we just defined, and we set the
            //   manifest module to be that module as well.
            {
                var modulesField        = assembly.GetType().GetField("modules", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                var manifestModuleField = assembly.GetType().GetField("manifest_module", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                if (modulesField != null)
                {
                    modulesField.SetValue(assembly, new ModuleBuilder[] { module });
                }

                if (manifestModuleField != null)
                {
                    manifestModuleField.SetValue(assembly, module);
                }
            }

            var type = module.DefineType(assemblyName + ".PreventCodeStrippingViaReferences", TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.NotPublic);

            CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(typeof(PreserveAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
            type.SetCustomAttribute(attributeBuilder);

            var staticConstructor = type.DefineTypeInitializer();
            var il = staticConstructor.GetILGenerator();

            var falseLocal = il.DeclareLocal(typeof(bool));

            il.Emit(OpCodes.Ldc_I4_0);                  // Load false
            il.Emit(OpCodes.Stloc, falseLocal);         // Set to falseLocal

            HashSet <Type> seenTypes = new HashSet <Type>();

            if (UnityVersion.Major == 2019 && UnityVersion.Minor == 2)
            {
                // This here is a hack that fixes Unity's assembly updater triggering faultily in Unity 2019.2
                // (and in early 2019.3 alphas/betas, but we're not handling those). When it triggers, it edits
                // the generated AOT assembly such that it immediately causes Unity to hard crash. Having this
                // type reference present in the assembly prevents that from happening. (Any concrete type in
                // the serialization assembly would work, this one is just a random pick.)
                //
                // Unity should have fixed this in 2019.3, but said that a backport to 2019.2 is not guaranteed
                // to occur, though it might.

                supportSerializedTypes.Add(typeof(DateTimeFormatter));
            }

            //var endPoint = il.DefineLabel();
            //il.Emit(OpCodes.Br, endPoint);

            foreach (var serializedType in supportSerializedTypes)
            {
                if (serializedType == null)
                {
                    continue;
                }

                bool isAbstract = serializedType.IsAbstract || serializedType.IsInterface;

                if (serializedType.IsGenericType && (serializedType.IsGenericTypeDefinition || !serializedType.IsFullyConstructedGenericType()))
                {
                    Debug.LogError("Skipping type '" + serializedType.GetNiceFullName() + "'! Type is a generic type definition, or its arguments contain generic parameters; type must be a fully constructed generic type.");
                    continue;
                }

                if (seenTypes.Contains(serializedType))
                {
                    continue;
                }

                seenTypes.Add(serializedType);

                // Reference serialized type
                {
                    if (serializedType.IsValueType)
                    {
                        var local = il.DeclareLocal(serializedType);

                        il.Emit(OpCodes.Ldloca, local);
                        il.Emit(OpCodes.Initobj, serializedType);
                    }
                    else if (!isAbstract)
                    {
                        var constructor = serializedType.GetConstructor(Type.EmptyTypes);

                        if (constructor != null)
                        {
                            il.Emit(OpCodes.Newobj, constructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }
                }

                // Reference and/or create formatter type
                if (!FormatterUtilities.IsPrimitiveType(serializedType) && !typeof(UnityEngine.Object).IsAssignableFrom(serializedType) && !isAbstract)
                {
                    var actualFormatter = FormatterLocator.GetFormatter(serializedType, SerializationPolicies.Unity);

                    if (actualFormatter.GetType().IsDefined <EmittedFormatterAttribute>())
                    {
                        //TODO: Make emitted formatter code compatible with IL2CPP
                        //// Emit an actual AOT formatter into the generated assembly

                        //if (this.emitAOTFormatters)
                        //{
                        //    var emittedFormatter = FormatterEmitter.EmitAOTFormatter(typeEntry.Type, module, SerializationPolicies.Unity);
                        //    var emittedFormatterConstructor = emittedFormatter.GetConstructor(Type.EmptyTypes);

                        //    il.Emit(OpCodes.Newobj, emittedFormatterConstructor);
                        //    il.Emit(OpCodes.Pop);
                        //}
                    }

                    var formatters = FormatterLocator.GetAllCompatiblePredefinedFormatters(serializedType, SerializationPolicies.Unity);

                    foreach (var formatter in formatters)
                    {
                        // Reference the pre-existing formatter

                        var formatterConstructor = formatter.GetType().GetConstructor(Type.EmptyTypes);

                        if (formatterConstructor != null)
                        {
                            il.Emit(OpCodes.Newobj, formatterConstructor);
                            il.Emit(OpCodes.Pop);
                        }
                    }

                    //// Make sure we have a proper reflection formatter variant if all else goes wrong
                    //il.Emit(OpCodes.Newobj, typeof(ReflectionFormatter<>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes));
                    //il.Emit(OpCodes.Pop);
                }

                ConstructorInfo serializerConstructor;

                // Reference serializer variant
                if (serializedType.IsValueType)
                {
                    serializerConstructor = Serializer.Get(serializedType).GetType().GetConstructor(Type.EmptyTypes);

                    il.Emit(OpCodes.Newobj, serializerConstructor);

                    // The following section is a fix for an issue on IL2CPP for PS4, where sometimes bytecode isn't
                    //   generated for methods in base types of needed types - FX, Serializer<T>.ReadValueWeak()
                    //   may be missing. This only seems to happen in a relevant way for value types.
                    {
                        var endLabel = il.DefineLabel();

                        // Load a false local value, then jump to the end of this segment of code due to that
                        //   false value. This is an attempt to trick any potential code flow analysis made
                        //   by IL2CPP that checks whether this segment of code is actually run.
                        //
                        // We don't run the code because if we did, that would actually throw a bunch of
                        //   exceptions from invalid calls to ReadValueWeak and WriteValueWeak.
                        il.Emit(OpCodes.Ldloc, falseLocal);
                        il.Emit(OpCodes.Brfalse, endLabel);

                        var baseSerializerType = typeof(Serializer <>).MakeGenericType(serializedType);

                        var readValueWeakMethod  = baseSerializerType.GetMethod("ReadValueWeak", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, new Type[] { typeof(IDataReader) }, null);
                        var writeValueWeakMethod = baseSerializerType.GetMethod("WriteValueWeak", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, new Type[] { typeof(string), typeof(object), typeof(IDataWriter) }, null);

                        il.Emit(OpCodes.Dup);                               // Duplicate serializer instance
                        il.Emit(OpCodes.Ldnull);                            // Load null argument for IDataReader reader
                        il.Emit(OpCodes.Callvirt, readValueWeakMethod);     // Call ReadValueWeak on serializer instance
                        il.Emit(OpCodes.Pop);                               // Pop result of ReadValueWeak

                        il.Emit(OpCodes.Dup);                               // Duplicate serializer instance
                        il.Emit(OpCodes.Ldnull);                            // Load null argument for string name
                        il.Emit(OpCodes.Ldnull);                            // Load null argument for object value
                        il.Emit(OpCodes.Ldnull);                            // Load null argument for IDataWriter writer
                        il.Emit(OpCodes.Callvirt, writeValueWeakMethod);    // Call WriteValueWeak on serializer instance

                        il.MarkLabel(endLabel);                             // This is where the code always jumps to, skipping the above
                    }

                    il.Emit(OpCodes.Pop);       // Pop the serializer instance
                }
                else
                {
                    serializerConstructor = typeof(ComplexTypeSerializer <>).MakeGenericType(serializedType).GetConstructor(Type.EmptyTypes);
                    il.Emit(OpCodes.Newobj, serializerConstructor);
                    il.Emit(OpCodes.Pop);
                }
            }

            //il.MarkLabel(endPoint);
            il.Emit(OpCodes.Ret);

            type.CreateType();

            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            if (File.Exists(fullDllPath))
            {
                File.Delete(fullDllPath);
            }

            if (File.Exists(fullDllPath + ".meta"))
            {
                File.Delete(fullDllPath + ".meta");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            assembly.Save(assemblyName);

            File.Move(newDllPath, fullDllPath);

            if (generateLinkXml)
            {
                File.WriteAllText(dirPath + "link.xml",
                                  @"<linker>
       <assembly fullname=""" + assemblyName + @""" preserve=""all""/>
</linker>");
            }

            try
            {
                AssetDatabase.Refresh();
            }
            catch (Exception)
            {
                // Sigh, Unity 5.3.0
            }

            var pluginImporter = PluginImporter.GetAtPath(fullDllPath) as PluginImporter;

            if (pluginImporter != null)
            {
                //pluginImporter.ClearSettings();

                pluginImporter.SetCompatibleWithEditor(false);
                pluginImporter.SetCompatibleWithAnyPlatform(true);

                // Disable for all standalones
                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux64, false);

                if (!UnityVersion.IsVersionOrGreater(2019, 2))
                {
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)17, false);       // StandaloneLinux
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)25, false);       // StandaloneLinuxUniversal
                }

                // StandaloneOSXUniversal (<= 2017.2) / StandaloneOSX (>= 2017.3)
                pluginImporter.SetCompatibleWithPlatform((BuildTarget)2, false);

                if (!UnityVersion.IsVersionOrGreater(2017, 3))
                {
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)4, false);        // StandaloneOSXIntel
                    pluginImporter.SetCompatibleWithPlatform((BuildTarget)27, false);       // StandaloneOSXIntel64
                }

                pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false);
                //pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false);

                //pluginImporter.SetCompatibleWithPlatform(BuildTarget.Android, false);

                pluginImporter.SaveAndReimport();
            }

            AssetDatabase.SaveAssets();
            #endif
        }
        /// <summary>
        /// Get the metadata document as per sync specification for $metadata.
        /// </summary>
        /// <returns></returns>
        private XDocument GetMetadataDocument()
        {
            // We only have 1 scope for now.
            //Note: Currently this is read from the service configuration and * is not allowed anymore for the SetEnableScope method.
            string scopeName = _configuration.ScopeNames[0];

            // Get the type list from the TypeToTableGlobalNameMapping key list.
            List <Type> typeList = _configuration.TypeToTableGlobalNameMapping.Keys.ToList();

            var document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));

            // Add Schema node
            // example:
            //  <Edmx Namespace="http://schemas.microsoft.com/ado/2007/06/edmx">
            //     <DataServices Namespace="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
            //        <Schema Namespace="SyncServiceLibUnitTest"
            //         Alias="Self"
            //         xmlns="http://schemas.microsoft.com/ado/2009/08/edm"
            //         xmlns:sync="http://schemas.microsoft.com/sync/2010/03/syncprotocol">

            var edmxNode = new XElement(FormatterConstants.EdmxNamespace + "Edmx",
                                        new XAttribute("Version", "1.0"),
                                        new XAttribute(XNamespace.Xmlns + FormatterConstants.EdmxNsPrefix, FormatterConstants.EdmxNamespace));

            var dataservicesNode = new XElement(FormatterConstants.EdmxNamespace + "DataServices",
                                                new XAttribute(FormatterConstants.ODataMetadataNamespace + "DataServiceVersion", "2.0"),
                                                new XAttribute(XNamespace.Xmlns + FormatterConstants.ODataMetadataNsPrefix, FormatterConstants.ODataMetadataNamespace));

            var schemaNode = new XElement("Schema",
                                          new XAttribute(FormatterConstants.AtomPubXmlNsPrefix, _baseEdmNamespace),
                                          new XAttribute(XNamespace.Xmlns + FormatterConstants.SyncNsPrefix, FormatterConstants.SyncNamespace),
                                          new XAttribute("Namespace", _configuration.ServiceTypeNamespace),
                                          new XAttribute("Alias", "Self"));

            // Add entitycontainer node
            // example:
            // <EntityContainer Name="scope_name">
            var entityContainerNode = new XElement(_baseEdmNamespace + "EntityContainer",
                                                   new XAttribute("Name", scopeName));

            schemaNode.Add(entityContainerNode);

            // Add each entry as an EntityType node.
            foreach (var type in typeList)
            {
                // Add the type to the entityContainer Node as an EntitySet node
                // example:
                // <EntitySet Name="ScheduleItem" EntityType="SyncServiceLibUnitTest.ScheduleItem" />
                var entitySetNode = new XElement(_baseEdmNamespace + "EntitySet",
                                                 new XAttribute("Name", type.Name),
                                                 new XAttribute("EntityType", type.FullName));

                entityContainerNode.Add(entitySetNode);

                // Create entity type node
                // example: <EntityType Name="ScheduleItem">
                var entityType = new XElement(_baseEdmNamespace + "EntityType", new XAttribute("Name", type.Name));

                schemaNode.Add(entityType);

                // Get the keys from the Key attribute applied on the entity classes.
                PropertyInfo[] keyList = ReflectionUtility.GetPrimaryKeysPropertyInfoMapping(type);

                if (keyList.Length > 0)
                {
                    // create <Key> node
                    var keyNode = new XElement(_baseEdmNamespace + "Key");
                    foreach (var key in keyList)
                    {
                        // add PropertyRef nodes
                        // example: <PropertyRef Name="ScheduleItemID" />
                        var propertyRefNode = new XElement(_baseEdmNamespace + "PropertyRef", new XAttribute("Name", key.Name));

                        keyNode.Add(propertyRefNode);
                    }

                    entityType.Add(keyNode);
                }

                PropertyInfo[] entityProperties = ReflectionUtility.GetPropertyInfoMapping(type);

                foreach (var property in entityProperties)
                {
                    // Check if the property has a SyncEntityPropertyNullable attribute.
                    // Presence of this attribute indicates that the property is nullable/non-nullable in the underlying data store.
                    // Some data types such as string are nullable in .NET but may or may not be nullable in the data store (such as a
                    // SQL Server table in a database.)
                    bool isNullable = (0 != property.GetCustomAttributes(
                                           SyncServiceConstants.SYNC_ENTITY_PROPERTY_NULLABLE_ATTRIBUTE_TYPE, false).ToList().Count);

                    // create Property node
                    // example:
                    // <Property Name="ScheduleItemID" Type="Edm.Guid" Nullable="false" />
                    var propertyNode = new XElement(_baseEdmNamespace + "Property",
                                                    new XAttribute("Name", property.Name),
                                                    new XAttribute("Type", FormatterUtilities.GetEdmType(property.PropertyType)),
                                                    new XAttribute("Nullable", isNullable));

                    entityType.Add(propertyNode);
                }
            }

            // Add filter parameter information to the document.
            if (_configuration.FilterParameters.Count > 0)
            {
                // Write the scynscopeparameters node.
                // example: <sync:SyncScopeParameters>
                var syncScopeParamsNode = new XElement(FormatterConstants.SyncNamespace + "SyncScopeParameters");

                // We only want to add distinct filter parameters. A single parameter may be applied to many tables internally.
                var distinctFilterParams = new List <string>();
                foreach (var filterParameter in _configuration.FilterParameters)
                {
                    // Continue with the next filter parameter if we already processed the current one.
                    if (distinctFilterParams.Contains(filterParameter.QueryStringKey))
                    {
                        continue;
                    }

                    distinctFilterParams.Add(filterParameter.QueryStringKey);

                    string edmType = FormatterUtilities.GetEdmType(filterParameter.ValueType);

                    // The 'Name' of the parameter is the query string key configured in the InitializeService method using the
                    // AddFilterParameterConfiguration method.
                    // example: <sync:ScopeParameter Name="userid" Type="Edm.Guid" />
                    syncScopeParamsNode.Add(
                        new XElement(FormatterConstants.SyncNamespace + "ScopeParameter",
                                     new XAttribute("Name", filterParameter.QueryStringKey),
                                     new XAttribute("Type", edmType)));
                }

                schemaNode.Add(syncScopeParamsNode);
            }
            dataservicesNode.Add(schemaNode);
            edmxNode.Add(dataservicesNode);
            document.Add(edmxNode);
            return(document);
        }
Beispiel #5
0
 public IList <MemberInfo> SelectMembers(Type type)
 {
     return(FormatterUtilities.GetSerializableMembers(type, this.Policy));
 }
Beispiel #6
0
 protected override IEnumerable <MemberInfo> GetMembers(Type type)
 {
     return(FormatterUtilities.GetSerializableMembers(type, SerializationPolicy.instance));
 }