Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / DataServiceConfiguration.cs / 1305376 / DataServiceConfiguration.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides an implementation of the IDataServiceConfiguration // interface. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services { #region Namespaces. using System; using System.Collections.Generic; using System.Data.Services.Client; using System.Data.Services.Providers; using System.Data.Services.Common; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Net; #endregion Namespaces. ///Use this class to manage the configuration data for a data service. public sealed class DataServiceConfiguration : IDataServiceConfiguration { #region Private fields. ///Whether this configuration has been sealed. private bool configurationSealed; ///Maximum number of change sets and query operations in a batch. private int maxBatchCount; ///Maximum number of changes in a change set. private int maxChangeSetCount; ///Maximum number of segments to be expanded allowed in a request. private int maxExpandCount; ///Maximum number of segments in a single $expand path. private int maxExpandDepth; ///Maximum number of elements in each returned collection (top-level or expanded). private int maxResultsPerCollection; ///maximum number of objects that can be referred in a single insert request. private int maxObjectCountOnInsert; ///The provider for the web service. private IDataServiceMetadataProvider provider; ///Rights used for unspecified resource sets. private EntitySetRights rightsForUnspecifiedResourceContainer; ///Rights used for unspecified service operations. private ServiceOperationRights rightsForUnspecifiedServiceOperation; ///Page size for unspecified resource sets private int defaultPageSize; ////// A lookup of containers to their rights. /// For IDSP there is no guarantee that the provider will always return the same metadata instance. We should /// use the name instead of the instance as key since the configuration is cached across requests. /// private DictionaryresourceRights; /// /// A lookup of service operations to their rights. /// For IDSP there is no guarantee that the provider will always return the same metadata instance. We should /// use the name instead of the instance as key since the configuration is cached across requests. /// private DictionaryserviceRights; /// /// A lookup of resource sets to their page sizes. /// For IDSP there is no guarantee that the provider will always return the same metadata instance. We should /// use the name instead of the instance as key since the configuration is cached across requests. /// private DictionarypageSizes; /// A list of known types. private ListknownTypes; /// Whether verbose errors should be returned by default. private bool useVerboseErrors; ///Holds configuration of service behavior private DataServiceBehavior dataServiceBehavior; ////// Perform type conversion from the type specified in the payload to the actual property type. /// private bool typeConversion; ////// A lookup of resource sets to the corresponding QueryInterceptors. /// For IDSP there is no guarantee that the provider will always return the same metadata instance. We should /// use the name instead of the instance as key since the configuration is cached across requests. /// private Dictionary> readAuthorizationMethods; /// /// A lookup of resource sets to the corresponding ChangeInterceptors. /// For IDSP there is no guarantee that the provider will always return the same metadata instance. We should /// use the name instead of the instance as key since the configuration is cached across requests. /// private Dictionary> writeAuthorizationMethods; /// This is set to true if EnableAccess("*") is called. False otherwise. private bool accessEnabledForAllResourceTypes; ///List of fully qualified type names that were marked as visible by calling EnableAccess(). private HashSetaccessEnabledResourceTypes; #endregion Private fields. #region Constructor. /// /// Initializes a new /// Non-null provider for this configuration. internal DataServiceConfiguration(IDataServiceMetadataProvider provider) { Debug.Assert(provider != null, "provider != null"); this.provider = provider; this.resourceRights = new Dictionarywith /// the specified . /// (EqualityComparer .Default); this.serviceRights = new Dictionary (EqualityComparer .Default); this.pageSizes = new Dictionary (EqualityComparer .Default); this.rightsForUnspecifiedResourceContainer = EntitySetRights.None; this.rightsForUnspecifiedServiceOperation = ServiceOperationRights.None; this.knownTypes = new List (); this.maxBatchCount = Int32.MaxValue; this.maxChangeSetCount = Int32.MaxValue; this.maxExpandCount = Int32.MaxValue; this.maxExpandDepth = Int32.MaxValue; this.maxResultsPerCollection = Int32.MaxValue; this.maxObjectCountOnInsert = Int32.MaxValue; this.readAuthorizationMethods = new Dictionary >(EqualityComparer .Default); this.writeAuthorizationMethods = new Dictionary >(EqualityComparer .Default); this.accessEnabledResourceTypes = new HashSet (EqualityComparer .Default); this.dataServiceBehavior = new DataServiceBehavior(); // default value is true since in V1, we always did the type conversion // and this configuration settings was introduced in V2 this.typeConversion = true; } #endregion Constructor. #region Public Properties /// /// Specifies whether the data service runtime should do type conversion from the payload type /// to the actual property type in POST/PUT/MERGE requests. /// public bool EnableTypeConversion { get { return this.typeConversion; } set { this.CheckNotSealed(); this.typeConversion = value; } } ///Maximum number of change sets and query operations in a batch. public int MaxBatchCount { get { return this.maxBatchCount; } set { this.maxBatchCount = this.CheckNonNegativeProperty(value, "MaxBatchCount"); } } ///Maximum number of changes in a change set. public int MaxChangesetCount { get { return this.maxChangeSetCount; } set { this.maxChangeSetCount = this.CheckNonNegativeProperty(value, "MaxChangesetCount"); } } ///Maximum number of segments to be expanded allowed in a request. public int MaxExpandCount { get { return this.maxExpandCount; } set { this.maxExpandCount = this.CheckNonNegativeProperty(value, "MaxExpandCount"); } } ///Maximum number of segments in a single $expand path. public int MaxExpandDepth { get { return this.maxExpandDepth; } set { this.maxExpandDepth = this.CheckNonNegativeProperty(value, "MaxExpandDepth"); } } ///Maximum number of elements in each returned collection (top-level or expanded). public int MaxResultsPerCollection { get { return this.maxResultsPerCollection; } set { if (this.IsPageSizeDefined) { throw new InvalidOperationException(Strings.DataService_SDP_PageSizeWithMaxResultsPerCollection); } this.maxResultsPerCollection = this.CheckNonNegativeProperty(value, "MaxResultsPerCollection"); } } ///Maximum number of objects that can be referred in a single POST request. public int MaxObjectCountOnInsert { get { return this.maxObjectCountOnInsert; } set { this.maxObjectCountOnInsert = this.CheckNonNegativeProperty(value, "MaxObjectCountOnInsert"); } } ///Gets or sets whether verbose errors should be used by default. ////// This property sets the default for the whole service; individual responses may behave differently /// depending on the value of the VerboseResponse property of the arguments to the HandleException /// method on the public bool UseVerboseErrors { get { return this.useVerboseErrors; } set { this.CheckNotSealed(); this.useVerboseErrors = value; } } ///class. /// /// Gets settings that define service behavior. /// public DataServiceBehavior DataServiceBehavior { get { return this.dataServiceBehavior; } } #endregion Public Properties #region Internal Properties ///True if all resource types have been made visible by calling EnableAccess("*"). False otherwise. internal bool AccessEnabledForAllResourceTypes { [DebuggerStepThrough] get { return this.accessEnabledForAllResourceTypes; } } #endregion Internal Properties #region Private Properties ////// Whether size of a page has been defined. /// private bool IsPageSizeDefined { get { return this.pageSizes.Count > 0 || this.defaultPageSize > 0; } } #endregion #region Public Methods ///Sets the access rights on the specified resource set. /// /// Name of resource set to set; '*' to indicate all /// resource sets not otherwise specified. /// /// Rights to be granted to this resource. public void SetEntitySetAccessRule(string name, EntitySetRights rights) { this.CheckNotSealed(); if (name == null) { throw Error.ArgumentNull("name"); } WebUtil.CheckResourceContainerRights(rights, "rights"); if (name == "*") { this.rightsForUnspecifiedResourceContainer = rights; } else { ResourceSet container; if (!this.provider.TryResolveResourceSet(name, out container) || container == null) { throw new ArgumentException(Strings.DataServiceConfiguration_ResourceSetNameNotFound(name), "name"); } this.resourceRights[container.Name] = rights; } } ///Sets the access rights on the specified service operation. /// /// Name of service operation to set; '*' to indicate all /// service operations not otherwise specified. /// /// Rights to be granted to this operation. public void SetServiceOperationAccessRule(string name, ServiceOperationRights rights) { this.CheckNotSealed(); if (name == null) { throw new ArgumentNullException("name"); } WebUtil.CheckServiceOperationRights(rights, "rights"); if (name == "*") { this.rightsForUnspecifiedServiceOperation = rights; } else { ServiceOperation serviceOperation; if (!this.provider.TryResolveServiceOperation(name, out serviceOperation) || serviceOperation == null) { throw new ArgumentException(Strings.DataServiceConfiguration_ServiceNameNotFound(name), "name"); } this.serviceRights[serviceOperation.Name] = rights; } } ////// Add the type to the list of known types. If there is a type that needs to be added since /// Astoria runtime can't detect it using the default set of rules, providers can add them using /// this method /// /// type which needs to be added to the known types collection public void RegisterKnownType(Type type) { this.CheckNotSealed(); this.knownTypes.Add(type); } ///Sets the page size per entity set /// Name of entity set, '*' to indicate those for which page size is not explicitly specified /// Page size for the resource set(s) specified inpublic void SetEntitySetPageSize(String name, int size) { WebUtil.CheckArgumentNull(name, "name"); if (size < 0) { throw new ArgumentOutOfRangeException("size", size, Strings.DataService_SDP_PageSizeMustbeNonNegative(size, name)); } // Treat a page size of Int32.MaxValue to be the same as not setting the page size. if (size == Int32.MaxValue) { size = 0; } if (this.MaxResultsPerCollection != Int32.MaxValue) { throw new InvalidOperationException(Strings.DataService_SDP_PageSizeWithMaxResultsPerCollection); } this.CheckNotSealed(); if (name == "*") { this.defaultPageSize = size; } else { ResourceSet container; if (!this.provider.TryResolveResourceSet(name, out container) || container == null) { throw new ArgumentException(Strings.DataServiceConfiguration_ResourceSetNameNotFound(name), "name"); } this.pageSizes[container.Name] = size; } } /// /// This method is used to register a type with the Astoria runtime which may be returned in the �open properties� of /// an open type such that the type is visible in $metadata output and usable with CRUD operations. /// /// The typename parameter must be a namespace qualified type name (format: <namespace>.<typename>). /// The name provided must be as it would show up in a CSDL document (ie. model types, not CLR types) /// /// The types registered via calls to EnableAccess will be additive to those implicitly made accessible via /// DSC.SetEntitySetAccessRule(�) invocations /// � Note: The Astoria runtime layer won�t be able to determine if a typename specified maps to an Entity Type, /// Complex Type, etc until it actually obtains type info (entity types, complex types, etc) from the underlying provider /// � �*� can be used as the value of �typename�, which will be interpreted as matching all types /// /// When Astoria enumerates types or needs to obtain a type (Complex Types, Entity Types) from the underlying provider /// it will first determine if the type should be visible (show in $metadata and accessible via operations exposed by the /// service) as per the standard v1 checks (ie. driven by SetEntitySetAccessRule calls). If the type is not visible via V1 /// rules, then we consult the set of types registered via EnableAccess(<typename>) invocations. If the type was /// included in such a call then the type is visible via $metadata and can be accessed via CRUD ops, etc. /// /// If a type is not made visible via one of the mechanisms above, then: /// � That type must not be included a response to a $metadata request /// � Instances of the type must not be returned to the client as the response of a request to the data service. /// If such a type instance would be required the service MUST fail the request. Failure semantics are covered /// in the area of the specification which covers request/response semantics with respect to open types. /// /// Invoking this method multiple times with the same type name is allowed and considered a �NO OP�. /// /// The namespace qualified complex type name to be made visible via the data service public void EnableTypeAccess(string typeName) { WebUtil.CheckStringArgumentNull(typeName, "typeName"); this.CheckNotSealed(); if (typeName == "*") { this.accessEnabledForAllResourceTypes = true; } else { ResourceType resourceType; if (!this.provider.TryResolveResourceType(typeName, out resourceType) || resourceType == null) { throw new ArgumentException(Strings.DataServiceConfiguration_ResourceTypeNameNotFound(typeName), "typeName"); } if (resourceType.ResourceTypeKind != ResourceTypeKind.ComplexType) { throw new ArgumentException(Strings.DataServiceConfiguration_NotComplexType(typeName), "typeName"); } Debug.Assert(resourceType.FullName == typeName, "resourceType.FullName == typeName"); this.accessEnabledResourceTypes.Add(typeName); } } #endregion Public Methods #region Internal methods. ///Composes all query interceptors into a single expression. /// Web service instance. /// Container for which interceptors should run. ///An expression the filter for query interceptors, possibly null. internal static Expression ComposeQueryInterceptors(IDataService service, ResourceSetWrapper container) { Debug.Assert(service != null, "service != null"); Debug.Assert(container != null, "container != null"); MethodInfo[] methods = container.QueryInterceptors; if (methods == null || methods.Length == 0) { return null; } LambdaExpression filter = null; for (int i = 0; i < methods.Length; i++) { Expression predicate = null; try { predicate = (Expression)methods[i].Invoke(service.Instance, WebUtil.EmptyObjectArray); } catch (TargetInvocationException tie) { ErrorHandler.HandleTargetInvocationException(tie); throw; } if (predicate == null) { throw new InvalidOperationException(Strings.DataService_AuthorizationReturnedNullQuery(methods[i].Name, methods[i].DeclaringType.FullName)); } Debug.Assert(predicate is LambdaExpression, "predicate is LambdaExpression -- otherwise signature check missed something."); if (filter == null) { filter = (LambdaExpression)predicate; } else { ParameterExpression parameter = filter.Parameters[0]; Expression adjustedPredicate = ParameterReplacerVisitor.Replace( ((LambdaExpression)predicate).Body, // expression ((LambdaExpression)predicate).Parameters[0], // oldParameter parameter); // newParameter filter = Expression.Lambda(Expression.And(filter.Body, adjustedPredicate), parameter); } } return filter; } ////// Composes the specified /// Data service on which to invoke method. /// resource set to compose with. /// Query to compose. ///for the /// given with authorization /// callbacks. /// The resulting composed query. internal static IQueryable ComposeResourceContainer(IDataService service, ResourceSetWrapper container, IQueryable query) { Debug.Assert(service != null, "service != null"); Debug.Assert(container != null, "container != null"); Debug.Assert(query != null, "query != null"); MethodInfo[] methods = container.QueryInterceptors; if (methods != null) { for (int i = 0; i < methods.Length; i++) { Expression predicate = null; try { predicate = (Expression)methods[i].Invoke(service.Instance, WebUtil.EmptyObjectArray); } catch (TargetInvocationException tie) { ErrorHandler.HandleTargetInvocationException(tie); throw; } if (predicate == null) { throw new InvalidOperationException(Strings.DataService_AuthorizationReturnedNullQuery(methods[i].Name, methods[i].DeclaringType.FullName)); } Debug.Assert(predicate is LambdaExpression, "predicate is LambdaExpression -- otherwise signature check missed something."); query = RequestUriProcessor.InvokeWhereForType(query, (LambdaExpression)predicate); } } return query; } ///Checks whether this request has the specified rights. /// Container to check. /// Required rights. ///Thrown if internal static void CheckResourceRights(ResourceSetWrapper container, EntitySetRights requiredRights) { Debug.Assert(container != null, "container != null"); Debug.Assert(requiredRights != EntitySetRights.None, "requiredRights != EntitySetRights.None"); if ((requiredRights & container.Rights) == 0) { throw DataServiceException.CreateForbidden(); } } ///aren't available. Checks whether this request has the specified reading rights. /// Container to check. /// Whether a single or multiple resources are requested. ///Thrown if internal static void CheckResourceRightsForRead(ResourceSetWrapper container, bool singleResult) { Debug.Assert(container != null, "container != null"); EntitySetRights requiredRights = singleResult ? EntitySetRights.ReadSingle : EntitySetRights.ReadMultiple; CheckResourceRights(container, requiredRights); } ///aren't available. Checks whether this request has the specified rights. /// Operation to check. /// Required rights. ///Thrown if internal static void CheckServiceRights(ServiceOperationWrapper operation, ServiceOperationRights requiredRights) { Debug.Assert(operation != null, "operation != null"); Debug.Assert(requiredRights != ServiceOperationRights.None, "requiredRights != EntitySetRights.None"); ServiceOperationRights effectiveRights = operation.Rights; if ((requiredRights & effectiveRights) == 0) { throw DataServiceException.CreateForbidden(); } } ///aren't available. Checks whether this request has the specified rights. /// Operation to check. /// Whether a single or multiple resources are requested. ///Thrown if internal static void CheckServiceRights(ServiceOperationWrapper operation, bool singleResult) { Debug.Assert(operation != null, "operation != null"); if (operation.ResultKind != ServiceOperationResultKind.Void) { ServiceOperationRights requiredRights = singleResult ? ServiceOperationRights.ReadSingle : ServiceOperationRights.ReadMultiple; CheckServiceRights(operation, requiredRights); } } ///aren't available. Gets a string with methods allowed on the target for the /// configuration object which has the data /// Description with target. ///. A string with methods allowed on the description; possibly null. internal static string GetAllowedMethods(DataServiceConfiguration configuration, RequestDescription description) { Debug.Assert(description != null, "description != null"); Debug.Assert( description.TargetKind != RequestTargetKind.Nothing, "description.TargetKind != RequestTargetKind.Void - otherwise it hasn't been determined yet"); Debug.Assert( description.TargetKind != RequestTargetKind.VoidServiceOperation, "description.TargetKind != RequestTargetKind.VoidServiceOperation - this method is only for containers"); if (description.TargetKind == RequestTargetKind.Metadata || description.TargetKind == RequestTargetKind.ServiceDirectory) { return XmlConstants.HttpMethodGet; } else if (description.TargetKind == RequestTargetKind.Batch) { return XmlConstants.HttpMethodPost; } else { int index = description.GetIndexOfTargetEntityResource(); Debug.Assert(index >= 0 && index < description.SegmentInfos.Length, "index >=0 && index/// Gets a string representation of allowed methods on the container (with the specified target cardinality), /// suitable for an 'Allow' header. /// /// configuration object which has the data /// Targetted container, possibly null. /// Description with target. /// A value for an 'Allow' header; null if internal static string GetAllowedMethods(DataServiceConfiguration configuration, ResourceSetWrapper container, RequestDescription description) { if (container == null) { return null; } else { System.Text.StringBuilder result = new System.Text.StringBuilder(); EntitySetRights rights = configuration.GetResourceSetRights(container.ResourceSet); if (description.IsSingleResult) { AppendRight(rights, EntitySetRights.ReadSingle, XmlConstants.HttpMethodGet, result); AppendRight(rights, EntitySetRights.WriteReplace, XmlConstants.HttpMethodPut, result); if (description.TargetKind != RequestTargetKind.MediaResource) { AppendRight(rights, EntitySetRights.WriteMerge, XmlConstants.HttpMethodMerge, result); AppendRight(rights, EntitySetRights.WriteDelete, XmlConstants.HttpMethodDelete, result); } } else { AppendRight(rights, EntitySetRights.ReadMultiple, XmlConstants.HttpMethodGet, result); AppendRight(rights, EntitySetRights.WriteAppend, XmlConstants.HttpMethodPost, result); } return result.ToString(); } } ///is null. Gets the effective rights on the specified container. /// Container to get rights for. ///The effective rights as per this configuration. internal EntitySetRights GetResourceSetRights(ResourceSet container) { Debug.Assert(container != null, "container != null"); Debug.Assert(this.resourceRights != null, "this.resourceRights != null"); EntitySetRights result; if (!this.resourceRights.TryGetValue(container.Name, out result)) { result = this.rightsForUnspecifiedResourceContainer; } return result; } ///Gets the effective rights on the specified operation. /// Operation to get rights for. ///The effective rights as per this configuration. internal ServiceOperationRights GetServiceOperationRights(ServiceOperation serviceOperation) { Debug.Assert(serviceOperation != null, "operation != null"); Debug.Assert(this.serviceRights != null, "this.serviceRights != null"); ServiceOperationRights result; if (!this.serviceRights.TryGetValue(serviceOperation.Name, out result)) { result = this.rightsForUnspecifiedServiceOperation; } return result; } ///Gets the page size per entity set /// Entity set for which to get the page size ///Page size for the internal int GetResourceSetPageSize(ResourceSet container) { Debug.Assert(container != null, "container != null"); Debug.Assert(this.pageSizes != null, "this.pageSizes != null"); int pageSize; if (!this.pageSizes.TryGetValue(container.Name, out pageSize)) { pageSize = this.defaultPageSize; } return pageSize; } ///Returns the list of types registered by the data service. ///The list of types as registered by the data service internal IEnumerableGetKnownTypes() { return this.knownTypes; } /// Get the list of access enabled resourceType names. ///List of namespace qualified resourceType names that were marked as visible by calling EnableAccess(). internal IEnumerableGetAccessEnabledResourceTypes() { Debug.Assert(this.accessEnabledResourceTypes != null, "this.accessEnabledResourceTypes != null"); return this.accessEnabledResourceTypes; } /// /// Initializes the DataServiceConfiguration instance by: /// 1. Invokes the static service initialization methods on the specified type family. /// 2. Register authorization callbacks specified on the given /// Type of service to initialize for. internal void Initialize(Type type) { Debug.Assert(type != null, "type != null"); this.InvokeStaticInitialization(type); this.RegisterCallbacks(type); } ///. /// /// Returns the list of QueryInterceptors for the given resource set /// /// resource set instance ///List of QueryInterceptors for the resource set, null if there is none defined for the resource set. internal MethodInfo[] GetReadAuthorizationMethods(ResourceSet resourceSet) { Debug.Assert(resourceSet != null, "resourceSet != null"); Listmethods; if (this.readAuthorizationMethods.TryGetValue(resourceSet.Name, out methods)) { return methods.ToArray(); } return null; } /// /// Returns the list of ChangeInterceptors for the given resource set /// /// resource set instance ///List of ChangeInterceptors for the resource set, null if there is none defined for the resource set. internal MethodInfo[] GetWriteAuthorizationMethods(ResourceSet resourceSet) { Debug.Assert(resourceSet != null, "resourceSet != null"); Listmethods; if (this.writeAuthorizationMethods.TryGetValue(resourceSet.Name, out methods)) { return methods.ToArray(); } return null; } /// Seals this configuration instance and prevents further changes. ////// This method should be called after the configuration has been set up and before it's placed on the /// metadata cache for sharing. /// internal void Seal() { Debug.Assert(!this.configurationSealed, "!configurationSealed - otherwise .Seal is invoked multiple times"); this.configurationSealed = true; this.provider = null; } ////// Validated if server options used by the service are compatible with MaxProtocolVersion /// /// Whether friendly feeds are compatible with V1. internal void ValidateServerOptions(bool friendlyFeedsV1Compatible) { Debug.Assert(this.configurationSealed, "Configuration must be sealed to validate server options"); if (this.DataServiceBehavior.MaxProtocolVersion == DataServiceProtocolVersion.V1) { if (!friendlyFeedsV1Compatible) { throw new InvalidOperationException(Strings.DataServiceConfiguration_FriendlyFeedsWithKeepInContentFalseNotSupportedInV1Server); } if (this.IsPageSizeDefined) { throw new InvalidOperationException(Strings.DataServiceConfiguration_ServerPagingNotSupportedInV1Server); } } } ////// Validates that the versions of features used in the request are less then or equal than the configured /// MaxProtocolVersion. /// /// Request description internal void ValidateMaxProtocolVersion(RequestDescription requestDescription) { Debug.Assert( Enum.GetValues(typeof(DataServiceProtocolVersion)).Length == 2, "This method has to be modified when adding/removing DataServiceProtocolVersion values."); Version maxProtocolVersion = new Version(this.DataServiceBehavior.MaxProtocolVersion == DataServiceProtocolVersion.V1 ? 1 : 2, 0); if (requestDescription.MaxFeatureVersion > maxProtocolVersion) { throw DataServiceException.CreateBadRequestError(Strings.DataServiceConfiguration_V2ResponseForV1Server); } // As a cross check let's verify if the version of the response is not higher than the configured max protocol version. Debug.Assert(maxProtocolVersion >= requestDescription.ResponseVersion, "ResponseVersion > MaxProtocolVersion"); } #endregion Internal methods. #region Private methods. ////// Appends the /// Rights to be checked. /// Right being looked for. /// Name of right to append. /// Comma-separated list of right names to append to. private static void AppendRight(EntitySetRights entitySetRights, EntitySetRights test, string name, System.Text.StringBuilder builder) { Debug.Assert(builder != null, "builder != null"); if (0 != (entitySetRights & test)) { if (builder.Length > 0) { builder.Append(", "); } builder.Append(name); } } ///of a right if the right is enabled /// on . /// Checks that the specified /// Service type. /// Method to check. /// Container associated with the interceptor. private static void CheckQueryInterceptorSignature(Type type, MethodInfo method, ResourceSet container) { Debug.Assert(type != null, "type != null"); Debug.Assert(method != null, "method != null"); Debug.Assert(container != null, "container != null"); ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 0) { throw new InvalidOperationException(Strings.DataService_QueryInterceptorIncorrectParameterCount(method.Name, type.FullName, parameters.Length)); } Type lambdaType = typeof(Func<,>).MakeGenericType(container.ResourceType.InstanceType, typeof(bool)); Type expectedReturnType = typeof(Expression<>).MakeGenericType(lambdaType); Type returnType = method.ReturnType; if (returnType == typeof(void)) { throw new InvalidOperationException(Strings.DataService_AuthorizationMethodVoid(method.Name, type.FullName, expectedReturnType)); } else if (!expectedReturnType.IsAssignableFrom(returnType)) { Type nullableLambdaType = typeof(Func<,>).MakeGenericType(container.ResourceType.InstanceType, typeof(bool?)); if (!(typeof(Expression<>).MakeGenericType(nullableLambdaType).IsAssignableFrom(returnType))) { throw new InvalidOperationException( Strings.DataService_AuthorizationReturnTypeNotAssignable(method.Name, type.FullName, returnType.FullName, expectedReturnType.FullName)); } } } ///has a correct signature. Verifies that the specified /// Method with parameter to check. /// Parameter to check. private static void CheckParameterIsNotOut(MethodInfo method, ParameterInfo parameter) { Debug.Assert(method != null, "method != null"); Debug.Assert(parameter != null, "parameter != null"); if (parameter.IsOut) { throw new InvalidOperationException(Strings.DataService_ParameterIsOut(method.DeclaringType.FullName, method.Name, parameter.Name)); } } ///is not an [out] parameter. /// Invokes the static service initialization methods on the /// specified type family. /// /// Type of service to initialize for. private void InvokeStaticInitialization(Type type) { Debug.Assert(type != null, "type != null"); // Build a stack going from most-specific to least-specific type. BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public; while (type != null) { MethodInfo method = type.GetMethod(XmlConstants.ClrServiceInitializationMethodName, flags, null, new Type[] { typeof(IDataServiceConfiguration) }, null); if (method == null) { method = type.GetMethod(XmlConstants.ClrServiceInitializationMethodName, flags, null, new Type[] { typeof(DataServiceConfiguration) }, null); } if (method != null && method.ReturnType == typeof(void)) { Debug.Assert(method.IsStatic, "method.IsStatic"); Debug.Assert(method.Name == XmlConstants.ClrServiceInitializationMethodName, "Making sure that the method name is as expected"); ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 1 && !parameters[0].IsOut) { object[] initializeParameters = new object[] { this }; try { method.Invoke(null, initializeParameters); } catch (TargetInvocationException exception) { ErrorHandler.HandleTargetInvocationException(exception); throw; } return; } } type = type.BaseType; } } ////// Register authorization callbacks specified on the given /// /// Type of web data service to check. private void RegisterCallbacks(Type type) { Debug.Assert(type != null, "type != null"); Debug.Assert(this.provider != null, "this.provider != null"); BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public; while (type != null) { MethodInfo[] methods = type.GetMethods(flags); for (int i = 0; i < methods.Length; i++) { MethodInfo method = methods[i]; QueryInterceptorAttribute[] queryAttributes = (QueryInterceptorAttribute[]) method.GetCustomAttributes(typeof(QueryInterceptorAttribute), true /* inherit */); foreach (QueryInterceptorAttribute attribute in queryAttributes) { ResourceSet container; if (!this.provider.TryResolveResourceSet(attribute.EntitySetName, out container) || container == null) { string message = Strings.DataService_AttributeEntitySetNotFound( attribute.EntitySetName, method.Name, type.FullName); throw new InvalidOperationException(message); } CheckQueryInterceptorSignature(type, method, container); if (!method.IsAbstract) { if (!this.readAuthorizationMethods.ContainsKey(container.Name)) { this.readAuthorizationMethods[container.Name] = new List. /// (); } this.readAuthorizationMethods[container.Name].Add(method); } } ChangeInterceptorAttribute[] changeAttributes = (ChangeInterceptorAttribute[]) method.GetCustomAttributes(typeof(ChangeInterceptorAttribute), true /* inherit */); foreach (ChangeInterceptorAttribute attribute in changeAttributes) { ResourceSet container; if (!this.provider.TryResolveResourceSet(attribute.EntitySetName, out container) || container == null) { string message = Strings.DataService_AttributeEntitySetNotFound( attribute.EntitySetName, method.Name, type.FullName); throw new InvalidOperationException(message); } // Check the signature. ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 2) { string message = Strings.DataService_ChangeInterceptorIncorrectParameterCount( method.Name, type.FullName, parameters.Length); throw new InvalidOperationException(message); } CheckParameterIsNotOut(method, parameters[0]); CheckParameterIsNotOut(method, parameters[1]); Type elementParameterType = parameters[0].ParameterType; if (!elementParameterType.IsAssignableFrom(container.ResourceType.InstanceType)) { string message = Strings.DataService_AuthorizationParameterNotAssignable( parameters[0].Name, method.Name, type.FullName, elementParameterType.FullName, container.ResourceType.InstanceType); throw new InvalidOperationException(message); } Type actionParameterType = parameters[1].ParameterType; if (actionParameterType != typeof(UpdateOperations)) { string message = Strings.DataService_AuthorizationParameterNotResourceAction( parameters[1].Name, method.Name, type.FullName, typeof(UpdateOperations).FullName); throw new InvalidOperationException(message); } Type returnType = method.ReturnType; if (returnType != typeof(void)) { string message = Strings.DataService_AuthorizationMethodNotVoid( method.Name, type.FullName, returnType.FullName); throw new InvalidOperationException(message); } if (!method.IsAbstract) { if (!this.writeAuthorizationMethods.ContainsKey(container.Name)) { this.writeAuthorizationMethods[container.Name] = new List (); } this.writeAuthorizationMethods[container.Name].Add(method); } } } type = type.BaseType; } } /// /// Checks that the specified /// Value to check. /// Parameter name. ///for the named property is not negative and that the /// configuration isn't sealed. /// The ///to set. /// This method is typically used in properties with the following pattern: /// private int CheckNonNegativeProperty(int value, string propertyName) { this.CheckNotSealed(); if (value < 0) { throw new ArgumentOutOfRangeException("value", value, Strings.PropertyRequiresNonNegativeNumber(propertyName)); } return value; } ///public int Foo { get {... } set { this.foo = this.CheckNonNegativeProperty(value, "Foo"); } }
///Checks that this configuration hasn't been sealed yet. private void CheckNotSealed() { if (this.configurationSealed) { string message = Strings.DataServiceConfiguration_NoChangesAllowed(XmlConstants.ClrServiceInitializationMethodName); throw new InvalidOperationException(message); } } #endregion Private methods. } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HostProtectionException.cs
- RelAssertionDirectKeyIdentifierClause.cs
- OdbcFactory.cs
- New.cs
- CodeSnippetTypeMember.cs
- FrameDimension.cs
- FileUtil.cs
- ErrorHandler.cs
- HtmlInputFile.cs
- ClipboardProcessor.cs
- FontDifferentiator.cs
- SspiNegotiationTokenProviderState.cs
- WorkflowApplicationAbortedException.cs
- TemplateField.cs
- XmlNodeComparer.cs
- DependencyPropertyKind.cs
- FileController.cs
- Claim.cs
- RequestCachePolicy.cs
- OutputScopeManager.cs
- _Semaphore.cs
- XmlValidatingReaderImpl.cs
- QueryAccessibilityHelpEvent.cs
- ToolStripSplitButton.cs
- LinqTreeNodeEvaluator.cs
- TimeSpan.cs
- UnmanagedMemoryStreamWrapper.cs
- PeerEndPoint.cs
- Help.cs
- DocumentOrderComparer.cs
- Metadata.cs
- XmlQualifiedNameTest.cs
- DockPattern.cs
- SamlAction.cs
- SqlServer2KCompatibilityAnnotation.cs
- GridEntry.cs
- ExceptionAggregator.cs
- CodeTypeReferenceExpression.cs
- ProcessingInstructionAction.cs
- ReachDocumentReferenceCollectionSerializer.cs
- InternalConfigHost.cs
- FrameworkElementAutomationPeer.cs
- HttpClientCertificate.cs
- TypeSemantics.cs
- Psha1DerivedKeyGenerator.cs
- ServiceModelSecurityTokenRequirement.cs
- ToolStripManager.cs
- DesignTimeResourceProviderFactoryAttribute.cs
- PasswordBox.cs
- StylusPointProperties.cs
- BCryptSafeHandles.cs
- NetCodeGroup.cs
- VisualBasicSettingsHandler.cs
- SecurityRuntime.cs
- SimpleHandlerBuildProvider.cs
- XPathDocumentNavigator.cs
- PerformanceCounterPermission.cs
- BitmapCache.cs
- EncoderParameter.cs
- DataGridViewRowHeightInfoPushedEventArgs.cs
- Visitors.cs
- GeometryHitTestResult.cs
- AsyncResult.cs
- ConfigurationSectionGroup.cs
- DataControlFieldTypeEditor.cs
- HwndProxyElementProvider.cs
- ComponentDispatcher.cs
- ArgumentReference.cs
- SQLInt64.cs
- ValidatedMobileControlConverter.cs
- Literal.cs
- RequestNavigateEventArgs.cs
- MouseBinding.cs
- DynamicResourceExtensionConverter.cs
- WindowsListViewItemCheckBox.cs
- AssemblyInfo.cs
- DbConnectionPoolOptions.cs
- XamlReaderHelper.cs
- GlobalizationAssembly.cs
- LogicalExpr.cs
- cookiecollection.cs
- GridLengthConverter.cs
- GridViewCommandEventArgs.cs
- DesignTimeTemplateParser.cs
- BitmapEffectGeneralTransform.cs
- DeferredSelectedIndexReference.cs
- ColorPalette.cs
- MobileCapabilities.cs
- HitTestWithPointDrawingContextWalker.cs
- TraceContextEventArgs.cs
- ArglessEventHandlerProxy.cs
- SQLInt64.cs
- ActiveXHost.cs
- EventEntry.cs
- ProcessHostConfigUtils.cs
- CardSpacePolicyElement.cs
- XmlElementAttribute.cs
- AttributeQuery.cs
- ValueProviderWrapper.cs
- DocumentGridPage.cs