internal static void ValidateInterceptorSignature(SyncInterceptorAttribute attr, MethodInfo methodInfo, string parentTypeName) { // Retrieve the set of parameters ParameterInfo[] parameters = methodInfo.GetParameters(); if (attr is SyncRequestInterceptorAttribute || attr is SyncResponseInterceptorAttribute) { // Ensure methodInfo is of format public void MethodName(SyncOperationContext context) if (methodInfo.ReturnType != SyncServiceConstants.VOID_TYPE || parameters.Length != 1 || (parameters[0].ParameterType != SyncServiceConstants.SYNC_OPERATIONCONTEXT_TYPE)) { throw new InvalidOperationException(string.Format(SyncServiceConstants.SYNC_INCORRECT_INTERCEPTOR_SIGNATURE, methodInfo.Name, parentTypeName, attr.GetType().Name, SyncServiceConstants.SYNC_REQUEST_INTERCEPTOR_FORMAT)); } } else { // Ensure methodInfo is of format public SyncUploadConflictResolution MethodName(SyncUploadConflictContext context) if (methodInfo.ReturnType != SyncServiceConstants.SYNC_CONFLICT_RESOLUTION_TYPE || parameters.Length != 2 || (parameters[0].ParameterType != SyncServiceConstants.SYNC_CONFLICT_CONTEXT_TYPE) || (parameters[1].ParameterType != SyncServiceConstants.IOFFLINEENTITY_BYREFTYPE)) { throw new InvalidOperationException(string.Format(SyncServiceConstants.SYNC_INCORRECT_INTERCEPTOR_SIGNATURE, methodInfo.Name, parentTypeName, attr.GetType().Name, SyncServiceConstants.SYNC_CONFLICT_INTERCEPTOR_FORMAT)); } } }
/// <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); } }
internal static Exception ThrowDuplicateInterceptorForArgumentException(string className, string scopeName, SyncInterceptorAttribute attr, string argumentName) { return(new InvalidOperationException( string.Format("SyncService '{0}' has mutiple '{1}' interceptors on SyncOperations '{2}' defined for Type '{3}' and scopename '{4}'", className, attr.GetType().Name, attr.Operation, argumentName, scopeName))); }
private void CheckForDuplicateAndAddInterceptors(SyncInterceptorAttribute attr, MethodInfo info, string className, ref MethodInfo nonFilteredInfo, Dictionary <Type, MethodInfo> filteredInfo) { // Check we dont have two non filtered interceptors for same operation if (nonFilteredInfo != null) { throw WebUtil.ThrowDuplicateInterceptorException(className, this.ScopeName, attr); } // Check we dont have a filtered and non filtered interceptors for same operation if ((attr.EntityType != null && nonFilteredInfo != null) || (attr.EntityType == null && filteredInfo.Count != 0)) { throw WebUtil.ThrowFilteredAndNonFilteredInterceptorException(className, this.ScopeName, attr); } if (attr.EntityType != null) { // If filtered, ensure we dont have duplicates in type if (filteredInfo.ContainsKey(attr.EntityType)) { throw WebUtil.ThrowDuplicateInterceptorForArgumentException(className, this.ScopeName, attr, attr.EntityType.FullName); } // Check that argument is of type IOfflineEntity if (!SyncServiceConstants.IOFFLINEENTITY_TYPE.IsAssignableFrom(attr.EntityType)) { throw WebUtil.ThrowInterceptorArgumentNotIOEException(className, this.ScopeName, attr, attr.EntityType.FullName); } // If not then its valid. So add it to the list filteredInfo.Add(attr.EntityType, info); } else { // Its a valid non filtered interceptor. nonFilteredInfo = info; } }
/// <summary> /// Adds the MethodInfo signature for the specified interceptor type and operation. This /// method also ensures that the interceptor is valid and is not a duplicate entry before /// adding it. /// </summary> /// <param name="attr">Interceptor Attribute</param> /// <param name="info">MethodInfo signature</param> /// <param name="className">ClassName for error messages</param> internal void AddInterceptor(SyncInterceptorAttribute attr, MethodInfo info, string className) { if (attr is SyncRequestInterceptorAttribute) { // Its a Request interceptor. Check for Operation if ((attr.Operation & SyncOperations.Download) == SyncOperations.Download) { // Configured for Download. Ensure no duplicates if (this._downloadRequestInterceptor != null) { throw WebUtil.ThrowDuplicateInterceptorException(className, this.ScopeName, attr); } this._downloadRequestInterceptor = info; } if ((attr.Operation & SyncOperations.Upload) == SyncOperations.Upload) { // Configured for Upload. Ensure no duplicates CheckForDuplicateAndAddInterceptors(attr, info, className, ref _uploadRequestInterceptor, _uploadTypedRequestInterceptors); } } else if (attr is SyncResponseInterceptorAttribute) { // Its a Response interceptor. Check for Operation if ((attr.Operation & SyncOperations.Download) == SyncOperations.Download) { // Configured for Download. CheckForDuplicateAndAddInterceptors(attr, info, className, ref _downloadResponseInterceptor, _downloadTypedResponseInterceptors); } if ((attr.Operation & SyncOperations.Upload) == SyncOperations.Upload) { // Configured for Upload. CheckForDuplicateAndAddInterceptors(attr, info, className, ref _uploadResponseInterceptor, _uploadTypedResponseInterceptors); } } else { // Its a conflict interceptor. Check we dont have another conflict interceptor for the same scope CheckForDuplicateAndAddInterceptors(attr, info, className, ref _conflictInterceptor, _conflictTypedInterceptors); } }
private void CheckForDuplicateAndAddInterceptors(SyncInterceptorAttribute attr, MethodInfo info, string className, ref MethodInfo nonFilteredInfo, Dictionary<Type, MethodInfo> filteredInfo) { // Check we dont have two non filtered interceptors for same operation if (nonFilteredInfo != null) { throw WebUtil.ThrowDuplicateInterceptorException(className, this.ScopeName, attr); } // Check we dont have a filtered and non filtered interceptors for same operation if ((attr.EntityType != null && nonFilteredInfo != null) || (attr.EntityType == null && filteredInfo.Count != 0)) { throw WebUtil.ThrowFilteredAndNonFilteredInterceptorException(className, this.ScopeName, attr); } if (attr.EntityType != null) { // If filtered, ensure we dont have duplicates in type if (filteredInfo.ContainsKey(attr.EntityType)) { throw WebUtil.ThrowDuplicateInterceptorForArgumentException(className, this.ScopeName, attr, attr.EntityType.FullName); } // Check that argument is of type IOfflineEntity if (!SyncServiceConstants.IOFFLINEENTITY_TYPE.IsAssignableFrom(attr.EntityType)) { throw WebUtil.ThrowInterceptorArgumentNotIOEException(className, this.ScopeName, attr, attr.EntityType.FullName); } // If not then its valid. So add it to the list filteredInfo.Add(attr.EntityType, info); } else { // Its a valid non filtered interceptor. nonFilteredInfo = info; } }
internal static Exception ThrowInterceptorArgumentNotIOEException(string className, string scopeName, SyncInterceptorAttribute attr, string argumentName) { return(new InvalidOperationException( string.Format("SyncService '{0}' filtered interceptor definition '{1}' for scope '{2}' declares a Type '{3}' that does not derive from IOfflineEntity.", className, attr.GetType().Name, scopeName, argumentName))); }
internal static Exception ThrowFilteredAndNonFilteredInterceptorException(string className, string scopeName, SyncInterceptorAttribute attr) { return(new InvalidOperationException( string.Format("SyncService '{0}' has both filtered and non-filtered '{1}' interceptor's defined for scope '{2}'.", className, attr.GetType().Name, scopeName))); }