/// <summary>
        /// This method processes a single SyncInterceptorAttribute defined on a method. Processing involves the following
        /// 1. Ensure that the MethodInfo signature is the right one for the interceptor.
        /// 2. Retrieve the ScopeNames defined in the attribute and ensure they are valid scopes configures via the
        /// ISyncScopeConfiguration.SetEnableScope() API.
        /// 3. Create a SyncInterceptorInfoWrapper object for the scope if none is present.
        /// 4. Add the interceptor to the wrapper object.
        /// </summary>
        /// <param name="attr">The SyncInterceptorAttribute to process.</param>
        /// <param name="syncServiceType">Actual SyncService type</param>
        /// <param name="methodInfo">User Method on which the attribute is applied</param>
        private void ProcessSyncInterceptor(SyncInterceptorAttribute attr, Type syncServiceType, MethodInfo methodInfo)
        {
            // Validate the method signature attribute
            WebUtil.ValidateInterceptorSignature(attr, methodInfo, syncServiceType.Name);

            // Read the list of scopeNames from the attribute
            string[] scopeNames = attr.ScopeName.Select(e => e.ToLowerInvariant()).ToArray();

            foreach (string scopeName in scopeNames)
            {
                // Check to ensure the scopeName is valid configured scope.
                if (!this.ScopeNames.Contains(scopeName))
                {
                    // ScopeName is not part of configured scopes. Throw.
                    throw new InvalidOperationException(
                              string.Format(CultureInfo.InvariantCulture, "ScopeName '{0}' defined in '{1}' on method '{2}' is not in the list of configured sync scopes.",
                                            scopeName, attr.GetType().Name, methodInfo.Name));
                }
                SyncInterceptorsInfoWrapper wrapper = null;
                // Check and create the wrapper object for the current scope if none exists.
                if (!this.SyncInterceptors.TryGetValue(scopeName, out wrapper))
                {
                    wrapper = new SyncInterceptorsInfoWrapper(scopeName);
                    this.SyncInterceptors.Add(scopeName, wrapper);
                }

                // Add interceptor to the wrapper.
                wrapper.AddInterceptor(attr, methodInfo, syncServiceType.Name);
            }
        }
        /// <summary>
        /// Checks to see if a typed SyncResponseInterceptor for a specific operation has been configured by the user
        /// </summary>
        /// <returns>bool</returns>
        internal bool HasTypedResponseInterceptor(string scopeName, SyncOperations operation, Type type)
        {
            SyncInterceptorsInfoWrapper wrapper = null;

            if (this.SyncInterceptors.TryGetValue(scopeName.ToLowerInvariant(), out wrapper))
            {
                return(wrapper.HasResponseInterceptor(operation, type));
            }
            return(false);
        }
        /// <summary>
        /// Checks to see if a typed SyncConflictInterceptor has been configured by the user
        /// </summary>
        /// <returns>bool</returns>
        internal bool HasTypedConflictInterceptor(string scopeName, Type type)
        {
            SyncInterceptorsInfoWrapper wrapper = null;

            if (this.SyncInterceptors.TryGetValue(scopeName.ToLowerInvariant(), out wrapper))
            {
                return(wrapper.HasConflictInterceptor(type));
            }
            return(false);
        }
        /// <summary>
        /// Utility function that invokes the actual user interceptor extension method. If entityType is null
        /// it looks for the generic interceptor. If its not null then it looks for a typed interceptor for the
        /// specific type being passed.
        /// </summary>
        /// <param name="context">The context to pass as parameter to user code</param>
        /// <param name="entityType">Type of the entity being processed</param>
        /// <param name="isRequest">True if intercepting a request operation else false.</param>
        internal void InvokeOperationInterceptors(SyncOperationContext context, Type entityType, bool isRequest)
        {
            SyncInterceptorsInfoWrapper wrapper = null;

            if (this.SyncInterceptors.TryGetValue(context.ScopeName, out wrapper))
            {
                MethodInfo methodInfo = null;
                switch (context.Operation)
                {
                case SyncOperations.Download:
                    if (entityType == null)
                    {
                        methodInfo = (isRequest) ? wrapper.DownloadRequestInterceptor : wrapper.DownloadResponseInterceptor;
                    }
                    else
                    {
                        Debug.Assert(!isRequest, "Cannot fire typed interceptor for DownloadRequest");
                        methodInfo = wrapper.GetResponseInterceptor(SyncOperations.Download, entityType);
                    }
                    break;

                case SyncOperations.Upload:
                    if (entityType == null)
                    {
                        methodInfo = (isRequest) ? wrapper.UploadRequestInterceptor : wrapper.UploadResponseInterceptor;
                    }
                    else
                    {
                        methodInfo = (isRequest) ?
                                     wrapper.GetRequestInterceptor(entityType) :
                                     wrapper.GetResponseInterceptor(SyncOperations.Upload, entityType);
                    }
                    break;
                }

                if (methodInfo != null)
                {
                    InvokeUserInterceptorMethod(methodInfo, OperationContext.Current.InstanceContext.GetServiceInstance(), new object[] { context });
                }
            }
        }
        /// <summary>
        /// Utility for invoking user code for conflict interceptors
        /// </summary>
        /// <param name="context">The context to pass as parameter to user code</param>
        /// <param name="mergedVersion">The merged version for Merge resolution</param>
        /// <param name="entityType">Entity type of the conflict being raised</param>
        /// <returns>Actual resolution picked by user</returns>
        internal SyncConflictResolution?InvokeConflictInterceptor(SyncConflictContext context, Type entityType, out IOfflineEntity mergedVersion)
        {
            SyncInterceptorsInfoWrapper wrapper = null;

            if (this.SyncInterceptors.TryGetValue(context.ScopeName, out wrapper))
            {
                // Look for unfiltered Conflict and if that is null then look for filtered one.
                // Its an error to have both unfiltered and filtered ConflictInterceptor so both cannot be set.
                MethodInfo methodInfo = wrapper.ConflictInterceptor ?? wrapper.GetConflictInterceptor(entityType);
                if (methodInfo != null)
                {
                    object[] inputParams = new object[] { context, null };
                    SyncConflictResolution resolution = (SyncConflictResolution)InvokeUserInterceptorMethod(methodInfo, OperationContext.Current.InstanceContext.GetServiceInstance(), inputParams);
                    // Merged version is in the second parameter which is passed by reference. Look it up
                    mergedVersion = (IOfflineEntity)inputParams[1];
                    return(resolution);
                }
            }
            mergedVersion = null;
            return(null);
        }
Пример #6
0
        /// <summary>
        /// This method processes a single SyncInterceptorAttribute defined on a method. Processing involves the following
        /// 1. Ensure that the MethodInfo signature is the right one for the interceptor.
        /// 2. Retrieve the ScopeNames defined in the attribute and ensure they are valid scopes configures via the 
        /// ISyncScopeConfiguration.SetEnableScope() API.
        /// 3. Create a SyncInterceptorInfoWrapper object for the scope if none is present.
        /// 4. Add the interceptor to the wrapper object.
        /// </summary>
        /// <param name="attr">The SyncInterceptorAttribute to process.</param>
        /// <param name="syncServiceType">Actual SyncService type</param>
        /// <param name="methodInfo">User Method on which the attribute is applied</param>
        private void ProcessSyncInterceptor(SyncInterceptorAttribute attr, Type syncServiceType, MethodInfo methodInfo)
        {
            // Validate the method signature attribute
            WebUtil.ValidateInterceptorSignature(attr, methodInfo, syncServiceType.Name);

            // Read the list of scopeNames from the attribute
            string[] scopeNames = attr.ScopeName.Select(e => e.ToLowerInvariant()).ToArray();

            foreach (string scopeName in scopeNames)
            {
                // Check to ensure the scopeName is valid configured scope.
                if (!this.ScopeNames.Contains(scopeName))
                {
                    // ScopeName is not part of configured scopes. Throw.
                    throw new InvalidOperationException(
                        string.Format(CultureInfo.InvariantCulture, "ScopeName '{0}' defined in '{1}' on method '{2}' is not in the list of configured sync scopes.",
                        scopeName, attr.GetType().Name, methodInfo.Name));
                }
                SyncInterceptorsInfoWrapper wrapper = null;
                // Check and create the wrapper object for the current scope if none exists.
                if (!this.SyncInterceptors.TryGetValue(scopeName, out wrapper))
                {
                    wrapper = new SyncInterceptorsInfoWrapper(scopeName);
                    this.SyncInterceptors.Add(scopeName, wrapper);
                }

                // Add interceptor to the wrapper.
                wrapper.AddInterceptor(attr, methodInfo, syncServiceType.Name);
            }
        }