I am trying to create a azure cosmos database and collection in my c# code.
await client.CreateDatabaseIfNotExistsAsync(new Database() { Id = "data"});
DocumentCollection dCollection = await client.CreateDocumentCollectionIfNotExistsAsync(UriFactory.CreateDatabaseUri("data"), new DocumentCollection { Id = "coll"}, new RequestOptions { OfferThroughput = 400, , PartitionKey = new PartitionKey("/id") });
// dashboardCollection.PartitionKey.Paths.Add("/id");
When I go to portal.azure.com and check my document DB, the collection is created. When I go to Scale and Settings for the collection, I don't see a partition key.
I created another collection manually and it shows the partition key in the Scale and Settings section.
The delete function is throwing an error because of this partition key error
Inserted a record with id 1 successfully into the document DB. The following delete fails saying that the partitionKey is invalid.
ResourceResponse<Document> response = await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri("data", "coll", "1"), new RequestOptions { PartitionKey = new PartitionKey("1") });
I am from the CosmosDB engineering team.
When creating a DocumentCollection, please ensure that the partition key is provided in the DocumentCollection object, like so:
PartitionKeyDefinition pkDefn = new PartitionKeyDefinition() { Paths = new Collection<string>() { "/id" } };
DocumentCollection dCollection = await client.CreateDocumentCollectionIfNotExistsAsync(UriFactory.CreateDatabaseUri("data"), new DocumentCollection { Id = "coll", PartitionKey = pkDefn }, new RequestOptions { OfferThroughput = 400, PartitionKey = new PartitionKey("/id") });
The PartitionKey on the RequestOptions is not honored during collection CRUD requests, since we expect the PartitionKey to be part of the collection object. The PartitionKey on the RequestOptions is honored during document CRUD requests.
Related
I am using stripe API and .net to create subscriptions.
my issue is that when i create a subscription the meta data is saved on the subscription instead of being saved on the payment.
is there a way to save the meta data on the first subscription payment instead?
that is what i have tried so far :
var subscriptionOptions = new SubscriptionCreateOptions
{
Customer = customerID,
Items = new List<SubscriptionItemOptions>
{
new SubscriptionItemOptions
{
Price = priceID,
Quantity = 1
},
},
PaymentBehavior = "default_incomplete",
Metadata = new Dictionary<string, string>
{
{ "id", "123"},
{ "name", "david" },
},
};
subscriptionOptions.AddExpand("latest_invoice.payment_intent");
var subscriptionService = new SubscriptionService();
try
{
Subscription subscription = await subscriptionService.CreateAsync(subscriptionOptions);
return new SubscriptionCreateResponse
{
SubscriptionId = subscription.Id,
ClientSecret = subscription.LatestInvoice.PaymentIntent.ClientSecret,
};
}
No, the subscription metadata is not propagated to the generated invoices or the payment intents used within those invoices. If you want metadata on either of those, you'll need to set up a process to update that using your own code.
You could, for example, set this up using webhooks. You could listen for invoice.paid webhooks and then retrieve the subscription to get the metadata and update the Payment Intent related to that invoice.
I have a table of random unique number that they served as account Id for a user.
This scenario will use in Register method of Web API to get first unique Number and attached it into a user and after a successful creation, the fetched unique Number will be removed from database:
public async Task<ActionResult> Register([FromBody] RegisterDto model)
{
//get the first unique number from the database
var UniqueNumber = _context.UniqueNumbers.First();
var user = new User
{
UserName = model.Email,
Email = model.Email,
PhoneNumber = model.PhoneNumber,
FirstName = model.FirstName,
LastName = model.LastName,
UserProfile = new UserProfile()
{
AccountNumber = UniqueNumber.Number,
},
};
//creating user
var createResult = await _userManager.CreateAsync(user, model.Password);
if (!createResult.Succeeded) return BadRequest(new { isSucceeded = createResult.Succeeded, errors = createResult.Errors });
//Delete the fetched UniqueId from the database
_context.UniqueNumbers.Remove(UniqueNumber);
_context.SaveChanges();
return Ok(new
{
isSucceeded = true
});
}
My question is how do I prevent collision in multiple calls on API since it may return same unique number for multiple calls?
On EF Core and Microsoft SQL Server you should simply use a SEQUENCE object to generate your keys. See Sequences - EF Core
If really, really want to proceed with your original design you could use FromSql to run a DELETE … OUTPUT, something like:
var UniqueNumber = _context.UniqueNumbers.FromSql("delete top (1) from UniqueNumbers output deleted.*").Single();
I'm trying to connect my Azure Scheduler via my .Net Application however, at the current state I'm getting KeyNotFoundException: The given key was not present in the dictionary.
I have tried to example in https://github.com/Azure-Samples/scheduler-dotnet-getting-started/tree/master/SchedulerArmSDKTemplate
The problem with the above example is, I think it is based on previous version of the packages. So on the latest version, I tried to make it work by myself but I wasn't able to. The amount of documentation around this and AD Connect is really limited, especially when it comes to new Portal and latest versions. My code sample is below, I'm not sure what I'm doing wrong at this point:
var tenantId = "{tenantId}"; // I have put objectId from Azure AD Properties
var clientId = "{clientId}"; // Here, I have created new App Registration in Azure AD and copied the AppId value
var subscriptionId = "{subscriptionId}"; //Subscription Id of the scheduler resource
UserLoginInformation loginInformation = new UserLoginInformation()
{
ClientId = clientId
};
ServiceClientCredentials serviceClientCredentials = new AzureCredentials(loginInformation, tenantId, AzureEnvironment.AzureGlobalCloud);
SchedulerManagementClient schedulerManagementClient =
new SchedulerManagementClient(serviceClientCredentials) { SubscriptionId = subscriptionId };
var schedulers = await schedulerManagementClient.JobCollections.GetWithHttpMessagesAsync("{resourceGroup}", "{jobCollectionName}");
Tennat Id is not the application objectid. We could get it from the Azure portal, more detail please refer to the screenshot.
If user is not required multi-factor authentication. please have a try to use the following code.
var tenantId = "tenantId"; // Not the object id, it is Azure directory Id
var clientId = "client Id"; // Here, I have created new App Registration in Azure AD and copied the AppId value
var subscriptionId = "subscription Id"; //Subscription Id of the scheduler resource
var resourceGroup = "resource group";
var jobCollectionName = "job name";
UserLoginInformation loginInformation = new UserLoginInformation()
{
ClientId = clientId,
UserName = "xxx#example.com",
Password = "xxxxxx"
};
ServiceClientCredentials serviceClientCredentials = new AzureCredentials(loginInformation, tenantId, AzureEnvironment.AzureGlobalCloud);
SchedulerManagementClient schedulerManagementClient =
new SchedulerManagementClient(serviceClientCredentials) { SubscriptionId = subscriptionId };
var schedulers = await schedulerManagementClient.JobCollections.GetWithHttpMessagesAsync($"{resourceGroup}", $"{jobCollectionName}");
I'd like to programmatically read my Google Fit GPS data via the REST API. I'm able to get a list of data sources but I just can't seem to get any session or dataset results back.
For example:
GET https://www.googleapis.com/fitness/v1/users/me/sessions?oauth_token=mytoken
and:
POST https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate?oauth_token=mytoken
{"aggregateBy": [{"dataTypeName": "com.google.location.sample"}]}
What am I missing? Is it even possible for my app to download data that it wasn't responsible for storing?
FWIW, I'm using the following Google.Apis.Fitness.v1 package test code in C#:
var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "myid",
ClientSecret = "mysecret"
},
new[]
{
FitnessService.Scope.FitnessLocationRead,
FitnessService.Scope.FitnessActivityRead,
FitnessService.Scope.FitnessBodyRead
},
"user",
CancellationToken.None,
new FileDataStore("google-fit.json", true));
var service = new FitnessService(
new BaseClientService.Initializer {HttpClientInitializer = credential});
var dataSources = await service.Users.DataSources.List("me").ExecuteAsync();
var sessions = await service.Users.Sessions.List("me").ExecuteAsync();
var dataSets = await service.Users.Dataset.Aggregate(
new AggregateRequest {AggregateBy = new[] {
new AggregateBy {DataTypeName = "com.google.location.sample"}}}, "me")
.ExecuteAsync();
I am trying to add multiple users async with AAD graph Like this:
IUser user1 = ...;
IUser user2 = ...;
IUser user3 = ...;
List<Task> addTasks = new List<Task>();
addTasks.Add(activeDirectoryClient.Users.AddUserAsync(user1));
addTasks.Add(activeDirectoryClient.Users.AddUserAsync(user2));
addTasks.Add(activeDirectoryClient.Users.AddUserAsync(user3));
await Task.WhenAll(addTasks);
I get this error message :
{"odata.error":{"code":"Request_BadRequest","message":{"lang":"en","value":"Another object with the same value for property userPrincipalName already exists."},"values":[{"item":"PropertyName","value":"userPrincipalName"},{"item":"PropertyErrorCode","value":"ObjectConflict"}]}}
If I use this code :
IUser user1 = ...;
IUser user2 = ...;
IUser user3 = ...;
List<Task> addTasks = new List<Task>();
await activeDirectoryClient.Users.AddUserAsync(user1);
await activeDirectoryClient.Users.AddUserAsync(user2);
await activeDirectoryClient.Users.AddUserAsync(user3);
This is working well.
Maybe we can't add multiple users in AAD at the same time ?
EDIT
Here is the users part:
IUser newStudentUser = new User
{
DisplayName = $"Etudiant de l'école {school}",
UserPrincipalName = $"etudiant-{school}#........fr",
AccountEnabled = true,
MailNickname = $"Etudiant {school}",
UsageLocation = "US",
PasswordProfile = new PasswordProfile
{
Password = "......."
}
};
IUser newTeacherUser = new User
{
DisplayName = $"Professeur de l'école {school}",
UserPrincipalName = $"professeur-{school}#........fr",
AccountEnabled = true,
MailNickname = $"Professeur {school}",
UsageLocation = "US",
PasswordProfile = new PasswordProfile
{
Password = "......."
}
};
IUser newDirectorUser = new User
{
DisplayName = $"Directeur de l'école {school}",
UserPrincipalName = $"directeur-{school}#........fr",
AccountEnabled = true,
MailNickname = $"Directeur {school}",
UsageLocation = "US",
PasswordProfile = new PasswordProfile
{
Password = "......."
}
};
In your case, you want to batch the creation of multiple users.
At present, the GraphClient does support batch processing but there are some limitation (Batch processing | Graph API concepts):
A single batch can contain a maximum of five queries and/or change sets combined.
A change set can contain a maximum of one source object modification and up to 20 add-link and delete-link operations combined. All operations in the change set must be on a single source entity.
So in your case you can't batch the creation of more than 5 users.
While adding an entity to Graph API client, you can choose to defer the execution of the query using the deferredSave parameter.
await activeDirectoryClient.Users.AddUserAsync(user, deferredSave: true);
The Graph API client has a DataServiceContextWrapper that tracks changes. It provides a SaveChanges(Async) method.
await activeDirectoryClient.Context.SaveChangesAsync();
Calling this method you can specify the SaveChangesOptions:
Batch: All pending changes are saved in a single batch request.
BatchWithIndependentOperations: the one you want to use because the creation of the user should be in a single query.
ContinueOnError: Pending changes are saved by using multiple requests to the server, and the operation continues after an error occurs.
None: Pending changes are saved by using multiple requests to the server, but the operation stops on the first failure (default).
PatchOnUpdate:
ReplaceOnUpdate: Pending updates are made by replacing all values of the entity in the data source with values from the updated entity.
Now you have enough information to write the code to batch the creation of the users:
// Only 5 users per batch !!!!
var user1 = ...;
var user2 = ...;
var user3 = ...;
await activeDirectoryClient.Users.AddUserAsync(newStudentUser, deferredSave: true);
await activeDirectoryClient.Users.AddUserAsync(newTeacherUser, deferredSave: true);
await activeDirectoryClient.Users.AddUserAsync(newDirectorUser, deferredSave: true);
// In debug mode, you should use the SaveChangesAsync method with the default options
// Becasue the BatchWithIndependentOperations will not throw any exception even if there is a problem while creating the user.
//await activeDirectoryClient.Context.SaveChangesAsync();
await activeDirectoryClient.Context
.SaveChangesAsync(SaveChangesOptions.BatchWithIndependentOperations);