Ejemplo n.º 1
0
        /// <summary>
        /// Copies the individual properties from the entity back in to the DataTable's first row.
        /// This should be used only when merging a user conflict resolution back in to a DataRow.
        /// This returns the merged results as an object array
        /// </summary>
        /// <param name="entity">Entity from which to read values</param>
        /// <param name="table">The Table whose first DataRow will be updated.</param>
        /// <returns>The contents of the DataRow as an object array</returns>
        internal object[] CopyEntityToDataRow(IOfflineEntity entity, DataTable table)
        {
            Debug.Assert(table.Rows.Count == 1, "table.Rows.Count ==1");
            if (table.Rows.Count != 1)
            {
                throw new InvalidOperationException("Cannot copy Entity to a DataTable whose row count != 1");
            }

            Dictionary <string, string> mappingInfo = _localToGlobalPropertyMapping[entity.GetType()];

            // Check for tombstones
            bool isRowDeleted = false;

            if (table.Rows[0].RowState == DataRowState.Deleted)
            {
                isRowDeleted = true;
                table.Rows[0].RejectChanges();
            }


            // Retrieve the current row values
            object[]       rowValues  = table.Rows[0].ItemArray;
            PropertyInfo[] properties = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            for (int i = 0; i < table.Columns.Count; i++)
            {
                // Iterate over each non sync column and read its value from the entity
                if (IsSyncSpecificColumn(table.Columns[i].ColumnName))
                {
                    continue;
                }

                // Read the value of the property
                string columnName = null;
                mappingInfo.TryGetValue(table.Columns[i].ColumnName, out columnName);
                columnName = columnName ?? table.Columns[i].ColumnName;

                // Retrieve the PropertyInfo
                PropertyInfo info = properties.Where(e => e.Name.Equals(columnName, StringComparison.Ordinal)).FirstOrDefault();

                Debug.Assert(info != null, "PropertyInfo is not null.");
                // Get the property's value and put it in the object array
                rowValues[i] = info.GetValue(entity, null) ?? DBNull.Value;
            }

            // Write the row values back to the DataRow
            table.Rows[0].ItemArray = rowValues;

            if (isRowDeleted)
            {
                table.Rows[0].Delete();
            }
            return(rowValues);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Writes the <entry/> tag and all its related elements.
        /// </summary>
        /// <param name="live">Actual entity whose value is to be emitted.</param>
        /// <param name="tempId">The temporary Id if any</param>
        /// <param name="emitPartial">Bool flag that denotes whether a partial metadata only entity is to be written</param>
        /// <returns>XElement representation of the entry element</returns>
        private XElement WriteEntry(IOfflineEntity live, string tempId, bool emitPartial)
        {
            string typeName = live.GetType().FullName;

            if (!live.ServiceMetadata.IsTombstone)
            {
                var entryElement = new XElement(FormatterConstants.AtomXmlNamespace + C.Entry);
                entryElement.Add(new XAttribute(C.Caption, typeName));

                if (!emitPartial)
                {
                    // Write the entity contents
                    WriteEntityContents(entryElement, live);
                }

                return(entryElement);
            }
            // Write the at:deleted-entry tombstone element
            var  tombstoneElement = new XElement(FormatterConstants.AtomXmlNamespace + C.Tombstone, new XAttribute(C.Caption, typeName));
            Guid id;

            if (!Guid.TryParse(live.ServiceMetadata.Id, out id))
            {
                string[] split = live.ServiceMetadata.Id.Split('\'');
                id = Guid.Parse(split[1]);
            }
            tombstoneElement.Add(id.ToString());
            return(tombstoneElement);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Build the OData Atom primary keystring representation
        /// </summary>
        /// <param name="live">Entity for which primary key is required</param>
        /// <returns>String representation of the primary key</returns>
        public static string GetPrimaryKeyString(IOfflineEntity live)
        {
            StringBuilder builder = new StringBuilder();

            string sep = string.Empty;

            foreach (PropertyInfo keyInfo in GetPrimaryKeysPropertyInfoMapping(live.GetType()))
            {
                if (keyInfo.PropertyType == FormatterConstants.GuidType)
                {
                    builder.AppendFormat("{0}{1}=guid'{2}'", sep, keyInfo.Name, keyInfo.GetValue(live, null));
                }
                else if (keyInfo.PropertyType == FormatterConstants.StringType)
                {
                    builder.AppendFormat("{0}{1}='{2}'", sep, keyInfo.Name, keyInfo.GetValue(live, null));
                }
                else
                {
                    builder.AppendFormat("{0}{1}={2}", sep, keyInfo.Name, keyInfo.GetValue(live, null));
                }

                if (string.IsNullOrEmpty(sep))
                {
                    sep = ", ";
                }
            }
            return(builder.ToString());
        }
Ejemplo n.º 4
0
        /// <summary>
        /// This writes the public contents of the Entity in the properties element.
        /// </summary>
        /// <param name="entity">Entity</param>
        /// <returns>XElement representation of the properties element</returns>
        XElement WriteEntityContents(IOfflineEntity entity)
        {
            XElement contentElement = new XElement(FormatterConstants.ODataMetadataNamespace + FormatterConstants.PropertiesElementName);

            // Write only the primary keys if its an tombstone
            PropertyInfo[] properties = ReflectionUtility.GetPropertyInfoMapping(entity.GetType());

            // Write individual properties to the feed,
            foreach (PropertyInfo fi in properties)
            {
                string edmType   = FormatterUtilities.GetEdmType(fi.PropertyType);
                object value     = fi.GetValue(entity, null);
                string valString = value as string;
                if (valString != null)
                {
                    value = AtomHelper.CleanInvalidXmlChars(valString);
                }
                Type propType = fi.PropertyType;
                if (fi.PropertyType.IsGenericType && fi.PropertyType.Name.Equals(FormatterConstants.NullableTypeName, StringComparison.InvariantCulture))
                {
                    // Its a Nullable<T> property
                    propType = fi.PropertyType.GetGenericArguments()[0];
                }

                if (value == null)
                {
                    contentElement.Add(
                        new XElement(FormatterConstants.ODataDataNamespace + fi.Name,
                                     new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubTypeElementName, edmType),
                                     new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubIsNullElementName, true)));
                }
                else if (propType == FormatterConstants.DateTimeType ||
                         propType == FormatterConstants.TimeSpanType ||
                         propType == FormatterConstants.DateTimeOffsetType)
                {
                    contentElement.Add(
                        new XElement(FormatterConstants.ODataDataNamespace + fi.Name,
                                     new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubTypeElementName, edmType),
                                     FormatterUtilities.ConvertDateTimeForType_Atom(value, propType)));
                }
                else if (propType != FormatterConstants.ByteArrayType)
                {
                    contentElement.Add(
                        new XElement(FormatterConstants.ODataDataNamespace + fi.Name,
                                     new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubTypeElementName, edmType),
                                     value));
                }
                else
                {
                    byte[] bytes = (byte[])value;
                    contentElement.Add(
                        new XElement(FormatterConstants.ODataDataNamespace + fi.Name,
                                     new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubTypeElementName, edmType),
                                     Convert.ToBase64String(bytes)));
                }
            }

            return(contentElement);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// This function loops the rejected entites and sends back a SyncError for each entity. For each entity it does the following
        /// 1. Retrieve the current version in server.
        /// 1.a If its null then it copies the primary key to a new object and marks it as tombstone.
        /// 2. Adds the SyncError to existing list of SyncErrors.
        /// </summary>
        /// <param name="sqlProvider"></param>
        private void ProcessRejectedEntities(SqlSyncProviderService sqlProvider)
        {
            if (this._rejectedEntities == null || this._rejectedEntities.Count == 0)
            {
                return;
            }

            try
            {
                List <IOfflineEntity> serverVersions = sqlProvider.GetCurrentServerVersionForEntities(this._rejectedEntities.Keys);
                if (serverVersions.Count != this._rejectedEntities.Count)
                {
                    // Ensure we get a server version for each entity we passed
                    throw new InvalidOperationException("Did not get server versions for all rejected entities.");
                }
                for (int i = 0; i < this._rejectedEntities.Keys.Count; i++)
                {
                    IOfflineEntity server = serverVersions[i];
                    IOfflineEntity client = this._rejectedEntities.Keys.ElementAt(i);

                    if (server == null)
                    {
                        // This means the server didnt contain a version for the entity. Need to send a tombstone back then
                        // create a new object and copy the values over
                        ConstructorInfo constructorInfo = client.GetType().GetConstructor(Type.EmptyTypes);
                        server = (IOfflineEntity)constructorInfo.Invoke(null);
                        // Copy the primary key values over
                        foreach (PropertyInfo info in ReflectionUtility.GetPrimaryKeysPropertyInfoMapping(client.GetType()))
                        {
                            info.SetValue(server, info.GetValue(client, null), null);
                        }
                        server.ServiceMetadata.IsTombstone = true;
                    }

                    SyncError error = new SyncError()
                    {
                        ErrorEntity = client,
                        LiveEntity  = server,
                        Description = this._rejectedEntities[client]
                    };

                    _applyChangesResponse.Errors.Add(error);
                }
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Error in reading server row values. " + e.Message);
            }
        }
Ejemplo n.º 6
0
        internal void GetEntityFromDataRow(DataColumnCollection columnCollection, DataRow row, IOfflineEntity objectToConvert)
        {
            Type t = objectToConvert.GetType();
            Dictionary <string, string> mappingInfo = _localToGlobalPropertyMapping[t];

            bool isDeleted = false;

            if (row.RowState == DataRowState.Deleted)
            {
                isDeleted = true;
                row.RejectChanges();
            }

            // Note: Call BeginEdit only after check for Deleted row state,
            // otherwise this call will crash.
            row.BeginEdit();

            for (Int32 i = 0; i <= columnCollection.Count - 1; i++)
            {
                if (IsSyncSpecificColumn(columnCollection[i].ColumnName))
                {
                    continue;
                }

                //NOTE: the datarow column names must match exactly (including case) to the IOfflineEntity's property names
                object columnValue = row[columnCollection[i].ColumnName];

                if (DBNull.Value != columnValue)
                {
                    t.InvokeMember((mappingInfo.ContainsKey(columnCollection[i].ColumnName))
                                        ? mappingInfo[columnCollection[i].ColumnName]
                                        : columnCollection[i].ColumnName,
                                   BindingFlags.SetProperty, null,
                                   objectToConvert,
                                   new[] { columnValue });
                }
            }

            if (isDeleted)
            {
                row.Delete();

                // Mark the IsTombstone field if the RowState was deleted.
                objectToConvert.ServiceMetadata.IsTombstone = true;
            }

            row.EndEdit();
        }
Ejemplo n.º 7
0
        /// <summary>
        /// This writes the public contents of the Entity in the properties element.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="entity">Entity</param>
        /// <returns>XElement representation of the properties element</returns>
        void WriteEntityContents(XElement element, IOfflineEntity entity)
        {
            // Write only the primary keys if its an tombstone
            PropertyInfo[] properties = ReflectionUtility.GetPropertyInfoMapping(entity.GetType());

            // Write individual properties to the feed,
            foreach (PropertyInfo fi in properties.OrderBy(val => val.Name.StartsWith("__") ? val.Name.Substring(2) : val.Name))
            {
                object value    = fi.GetValue(entity, null);
                Type   propType = fi.PropertyType;
                if (fi.PropertyType.IsGenericType && fi.PropertyType.Name.Equals(FormatterConstants.NullableTypeName, StringComparison.InvariantCulture))
                {
                    // Its a Nullable<T> property
                    propType = fi.PropertyType.GetGenericArguments()[0];
                }

                if (value == null)
                {
                    element.Add(new XElement(FormatterConstants.AtomXmlNamespace + C.NullableProperty));
                }
                else if (propType == FormatterConstants.DateTimeType ||
                         propType == FormatterConstants.TimeSpanType ||
                         propType == FormatterConstants.DateTimeOffsetType)
                {
                    element.Add(new XElement(FormatterConstants.AtomXmlNamespace + C.Property, FormatterUtilities.ConvertDateTimeForType_Atom(value, propType)));
                }
                else if (propType != FormatterConstants.ByteArrayType)
                {
                    element.Add(new XElement(FormatterConstants.AtomXmlNamespace + C.Property, value));
                }
                else
                {
                    byte[] bytes = (byte[])value;
                    element.Add(new XElement(FormatterConstants.AtomXmlNamespace + C.Property, Convert.ToBase64String(bytes)));
                }
            }
        }
        internal void GetEntityFromDataRow(DataColumnCollection columnCollection, DataRow row, IOfflineEntity objectToConvert)
        {
            Type t = objectToConvert.GetType();
            Dictionary<string, string> mappingInfo = _localToGlobalPropertyMapping[t];

            bool isDeleted = false;
            if (row.RowState == DataRowState.Deleted)
            {
                isDeleted = true;
                row.RejectChanges();
            }

            // Note: Call BeginEdit only after check for Deleted row state, 
            // otherwise this call will crash.
            row.BeginEdit();

            for (Int32 i = 0; i <= columnCollection.Count - 1; i++)
            {
                if (IsSyncSpecificColumn(columnCollection[i].ColumnName))
                {
                    continue;
                }

                //NOTE: the datarow column names must match exactly (including case) to the IOfflineEntity's property names
                object columnValue = row[columnCollection[i].ColumnName];

                if (DBNull.Value != columnValue)
                {
                    t.InvokeMember((mappingInfo.ContainsKey(columnCollection[i].ColumnName)) 
                                        ? mappingInfo[columnCollection[i].ColumnName]  
                                        : columnCollection[i].ColumnName,
                                   BindingFlags.SetProperty, null,
                                   objectToConvert,
                                   new[] {columnValue});
                }
            }

            if (isDeleted)
            {
                row.Delete();

                // Mark the IsTombstone field if the RowState was deleted.
                objectToConvert.ServiceMetadata.IsTombstone = true;
            }

            row.EndEdit();
        }
        /// <summary>
        /// Copies the individual properties from the entity back in to the DataTable's first row.
        /// This should be used only when merging a user conflict resolution back in to a DataRow.
        /// This returns the merged results as an object array
        /// </summary>
        /// <param name="entity">Entity from which to read values</param>
        /// <param name="table">The Table whose first DataRow will be updated.</param>
        /// <returns>The contents of the DataRow as an object array</returns>
        internal object[] CopyEntityToDataRow(IOfflineEntity entity, DataTable table)
        {
            Debug.Assert(table.Rows.Count == 1, "table.Rows.Count ==1");
            if (table.Rows.Count != 1)
            {
                throw new InvalidOperationException("Cannot copy Entity to a DataTable whose row count != 1");
            }

            Dictionary<string, string> mappingInfo = _localToGlobalPropertyMapping[entity.GetType()];

            // Check for tombstones
            bool isRowDeleted = false;
            if (table.Rows[0].RowState == DataRowState.Deleted)
            {
                isRowDeleted = true;
                table.Rows[0].RejectChanges();
            }


            // Retrieve the current row values
            object[] rowValues = table.Rows[0].ItemArray;
            PropertyInfo[] properties = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            for (int i = 0; i < table.Columns.Count; i++)
            {
                // Iterate over each non sync column and read its value from the entity
                if (IsSyncSpecificColumn(table.Columns[i].ColumnName))
                {
                    continue;
                }

                // Read the value of the property
                string columnName = null;
                mappingInfo.TryGetValue(table.Columns[i].ColumnName, out columnName);
                columnName = columnName ?? table.Columns[i].ColumnName;
         
                // Retrieve the PropertyInfo
                PropertyInfo info = properties.Where(e => e.Name.Equals(columnName, StringComparison.Ordinal)).FirstOrDefault();

                Debug.Assert(info != null, "PropertyInfo is not null.");
                // Get the property's value and put it in the object array
                rowValues[i] = info.GetValue(entity, null) ?? DBNull.Value;
            }

            // Write the row values back to the DataRow
            table.Rows[0].ItemArray = rowValues;

            if (isRowDeleted)
            {
                table.Rows[0].Delete();
            }
            return rowValues;
        }
Ejemplo n.º 10
0
        /// <summary>
        /// This writes the public contents of the Entity in the properties element.
        /// </summary>
        /// <param name="entity">Entity</param>
        /// <returns>XElement representation of the properties element</returns>
        XElement WriteEntityContents(IOfflineEntity entity)
        {
            XElement contentElement = new XElement(FormatterConstants.ODataMetadataNamespace + FormatterConstants.PropertiesElementName);

            // Write only the primary keys if its an tombstone
            IEnumerable<PropertyInfo> properties = ReflectionUtility.GetPropertyInfoMapping(entity.GetType());

            // Write individual properties to the feed,
            foreach (PropertyInfo fi in properties)
            {
                string edmType = FormatterUtilities.GetEdmType(fi.PropertyType);
                object value = fi.GetValue(entity, null);
                Type propType = fi.PropertyType;
                if(fi.PropertyType.IsGenericType() && fi.PropertyType.Name.Equals(FormatterConstants.NullableTypeName, StringComparison.CurrentCultureIgnoreCase))
                {
                    // Its a Nullable<T> property
                    propType = fi.PropertyType.GetGenericArguments()[0];
                }

                if (value == null)
                {
                    contentElement.Add(
                        new XElement(FormatterConstants.ODataDataNamespace + fi.Name,
                            new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubTypeElementName, edmType),
                            new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubIsNullElementName, true)));
                }
                else if (propType == FormatterConstants.DateTimeType ||
                    propType == FormatterConstants.TimeSpanType ||
                    propType == FormatterConstants.DateTimeOffsetType)
                {
                    contentElement.Add(
                        new XElement(FormatterConstants.ODataDataNamespace + fi.Name,
                            new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubTypeElementName, edmType),
                            FormatterUtilities.ConvertDateTimeForType_Atom(value, propType)));

                }
                else if (propType != FormatterConstants.ByteArrayType)
                {
                    contentElement.Add(
                        new XElement(FormatterConstants.ODataDataNamespace + fi.Name,
                            new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubTypeElementName, edmType),
                            value));
                }
                else
                {
                    byte[] bytes = (byte[])value;
                    contentElement.Add(
                        new XElement(FormatterConstants.ODataDataNamespace + fi.Name,
                            new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.AtomPubTypeElementName, edmType),
                            Convert.ToBase64String(bytes)));
                }
            }

            return contentElement;
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Writes the <entry/> tag and all its related elements.
        /// </summary>
        /// <param name="live">Actual entity whose value is to be emitted.</param>
        /// <param name="tempId">The temporary Id if any</param>
        /// <param name="emitPartial">Bool flag that denotes whether a partial metadata only entity is to be written</param>
        /// <returns>XElement representation of the entry element</returns>
        private XElement WriteEntry(IOfflineEntity live, string tempId, bool emitPartial)
        {
            string typeName = live.GetType().FullName;

            if (!live.GetServiceMetadata().IsTombstone)
            {
                XElement entryElement = new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubEntryElementName);

                // Add Etag
                if (!string.IsNullOrEmpty(live.GetServiceMetadata().ETag))
                {
                    entryElement.Add(new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.EtagElementName, live.GetServiceMetadata().ETag));
                }

                // Add TempId element
                if (!string.IsNullOrEmpty(tempId))
                {
                    entryElement.Add(new XElement(FormatterConstants.SyncNamespace + FormatterConstants.TempIdElementName, tempId));
                }

                // Add Id element
                entryElement.Add(new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubIdElementName,
                    string.IsNullOrEmpty(live.GetServiceMetadata().Id) ? string.Empty : live.GetServiceMetadata().Id));

                // Add title element
                entryElement.Add(new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubTitleElementName,
                        new XAttribute(FormatterConstants.AtomPubTypeElementName, "text")));

                // Add updated element
                entryElement.Add(new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubUpdatedElementName,
                            XmlConvert.ToString(DateTime.Now)));

                // Add author element
                entryElement.Add(new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubAuthorElementName,
                            new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubNameElementName)));

                // Write the <link> element
                entryElement.Add(
                    new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubLinkElementName,
                        new XAttribute(FormatterConstants.AtomPubRelAttrName, FormatterConstants.AtomPubEditLinkAttributeName),
                        new XAttribute(FormatterConstants.AtomPubTitleElementName, typeName),
                        new XAttribute(FormatterConstants.AtomPubHrefAttrName,
                            (live.GetServiceMetadata().EditUri != null) ? live.GetServiceMetadata().EditUri.ToString() : string.Empty)));

                // Write the <category> element
                entryElement.Add(
                    new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubCategoryElementName,
                        new XAttribute(FormatterConstants.AtomPubTermAttrName, live.GetType().FullName),
                        new XAttribute(FormatterConstants.AtomPubSchemaAttrName, FormatterConstants.ODataSchemaNamespace)));

                XElement contentElement = new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubContentElementName);

                if (!emitPartial)
                {
                    // Write the entity contents
                    contentElement.Add(WriteEntityContents(live));
                }

                // Add the contents entity to the outer entity.
                entryElement.Add(contentElement);

                return entryElement;
            }
            
            // Write the at:deleted-entry tombstone element
            XElement tombstoneElement = new XElement(FormatterConstants.AtomDeletedEntryNamespace + FormatterConstants.AtomDeletedEntryElementName);
            tombstoneElement.Add(new XElement(FormatterConstants.AtomNamespaceUri + FormatterConstants.AtomReferenceElementName, live.GetServiceMetadata().Id));
            tombstoneElement.Add(new XElement(FormatterConstants.SyncNamespace + FormatterConstants.AtomPubCategoryElementName, typeName));
            return tombstoneElement;
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Writes the <entry/> tag and all its related elements.
        /// </summary>
        /// <param name="live">Actual entity whose value is to be emitted.</param>
        /// <param name="tempId">The temporary Id if any</param>
        /// <param name="emitPartial">Bool flag that denotes whether a partial metadata only entity is to be written</param>
        /// <returns>XElement representation of the entry element</returns>
        private XElement WriteEntry(IOfflineEntity live, string tempId, bool emitPartial)
        {
            string typeName = live.GetType().FullName;

            if (!live.ServiceMetadata.IsTombstone)
            {
                XElement entryElement = new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubEntryElementName);

                // Add Etag
                if (!string.IsNullOrEmpty(live.ServiceMetadata.ETag))
                {
                    entryElement.Add(new XAttribute(FormatterConstants.ODataMetadataNamespace + FormatterConstants.EtagElementName, live.ServiceMetadata.ETag));
                }

                // Add TempId element
                if (!string.IsNullOrEmpty(tempId))
                {
                    entryElement.Add(new XElement(FormatterConstants.SyncNamespace + FormatterConstants.TempIdElementName, tempId));
                }

                // Add Id element
                entryElement.Add(new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubIdElementName,
                                              string.IsNullOrEmpty(live.ServiceMetadata.Id) ? string.Empty : live.ServiceMetadata.Id));

                // Add title element
                entryElement.Add(new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubTitleElementName,
                                              new XAttribute(FormatterConstants.AtomPubTypeElementName, "text")));

                // Add updated element
                entryElement.Add(new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubUpdatedElementName,
                                              XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.Utc)));

                // Add author element
                entryElement.Add(new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubAuthorElementName,
                                              new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubNameElementName)));

                // Write the <link> element
                entryElement.Add(
                    new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubLinkElementName,
                                 new XAttribute(FormatterConstants.AtomPubRelAttrName, FormatterConstants.AtomPubEditLinkAttributeName),
                                 new XAttribute(FormatterConstants.AtomPubTitleElementName, typeName),
                                 // TODO fix me
                                 new XAttribute(FormatterConstants.AtomPubHrefAttrName,
                                                (live.ServiceMetadata.EditUri != null) ? live.ServiceMetadata.EditUri.ToString() : string.Empty)));

                // Write the <category> element
                entryElement.Add(
                    new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubCategoryElementName,
                                 new XAttribute(FormatterConstants.AtomPubTermAttrName, live.GetType().FullName),
                                 new XAttribute(FormatterConstants.AtomPubSchemaAttrName, FormatterConstants.ODataSchemaNamespace)));

                XElement contentElement = new XElement(FormatterConstants.AtomXmlNamespace + FormatterConstants.AtomPubContentElementName);

                if (!emitPartial)
                {
                    // Write the entity contents
                    contentElement.Add(WriteEntityContents(live));
                }

                // Add the contents entity to the outer entity.
                entryElement.Add(contentElement);

                return(entryElement);
            }
            else
            {
                // Write the at:deleted-entry tombstone element
                XElement tombstoneElement = new XElement(FormatterConstants.AtomDeletedEntryNamespace + FormatterConstants.AtomDeletedEntryElementName);
                tombstoneElement.Add(new XElement(FormatterConstants.AtomNamespaceUri + FormatterConstants.AtomReferenceElementName, live.ServiceMetadata.Id));
                tombstoneElement.Add(new XElement(FormatterConstants.SyncNamespace + FormatterConstants.AtomPubCategoryElementName, typeName));
                return(tombstoneElement);
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// This writes the public contents of the Entity in the properties element.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="entity">Entity</param>
        /// <returns>XElement representation of the properties element</returns>
        void WriteEntityContents(XElement element, IOfflineEntity entity)
        {
            // Write only the primary keys if its an tombstone
            PropertyInfo[] properties = ReflectionUtility.GetPropertyInfoMapping(entity.GetType());

            // Write individual properties to the feed,
            foreach (PropertyInfo fi in properties.OrderBy(val => val.Name.StartsWith("__") ? val.Name.Substring(2) : val.Name))
            {
                object value = fi.GetValue(entity, null);
                Type propType = fi.PropertyType;
                if (fi.PropertyType.IsGenericType && fi.PropertyType.Name.Equals(FormatterConstants.NullableTypeName, StringComparison.InvariantCulture))
                {
                    // Its a Nullable<T> property
                    propType = fi.PropertyType.GetGenericArguments()[0];
                }

                if (value == null)
                {
                    element.Add(new XElement(FormatterConstants.AtomXmlNamespace + C.NullableProperty));
                }
                else if (propType == FormatterConstants.DateTimeType ||
                    propType == FormatterConstants.TimeSpanType ||
                    propType == FormatterConstants.DateTimeOffsetType)
                {
                    element.Add(new XElement(FormatterConstants.AtomXmlNamespace + C.Property, FormatterUtilities.ConvertDateTimeForType_Atom(value, propType)));
                }
                else if (propType != FormatterConstants.ByteArrayType)
                {
                    element.Add(new XElement(FormatterConstants.AtomXmlNamespace + C.Property, value));
                }
                else
                {
                    byte[] bytes = (byte[])value;
                    element.Add(new XElement(FormatterConstants.AtomXmlNamespace + C.Property, Convert.ToBase64String(bytes)));
                }
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Build the OData Atom primary keystring representation
        /// </summary>
        /// <param name="live">Entity for which primary key is required</param>
        /// <returns>String representation of the primary key</returns>
        public static string GetPrimaryKeyString(IOfflineEntity live)
        {
            StringBuilder builder = new StringBuilder();

            string sep = string.Empty;
            foreach (PropertyInfo keyInfo in GetPrimaryKeysPropertyInfoMapping(live.GetType()))
            {
                if (keyInfo.PropertyType == FormatterConstants.GuidType)
                    builder.AppendFormat("{0}{1}=guid'{2}'", sep, keyInfo.Name, keyInfo.GetValue(live, null));
                else if (keyInfo.PropertyType == FormatterConstants.StringType)
                    builder.AppendFormat("{0}{1}='{2}'", sep, keyInfo.Name, keyInfo.GetValue(live, null));
                else
                    builder.AppendFormat("{0}{1}={2}", sep, keyInfo.Name, keyInfo.GetValue(live, null));

                if(string.IsNullOrEmpty(sep))
                    sep = ", ";

            }
            return builder.ToString();
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Writes the Json object tag and all its related elements.
        /// </summary>
        /// <param name="live">Actual entity whose value is to be emitted.</param>
        /// <param name="entryElement">This is the parent entry element that is needs to go in to. Will be null for regular items and non null for
        /// conflict/error items only</param>
        /// <param name="tempId">The tempId for the element if passed in by the client.</param>
        /// <param name="emitPartial">Bool flag that denotes whether a partial metadata only entity is to be written</param>
        /// <returns>XElement representation of the entry element</returns>
        private XElement WriteEntry(IOfflineEntity live, XElement entryElement, string tempId, bool emitPartial)
        {
            string typeName = live.GetType().FullName;

            if (entryElement == null)
            {
                entryElement = new XElement("item",
                                            new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Object));
            }

            // Write the _metadata object for this entry
            XElement entryMetadata = new XElement(FormatterConstants.JsonSyncEntryMetadataElementName,
                                                  new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Object));

            // Add the tempId to metadata
            if (!string.IsNullOrEmpty(tempId))
            {
                entryMetadata.Add(new XElement(FormatterConstants.TempIdElementName,
                                               new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String), tempId));
            }

            // Add the uri to metadata
            entryMetadata.Add(new XElement(FormatterConstants.JsonSyncEntryUriElementName,
                                           new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                                           string.IsNullOrEmpty(live.ServiceMetadata.Id) ? string.Empty : live.ServiceMetadata.Id));

            // Add the etag to metadata
            if (!string.IsNullOrEmpty(live.ServiceMetadata.ETag))
            {
                entryMetadata.Add(new XElement(FormatterConstants.EtagElementName,
                                               new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String), live.ServiceMetadata.ETag));
            }

            // Add the edituri to metadata
            if (live.ServiceMetadata.EditUri != null)
            {
                entryMetadata.Add(new XElement(FormatterConstants.EditUriElementName,
                                               new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String), live.ServiceMetadata.EditUri));
            }

            // Add the type to metadata
            entryMetadata.Add(new XElement(FormatterConstants.JsonSyncEntryTypeElementName,
                                           new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                                           typeName));

            // Write the tombstone element
            if (live.ServiceMetadata.IsTombstone)
            {
                entryMetadata.Add(new XElement(FormatterConstants.IsDeletedElementName,
                                               new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Boolean),
                                               true));
            }
            else if (!emitPartial)
            {
                // Write the entity contents only when its not a tombstone
                WriteEntityContentsToElement(entryElement, live);
            }

            // Add the metadata to the entry element
            entryElement.Add(entryMetadata);

            return(entryElement);
        }
        //Note: Removed ref here
        private void AddEntityToDataSet(IOfflineEntity objectToRead, DataSet dataSet, string tableName)
        {
            Type t = objectToRead.GetType();
            PropertyInfo[] properties = t.GetProperties();

            Dictionary<string, string> globalToLocalMappingInfo = _globalToLocalPropertyMapping[t];

            Dictionary<string, string> localToGlobalMappingInfo = _localToGlobalPropertyMapping[t];

            // We need to create the table if it doesn't already exist
            DataTable dataTable = dataSet.Tables[tableName];

            if (dataTable == null)
            {            
                dataSet.Tables.Add(tableName);

                dataTable = dataSet.Tables[tableName];

                // Create the columns of the table based off the 
                // properties we reflected from the type
                foreach (PropertyInfo property in properties)
                {
                    // Do not add service related properties.
                    if (IsOfflineEntityServiceProperty(property.PropertyType))
                    {
                        continue;
                    }

                    Type type = property.PropertyType;
                    if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        type = property.PropertyType.GetGenericArguments()[0];
                    }

                    if (globalToLocalMappingInfo.ContainsKey(property.Name))
                    {
                        dataTable.Columns.Add(globalToLocalMappingInfo[property.Name], type);
                    }
                    else
                    {
                        dataTable.Columns.Add(property.Name, type);
                    }
                }

                // SQL Provider does not set primary keys on DataTable. So set Primary Keys if its not set
                ReflectionUtility.SetDataTablePrimaryKeys(dataTable, objectToRead.GetType(), globalToLocalMappingInfo);
            }

            dataTable.BeginLoadData();

            // Now the table should exist so add records to it.
            var columnArray = new object[dataTable.Columns.Count];

            for (int i = 0; i <= columnArray.Length - 1; i++)
            {
                // The property name to be set on the IOfflineEntity is the ColumnName unless there is a
                // SyncEntityPropertyMappingAttribute for the property in which case the name of that property is used instead.
                string colName = dataTable.Columns[i].ColumnName;
                if (localToGlobalMappingInfo.ContainsKey(colName))
                {
                    colName = localToGlobalMappingInfo[colName];
                }

                if (objectToRead.ServiceMetadata.IsTombstone && !dataTable.PrimaryKey.Contains(dataTable.Columns[i]))
                {
                    columnArray[i] = DBNull.Value;
                }
                else
                {
                    columnArray[i] = t.InvokeMember(colName,
                                                BindingFlags.GetProperty, null,
                                                objectToRead, new object[0]);
                    if (columnArray[i] != null)
                    {
                        if (columnArray[i].Equals(new Guid("00000000-0000-0000-0000-000000000000")))
                            columnArray[i] = DBNull.Value;
                    }
                }
            }

            // Add the row to the table in the dataset
            DataRow row = dataTable.LoadDataRow(columnArray, true);

            // If the entity is a tombstone, set the DataRowState property by calling the Delete or SetAdded method.
            if (objectToRead.ServiceMetadata.IsTombstone)
            {
                row.Delete();
            }
            else
            {
                row.SetAdded();
            }

            dataTable.EndLoadData();
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Generate the Id for an entity. The format currently is the OData Id.
        /// i.e. http://baseUri/tableName(primarykeylist)
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        internal static string GenerateOfflineEntityId(IOfflineEntity entity)
        {
            var primaryKeyString = ReflectionUtility.GetPrimaryKeyString(entity);

            if (String.IsNullOrEmpty(primaryKeyString))
            {
                throw SyncServiceException.CreateInternalServerError(
                          String.Format("GetPrimaryKeyString method returned an empty string for entity type {0}.", entity.GetType()));
            }

            return(String.Format(@"{0}/{1}({2})", "http://bitmobile.com/" + AppDomain.CurrentDomain.FriendlyName /*WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri*/, entity.GetType().Name, primaryKeyString));
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Parse the Id string and populate key fields of the object. This is called when the client sends tombstones
        /// and the Key fields are not present in the input payload.
        /// The approach used is to parse each key field individually and set it to a property with the same name.
        /// For example: For http://host/service.svc/Tag(ID=1), we parse out ID=1 and then populate the ID property of the targetObject with the
        /// value 1.
        /// </summary>
        /// <param name="entity">Entity for which we need to set the key fields.</param>
        /// <param name="serviceBaseUri">
        /// Base Uri of the service. The ServiceMetadata.Id property has the Uri which we want to strip off before attempting to
        /// parse the keys and values.
        /// </param>
        internal static void ParseIdStringAndPopulateKeyFields(IOfflineEntity entity, Uri serviceBaseUri)
        {
            Debug.Assert(null != entity);
            Debug.Assert(!String.IsNullOrEmpty(entity.ServiceMetadata.Id));

            string idString = entity.ServiceMetadata.Id;

            // Remove the ServiceUri and the entity type name from the EntityId
            // Note: Case sensitive comparisons are made since the client isn't supposed to change the Id for an
            // entity.
            string serviceUriWithTableName = serviceBaseUri + "/" + entity.GetType().Name;

            // If the Id does not have the correct format of serviceUri/TableName, then we should not continue further.
            if (!idString.StartsWith(serviceUriWithTableName, false, CultureInfo.InvariantCulture))
            {
                throw SyncServiceException.CreateBadRequestError(String.Format(Strings.EntityIdFormatIsIncorrect, idString));
            }

            // Remove the host and the table name from the Id.
            // Example: http://host/service.svc/table(id=123) will become (id=123)
            idString = idString.Remove(0, serviceUriWithTableName.Length);

            // Remove leading '/' if any. After this the id string is of the format (ID=1) or (ID=guid'<guidValue>')
            // If there are multiple Id values then, they are comma separated.));))
            if (idString.StartsWith("/"))
            {
                idString = idString.Substring(1);
            }

            // Make sure the ( and ) parenthesis exist.
            if (String.IsNullOrEmpty(idString) || idString[0] != '(' || idString[idString.Length - 1] != ')')
            {
                throw SyncServiceException.CreateBadRequestError(String.Format(Strings.EntityIdFormatIsIncorrect, entity.ServiceMetadata.Id));
            }

            // Remove the ( and ) characters.
            idString = idString.Substring(1, idString.Length - 2);

            // Get the key properties for the entity.
            var keyFieldPropertyInfoList = ReflectionUtility.GetPrimaryKeysPropertyInfoMapping(entity.GetType());

            // Split the string and get individual keyvalue pair strings. They key and value are still a single string separated by '='.
            // for types such as Guid, the value will be prefixed with 'guid'.
            string[] primaryKeyValuePair = idString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            // Throw if there is a mismatch between the key count of the entity and that passed in the URI.
            if (primaryKeyValuePair.Length != keyFieldPropertyInfoList.Length)
            {
                throw SyncServiceException.CreateBadRequestError(String.Format(Strings.BadRequestKeyCountMismatch, entity.ServiceMetadata.Id, entity.GetType()));
            }

            // At this point, we have key value pairs of the form "ID=1".
            foreach (var keyValuePair in primaryKeyValuePair)
            {
                // example: ID=1
                string[] keyValue = keyValuePair.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);

                // Every key should have only 2 components.
                Debug.Assert(2 == keyValue.Length);

                // Get the property from the key list.
                string key          = keyValue[0].Trim();
                var    propertyInfo = keyFieldPropertyInfoList.Where(p => p.Name == key).FirstOrDefault();

                if (null == propertyInfo)
                {
                    throw SyncServiceException.CreateBadRequestError(
                              String.Format(Strings.BadRequestKeyNotFoundInResource, key, entity.ServiceMetadata.Id, entity.GetType()));
                }

                // Get typed value of the value.
                object targetValue;
                // Parse the value based on the target type.
                if (!ODataIdParser.TryKeyStringToPrimitive(keyValue[1], propertyInfo.PropertyType, out targetValue))
                {
                    throw SyncServiceException.CreateBadRequestError(
                              String.Format(Strings.UnableToParseKeyValueForProperty, keyValuePair, entity.ServiceMetadata.Id));
                }

                // Set the property value.
                propertyInfo.SetValue(entity, targetValue, null);
            }
        }
Ejemplo n.º 19
0
        //Note: Removed ref here
        private void AddEntityToDataSet(IOfflineEntity objectToRead, DataSet dataSet, string tableName)
        {
            Type t = objectToRead.GetType();

            PropertyInfo[] properties = t.GetProperties();

            Dictionary <string, string> globalToLocalMappingInfo = _globalToLocalPropertyMapping[t];

            Dictionary <string, string> localToGlobalMappingInfo = _localToGlobalPropertyMapping[t];

            // We need to create the table if it doesn't already exist
            DataTable dataTable = dataSet.Tables[tableName];

            if (dataTable == null)
            {
                dataSet.Tables.Add(tableName);

                dataTable = dataSet.Tables[tableName];

                // Create the columns of the table based off the
                // properties we reflected from the type
                foreach (PropertyInfo property in properties)
                {
                    // Do not add service related properties.
                    if (IsOfflineEntityServiceProperty(property.PropertyType))
                    {
                        continue;
                    }

                    Type type = property.PropertyType;
                    if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable <>))
                    {
                        type = property.PropertyType.GetGenericArguments()[0];
                    }

                    if (globalToLocalMappingInfo.ContainsKey(property.Name))
                    {
                        dataTable.Columns.Add(globalToLocalMappingInfo[property.Name], type);
                    }
                    else
                    {
                        dataTable.Columns.Add(property.Name, type);
                    }
                }

                // SQL Provider does not set primary keys on DataTable. So set Primary Keys if its not set
                ReflectionUtility.SetDataTablePrimaryKeys(dataTable, objectToRead.GetType(), globalToLocalMappingInfo);
            }

            dataTable.BeginLoadData();

            // Now the table should exist so add records to it.
            var columnArray = new object[dataTable.Columns.Count];

            for (int i = 0; i <= columnArray.Length - 1; i++)
            {
                // The property name to be set on the IOfflineEntity is the ColumnName unless there is a
                // SyncEntityPropertyMappingAttribute for the property in which case the name of that property is used instead.
                string colName = dataTable.Columns[i].ColumnName;
                if (localToGlobalMappingInfo.ContainsKey(colName))
                {
                    colName = localToGlobalMappingInfo[colName];
                }

                if (objectToRead.ServiceMetadata.IsTombstone && !dataTable.PrimaryKey.Contains(dataTable.Columns[i]))
                {
                    columnArray[i] = DBNull.Value;
                }
                else
                {
                    columnArray[i] = t.InvokeMember(colName,
                                                    BindingFlags.GetProperty, null,
                                                    objectToRead, new object[0]);
                    if (columnArray[i] != null)
                    {
                        if (columnArray[i].Equals(new Guid("00000000-0000-0000-0000-000000000000")))
                        {
                            columnArray[i] = DBNull.Value;
                        }
                    }
                }
            }

            // Add the row to the table in the dataset
            DataRow row = dataTable.LoadDataRow(columnArray, true);

            // If the entity is a tombstone, set the DataRowState property by calling the Delete or SetAdded method.
            if (objectToRead.ServiceMetadata.IsTombstone)
            {
                row.Delete();
            }
            else
            {
                row.SetAdded();
            }

            dataTable.EndLoadData();
        }
        /// <summary>
        /// Writes the Json object tag and all its related elements.
        /// </summary>
        /// <param name="live">Actual entity whose value is to be emitted.</param>
        /// <param name="entryElement">This is the parent entry element that is needs to go in to. Will be null for regular items and non null for 
        /// conflict/error items only</param>
        /// <param name="tempId">The tempId for the element if passed in by the client.</param>
        /// <param name="emitPartial">Bool flag that denotes whether a partial metadata only entity is to be written</param>
        /// <returns>XElement representation of the entry element</returns>
        private XElement WriteEntry(IOfflineEntity live, XElement entryElement, string tempId, bool emitPartial)
        {
            string typeName = live.GetType().FullName;

            if (entryElement == null)
            {
                entryElement = new XElement("item",
                   new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Object));
            }

            // Write the _metadata object for this entry
            XElement entryMetadata = new XElement(FormatterConstants.JsonSyncEntryMetadataElementName,
                new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Object));

            // Add the tempId to metadata
            if (!string.IsNullOrEmpty(tempId))
            {
                entryMetadata.Add(new XElement(FormatterConstants.TempIdElementName,
                    new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String), tempId));
            }

            // Add the uri to metadata
            entryMetadata.Add(new XElement(FormatterConstants.JsonSyncEntryUriElementName,
                new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                string.IsNullOrEmpty(live.ServiceMetadata.Id) ? string.Empty : live.ServiceMetadata.Id));

            // Add the etag to metadata
            if (!string.IsNullOrEmpty(live.ServiceMetadata.ETag))
            {
                entryMetadata.Add(new XElement(FormatterConstants.EtagElementName,
                    new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String), live.ServiceMetadata.ETag));
            }

            // Add the edituri to metadata
            if (live.ServiceMetadata.EditUri != null)
            {
                entryMetadata.Add(new XElement(FormatterConstants.EditUriElementName,
                    new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String), live.ServiceMetadata.EditUri));
            }

            // Add the type to metadata
            entryMetadata.Add(new XElement(FormatterConstants.JsonSyncEntryTypeElementName,
                new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                typeName));

            // Write the tombstone element
            if (live.ServiceMetadata.IsTombstone)
            {
                entryMetadata.Add(new XElement(FormatterConstants.IsDeletedElementName,
                    new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Boolean),
                    true));
            }
            else if (!emitPartial)
            {
                // Write the entity contents only when its not a tombstone
                WriteEntityContentsToElement(entryElement, live);
            }

            // Add the metadata to the entry element
            entryElement.Add(entryMetadata);

            return entryElement;
        }
Ejemplo n.º 21
0
        /// <summary>
        /// This writes the public contents of the Entity to the passed in XElement.
        /// </summary>
        /// <param name="contentElement">The XElement to which the type properties is added to</param>
        /// <param name="entity">Entity</param>
        /// <returns>XElement representation of the properties element</returns>
        void WriteEntityContentsToElement(XElement contentElement, IOfflineEntity entity)
        {
            PropertyInfo[] properties = ReflectionUtility.GetPropertyInfoMapping(entity.GetType());

            // Write individual properties to the feed,
            foreach (PropertyInfo fi in properties)
            {
                object objValue = fi.GetValue(entity, null);
                if (objValue == null)
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                                     new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Null),
                                     objValue));
                }
                else if (fi.PropertyType == FormatterConstants.CharType ||
                         fi.PropertyType == FormatterConstants.StringType ||
                         fi.PropertyType == FormatterConstants.GuidType)
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                                     new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                                     objValue));
                }
                else if (fi.PropertyType == FormatterConstants.DateTimeType ||
                         fi.PropertyType == FormatterConstants.TimeSpanType ||
                         fi.PropertyType == FormatterConstants.DateTimeOffsetType)
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                                     new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                                     FormatterUtilities.ConvertDateTimeForType_Json(objValue, fi.PropertyType)));
                }
                else if (fi.PropertyType == FormatterConstants.BoolType)
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                                     new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Boolean),
                                     objValue));
                }
                else if (fi.PropertyType == FormatterConstants.ByteArrayType)
                {
                    byte[] bytes = (byte[])objValue;
                    contentElement.Add(
                        new XElement(fi.Name,
                                     new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                                     Convert.ToBase64String(bytes)));
                }
                else if (fi.PropertyType.IsGenericType && fi.PropertyType.Name.Equals(FormatterConstants.NullableTypeName, StringComparison.InvariantCulture))
                {
                    // Its a Nullable<T> property
                    Type genericParamType = fi.PropertyType.GetGenericArguments()[0];

                    string elementType = JsonElementTypes.Number;
                    if (genericParamType == FormatterConstants.BoolType)
                    {
                        elementType = JsonElementTypes.Boolean;
                    }
                    else if (genericParamType == FormatterConstants.DateTimeType ||
                             genericParamType == FormatterConstants.TimeSpanType ||
                             genericParamType == FormatterConstants.DateTimeOffsetType)
                    {
                        contentElement.Add(
                            new XElement(fi.Name,
                                         new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                                         FormatterUtilities.ConvertDateTimeForType_Json(objValue, genericParamType)));
                        continue;
                    }
                    else if (genericParamType == FormatterConstants.CharType ||
                             genericParamType == FormatterConstants.GuidType)
                    {
                        elementType = JsonElementTypes.String;
                    }

                    contentElement.Add(
                        new XElement(fi.Name,
                                     new XAttribute(FormatterConstants.JsonTypeAttributeName, elementType),
                                     objValue));
                }
                else // Its a number
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                                     new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Number),
                                     objValue));
                }
            }
        }
        /// <summary>
        /// This writes the public contents of the Entity to the passed in XElement.
        /// </summary>
        /// <param name="contentElement">The XElement to which the type properties is added to</param>
        /// <param name="entity">Entity</param>
        /// <returns>XElement representation of the properties element</returns>
        void WriteEntityContentsToElement(XElement contentElement, IOfflineEntity entity)
        {
            PropertyInfo[] properties = ReflectionUtility.GetPropertyInfoMapping(entity.GetType());

            // Write individual properties to the feed,
            foreach (PropertyInfo fi in properties)
            {
                object objValue = fi.GetValue(entity, null);
                if (objValue == null)
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                            new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Null),
                            objValue));
                }
                else if (fi.PropertyType == FormatterConstants.CharType ||
                    fi.PropertyType == FormatterConstants.StringType ||
                    fi.PropertyType == FormatterConstants.GuidType)
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                            new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                            objValue));
                }
                else if (fi.PropertyType == FormatterConstants.DateTimeType ||
                    fi.PropertyType == FormatterConstants.TimeSpanType ||
                    fi.PropertyType == FormatterConstants.DateTimeOffsetType)
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                            new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                            FormatterUtilities.ConvertDateTimeForType_Json(objValue, fi.PropertyType)));
                }
                else if (fi.PropertyType == FormatterConstants.BoolType)
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                            new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Boolean),
                            objValue));
                }
                else if (fi.PropertyType == FormatterConstants.ByteArrayType)
                {
                    byte[] bytes = (byte[])objValue;
                    contentElement.Add(
                        new XElement(fi.Name,
                            new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                            Convert.ToBase64String(bytes)));
                }
                else if (fi.PropertyType.IsGenericType && fi.PropertyType.Name.Equals(FormatterConstants.NullableTypeName, StringComparison.InvariantCulture))
                {
                    // Its a Nullable<T> property
                    Type genericParamType = fi.PropertyType.GetGenericArguments()[0];

                    string elementType = JsonElementTypes.Number;
                    if (genericParamType == FormatterConstants.BoolType)
                    {
                        elementType = JsonElementTypes.Boolean;
                    }
                    else if (genericParamType == FormatterConstants.DateTimeType ||
                        genericParamType == FormatterConstants.TimeSpanType ||
                        genericParamType == FormatterConstants.DateTimeOffsetType)
                    {
                        contentElement.Add(
                            new XElement(fi.Name,
                                new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.String),
                                FormatterUtilities.ConvertDateTimeForType_Json(objValue, genericParamType)));
                        continue;
                    }
                    else if (genericParamType == FormatterConstants.CharType ||
                        genericParamType == FormatterConstants.GuidType)
                    {
                        elementType = JsonElementTypes.String;
                    }

                    contentElement.Add(
                        new XElement(fi.Name,
                            new XAttribute(FormatterConstants.JsonTypeAttributeName, elementType),
                            objValue));

                }
                else // Its a number
                {
                    contentElement.Add(
                        new XElement(fi.Name,
                            new XAttribute(FormatterConstants.JsonTypeAttributeName, JsonElementTypes.Number),
                            objValue));
                }
            }
        }
        /// <summary>
        /// Generate and save the SyncId of the LiveEntity. 
        /// This value is used later after all changes are applied to project on the latest 
        /// server knowledge and add positive exceptions to the updated client knowledge that is sent in the response.
        /// </summary>
        /// <param name="tableName">Table name that the entity represents</param>
        /// <param name="c">Conflicting entity for which we need to save the SyncId.</param>
        private SyncId GenerateSyncIdForConflictingEntity(string tableName, IOfflineEntity c)
        {
            Debug.Assert(null != c, "null != c");

            var pkValues = new List<object>();

            // Get the primary key values from the LiveEntity
            Type entityType = c.GetType();

            // The ordering of keys here is assumed to be the same order in which SyncId's are generated.
            // Otherwise, behavior is undefined and incorrect positive exceptions are added.
            PropertyInfo[] primaryKeyPropertyInfoMapping = ReflectionUtility.GetPrimaryKeysPropertyInfoMapping(entityType);

            foreach (var propertyInfo in primaryKeyPropertyInfoMapping)
            {
                pkValues.Add(propertyInfo.GetValue(c, null));
            }

            // Generate the SyncId for the conflicting item.
            SyncId rowId = SyncUtil.InitRowId(tableName, pkValues);

            return rowId;
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Writes the <entry/> tag and all its related elements.
        /// </summary>
        /// <param name="live">Actual entity whose value is to be emitted.</param>
        /// <param name="tempId">The temporary Id if any</param>
        /// <param name="emitPartial">Bool flag that denotes whether a partial metadata only entity is to be written</param>
        /// <returns>XElement representation of the entry element</returns>
        private XElement WriteEntry(IOfflineEntity live, string tempId, bool emitPartial)
        {
            string typeName = live.GetType().FullName;

            if (!live.ServiceMetadata.IsTombstone)
            {
                var entryElement = new XElement(FormatterConstants.AtomXmlNamespace + C.Entry);
                entryElement.Add(new XAttribute(C.Caption, typeName));

                if (!emitPartial)
                {
                    // Write the entity contents
                    WriteEntityContents(entryElement, live);
                }

                return entryElement;
            }
            // Write the at:deleted-entry tombstone element
            var tombstoneElement = new XElement(FormatterConstants.AtomXmlNamespace + C.Tombstone, new XAttribute(C.Caption, typeName));
            Guid id;
            if (!Guid.TryParse(live.ServiceMetadata.Id, out id))
            {
                string[] split = live.ServiceMetadata.Id.Split('\'');
                id = Guid.Parse(split[1]);
            }
            tombstoneElement.Add(id.ToString());
            return tombstoneElement;
        }