Beispiel #1
0
        //Note: This method changes the state of a static class. So results may not be as expected in multi-threaded scenarios.
        internal void InvokeTestHookInitializeMethod(Type type)
        {
            if (WebUtil.IsFriendClass(type))
            {
                const BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;
                MethodInfo         info        = type.GetMethod("InitializeConfigurationTestHook", bindingAttr, null, new[] { typeof(ISyncServiceConfiguration) }, null);

                if ((info != null) && (info.ReturnType == typeof(void)))
                {
                    ParameterInfo[] parameters = info.GetParameters();
                    if ((parameters.Length == 1) && !parameters[0].IsOut)
                    {
                        var objArray = new object[] { this };
                        try
                        {
                            info.Invoke(null, objArray);
                        }
                        catch (TargetInvocationException exception)
                        {
                            SyncTracer.Warning("Exception invoking the TestHookInitialization method. Details {0}", WebUtil.GetExceptionMessage(exception));
                            ErrorHandler.HandleTargetInvocationException(exception);
                            throw;
                        }
                        return;
                    }
                }
            }
        }
 /// <summary>
 /// Delegate passed into the custom body writer to form the outgoing response.
 /// </summary>
 /// <param name="writer"></param>
 /// <param name="syncWriter"></param>
 private static void WriteResponse(XmlDictionaryWriter writer, SyncWriter syncWriter)
 {
     try
     {
         syncWriter.WriteFeed(writer);
     }
     catch (Exception exception)
     {
         // An exception at this point seems to be unrecoverable but ideally we should not hit exceptions since we are only
         // writing to the XmlDictionaryWriter.
         SyncServiceTracer.TraceError("Exception in WriteResponse method. Details: {0}", WebUtil.GetExceptionMessage(exception));
     }
 }
Beispiel #3
0
        /// <summary>
        /// Invokes the InitializeService user method.
        /// </summary>
        /// <param name="type">service type (used for reflection)</param>
        private void InvokeStaticInitialization(Type type)
        {
            // Search for the InitializeService method going from most-specific to least-specific type.

            const BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;

            while (type != null)
            {
                MethodInfo info = type.GetMethod("InitializeService", bindingAttr, null, new[] { typeof(ISyncServiceConfiguration) }, null);

                if ((info != null) && (info.ReturnType == typeof(void)))
                {
                    ParameterInfo[] parameters = info.GetParameters();

                    if ((parameters.Length == 1) && !parameters[0].IsOut)
                    {
                        var objArray = new object[] { this };

                        try
                        {
                            info.Invoke(null, objArray);

                            return;
                        }
                        catch (TargetInvocationException exception)
                        {
                            SyncTracer.Warning("Exception invoking the static InitializeService method. Details {0}", WebUtil.GetExceptionMessage(exception));

                            ErrorHandler.HandleTargetInvocationException(exception);

                            throw;
                        }
                    }
                }

                type = type.BaseType;
            }

            // We should never exit from here when the InitializeService method is implemented.
            throw SyncServiceException.CreateInternalServerError(Strings.InitializeServiceMethodNotImplemented);
        }
Beispiel #4
0
        /// <summary>Check whether a connection can be opened successfully to the database.</summary>
        /// <param name="configuration">Service configuration</param>
        /// <returns>Result of the diagnostic check</returns>
        private static DiagTestResult CheckSqlConnection(SyncServiceConfiguration configuration)
        {
            var result = new DiagTestResult();

            try
            {
                new SqlConnectionStringBuilder(configuration.ServerConnectionString);
            }
            catch (KeyNotFoundException keyNotFoundException)
            {
                result.TestResult = DiagConstants.INVALID_SQL_CONNECTION_STRING;

                if (IsLocalRequest)
                {
                    result.ExceptionDetails = WebUtil.GetExceptionMessage(keyNotFoundException);
                }
            }
            catch (FormatException formatException)
            {
                result.TestResult = DiagConstants.INVALID_SQL_CONNECTION_STRING;

                if (IsLocalRequest)
                {
                    result.ExceptionDetails = WebUtil.GetExceptionMessage(formatException);
                }
            }
            catch (ArgumentException argumentException)
            {
                result.TestResult = DiagConstants.INVALID_SQL_CONNECTION_STRING;

                if (IsLocalRequest)
                {
                    result.ExceptionDetails = WebUtil.GetExceptionMessage(argumentException);
                }
            }
            catch (Exception e)
            {
                result.TestResult = DiagConstants.UNKNOWN_ERROR;

                if (IsLocalRequest)
                {
                    result.ExceptionDetails = WebUtil.GetExceptionMessage(e);
                }
            }

            if (result.TestResult == DiagConstants.NOT_DETERMINED)
            {
                try
                {
                    using (var connection = new SqlConnection(configuration.ServerConnectionString))
                    {
                        connection.Open();
                    }

                    result.TestResult = DiagConstants.SUCCESS;
                }
                catch (InvalidOperationException invalidOperationException)
                {
                    result.TestResult = DiagConstants.ERROR_OPENING_SQL_CONNECTION;

                    if (IsLocalRequest)
                    {
                        result.ExceptionDetails = WebUtil.GetExceptionMessage(invalidOperationException);
                    }
                }
                catch (SqlException sqlException)
                {
                    result.TestResult = DiagConstants.ERROR_OPENING_SQL_CONNECTION;

                    if (IsLocalRequest)
                    {
                        result.ExceptionDetails = WebUtil.GetExceptionMessage(sqlException);
                    }
                }
                catch (ArgumentException argumentException)
                {
                    result.TestResult = DiagConstants.ERROR_OPENING_SQL_CONNECTION;

                    if (IsLocalRequest)
                    {
                        result.ExceptionDetails = WebUtil.GetExceptionMessage(argumentException);
                    }
                }
                catch (Exception e)
                {
                    result.TestResult = DiagConstants.UNKNOWN_ERROR;

                    if (IsLocalRequest)
                    {
                        result.ExceptionDetails = WebUtil.GetExceptionMessage(e);
                    }
                }
            }

            return(result);
        }
Beispiel #5
0
        // This method ensures that we have a valid feed through the formatters. The BodyWriter delegate in WCF
        // seems to not recover from an unhandled exception caused by the formatters and sends out an empty response to the caller.
        // This is a workaround for this issue until we find a better solution.
        private SyncWriter GetSyncWriterWithContents()
        {
            var conflictEntryKeys = new List <string>();
            var errorEntryKeys    = new List <string>();
            var primaryKeyToIncomingEntitiesMapping = new Dictionary <string, IOfflineEntity>();

            // Save the mapping between entity PK string -> entity
            foreach (var entity in _incomingEntities)
            {
                string primaryKey = ReflectionUtility.GetPrimaryKeyString(entity);
                if (primaryKeyToIncomingEntitiesMapping.ContainsKey(primaryKey))
                {
                    throw SyncServiceException.CreateInternalServerError(Strings.MultipleEntriesWithSamePrimaryKeyInIncomingRequest);
                }

                primaryKeyToIncomingEntitiesMapping.Add(primaryKey, entity);
            }

            if (_rejectedEntities != null)
            {
                foreach (var entity in _rejectedEntities.Keys)
                {
                    string primaryKey = ReflectionUtility.GetPrimaryKeyString(entity);
                    if (primaryKeyToIncomingEntitiesMapping.ContainsKey(primaryKey))
                    {
                        throw SyncServiceException.CreateInternalServerError(Strings.MultipleEntriesWithSamePrimaryKeyInIncomingRequest);
                    }

                    primaryKeyToIncomingEntitiesMapping.Add(primaryKey, entity);
                }
            }

            // Get the appropriate SyncWriter instance based on the serialization format.
            var oDataWriter = WebUtil.GetSyncWriter(_responseSerializationFormat, _baseUri);

            oDataWriter.StartFeed(_applyChangesResponse.IsLastBatch, _applyChangesResponse.ServerBlob);

            // Write conflict entities.
            foreach (var entity in _applyChangesResponse.Conflicts)
            {
                // Add the primary key string to the conflictEntryKey list.
                // The primary keys are the same for both Live and Losing entities.
                conflictEntryKeys.Add(ReflectionUtility.GetPrimaryKeyString(entity.LiveEntity));

                string tempId;

                // If the client change lost, then we need to set the Id property
                // only if the property was not null/empty in the incoming request.
                string entityId = WebUtil.GenerateOfflineEntityId(entity.LiveEntity);

                // Set the Id property of the Live entity (server's copy).
                entity.LiveEntity.ServiceMetadata.Id = entityId;

                // Set the Id property of the Losing entity to the incoming entity's Id value
                entity.LosingEntity.ServiceMetadata.Id = entityId;

                // get the original tempId. Null value is ok.
                _idToTempIdMapping.TryGetValue(entityId, out tempId);

                if (entity.Resolution == SyncConflictResolution.ServerWins)
                {
                    // The losing entity is the client's copy.

                    // When resolution is ServerWins, we only need to set the losing change tempId.
                    oDataWriter.AddConflictItem(entity.LiveEntity, null /*tempId*/, entity.LosingEntity, tempId, entity.Resolution);
                }
                // If the client change won, then just set the Id property since an insert would have succeeded.
                else
                {
                    // When resolution is ClientWins, we only need to set the LiveEntity tempId.
                    oDataWriter.AddConflictItem(entity.LiveEntity, tempId, entity.LosingEntity, null /* tempId */, entity.Resolution);
                }
            }

            // Write error entities.
            foreach (var syncError in _applyChangesResponse.Errors)
            {
                Debug.Assert(null != syncError.LiveEntity);
                Debug.Assert(null != syncError.ErrorEntity);

                string entityId = WebUtil.GenerateOfflineEntityId(syncError.LiveEntity);

                // Set the Id for Live and Losing entity.
                syncError.LiveEntity.ServiceMetadata.Id  = entityId;
                syncError.ErrorEntity.ServiceMetadata.Id = entityId;

                string primaryKeyString = ReflectionUtility.GetPrimaryKeyString(syncError.ErrorEntity);

                // Add the string to the error key list.
                errorEntryKeys.Add(primaryKeyString);

                string tempId;

                _idToTempIdMapping.TryGetValue(entityId, out tempId);

                oDataWriter.AddErrorItem(syncError.LiveEntity, syncError.ErrorEntity, tempId, syncError.Description);
            }

            // Write all the inserted records here by iterating over the _incomingNewInsertEntities list
            foreach (var entity in _incomingNewInsertEntities)
            {
                string entityTempId;

                // Get the tempId of the entity.
                _idToTempIdMapping.TryGetValue(WebUtil.GenerateOfflineEntityId(entity), out entityTempId);

                // Write the output to the SyncWriter.
                oDataWriter.AddItem(entity, entityTempId);
            }

            return(oDataWriter);
        }
Beispiel #6
0
        public Stream ProcessRequest(HttpContextServiceHost ctx)
        {
            DateTime  startTime       = DateTime.Now;
            bool      logged          = false;
            Exception raisedException = null;

            try
            {
                try
                {
                    // Intialize the service host first, since most of the logic depends on it.
                    _serviceHost = ctx;// new HttpContextServiceHost(messageBody);
                    //_serviceHost.ValidateRequestHttpVerbAndSegments();

                    // Create the configuration. The first call will initialize the configuration
                    // and all other calls will be a no-op.
                    CreateConfiguration(CurrentScope());

                    // Raise event for user code
                    InvokeOnSyncRequestStart();
                    _requestDescription = new RequestParser(_serviceHost, _syncConfiguration).ParseIncomingRequest();

                    string email;
                    Guid   userId = Logon(ctx, out email);
                    ctx.UserId    = userId.ToString();
                    ctx.UserEMail = email;

                    Common.Logon.CheckLicense(CurrentScope(), ctx.Headers["deviceId"]);
                    Common.Logon.CheckCoreVersion(CurrentScope(), ctx.Headers["coreversion"]);
                    ctx.ResourceVersion = Common.Logon.GetResourceVersion(CurrentScope());

                    //add request parameters
                    _requestDescription.RequestParams = new Dictionary <string, object>();
                    _requestDescription.RequestParams.Add("@UserId", userId);

                    if (null == _requestDescription.SyncBlob || 0 == _requestDescription.SyncBlob.Length)
                    {
                        InitializeNewClient(userId, "Default");
                    }

                    _requestProcessor = RequestProcessorFactory.GetRequestProcessorInstance(_requestDescription.RequestCommand, _syncConfiguration, _serviceHost);

                    _outgoingMessage = _requestProcessor.ProcessRequest(_requestDescription);

                    // Add sync properties
                    var responseProperties = _outgoingMessage.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
                    if (null != responseProperties)
                    {
                        responseProperties.Headers[SyncServiceConstants.SYNC_SERVICE_VERSION_KEY] = SyncServiceConstants.SYNC_SERVICE_VERSION_VALUE;
                        responseProperties.Headers[SyncServiceConstants.SYNC_SERVICE_USERID]      = userId.ToString();
                    }

                    // Raise event for user code
                    InvokeOnEndSyncRequest(_outgoingMessage);
                }
                catch (SyncServiceException syncServiceException)
                {
                    raisedException = syncServiceException;
                    ProcessSyncServiceException(ctx, syncServiceException); //_outgoingMessage is set inside
                }
                catch (DbSyncException dbSyncException)
                {
                    raisedException = dbSyncException;
                    if (dbSyncException.Message.StartsWith("Cannot find a valid scope"))
                    {
                        _outgoingMessage = CreateExceptionMessage(ctx, HttpStatusCode.Conflict, dbSyncException.Message);
                    }
                    else
                    {
                        _outgoingMessage = CreateExceptionMessageEx(dbSyncException, ctx);
                    }
                }
                catch (Exception exception)
                {
                    if (WebUtil.IsFatalException(exception))
                    {
                        throw;
                    }

                    raisedException = exception;
                    if (_outgoingMessage == null)
                    {
                        _outgoingMessage = CreateExceptionMessageEx(exception, ctx);
                    }

                    if (_outgoingMessage == null)
                    {
                        _outgoingMessage = CreateMessageFromUnhandledException(ctx, exception);
                    }
                }

                return(MessageToStream(_outgoingMessage, ctx));
            }
            finally
            {
                if (!logged)
                {
                    logged = LogRequestInfo(startTime, ctx.Headers);
                }
                if (raisedException != null)
                {
                    LogException(raisedException);
                }
                LogToDb(_requestDescription.RequestCommand, ctx, startTime, ctx.Headers, raisedException);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Read and parse the incoming request stream for a POST request.
        /// </summary>
        private void ReadIncomingRequestStreamForPost()
        {
            if (null == _serviceHost.RequestStream || !_serviceHost.RequestStream.CanRead)
            {
                SyncTracer.Info("Request stream for HTTP POST is empty, null or cannot be read.");
                return;
            }

            try
            {
                var reader = WebUtil.GetSyncReader(_serviceHost.GetRequestContentSerializationFormat(),
                                                   _serviceHost.RequestStream,
                                                   _configuration.TypeToTableGlobalNameMapping.Keys.ToArray());

                reader.Start();

                while (reader.Next())
                {
                    switch (reader.ItemType)
                    {
                    case ReaderItemType.Entry:
                        IOfflineEntity entity = reader.GetItem();

                        if (entity.ServiceMetadata.IsTombstone)
                        {
                            if (String.IsNullOrEmpty(entity.ServiceMetadata.Id))
                            {
                                throw SyncServiceException.CreateBadRequestError(Strings.TombstoneEntityHasNoId);
                            }

                            WebUtil.ParseIdStringAndPopulateKeyFields(entity, _serviceHost.ServiceBaseUri);
                        }

                        _entityList.Add(entity);

                        bool hasTempId = false;
                        if (reader.HasTempId())
                        {
                            // Save the entity id to tempId mapping for use later when writing response.
                            _idToTempIdMapping.Add(WebUtil.GenerateOfflineEntityId(entity), reader.GetTempId());

                            hasTempId = true;
                        }

                        // Make sure, we have atleast one of Id or TempId
                        if (String.IsNullOrEmpty(entity.ServiceMetadata.Id) && !hasTempId)
                        {
                            throw SyncServiceException.CreateBadRequestError(Strings.BothIdAndTempIdAreMissing);
                        }

                        break;

                    case ReaderItemType.SyncBlob:
                        _syncBlob = reader.GetServerBlob();

                        break;
                    }
                }
            }
            catch (XmlException exception)
            {
                SyncTracer.Warning("XmlException: {0}", WebUtil.GetExceptionMessage(exception));

                throw SyncServiceException.CreateBadRequestError(Strings.BadRequestPayload);
            }
        }