/// <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> /// 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> /// Selects the service operation to call. /// </summary> /// <param name="message">The Message object sent to invoke a service operation.</param> /// <param name="uriMatched">A value that specifies whether the URI matched a specific service operation.</param> /// <returns>The name of the service operation to call.</returns> protected override string SelectOperation(ref Message message, out bool uriMatched) { uriMatched = false; string[] segments = UriUtils.EnumerateSegments(message.Properties.Via, this.baseUri); Debug.Assert(segments != null, "We should be getting a non-null segments collection."); object property; HttpRequestMessageProperty httpRequestMessageProperty = null; if (message.Properties.TryGetValue(HttpRequestMessageProperty.Name, out property)) { httpRequestMessageProperty = (HttpRequestMessageProperty)property; } if (httpRequestMessageProperty == null) { return(base.SelectOperation(ref message, out uriMatched)); } // Dis-allow query options. DomainDataServiceOperationSelector.DisallowQueryOptions(message.Properties.Via); string identifier = null; if (segments.Length > 0 && UriUtils.ExtractSegmentIdentifier(segments[0], out identifier)) { // Disallow selection of entries within response sets. DomainDataServiceOperationSelector.DisallowEntrySelection(identifier, segments[0]); } // Service description or metadata request. if (0 == segments.Length || (1 == segments.Length && identifier == ServiceUtils.MetadataOperationName)) { DomainDataServiceOperationSelector.DisallowNonGetRequests(httpRequestMessageProperty.Method); // Metadata requests only available through GET. uriMatched = true; Collection <UriTemplateMatch> matches = DomainDataServiceOperationSelector.CreateAstoriaTemplate(this.baseUri).Match(message.Properties.Via); if (matches.Count > 0) { message.Properties.Add( ServiceUtils.UriTemplateMatchResultsPropertyName, matches[0]); // Dis-allow json requests for metadata documents. DomainDataServiceOperationSelector.DisallowJsonRequests( identifier != null ? RequestKind.MetadataDocument : RequestKind.ServiceDocument, httpRequestMessageProperty.Headers[HttpRequestHeader.Accept]); return(identifier ?? ServiceUtils.ServiceDocumentOperationName); } else { // Let the base error with Endpoint not found. return(base.SelectOperation(ref message, out uriMatched)); } } else { if (segments.Length > 1) { // More than 1 segments e.g. navigation is not supported. throw new DomainDataServiceException((int)HttpStatusCode.BadRequest, Resource.DomainDataService_MultipleSegments_NotAllowed); } // Remove the trailing parentheses from the URI. message.Headers.To = UriUtils.ReplaceLastSegment(message.Headers.To, identifier); string operationName; if (this.serviceRootQueryOperations.TryGetValue(identifier, out operationName)) { // Only allow GETs on resource sets. DomainDataServiceOperationSelector.DisallowNonGetRequests(httpRequestMessageProperty.Method); // Check if a resource set request matches current request. uriMatched = true; message.Properties.Add( ServiceUtils.UriTemplateMatchResultsPropertyName, DomainDataServiceOperationSelector.CreateAstoriaTemplate(this.baseUri).Match(message.Properties.Via)[0]); // Dis-allow json requests for resource sets. DomainDataServiceOperationSelector.DisallowJsonRequests(RequestKind.ResourceSet, httpRequestMessageProperty.Headers[HttpRequestHeader.Accept]); return(operationName); } } string result; try { // Delegate to base for all non-root query operations. result = base.SelectOperation(ref message, out uriMatched); } catch (Exception innerException) { if (innerException.IsFatal()) { throw; } else { throw new DomainDataServiceException((int)HttpStatusCode.NotFound, Resource.DomainDataService_Selection_Error, innerException); } } if (uriMatched == false) { throw new DomainDataServiceException((int)HttpStatusCode.NotFound, Resource.DomainDataService_Operation_NotFound); } else if (String.IsNullOrEmpty(result)) { DomainDataServiceException e = new DomainDataServiceException((int)HttpStatusCode.MethodNotAllowed, Resource.DomainDataService_Operation_Method_NotAllowed); e.ResponseAllowHeader = httpRequestMessageProperty.Method == ServiceUtils.HttpGetMethodName ? ServiceUtils.HttpPostMethodName : ServiceUtils.HttpGetMethodName; throw e; } // Dis-allow json returning service operation requests. DomainDataServiceOperationSelector.DisallowJsonRequests(RequestKind.ServiceOperation, httpRequestMessageProperty.Headers[HttpRequestHeader.Accept]); return(result); }