Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataWeb / Server / System / Data / Services / DataServiceConfiguration.cs / 1 / 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.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; #endregion Namespaces. ///Use this class to manage the configuration data for a data service. internal 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 IDataServiceProvider provider; ///Rights used for unspecified resource containers. private EntitySetRights rightsForUnspecifiedResourceContainer; ///Rights used for unspecified service operations. private ServiceOperationRights rightsForUnspecifiedServiceOperation; ///A lookup of containers to their rights. private DictionaryresourceRights; /// A lookup of service operations to their rights. private DictionaryserviceRights; /// A list of known types. private ListknownTypes; /// Whether verbose errors should be returned by default. private bool useVerboseErrors; #endregion Private fields. #region Constructor. ////// Initializes a new /// Non-null provider for this configuration. internal DataServiceConfiguration(IDataServiceProvider provider) { Debug.Assert(provider != null, "provider != null"); this.provider = provider; this.resourceRights = new Dictionarywith /// the specified . /// (); this.serviceRights = new Dictionary (); 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; } #endregion Constructor. #region IDataServiceConfiguration implementation. /// 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 { 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. /// Sets the access rights on the specified resource container. /// /// Name of resource container to set; '*' to indicate all /// resource containers 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 { ResourceContainer container = this.provider.TryResolveContainerName(name); if (container == null) { throw new ArgumentException(Strings.DataServiceConfiguration_ResourceNameNotFound(name), "name"); } this.resourceRights[container] = 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"); ServiceOperation serviceOperation = this.provider.TryResolveServiceOperation(name); if (name == "*") { this.rightsForUnspecifiedServiceOperation = rights; } else { if (serviceOperation == null) { throw new ArgumentException(Strings.DataServiceConfiguration_ServiceNameNotFound(name), "name"); } this.serviceRights[serviceOperation] = 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); } #endregion IDataServiceConfiguration implementation. #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, ResourceContainer container) { Debug.Assert(service != null, "service != null"); Debug.Assert(container != null, "container != null"); MethodInfo[] methods = container.ReadAuthorizationMethods; if (methods == null || methods.Length == 0) { return null; } LambdaExpression filter = null; for (int i = 0; i < methods.Length; i++) { Expression predicate = (Expression)methods[i].Invoke(service.Instance, WebUtil.EmptyObjectArray); 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 container to compose with. /// Query to compose. ///for the /// given with authorization /// callbacks. /// The resulting composed query. internal static IQueryable ComposeResourceContainer(IDataService service, ResourceContainer container, IQueryable query) { Debug.Assert(service != null, "service != null"); Debug.Assert(container != null, "container != null"); Debug.Assert(query != null, "query != null"); MethodInfo[] methods = container.ReadAuthorizationMethods; if (methods != null) { for (int i = 0; i < methods.Length; i++) { Expression predicate = (Expression)methods[i].Invoke(service.Instance, WebUtil.EmptyObjectArray); 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; } ///Applies the configuration to the current provider. /// Instance of the data source for the provider. ///This method should be called exactly once. internal void ApplyToProvider(object dataSourceInstance) { Debug.Assert(this.provider != null, "this.provider != null"); Debug.Assert(this.resourceRights != null, "this.resourceRights != null - otherwise, ApplyToProvider has been called multiple times."); this.provider.ApplyConfiguration(this, dataSourceInstance); this.resourceRights = null; this.serviceRights = null; this.knownTypes = null; } ///Checks whether this request has the specified rights. /// Container to check. /// Required rights. ///Thrown if internal void CheckResourceRights(ResourceContainer container, EntitySetRights requiredRights) { Debug.Assert(container != null, "container != null"); Debug.Assert(requiredRights != EntitySetRights.None, "requiredRights != EntitySetRights.None"); EntitySetRights effectiveRights = this.GetResourceContainerRights(container); if ((requiredRights & effectiveRights) == 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 void CheckResourceRightsForRead(ResourceContainer container, bool singleResult) { Debug.Assert(container != null, "container != null"); EntitySetRights requiredRights = singleResult ? EntitySetRights.ReadSingle : EntitySetRights.ReadMultiple; this.CheckResourceRights(container, requiredRights); } ///aren't available. Checks whether this request has the specified rights. /// Operation to check. /// Required rights. ///Thrown if internal void CheckServiceRights(ServiceOperation operation, ServiceOperationRights requiredRights) { Debug.Assert(operation != null, "operation != null"); Debug.Assert(requiredRights != ServiceOperationRights.None, "requiredRights != EntitySetRights.None"); ServiceOperationRights effectiveRights = this.GetServiceOperationRights(operation); 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 void CheckServiceRights(ServiceOperation operation, bool singleResult) { Debug.Assert(operation != null, "operation != null"); if (operation.ResultKind != ServiceOperationResultKind.Nothing) { ServiceOperationRights requiredRights = singleResult ? ServiceOperationRights.ReadSingle : ServiceOperationRights.ReadMultiple; this.CheckServiceRights(operation, requiredRights); } } ///aren't available. Gets a string with methods allowed on the target for the /// Description with target. ///. A string with methods allowed on the description; possibly null. internal string GetAllowedMethods(RequestDescription description) { Debug.Assert(description != null, "description != null"); Debug.Assert( description.TargetKind != RequestTargetKind.Nothing, "description.TargetKind != RequestTargetKind.Nothing - 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(); ResourceContainer container = description.SegmentInfos[index].TargetContainer; return this.GetAllowedMethods(container, description.IsSingleResult); } } ////// Gets a string representation of allowed methods on the container (with the specified target cardinality), /// suitable for an 'Allow' header. /// /// Targetted container, possibly null. /// true if a single entity is checked for rights; false otherwise. ///A value for an 'Allow' header; null if internal string GetAllowedMethods(ResourceContainer container, bool single) { if (container == null) { return null; } else { System.Text.StringBuilder result = new System.Text.StringBuilder(); EntitySetRights rights = this.GetResourceContainerRights(container); if (single) { AppendRight(rights, EntitySetRights.ReadSingle, XmlConstants.HttpMethodGet, result); AppendRight(rights, EntitySetRights.WriteDelete, XmlConstants.HttpMethodDelete, result); AppendRight(rights, EntitySetRights.WriteReplace, XmlConstants.HttpMethodPut, result); AppendRight(rights, EntitySetRights.WriteMerge, XmlConstants.HttpMethodMerge, 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 GetResourceContainerRights(ResourceContainer container) { Debug.Assert(container != null, "container != null"); EntitySetRights result; if (this.resourceRights == null) { result = container.Rights; } else { if (!this.resourceRights.TryGetValue(container, 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 operation) { Debug.Assert(operation != null, "operation != null"); ServiceOperationRights result; if (this.serviceRights == null) { result = operation.Rights; } else { if (!this.serviceRights.TryGetValue(operation, out result)) { result = this.rightsForUnspecifiedServiceOperation; } } return result; } ///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; } /// /// Invokes the static service initialization methods on the /// specified type family. /// /// Type of service to initialize for. internal 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[] methods = type.GetMethods(flags); for (int i = 0; i < methods.Length; i++) { MethodInfo method = methods[i]; Debug.Assert(method.IsStatic, "method.IsStatic"); if (method.Name == XmlConstants.ClrServiceInitializationMethodName && method.ReturnType == typeof(void)) { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(IDataServiceConfiguration) && !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. internal void RegisterCallbacks(Type type) { Debug.Assert(type != null, "type != 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) { ResourceContainer container = this.provider.TryResolveContainerName(attribute.EntitySetName); if (container == null) { string message = Strings.DataService_AttributeEntitySetNotFound( attribute.EntitySetName, method.Name, type.FullName); throw new InvalidOperationException(message); } CheckQueryInterceptorSignature(type, method, container); if (!method.IsAbstract) { container.AddReadAuthorizationMethod(method); } } ChangeInterceptorAttribute[] changeAttributes = (ChangeInterceptorAttribute[]) method.GetCustomAttributes(typeof(ChangeInterceptorAttribute), true /* inherit */); foreach (ChangeInterceptorAttribute attribute in changeAttributes) { ResourceContainer container = this.provider.TryResolveContainerName(attribute.EntitySetName); if (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.ElementType)) { string message = Strings.DataService_AuthorizationParameterNotAssignable( parameters[0].Name, method.Name, type.FullName, elementParameterType.FullName, container.ElementType); 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) { container.AddWriteAuthorizationMethod(method); } } } type = type.BaseType; } } ///. /// 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; } #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, ResourceContainer 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.ElementType, 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.ElementType, 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. /// 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. //---------------------------------------------------------------------- //// 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.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; #endregion Namespaces. ///Use this class to manage the configuration data for a data service. internal 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 IDataServiceProvider provider; ///Rights used for unspecified resource containers. private EntitySetRights rightsForUnspecifiedResourceContainer; ///Rights used for unspecified service operations. private ServiceOperationRights rightsForUnspecifiedServiceOperation; ///A lookup of containers to their rights. private DictionaryresourceRights; /// A lookup of service operations to their rights. private DictionaryserviceRights; /// A list of known types. private ListknownTypes; /// Whether verbose errors should be returned by default. private bool useVerboseErrors; #endregion Private fields. #region Constructor. ////// Initializes a new /// Non-null provider for this configuration. internal DataServiceConfiguration(IDataServiceProvider provider) { Debug.Assert(provider != null, "provider != null"); this.provider = provider; this.resourceRights = new Dictionarywith /// the specified . /// (); this.serviceRights = new Dictionary (); 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; } #endregion Constructor. #region IDataServiceConfiguration implementation. /// 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 { 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. /// Sets the access rights on the specified resource container. /// /// Name of resource container to set; '*' to indicate all /// resource containers 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 { ResourceContainer container = this.provider.TryResolveContainerName(name); if (container == null) { throw new ArgumentException(Strings.DataServiceConfiguration_ResourceNameNotFound(name), "name"); } this.resourceRights[container] = 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"); ServiceOperation serviceOperation = this.provider.TryResolveServiceOperation(name); if (name == "*") { this.rightsForUnspecifiedServiceOperation = rights; } else { if (serviceOperation == null) { throw new ArgumentException(Strings.DataServiceConfiguration_ServiceNameNotFound(name), "name"); } this.serviceRights[serviceOperation] = 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); } #endregion IDataServiceConfiguration implementation. #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, ResourceContainer container) { Debug.Assert(service != null, "service != null"); Debug.Assert(container != null, "container != null"); MethodInfo[] methods = container.ReadAuthorizationMethods; if (methods == null || methods.Length == 0) { return null; } LambdaExpression filter = null; for (int i = 0; i < methods.Length; i++) { Expression predicate = (Expression)methods[i].Invoke(service.Instance, WebUtil.EmptyObjectArray); 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 container to compose with. /// Query to compose. ///for the /// given with authorization /// callbacks. /// The resulting composed query. internal static IQueryable ComposeResourceContainer(IDataService service, ResourceContainer container, IQueryable query) { Debug.Assert(service != null, "service != null"); Debug.Assert(container != null, "container != null"); Debug.Assert(query != null, "query != null"); MethodInfo[] methods = container.ReadAuthorizationMethods; if (methods != null) { for (int i = 0; i < methods.Length; i++) { Expression predicate = (Expression)methods[i].Invoke(service.Instance, WebUtil.EmptyObjectArray); 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; } ///Applies the configuration to the current provider. /// Instance of the data source for the provider. ///This method should be called exactly once. internal void ApplyToProvider(object dataSourceInstance) { Debug.Assert(this.provider != null, "this.provider != null"); Debug.Assert(this.resourceRights != null, "this.resourceRights != null - otherwise, ApplyToProvider has been called multiple times."); this.provider.ApplyConfiguration(this, dataSourceInstance); this.resourceRights = null; this.serviceRights = null; this.knownTypes = null; } ///Checks whether this request has the specified rights. /// Container to check. /// Required rights. ///Thrown if internal void CheckResourceRights(ResourceContainer container, EntitySetRights requiredRights) { Debug.Assert(container != null, "container != null"); Debug.Assert(requiredRights != EntitySetRights.None, "requiredRights != EntitySetRights.None"); EntitySetRights effectiveRights = this.GetResourceContainerRights(container); if ((requiredRights & effectiveRights) == 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 void CheckResourceRightsForRead(ResourceContainer container, bool singleResult) { Debug.Assert(container != null, "container != null"); EntitySetRights requiredRights = singleResult ? EntitySetRights.ReadSingle : EntitySetRights.ReadMultiple; this.CheckResourceRights(container, requiredRights); } ///aren't available. Checks whether this request has the specified rights. /// Operation to check. /// Required rights. ///Thrown if internal void CheckServiceRights(ServiceOperation operation, ServiceOperationRights requiredRights) { Debug.Assert(operation != null, "operation != null"); Debug.Assert(requiredRights != ServiceOperationRights.None, "requiredRights != EntitySetRights.None"); ServiceOperationRights effectiveRights = this.GetServiceOperationRights(operation); 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 void CheckServiceRights(ServiceOperation operation, bool singleResult) { Debug.Assert(operation != null, "operation != null"); if (operation.ResultKind != ServiceOperationResultKind.Nothing) { ServiceOperationRights requiredRights = singleResult ? ServiceOperationRights.ReadSingle : ServiceOperationRights.ReadMultiple; this.CheckServiceRights(operation, requiredRights); } } ///aren't available. Gets a string with methods allowed on the target for the /// Description with target. ///. A string with methods allowed on the description; possibly null. internal string GetAllowedMethods(RequestDescription description) { Debug.Assert(description != null, "description != null"); Debug.Assert( description.TargetKind != RequestTargetKind.Nothing, "description.TargetKind != RequestTargetKind.Nothing - 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(); ResourceContainer container = description.SegmentInfos[index].TargetContainer; return this.GetAllowedMethods(container, description.IsSingleResult); } } ////// Gets a string representation of allowed methods on the container (with the specified target cardinality), /// suitable for an 'Allow' header. /// /// Targetted container, possibly null. /// true if a single entity is checked for rights; false otherwise. ///A value for an 'Allow' header; null if internal string GetAllowedMethods(ResourceContainer container, bool single) { if (container == null) { return null; } else { System.Text.StringBuilder result = new System.Text.StringBuilder(); EntitySetRights rights = this.GetResourceContainerRights(container); if (single) { AppendRight(rights, EntitySetRights.ReadSingle, XmlConstants.HttpMethodGet, result); AppendRight(rights, EntitySetRights.WriteDelete, XmlConstants.HttpMethodDelete, result); AppendRight(rights, EntitySetRights.WriteReplace, XmlConstants.HttpMethodPut, result); AppendRight(rights, EntitySetRights.WriteMerge, XmlConstants.HttpMethodMerge, 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 GetResourceContainerRights(ResourceContainer container) { Debug.Assert(container != null, "container != null"); EntitySetRights result; if (this.resourceRights == null) { result = container.Rights; } else { if (!this.resourceRights.TryGetValue(container, 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 operation) { Debug.Assert(operation != null, "operation != null"); ServiceOperationRights result; if (this.serviceRights == null) { result = operation.Rights; } else { if (!this.serviceRights.TryGetValue(operation, out result)) { result = this.rightsForUnspecifiedServiceOperation; } } return result; } ///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; } /// /// Invokes the static service initialization methods on the /// specified type family. /// /// Type of service to initialize for. internal 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[] methods = type.GetMethods(flags); for (int i = 0; i < methods.Length; i++) { MethodInfo method = methods[i]; Debug.Assert(method.IsStatic, "method.IsStatic"); if (method.Name == XmlConstants.ClrServiceInitializationMethodName && method.ReturnType == typeof(void)) { ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(IDataServiceConfiguration) && !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. internal void RegisterCallbacks(Type type) { Debug.Assert(type != null, "type != 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) { ResourceContainer container = this.provider.TryResolveContainerName(attribute.EntitySetName); if (container == null) { string message = Strings.DataService_AttributeEntitySetNotFound( attribute.EntitySetName, method.Name, type.FullName); throw new InvalidOperationException(message); } CheckQueryInterceptorSignature(type, method, container); if (!method.IsAbstract) { container.AddReadAuthorizationMethod(method); } } ChangeInterceptorAttribute[] changeAttributes = (ChangeInterceptorAttribute[]) method.GetCustomAttributes(typeof(ChangeInterceptorAttribute), true /* inherit */); foreach (ChangeInterceptorAttribute attribute in changeAttributes) { ResourceContainer container = this.provider.TryResolveContainerName(attribute.EntitySetName); if (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.ElementType)) { string message = Strings.DataService_AuthorizationParameterNotAssignable( parameters[0].Name, method.Name, type.FullName, elementParameterType.FullName, container.ElementType); 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) { container.AddWriteAuthorizationMethod(method); } } } type = type.BaseType; } } ///. /// 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; } #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, ResourceContainer 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.ElementType, 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.ElementType, 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. /// 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
- ObjectDataSourceFilteringEventArgs.cs
- IEnumerable.cs
- ConfigurationStrings.cs
- CharAnimationBase.cs
- PropertyGroupDescription.cs
- SafeRegistryHandle.cs
- FileDialog_Vista.cs
- BindingExpressionBase.cs
- NumberAction.cs
- StringKeyFrameCollection.cs
- bidPrivateBase.cs
- _CookieModule.cs
- ListBox.cs
- JobInputBins.cs
- HostExecutionContextManager.cs
- PieceNameHelper.cs
- NavigationProperty.cs
- SpeechUI.cs
- TableLayoutPanelCellPosition.cs
- ConfigXmlAttribute.cs
- DataGridViewRowHeightInfoNeededEventArgs.cs
- WindowPatternIdentifiers.cs
- TextModifierScope.cs
- _Events.cs
- DataBindEngine.cs
- securestring.cs
- ShimAsPublicXamlType.cs
- SymLanguageVendor.cs
- WindowsScrollBar.cs
- EncodingTable.cs
- ForwardPositionQuery.cs
- TextRangeBase.cs
- XmlTextEncoder.cs
- MultipleViewProviderWrapper.cs
- MarkupExtensionReturnTypeAttribute.cs
- PropertyInformationCollection.cs
- SchemaElementDecl.cs
- SqlMultiplexer.cs
- JournalNavigationScope.cs
- TripleDES.cs
- WebReferencesBuildProvider.cs
- Parsers.cs
- RoleGroup.cs
- ConfigXmlWhitespace.cs
- BrowserCapabilitiesFactory.cs
- FileLevelControlBuilderAttribute.cs
- Misc.cs
- DesignTimeValidationFeature.cs
- ColorTransformHelper.cs
- X509CertificateStore.cs
- UnsafeNativeMethods.cs
- translator.cs
- DbMetaDataFactory.cs
- HttpPostedFile.cs
- IdleTimeoutMonitor.cs
- ECDiffieHellmanCng.cs
- shaperfactoryquerycacheentry.cs
- RtfNavigator.cs
- HTTPNotFoundHandler.cs
- URIFormatException.cs
- ConnectionConsumerAttribute.cs
- SqlStream.cs
- SqlServices.cs
- TypeLoadException.cs
- TextRangeBase.cs
- WeakEventTable.cs
- XmlQueryRuntime.cs
- SystemNetworkInterface.cs
- TreeNodeClickEventArgs.cs
- FileAuthorizationModule.cs
- ByteStream.cs
- SkinBuilder.cs
- SizeFConverter.cs
- ContentHostHelper.cs
- QueryCacheManager.cs
- CodeMethodReturnStatement.cs
- BeginEvent.cs
- OdbcConnectionHandle.cs
- CommandField.cs
- CancellationHandler.cs
- ConstraintStruct.cs
- UriTemplateMatchException.cs
- BooleanAnimationBase.cs
- LinqDataSourceStatusEventArgs.cs
- InputManager.cs
- DynamicRendererThreadManager.cs
- LinearGradientBrush.cs
- ArraySortHelper.cs
- Renderer.cs
- CqlBlock.cs
- HostingEnvironmentException.cs
- MailMessageEventArgs.cs
- PackWebRequestFactory.cs
- CurrentTimeZone.cs
- InstallerTypeAttribute.cs
- AmbientValueAttribute.cs
- DataGridViewButtonColumn.cs
- DataGridViewCellMouseEventArgs.cs
- CodeTypeReferenceCollection.cs
- Variant.cs