Example #1
0
        /// <summary>
        /// Gets the <see cref="IETagHandler"/> from the configuration.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <returns>The <see cref="IETagHandler"/> for the configuration.</returns>
        public static IETagHandler GetETagHandler(this HttpConfiguration configuration)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

            object handler;

            if (!configuration.Properties.TryGetValue(ETagHandlerKey, out handler))
            {
                IETagHandler defaultETagHandler = new DefaultODataETagHandler();
                configuration.SetETagHandler(defaultETagHandler);
                return(defaultETagHandler);
            }

            if (handler == null)
            {
                throw Error.InvalidOperation(SRResources.NullETagHandler);
            }

            IETagHandler etagHandler = handler as IETagHandler;

            if (etagHandler == null)
            {
                throw Error.InvalidOperation(SRResources.InvalidETagHandler, handler.GetType());
            }

            return(etagHandler);
        }
Example #2
0
        private static EntityTagHeaderValue CreateETag(
            EntityInstanceContext entityInstanceContext,
            IETagHandler handler)
        {
            IEdmModel     model     = entityInstanceContext.EdmModel;
            IEdmEntitySet entitySet = entityInstanceContext.NavigationSource as IEdmEntitySet;

            IEnumerable <IEdmStructuralProperty> concurrencyProperties;

            if (model != null && entitySet != null)
            {
                concurrencyProperties = model.GetConcurrencyProperties(entitySet).OrderBy(c => c.Name);
            }
            else
            {
                concurrencyProperties = Enumerable.Empty <IEdmStructuralProperty>();
            }

            IDictionary <string, object> properties = new Dictionary <string, object>();

            foreach (IEdmStructuralProperty etagProperty in concurrencyProperties)
            {
                properties.Add(etagProperty.Name, entityInstanceContext.GetPropertyValue(etagProperty.Name));
            }
            EntityTagHeaderValue etagHeaderValue = handler.CreateETag(properties);

            return(etagHeaderValue);
        }
Example #3
0
        private static EntityTagHeaderValue CreateETag(
            ResourceContext resourceContext,
            IETagHandler handler)
        {
            IEdmModel model = resourceContext.EdmModel;

            IEnumerable <IEdmStructuralProperty> concurrencyProperties;

            if (model != null && resourceContext.NavigationSource != null)
            {
                concurrencyProperties = model.GetConcurrencyProperties(resourceContext.NavigationSource).OrderBy(c => c.Name);
            }
            else
            {
                concurrencyProperties = Enumerable.Empty <IEdmStructuralProperty>();
            }

            IDictionary <string, object> properties = new Dictionary <string, object>();

            foreach (IEdmStructuralProperty etagProperty in concurrencyProperties)
            {
                properties.Add(etagProperty.Name, resourceContext.GetPropertyValue(etagProperty.Name));
            }
            return(handler.CreateETag(properties));
        }
Example #4
0
        /// <inheritdoc/>
        protected async override Task <HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            HttpConfiguration configuration = request.GetConfiguration();

            if (configuration == null)
            {
                throw Error.InvalidOperation(SRResources.RequestMustContainConfiguration);
            }

            HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

            // Do not interfere with null responses, we want to buble it up to the top.
            // Do not handle 204 responses as the spec says a 204 response must not include an ETag header
            // unless the request's representation data was saved without any transformation applied to the body
            // (i.e., the resource's new representation data is identical to the representation data received in the
            // PUT request) and the ETag value reflects the new representation.
            // Even in that case returning an ETag is optional and it requires access to the original object which is
            // not possible with the current architecture, so if the user is interested he can set the ETag in that
            // case by himself on the response.
            if (response == null || !response.IsSuccessStatusCode || response.StatusCode == HttpStatusCode.NoContent)
            {
                return(response);
            }

            ODataPath path  = request.ODataProperties().Path;
            IEdmModel model = request.ODataProperties().Model;

            IEdmEntityType edmType = GetSingleEntityEntityType(path);
            object         value   = GetSingleEntityObject(response);

            IEdmEntityTypeReference typeReference = GetTypeReference(model, edmType, value);

            if (typeReference != null)
            {
                EntityInstanceContext context = CreateInstanceContext(typeReference, value);
                context.EdmModel         = model;
                context.NavigationSource = path.NavigationSource;
                IETagHandler         etagHandler = configuration.GetETagHandler();
                EntityTagHeaderValue etag        = CreateETag(context, etagHandler);

                if (etag != null)
                {
                    response.Headers.ETag = etag;
                }
            }

            return(response);
        }
        public void GetETagHandler_ReturnDefaultODataETagHandler_IfNotSet()
        {
            // Arrange
            HttpConfiguration config = new HttpConfiguration();

            // Act
            IETagHandler etagHandler = config.GetETagHandler();

            // Assert
            Assert.IsType <DefaultODataETagHandler>(etagHandler);
        }
Example #6
0
        /// <summary>
        /// Sets the <see cref="IETagHandler"/> on the configuration.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="handler">The <see cref="IETagHandler"/> for the configuration.</param>
        public static void SetETagHandler(this HttpConfiguration configuration, IETagHandler handler)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }
            if (handler == null)
            {
                throw Error.ArgumentNull("handler");
            }

            configuration.Properties[ETagHandlerKey] = handler;
        }
Example #7
0
        /// <inheritdoc/>
        public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
        {
            if (actionExecutedContext == null)
            {
                throw Error.ArgumentNull(nameof(actionExecutedContext));
            }

            if (actionExecutedContext.HttpContext == null)
            {
                throw Error.ArgumentNull("httpContext");
            }

            HttpRequest request = actionExecutedContext.HttpContext.Request;
            ODataPath   path    = request.ODataFeature().Path;

            if (path == null)
            {
                throw Error.ArgumentNull("path");
            }

            IEdmModel model = request.GetModel();

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            IETagHandler etagHandler = request.GetETagHandler();

            if (etagHandler == null)
            {
                throw Error.ArgumentNull("etagHandler");
            }

            // Need a value to operate on.
            ObjectResult result = actionExecutedContext.Result as ObjectResult;

            if (result == null)
            {
                return;
            }

            HttpResponse         response = actionExecutedContext.HttpContext.Response;
            EntityTagHeaderValue etag     = GetETag(response?.StatusCode, path, model, result.Value, etagHandler);

            if (etag != null)
            {
                response.Headers["ETag"] = etag.ToString();
            }
        }
Example #8
0
        private static EntityTagHeaderValue GetETag(
            int?statusCode,
            ODataPath path,
            IEdmModel model,
            object value,
            IETagHandler etagHandler)
        {
            if (path == null)
            {
                throw Error.ArgumentNull("path");
            }

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            if (etagHandler == null)
            {
                throw Error.ArgumentNull("etagHandler");
            }

            // Do not interfere with null responses, we want to bubble it up to the top.
            // Do not handle 204 responses as the spec says a 204 response must not include an ETag header
            // unless the request's representation data was saved without any transformation applied to the body
            // (i.e., the resource's new representation data is identical to the representation data received in the
            // PUT request) and the ETag value reflects the new representation.
            // Even in that case returning an ETag is optional and it requires access to the original object which is
            // not possible with the current architecture, so if the user is interested he can set the ETag in that
            // case by himself on the response.
            if (statusCode == null || !((int)statusCode.Value >= 200 && (int)statusCode.Value < 300) || statusCode.Value == (int)HttpStatusCode.NoContent)
            {
                return(null);
            }

            IEdmEntityType edmType = GetSingleEntityEntityType(path);

            IEdmEntityTypeReference typeReference = GetTypeReference(model, edmType, value);

            if (typeReference != null)
            {
                ResourceContext context = CreateInstanceContext(typeReference, value);
                context.EdmModel         = model;
                context.NavigationSource = path.NavigationSource;
                return(CreateETag(context, etagHandler));
            }

            return(null);
        }
Example #9
0
        private static EntityTagHeaderValue CreateETag(
            EntityInstanceContext entityInstanceContext,
            IETagHandler handler)
        {
            IEnumerable <IEdmStructuralProperty> concurrencyProperties =
                entityInstanceContext.EntityType.GetConcurrencyProperties().OrderBy(c => c.Name);

            IDictionary <string, object> properties = new Dictionary <string, object>();

            foreach (IEdmStructuralProperty etagProperty in concurrencyProperties)
            {
                properties.Add(etagProperty.Name, entityInstanceContext.GetPropertyValue(etagProperty.Name));
            }
            EntityTagHeaderValue etagHeaderValue = handler.CreateETag(properties);

            return(etagHeaderValue);
        }
Example #10
0
        public async Task GetEntryWithIfNoneMatchShouldReturnNotModifiedETagsTest_ForDouble()
        {
            string eTag;

            var getUri = this.BaseAddress + "/double/ETagsCustomers?$format=json";

            using (var response = await Client.GetAsync(getUri))
            {
                Assert.True(response.IsSuccessStatusCode);

                var json = await response.Content.ReadAsAsync <JObject>();

                var result = json.GetValue("value") as JArray;
                Assert.NotNull(result);

                // check the first
                eTag = result[0]["@odata.etag"].ToString();
                Assert.False(String.IsNullOrEmpty(eTag));
                Assert.Equal("W/\"Mi4w\"", eTag);

                EntityTagHeaderValue parsedValue;
                Assert.True(EntityTagHeaderValue.TryParse(eTag, out parsedValue));
                HttpConfiguration             config  = new HttpConfiguration();
                IETagHandler                  handler = config.GetETagHandler();
                IDictionary <string, object>  tags    = handler.ParseETag(parsedValue);
                KeyValuePair <string, object> pair    = Assert.Single(tags);
                Single value = Assert.IsType <Single>(pair.Value);
                Assert.Equal((Single)2.0, value);
            }

            var getRequestWithEtag = new HttpRequestMessage(HttpMethod.Get, this.BaseAddress + "/double/ETagsCustomers(0)");

            getRequestWithEtag.Headers.IfNoneMatch.ParseAdd(eTag);
            using (var response = await Client.SendAsync(getRequestWithEtag))
            {
                Assert.Equal(HttpStatusCode.NotModified, response.StatusCode);
            }
        }
        private static EntityTagHeaderValue CreateETag(
            EntityInstanceContext entityInstanceContext,
            IETagHandler handler)
        {
            IEdmModel model = entityInstanceContext.EdmModel;
            IEdmEntitySet entitySet = entityInstanceContext.NavigationSource as IEdmEntitySet;

            IEnumerable<IEdmStructuralProperty> concurrencyProperties;
            if (model != null && entitySet != null)
            {
                concurrencyProperties = model.GetConcurrencyProperties(entitySet).OrderBy(c => c.Name);
            }
            else
            {
                concurrencyProperties = Enumerable.Empty<IEdmStructuralProperty>();
            }

            IDictionary<string, object> properties = new Dictionary<string, object>();
            foreach (IEdmStructuralProperty etagProperty in concurrencyProperties)
            {
                properties.Add(etagProperty.Name, entityInstanceContext.GetPropertyValue(etagProperty.Name));
            }
            EntityTagHeaderValue etagHeaderValue = handler.CreateETag(properties);
            return etagHeaderValue;
        }
        public static ETag GetETag(this HttpRequest request, EntityTagHeaderValue entityTagHeaderValue)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            if (entityTagHeaderValue != null)
            {
                if (entityTagHeaderValue.Equals(EntityTagHeaderValue.Any))
                {
                    return(new ETag {
                        IsAny = true
                    });
                }

                // get the etag handler, and parse the etag
                IETagHandler etagHandler = request.GetRequestContainer().GetRequiredService <IETagHandler>();
                IDictionary <string, object> properties = etagHandler.ParseETag(entityTagHeaderValue) ?? new Dictionary <string, object>();
                IList <object> parsedETagValues         = properties.Select(property => property.Value).AsList();

                // get property names from request
                ODataPath            odataPath = request.ODataFeature().Path;
                IEdmModel            model     = request.GetModel();
                IEdmNavigationSource source    = odataPath.NavigationSource;
                if (model != null && source != null)
                {
                    IList <IEdmStructuralProperty> concurrencyProperties = model.GetConcurrencyProperties(source).ToList();
                    IList <string> concurrencyPropertyNames = concurrencyProperties.OrderBy(c => c.Name).Select(c => c.Name).AsList();
                    ETag           etag = new ETag();

                    if (parsedETagValues.Count != concurrencyPropertyNames.Count)
                    {
                        etag.IsWellFormed = false;
                    }

                    IEnumerable <KeyValuePair <string, object> > nameValues = concurrencyPropertyNames.Zip(
                        parsedETagValues,
                        (name, value) => new KeyValuePair <string, object>(name, value));
                    foreach (var nameValue in nameValues)
                    {
                        IEdmStructuralProperty property = concurrencyProperties.SingleOrDefault(e => e.Name == nameValue.Key);
                        Contract.Assert(property != null);

                        Type clrType = EdmLibHelpers.GetClrType(property.Type, model);
                        Contract.Assert(clrType != null);

                        if (nameValue.Value != null)
                        {
                            Type valueType = nameValue.Value.GetType();
                            etag[nameValue.Key] = valueType != clrType
                                ? Convert.ChangeType(nameValue.Value, clrType, CultureInfo.InvariantCulture)
                                : nameValue.Value;
                        }
                        else
                        {
                            etag[nameValue.Key] = nameValue.Value;
                        }
                    }

                    return(etag);
                }
            }

            return(null);
        }
        /// <summary>
        /// Sets the <see cref="IETagHandler"/> on the configuration.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="handler">The <see cref="IETagHandler"/> for the configuration.</param>
        public static void SetETagHandler(this HttpConfiguration configuration, IETagHandler handler)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }
            if (handler == null)
            {
                throw Error.ArgumentNull("handler");
            }

            configuration.Properties[ETagHandlerKey] = handler;
        }
        private static EntityTagHeaderValue CreateETag(
            EntityInstanceContext entityInstanceContext,
            IETagHandler handler)
        {
            IEnumerable<IEdmStructuralProperty> concurrencyProperties =
                entityInstanceContext.EntityType.GetConcurrencyProperties().OrderBy(c => c.Name);

            IDictionary<string, object> properties = new Dictionary<string, object>();
            foreach (IEdmStructuralProperty etagProperty in concurrencyProperties)
            {
                properties.Add(etagProperty.Name, entityInstanceContext.GetPropertyValue(etagProperty.Name));
            }
            EntityTagHeaderValue etagHeaderValue = handler.CreateETag(properties);
            return etagHeaderValue;
        }