Exemple #1
0
            /// <summary>
            /// Derived classes override this method to provide custom invocation behavior.
            /// </summary>
            /// <param name="instance">Instance to invoke the invoker against.</param>
            /// <param name="inputs">Input parameters post conversion.</param>
            /// <returns>Result of invocation.</returns>

            protected override async ValueTask <object> InvokeCoreAsync(object instance, object[] inputs)
            {
                ServiceInvokeResult invokeResult;

                try
                {
                    InvokeDescription description = new InvokeDescription(this.operation, inputs);
                    invokeResult = await((DomainService)instance).InvokeAsync(description, CancellationToken.None).ConfigureAwait(false);
                }
                catch (UnauthorizedAccessException ex)
                {
                    throw new DomainDataServiceException((int)System.Net.HttpStatusCode.Unauthorized, ex.Message, ex);
                }
                catch (Exception ex)
                {
                    if (ex.IsFatal())
                    {
                        throw;
                    }
                    else
                    {
                        throw new DomainDataServiceException(Resource.DomainDataService_General_Error, ex);
                    }
                }

                // This will throw if there are any validation erros
                DomainDataServiceException.HandleValidationErrors(invokeResult.ValidationErrors);
                return(invokeResult.Result);
            }
Exemple #2
0
            /// <summary>
            /// Derived classes override this method to provide custom invocation behavior.
            /// </summary>
            /// <param name="instance">Instance to invoke the invoker against.</param>
            /// <param name="inputs">Input parameters post conversion.</param>
            /// <param name="outputs">Optional out parameters.</param>
            /// <returns>Result of invocation.</returns>
            protected override object InvokeCore(object instance, object[] inputs, out object[] outputs)
            {
                outputs = ServiceUtils.EmptyObjectArray;

                IEnumerable <ValidationResult> validationErrors;
                object result;

                try
                {
                    InvokeDescription description = new InvokeDescription(this.operation, inputs);
                    result = ((DomainService)instance).Invoke(description, out validationErrors);
                }
                catch (UnauthorizedAccessException ex)
                {
                    throw new DomainDataServiceException((int)System.Net.HttpStatusCode.Unauthorized, ex.Message, ex);
                }
                catch (Exception ex)
                {
                    if (ex.IsFatal())
                    {
                        throw;
                    }
                    else
                    {
                        throw new DomainDataServiceException(Resource.DomainDataService_General_Error, ex);
                    }
                }

                DomainDataServiceException.HandleValidationErrors(validationErrors);

                return(result);
            }
Exemple #3
0
            /// <summary>Serializes the current exception description to the specified <paramref name="stream"/>.</summary>
            /// <param name="stream">Stream to write to.</param>
            internal void SerializeXmlErrorToStream(Stream stream)
            {
                Debug.Assert(stream != null, "stream != null");
                using (XmlWriter writer = ServiceUtils.CreateXmlWriterAndWriteProcessingInstruction(stream, ErrorSerializer.defaultEncoding))
                {
                    Debug.Assert(writer != null, "writer != null");
                    writer.WriteStartElement(ServiceUtils.XmlErrorElementName, ServiceUtils.DataWebMetadataNamespace);
                    string errorCode, message, messageLang;
                    DomainDataServiceException dataException = ExtractErrorValues(this._exception, out errorCode, out message, out messageLang);

                    writer.WriteStartElement(ServiceUtils.XmlErrorCodeElementName, ServiceUtils.DataWebMetadataNamespace);
                    writer.WriteString(errorCode);
                    writer.WriteEndElement();   // </code>

                    writer.WriteStartElement(ServiceUtils.XmlErrorMessageElementName, ServiceUtils.DataWebMetadataNamespace);
                    writer.WriteAttributeString(
                        ServiceUtils.XmlNamespacePrefix,   // prefix
                        ServiceUtils.XmlLangAttributeName, // localName
                        null,                              // ns
                        messageLang);                      // value
                    writer.WriteString(message);
                    writer.WriteEndElement();              // </message>

                    // Always assuming verbose errors.
                    Exception exception = (dataException == null) ? this._exception : dataException.InnerException;

                    SerializeXmlException(writer, exception);

                    writer.WriteEndElement();   // </error>
                    writer.Flush();
                }
            }
Exemple #4
0
 /// <summary>
 /// Checks if the HTTP request is a GET request and throws otherwise.
 /// </summary>
 /// <param name="httpMethod">Request HTTP method.</param>
 private static void DisallowNonGetRequests(string httpMethod)
 {
     if (httpMethod != ServiceUtils.HttpGetMethodName)
     {
         DomainDataServiceException e = new DomainDataServiceException((int)HttpStatusCode.MethodNotAllowed, Resource.DomainDataService_ResourceSets_Metadata_OnlyAllowedGet);
         e.ResponseAllowHeader = ServiceUtils.HttpGetMethodName;
         throw e;
     }
 }
Exemple #5
0
        /// <summary>
        /// Creates a delegate used for serializing the exception to outgoing stream.
        /// </summary>
        /// <param name="exception">Exception to serialize.</param>
        /// <param name="statusCode">Http status code from <paramref name="exception"/>.</param>
        /// <returns>Delegate that serializes the <paramref name="exception"/>.</returns>
        private static Action <Stream> HandleException(Exception exception, out HttpStatusCode statusCode)
        {
            Debug.Assert(TypeUtils.IsCatchableExceptionType(exception), "WebUtil.IsCatchableExceptionType(exception)");
            Debug.Assert(exception != null, "exception != null");

            DomainDataServiceException e = exception as DomainDataServiceException;

            statusCode = e != null ? (HttpStatusCode)e.StatusCode : HttpStatusCode.InternalServerError;

            return(new ErrorSerializer(exception).SerializeXmlErrorToStream);
        }
Exemple #6
0
            /// <summary>
            /// Gets values describing the <paramref name='exception' /> if it's a DomainDataServiceException;
            /// defaults otherwise.
            /// </summary>
            /// <param name='exception'>Exception to extract value from.</param>
            /// <param name='errorCode'>Error code from the <paramref name='exception' />; blank if not available.</param>
            /// <param name='message'>Message from the <paramref name='exception' />; blank if not available.</param>
            /// <param name='messageLang'>Message language from the <paramref name='exception' />; current default if not available.</param>
            /// <returns>The cast DataServiceException; possibly null.</returns>
            private static DomainDataServiceException ExtractErrorValues(Exception exception, out string errorCode, out string message, out string messageLang)
            {
                DomainDataServiceException dataException = exception as DomainDataServiceException;

                if (dataException != null)
                {
                    errorCode   = dataException.ErrorCode ?? string.Empty;
                    message     = dataException.Message ?? string.Empty;
                    messageLang = dataException.MessageLanguage ?? CultureInfo.CurrentCulture.Name;
                    return(dataException);
                }
                else
                {
                    errorCode   = string.Empty;
                    message     = Resource.DomainDataService_General_Error;
                    messageLang = CultureInfo.CurrentCulture.Name;
                    return(null);
                }
            }
Exemple #7
0
        /// <summary>
        /// Enables the creation of a custom FaultException that is returned from an exception in the course of a service method.
        /// </summary>
        /// <param name="error">The Exception object thrown in the course of the service operation.</param>
        /// <param name="version">The SOAP version of the message.</param>
        /// <param name="fault">The Message object that is returned to the client, or service, in the duplex case.</param>
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            Debug.Assert(error != null, "error != null");
            Debug.Assert(version != null, "version != null");

            HttpStatusCode  statusCode;
            Action <Stream> exceptionWriter = DomainDataServiceErrorHandler.HandleException(error, out statusCode);

            Message message = null;

            try
            {
                message = Message.CreateMessage(MessageVersion.None, string.Empty, new DelegateBodyWriter(exceptionWriter));
                message.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));

                HttpResponseMessageProperty response = new HttpResponseMessageProperty();
                response.Headers[HttpResponseHeader.ContentType]      = ServiceUtils.MimeApplicationXml;
                response.Headers[ServiceUtils.HttpDataServiceVersion] = ServiceUtils.DataServiceVersion1Dot0 + ";";
                response.StatusCode = statusCode;

                if (statusCode == HttpStatusCode.MethodNotAllowed)
                {
                    DomainDataServiceException e = (error as DomainDataServiceException);
                    if (e != null)
                    {
                        response.Headers[HttpResponseHeader.Allow] = e.ResponseAllowHeader;
                    }
                }

                message.Properties.Add(HttpResponseMessageProperty.Name, response);

                fault   = message;
                message = null;
            }
            finally
            {
                if (message != null)
                {
                    ((IDisposable)message).Dispose();
                }
            }
        }
            /// <summary>
            /// Derived classes override this method to provide custom invocation behavior.
            /// </summary>
            /// <param name="instance">Instance to invoke the invoker against.</param>
            /// <param name="inputs">Input parameters post conversion.</param>
            /// <param name="outputs">Optional out parameters.</param>
            /// <returns>Result of invocation.</returns>
            protected override object InvokeCore(object instance, object[] inputs, out object[] outputs)
            {
                outputs = ServiceUtils.EmptyObjectArray;

                // DEVNOTE(wbasheer): Need to perform query composition here for query options, potentially
                // need to inject the query options in the message properties somewhere.
                QueryDescription queryDesc = new QueryDescription(this.operation, inputs);

                IEnumerable <ValidationResult> validationErrors;
                int totalCount;
                IEnumerable <TEntity> result;

                try
                {
                    result = (IEnumerable <TEntity>)((DomainService)instance).Query(queryDesc, out validationErrors, out totalCount);
                }
                catch (UnauthorizedAccessException ex)
                {
                    throw new DomainDataServiceException((int)System.Net.HttpStatusCode.Unauthorized, ex.Message, ex);
                }
                catch (Exception ex)
                {
                    if (ex.IsFatal())
                    {
                        throw;
                    }
                    else
                    {
                        throw new DomainDataServiceException(Resource.DomainDataService_General_Error, ex);
                    }
                }
                DomainDataServiceException.HandleValidationErrors(validationErrors);

                // DEVNOTE(wbasheer): Potentially return something that contains both the sequence and
                // the count value obtained from the query operation.
                return(result);
            }
            /// <summary>
            /// Derived classes override this method to provide custom invocation behavior.
            /// </summary>
            /// <param name="instance">Instance to invoke the invoker against.</param>
            /// <param name="inputs">Input parameters post conversion.</param>
            /// <returns>Result of invocation.</returns>
            protected override async ValueTask <object> InvokeCoreAsync(object instance, object[] inputs)
            {
                // DEVNOTE(wbasheer): Need to perform query composition here for query options, potentially
                // need to inject the query options in the message properties somewhere.
                QueryDescription queryDesc = new QueryDescription(this.operation, inputs);

                IEnumerable <ValidationResult> validationErrors;
                IEnumerable <TEntity>          result;

                try
                {
                    var queryResult = await((DomainService)instance).QueryAsync <TEntity>(queryDesc, CancellationToken.None).ConfigureAwait(false);
                    validationErrors = queryResult.ValidationErrors;
                    result           = (IEnumerable <TEntity>)queryResult.Result;
                }
                catch (UnauthorizedAccessException ex)
                {
                    throw new DomainDataServiceException((int)System.Net.HttpStatusCode.Unauthorized, ex.Message, ex);
                }
                catch (Exception ex)
                {
                    if (ex.IsFatal())
                    {
                        throw;
                    }
                    else
                    {
                        throw new DomainDataServiceException(Resource.DomainDataService_General_Error, ex);
                    }
                }
                DomainDataServiceException.HandleValidationErrors(validationErrors);

                // DEVNOTE(wbasheer): Potentially return something that contains both the sequence and
                // the count value obtained from the query operation.
                return(result);
            }
Exemple #10
0
        /// <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);
        }
        /// <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)
            {
                if (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;
        }
 /// <summary>
 /// Checks if the HTTP request is a GET request and throws otherwise.
 /// </summary>
 /// <param name="httpMethod">Request HTTP method.</param>
 private static void DisallowNonGetRequests(string httpMethod)
 {
     if (httpMethod != ServiceUtils.HttpGetMethodName)
     {
         DomainDataServiceException e = new DomainDataServiceException((int)HttpStatusCode.MethodNotAllowed, Resource.DomainDataService_ResourceSets_Metadata_OnlyAllowedGet);
         e.ResponseAllowHeader = ServiceUtils.HttpGetMethodName;
         throw e;
     }
 }