/// <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); }
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); }
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)); }
/// <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); }
/// <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; }
/// <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(); } }
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); }
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); }
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); }
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; }