/// <summary> /// Infers resource sets and resource types corresponding to query operations in domain service. /// </summary> /// <param name="domainServiceDescription">Domain service description.</param> private void CollectResourceSets(DomainServiceDescription domainServiceDescription) { foreach (var operationEntry in domainServiceDescription.DomainOperationEntries) { // Only composable operations i.e. those that return IEnumerable<T> are expected to represent root resource sets. if (operationEntry.Operation == DomainOperation.Query && DomainDataServiceMetadata.IsRootQueryOperation(operationEntry)) { Type resourceInstanceType = operationEntry.AssociatedType; // There will always be an entity type associated with query operation, we need to make sure that we have all // the types in this type's hierarchy added to the provider types. ResourceType resourceType = this.CreateResourceTypeHierarchy(domainServiceDescription, resourceInstanceType); foreach (ResourceSet resourceSet in this.sets.Values) { Type resourceSetInstanceType = resourceSet.ResourceType.InstanceType; if (resourceSetInstanceType.IsAssignableFrom(resourceInstanceType) || resourceInstanceType.IsAssignableFrom(resourceSetInstanceType)) { throw new DomainDataServiceException((int)HttpStatusCode.InternalServerError, Resource.DomainDataService_MEST_NotAllowed); } } ResourceSet rs = new ResourceSet(resourceInstanceType.Name + ServiceUtils.ResourceSetPostFix, resourceType); this.sets.Add(operationEntry.Name, rs); } } }
/// <summary> /// Given an operation descriptions, detects if it corresponds to a root query operation. /// </summary> /// <param name="od">Given operation description.</param> /// <param name="metadata">Metadata for the domain data service.</param> /// <returns>null if operation does not correspond to root query operation, otherwise the name of the resource set.</returns> private static string GetRootQueryOperation(OperationDescription od, DomainDataServiceMetadata metadata) { ResourceSet resourceSet; if (metadata.Sets.TryGetValue(od.Name, out resourceSet)) { Debug.Assert(resourceSet != null, "resourceSet != null"); return(resourceSet.Name); } return(null); }
/// <summary> /// Infers service operations from domain service description. /// </summary> /// <param name="domainServiceDescription">Domain service description.</param> private void CollectServiceOperations(DomainServiceDescription domainServiceDescription) { foreach (var operationEntry in domainServiceDescription.DomainOperationEntries) { DomainDataServiceOperation op = null; if ((operationEntry.Operation == DomainOperation.Query && !DomainDataServiceMetadata.IsRootQueryOperation(operationEntry)) || operationEntry.Operation == DomainOperation.Invoke) { op = this.CreateServiceOperation(operationEntry); } if (op != null) { this.serviceOperations.Add(op.Name, op); } } }
/// <summary>Constructs the operation selector for runtime.</summary> /// <param name="endpoint">End point.</param> /// <param name="metadata">Domain data service metadata.</param> public DomainDataServiceOperationSelector( ServiceEndpoint endpoint, DomainDataServiceMetadata metadata) : base(DomainDataServiceOperationSelector.ExtractNonRootQueryServiceOperations(endpoint, metadata)) { this.baseUri = endpoint.ListenUri; this.serviceRootQueryOperations = new Dictionary <string, string>(); // Collect all the query operations, since they are to be handled by selector in this class. foreach (var od in endpoint.Contract.Operations) { string resourceSetName = DomainDataServiceOperationSelector.GetRootQueryOperation(od, metadata); if (!String.IsNullOrEmpty(resourceSetName)) { Debug.Assert(!this.serviceRootQueryOperations.ContainsKey(resourceSetName), "There should only be 1 default query operation per set."); // Note the fact that requests on resourceSet correspond to the given operation. this.serviceRootQueryOperations.Add(resourceSetName, od.Name); } } }
/// <summary>Constructs the data service provider object.</summary> /// <param name="domainServiceDataServiceMetadata">Metadata information for the current instance.</param> /// <param name="result">Root queryable for current request.</param> internal DomainDataServiceProvider(DomainDataServiceMetadata domainServiceDataServiceMetadata, object result) { this.metadata = domainServiceDataServiceMetadata; this.CurrentDataSource = new object(); this.Result = result; }
/// <summary> /// Creates a new domain data service instance. /// </summary> /// <param name="domainServiceDataServiceMetadata">Metadata for the domain data service.</param> /// <param name="result">Result of current request operation invocation.</param> internal DomainDataService(DomainDataServiceMetadata domainServiceDataServiceMetadata, object result) { this.provider = new DomainDataServiceProvider(domainServiceDataServiceMetadata, result); }
/// <summary> /// Obtains the service operations available on the model and hands over all those /// operations to the base class for processing. The root query operations are /// handled by this class itself. /// </summary> /// <param name="endpoint">Endpoint on which operations are defined.</param> /// <param name="metadata">Metadata of the domain service.</param> /// <returns>Endpoint that contains all the operations that base class needs to process.</returns> private static ServiceEndpoint ExtractNonRootQueryServiceOperations(ServiceEndpoint endpoint, DomainDataServiceMetadata metadata) { ContractDescription cd = new ContractDescription(endpoint.Contract.Name); // Provide all the non-root query operations to the base class, only provide those operations that // have some representation on the domain data service. foreach (OperationDescription od in endpoint.Contract.Operations) { if (metadata.ServiceOperations.Keys.Contains(od.Name)) { Debug.Assert( String.IsNullOrEmpty(DomainDataServiceOperationSelector.GetRootQueryOperation(od, metadata)), "Service operation must not be a root query operation."); cd.Operations.Add(od); } } return(new ServiceEndpoint(cd, endpoint.Binding, endpoint.Address) { ListenUri = endpoint.ListenUri }); }
/// <summary>Constructs factory for creating data services using the given domain service description.</summary> /// <param name="metadata">Data Service metadata object corresponding to domain service description.</param> internal DomainDataServiceFactory(DomainDataServiceMetadata metadata) { this.domainDataServiceMetadata = metadata; }
/// <summary> /// Loads properties for all the resource types. /// </summary> private void LoadResourceTypeProperties() { #if DEBUG // Remember the types we've visited. HashSet <ResourceType> visitedType = new HashSet <ResourceType>(EqualityComparer <ResourceType> .Default); #endif foreach (var resourceType in this.types.Values) { Type type = resourceType.InstanceType; ResourceType parentResourceType = resourceType.BaseType; #if DEBUG Debug.Assert(parentResourceType == null || visitedType.Contains(parentResourceType), "We must always visit the ancestors of a type before visiting that type."); visitedType.Add(resourceType); #endif foreach (PropertyDescriptor pi in TypeDescriptor.GetProperties(type)) { if (!TypeUtils.IsSerializableDataMember(pi)) { continue; } // Only primitive properties are currently supported. ResourceType propertyType = ResourceType.GetPrimitiveResourceType(pi.PropertyType); if (null != propertyType) { ResourceProperty rp = parentResourceType == null ? null : this.GetResourceProperty(parentResourceType, DomainDataServiceMetadata.GetNameFromPropertyDescriptor(pi)); if (rp == null) { ResourcePropertyKind kind = ResourcePropertyKind.Primitive; if (TypeUtils.IsKeyProperty(pi)) { kind |= ResourcePropertyKind.Key; } rp = new ResourceProperty( DomainDataServiceMetadata.GetNameFromPropertyDescriptor(pi), kind, propertyType) { CanReflectOnInstanceTypeProperty = false }; // We only need to add rp to the resourceType if rp is not defined on an ancestor type. resourceType.AddProperty(rp); } // We always add rp to this.resourceProperties map even if the property is defined on an ancestor type. this.AddResourcePropertyDescriptor(resourceType, rp, pi); } } } #if DEBUG foreach (var entry in this.resourceProperties) { Debug.Assert(entry.Value.Count > 0, "A ResourceType cannot have 0 properties, it should have at least its key property."); } #endif }