AllowedQueryOptions = (AllowedQueryOptions)(AllowedQueryOptions.Supported - AllowedQueryOptions.Skip - AllowedQueryOptions.Count))] // NOTE: This just tells OData to return well-formed errors when features not supported by DocumentDB are attempted on the OData endpoint public async Task <SingleResult <HouseDto> > Get([FromODataUri] string key, ODataQueryOptions <HouseDto> odataOptions) { // get a standard IQueryable from the standard DocumentDB client await EnsureClientIsConnected(); // apply the clause for getting the document by key // because our collection contains multiple document types, filter on that as well // execute the query safely with continuation and retries - you could also wrap the IQueryable using InterceptQuery and simply call ".ToArray()" var results = await DocumentDbExtensions.ExecuteQueryWithContinuationAndRetryAsync( client.CreateDocumentQuery <HouseDto>(collectionLink) .Where(x => x.DocumentType == DocumentType.House) .Where(x => x.Id == key)); if (results.Count == 0) { throw new HttpResponseException(HttpStatusCode.NotFound); } // return "not modified" if supplied etag matches if (odataOptions.IfNoneMatch != null) { if (results.Single().ETag == (string)odataOptions.IfNoneMatch["ETag"]) { throw new HttpResponseException(HttpStatusCode.NotModified); } } return(SingleResult.Create(results.AsQueryable())); }
public async Task <Tuple <Guid, bool> > IsAuthorized(string userName, string userPassword) { var userTokens = userName.Split("@".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); Tuple <Guid, bool> dataObj = new Tuple <Guid, bool>(Guid.Empty, false); List <dynamic> coll = await _dataAccess.QueryAsync(@"Select * from accounts a where a.userName = @userName AND a.userEmail = @userEmail ", DocumentDbExtensions.ToSqlParams(new { userName = userTokens[0], userEmail = string.Format("{0}@{1}", userTokens[0], userTokens[1]) })); var account = coll.FirstOrDefault(); if (account != null) { var validPass = PasswordHash.ValidatePassword(userPassword, account.userPassword.ToString()); dataObj = new Tuple <Guid, bool>(account.id, validPass); } return(dataObj); }
AllowedQueryOptions = (AllowedQueryOptions)(AllowedQueryOptions.Supported - AllowedQueryOptions.Skip - AllowedQueryOptions.Count))] // NOTE: This just tells OData to return well-formed errors when features not supported by DocumentDB are attempted on the OData endpoint public async Task <IQueryable <HouseDto> > Get() { // get a standard IQueryable from the standard DocumentDB client await EnsureClientIsConnected(); // configure the wrapped queryable to translate exceptions on enumeration (normally you would log this as well) EnumerationExceptionHandler enumerationExceptionHandler = (FeedResponseContext context, Exception exception) => { throw new HttpResponseException(new HttpResponseMessage() { StatusCode = HttpStatusCode.InternalServerError, Content = new StringContent(exception.ToString()), }); }; // this IQueryable will now work with DateTime/Offset types, follow result paging links, retry on error, and swallow any exceptions var safeWrappedQueryable = DocumentDbExtensions.InterceptQuery( client.CreateDocumentQuery <HouseDto>(collectionLink), enumerationExceptionHandler: enumerationExceptionHandler); // because our collection contains multiple document types, filter on that first safeWrappedQueryable = safeWrappedQueryable .Where(x => x.DocumentType == DocumentType.House); // OData will apply the query from the URL to the returned IQueryable return(safeWrappedQueryable); }
AllowedQueryOptions = (AllowedQueryOptions)(AllowedQueryOptions.Supported - AllowedQueryOptions.Skip - AllowedQueryOptions.Count))] // NOTE: This just tells OData to return well-formed errors when features not supported by DocumentDB are attempted on the OData endpoint public async Task <IQueryable <HouseHistoryDto> > Get([FromODataUri] string key) { // get a standard IQueryable from the standard DocumentDB client await EnsureClientIsConnected(); // configure the wrapped queryable to translate exceptions on enumeration (normally you would log this as well) EnumerationExceptionHandler enumerationExceptionHandler = (Exception exception) => { throw new HttpResponseException(new HttpResponseMessage() { StatusCode = HttpStatusCode.InternalServerError, Content = new StringContent(exception.ToString()), }); }; // this IQueryable will now work with DateTime/Offset types, follow result paging links, retry on error, and swallow any exceptions var safeWrappedQueryable = DocumentDbExtensions.InterceptQuery( client.CreateDocumentQuery <HouseHistoryDto>(collectionLink), enumerationExceptionHandler); // apply the clause for getting the document by key // because our collection contains multiple document types, filter on that as well // execute the query safely with continuation and retries - you could also wrap the IQueryable using InterceptQuery and simply call ".ToArray()" safeWrappedQueryable = safeWrappedQueryable .Where(x => x.DocumentType == DocumentType.HouseHistory) .Where(x => x.ModifiedId == key); // todo: bug bug //if (results.Count == 0) // throw new HttpResponseException(HttpStatusCode.NotFound); return(safeWrappedQueryable); }
public void CanRetrieveNullCollectionProperty() { /* todo: The service can return a null collection, but apparently the client needs that feature added as well * I suppose it's not that big a deal though, since you have control over the object at this point * var create = House.CreateHouse(Guid.NewGuid().ToString("D")); * create.TestWindows = null; * client.AddToHouses(create); * client.SaveChanges(); * client.Detach(create);*/ // because of the above bug, we must create the document directly, but this is the more important path anyway var connectionString = ConfigurationManager.AppSettings["connectionString"]; var databaseName = ConfigurationManager.AppSettings["databaseName"]; var collectionName = ConfigurationManager.AppSettings["collectionName"]; var collectionLink = string.Format("dbs/{0}/colls/{1}", databaseName, collectionName); var documentLinkFormat = collectionLink + "/docs/{0}"; var task = DocumentDB.GetDocumentClient(connectionString, databaseName, collectionName); task.Wait(); var docClient = task.Result; // make test document HouseDocument houseDocument = new HouseDocument(); houseDocument.Id = Guid.NewGuid().ToString("D"); houseDocument.TestWindows = null; // insert it directly to DocumentDB DocumentDbExtensions.ExecuteResultWithRetry(() => docClient.UpsertDocumentAsync(collectionLink, houseDocument)); // retrieve it directly from DocumentDB var retrievedDocument = DocumentDbExtensions.ExecuteQueryWithContinuationAndRetry( docClient.CreateDocumentQuery <HouseDocument>(collectionLink) .Where(x => x.Id == houseDocument.Id)) .Single(); // is the test set up properly? Assert.IsNull(retrievedDocument.TestWindows); // finally, test retrieval through OData var house = odataClient.Houses.ByKey(houseDocument.Id).GetValue(); Assert.IsNotNull(house); // note: house.TestWindows will actually be deserialized as an empty collection here, but the test is // that the OData service didn't throw an error when encountering that in the source document }
public async Task <IHttpActionResult> Put([FromODataUri] string key, HouseDto houseDto, ODataQueryOptions <HouseDto> odataOptions) { // get a standard DocumentDB client await EnsureClientIsConnected(); // convert the DTO into the Document type var houseDoc = JsonConvert.DeserializeObject <HouseDocument>(JsonConvert.SerializeObject(houseDto)); // DocumentDB Triggers are "opt-in", so opt-in var docdbOptions = new RequestOptions(); docdbOptions.PreTriggerInclude = new List <string> { "MaintainHistoryAndTimestamps" }; // DocumentDB ETag checks are "opt-in", so opt-in if requested if (odataOptions.IfMatch != null) { docdbOptions.AccessCondition = new AccessCondition() { Type = AccessConditionType.IfMatch, Condition = (string)odataOptions.IfMatch["ETag"], }; } // execute the replace document call safely with retries string documentLink = string.Format(documentLinkFormat, key); ResourceResponse <Document> replaced = null; try { replaced = await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => client.ReplaceDocumentAsync(documentLink, houseDoc, docdbOptions)); } catch (DocumentDbNonRetriableResponse e) { return(StatusCode((e.InnerException as DocumentClientException).StatusCode ?? HttpStatusCode.InternalServerError)); } // get the resulting document (it is returned above, but in non-typed form - probably should really be using AutoMapper or something like that here) var result = await DocumentDbExtensions.ExecuteQueryWithContinuationAndRetryAsync( client.CreateDocumentQuery <HouseDto>(collectionLink) .Where(x => x.DocumentType == DocumentType.House) .Where(x => x.Id == replaced.Resource.Id)); return(Updated(result.Single())); }
public static async Task <DocumentClient> GetDocumentClient(string connectionString, string databaseName, string collectionName) { string uriString = null; string authKey = null; string[] pieces = connectionString.Split(";".ToArray(), StringSplitOptions.RemoveEmptyEntries); foreach (string piece in pieces) { string[] subpieces = piece.Split("=".ToArray()); if (subpieces[0] == "AccountEndpoint") { uriString = subpieces[1]; } if (subpieces[0] == "AccountKey") { authKey = subpieces[1]; } } Uri serviceEndpoint = new Uri(uriString); var client = new DocumentClient(serviceEndpoint, authKey, new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, //ConnectionProtocol = Protocol.Tcp, RetryOptions = new RetryOptions() { MaxRetryAttemptsOnThrottledRequests = 0 } }, ConsistencyLevel.Session); string collectionLink = string.Format("dbs/{0}/colls/{1}", databaseName, collectionName); var database = await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => GetOrCreateDatabase(client, databaseName)); var collection = await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => GetOrCreateCollection(client, database, collectionName)); var response = await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => client.UpsertStoredProcedureAsync(collectionLink, updateAndRecalculateDetailedStatusStoredProcedure)); return(client); }
public async Task <IHttpActionResult> Delete([FromODataUri] string key) { // get a standard DocumentDB client await EnsureClientIsConnected(); // execute the delete document call safely with retries string documentLink = string.Format(documentLinkFormat, key); try { await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => client.DeleteDocumentAsync(documentLink)); } catch (DocumentDbNonRetriableResponse e) { return(StatusCode((e.InnerException as DocumentClientException).StatusCode ?? HttpStatusCode.InternalServerError)); } return(Ok()); }
AllowedQueryOptions = (AllowedQueryOptions)(AllowedQueryOptions.Supported - AllowedQueryOptions.Skip - AllowedQueryOptions.Count))] // NOTE: This just tells OData to return well-formed errors when features not supported by DocumentDB are attempted on the OData endpoint public async Task <IEnumerable <HouseHistoryDto> > Get([FromODataUri] string key) { // get a standard IQueryable from the standard DocumentDB client await EnsureClientIsConnected(); // apply the clause for getting the document by key // because our collection contains multiple document types, filter on that as well // execute the query safely with continuation and retries - you could also wrap the IQueryable using InterceptQuery and simply call ".ToArray()" var results = await DocumentDbExtensions.ExecuteQueryWithContinuationAndRetryAsync( client.CreateDocumentQuery <HouseHistoryDto>(collectionLink) .Where(x => x.DocumentType == DocumentType.HouseHistory) .Where(x => x.ModifiedId == key)); if (results.Count == 0) { throw new HttpResponseException(HttpStatusCode.NotFound); } return(results.AsQueryable()); }
public static async Task <DocumentClient> GetDocumentClient(string connectionString, string databaseName, string collectionName) { string uriString = null; string authKey = null; string[] pieces = connectionString.Split(";".ToArray(), StringSplitOptions.RemoveEmptyEntries); foreach (string piece in pieces) { string[] subpieces = piece.Split("=".ToArray()); if (subpieces[0] == "AccountEndpoint") { uriString = subpieces[1]; } if (subpieces[0] == "AccountKey") { authKey = subpieces[1] + "=="; } } Uri serviceEndpoint = new Uri(uriString); var client = new DocumentClient(serviceEndpoint, authKey, new ConnectionPolicy { ConnectionMode = ConnectionMode.Gateway, ConnectionProtocol = Protocol.Tcp }, ConsistencyLevel.Session); string collectionLink = string.Format("dbs/{0}/colls/{1}", databaseName, collectionName); var database = await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => GetOrCreateDatabase(client, databaseName)); var collection = await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => GetOrCreateCollection(client, database, collectionName)); return(client); }
public async Task <IHttpActionResult> Delete([FromODataUri] string key, ODataQueryOptions <HouseDto> odataOptions) { // get a standard DocumentDB client await EnsureClientIsConnected(); // DocumentDB Triggers are "opt-in", so opt-in var docdbOptions = new RequestOptions(); docdbOptions.PreTriggerInclude = new List <string> { "MaintainHistoryAndTimestamps" }; // DocumentDB ETag checks are "opt-in", so opt-in if requested if (odataOptions.IfMatch != null) { docdbOptions.AccessCondition = new AccessCondition() { Type = AccessConditionType.IfMatch, Condition = (string)odataOptions.IfMatch["ETag"], }; } // execute the delete document call safely with retries string documentLink = string.Format(documentLinkFormat, key); try { await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => client.DeleteDocumentAsync(documentLink, docdbOptions)); } catch (DocumentDbNonRetriableResponse e) { return(StatusCode((e.InnerException as DocumentClientException).StatusCode ?? HttpStatusCode.InternalServerError)); } return(Ok()); }
public async Task <IHttpActionResult> Post(HouseDto houseDto) { // get a standard DocumentDB client await EnsureClientIsConnected(); // convert the DTO into the Document type var houseDoc = JsonConvert.DeserializeObject <HouseDocument>(JsonConvert.SerializeObject(houseDto)); // DocumentDB Triggers are "opt-in", so opt-in var docdbOptions = new RequestOptions(); docdbOptions.PreTriggerInclude = new List <string> { "MaintainHistoryAndTimestamps" }; // execute the create document call safely with retries ResourceResponse <Document> created = null; try { created = await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => client.CreateDocumentAsync(collectionLink, houseDoc, docdbOptions)); } catch (DocumentDbNonRetriableResponse e) { return(StatusCode((e.InnerException as DocumentClientException).StatusCode ?? HttpStatusCode.InternalServerError)); } // get the resulting document (it is returned above, but in non-typed form - probably should really be using AutoMapper or something like that here) var result = await DocumentDbExtensions.ExecuteQueryWithContinuationAndRetryAsync( client.CreateDocumentQuery <HouseDto>(collectionLink) .Where(x => x.DocumentType == DocumentType.House) .Where(x => x.Id == created.Resource.Id)); return(Created(result.Single())); }
public async Task <IHttpActionResult> Patch([FromODataUri] string key, Delta <HouseDto> dtoUpdate, ODataQueryOptions <HouseDto> odataOptions) { // get a standard IQueryable from the standard DocumentDB client await EnsureClientIsConnected(); // apply the clause for getting the document by key // because our collection contains multiple document types, filter on that as well // execute the query safely with continuation and retries var results = await DocumentDbExtensions.ExecuteQueryWithContinuationAndRetryAsync( client.CreateDocumentQuery <HouseDto>(collectionLink) .Where(x => x.DocumentType == DocumentType.House) .Where(x => x.Id == key)); if (results.Count == 0) { return(NotFound()); } // patch the original with the delta var original = results.Single(); dtoUpdate.Patch(original); // convert the updated DTO into the Document type var updatedDoc = JsonConvert.DeserializeObject <HouseDocument>(JsonConvert.SerializeObject(original)); // DocumentDB Triggers are "opt-in", so opt-in var docdbOptions = new RequestOptions(); docdbOptions.PreTriggerInclude = new List <string> { "MaintainHistoryAndTimestamps" }; // DocumentDB ETag checks are "opt-in", so opt-in if requested if (odataOptions.IfMatch != null) { docdbOptions.AccessCondition = new AccessCondition() { Type = AccessConditionType.IfMatch, Condition = (string)odataOptions.IfMatch["ETag"], }; } ResourceResponse <Document> updated = null; try { // execute the replace document call safely with retries string documentLink = string.Format(documentLinkFormat, key); updated = await DocumentDbExtensions.ExecuteResultWithRetryAsync(() => client.ReplaceDocumentAsync(documentLink, updatedDoc, docdbOptions)); } catch (DocumentDbNonRetriableResponse e) { return(StatusCode((e.InnerException as DocumentClientException).StatusCode ?? HttpStatusCode.InternalServerError)); } // get the resulting document (it is returned above, but in non-typed form - probably should really be using AutoMapper or something like that here) var result = await DocumentDbExtensions.ExecuteQueryWithContinuationAndRetryAsync( client.CreateDocumentQuery <HouseDto>(collectionLink) .Where(x => x.DocumentType == DocumentType.House) .Where(x => x.Id == updated.Resource.Id)); return(Updated(result.Single())); }