C# Update Azure Cosmos Db json item with Upsert - c#

I'm (new to CosmosDb) and trying to update an item in an Azure Cosmos db, but it's inserting instead.
The object sent is
public class Bank
{
public string id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
I tried passing only the Code and the Name values back (i.e. I did not include the id in the object, which causes an insert (I wanted an update).
I am now including the id which results in an error.
Error returned is:
ResourceType Document is unexpected.
ActivityId: a0d50426-c556-4b17-9646-93052699026e, Windows/10.0.19044 documentdb-netcore-sdk/2.16.2
So, it's values after a front end update (only changing the Name value) are:
Code: "FNB"
Name: "aa First Update Test"
id: "d76ade3d-7d02-46e5-a458-e9f0781bf044"
The DAL code:
var documentUri = UriFactory.CreateDocumentUri(DBName, "Banks", bank.Code);
try
{
Document doc = await client.UpsertDocumentAsync(documentUri, bank);
}
How do I get it to update?
TIA

Your Code is not clear and dont have enough information.try these functions.
protected DataContext(string endpointUrl, string databaseId,
string masterKey)
{
_databaseId = databaseId;
_masterKey = masterKey;
_databaseUri = UriFactory.CreateDatabaseUri(_databaseId);
this._client = new DocumentClient(new Uri(endpointUrl), _masterKey);
this._client.CreateDatabaseIfNotExistsAsync(new Database
{ Id = _databaseId });
this._client.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(_databaseId),
new DocumentCollection { Id = CollectionId });
_databaseCollectionUri = UriFactory.CreateDocumentCollectionUri(
_databaseId, CollectionId);
}
insert and update using
public async Task<Document> UpsertDocumentAsync(T entity)
{
var result = await this._client.UpsertDocumentAsync(
_databaseCollectionUri, entity);
return result;
}
Or Try please using the nuget Microsoft.Azure.Cosmos;
string cosmosDbConnectionString = CosmosDbConnectionKey;
CosmosClient cosmosClient = new CosmosClient(cosmosDbConnectionString);
var db = CosmosDbNameKey;
var container = ContainerKey;
await container.UpsertItemAsync(Model, new PartitionKey(Model.PK));

What I needed was the DocumentCollection (DocumentCollection Link) in the Upsert, but I had the Document Link (documentUri)
So,
public async Task<ExBool> UpdateAsyncPOCO(Bank bank)
{
// NB: UpsertDocumentAsync should take the DocumentCollection link, instead of Document link.
// This is a DocumentLink
var documentUri = UriFactory.CreateDocumentUri(DBName, "Banks", bank.Code);
// This is a DocumentCollection
var CollectionUri = UriFactory.CreateDocumentCollectionUri("demo", "Banks");
try
{
Document doc = await client.UpsertDocumentAsync(CollectionUri, bank);
}
catch (Exception ex)
{
HandleException(ex);
}
return result;
}
Insert and update work perfectly now.
The model and values for the update:
Code: "updated FNB 2"
Name: "updated First National Bank 22"
id: "d76ade3d-7d02-46e5-a458-e9f0781bf044"
Similarly, the Insert
Code: "qwerty"
Name: "qwertyuiop"
id: ""

Related

How to prevent my injected database from being disposed

I have created a class, ObjectBuilder - I am injecting my dbContext into the class constructor and setting it to a read only attribute in the constructor method.
The class has a few different methods that use the dbContext, for example 'CreateorUpdateObject.
In my API controller I am instantiating the ObjectBuilder class. I am then trying to call the 'CreateorUpdateObject' method three times in a row. The first time everything works as intended. The second time, I get an ObjectDisposedException. I understand what this means. However I can't work out how to resolve this issue, seemingly executing a single method will always dispose the context - therefore none of the subsequent methods will work. I am not using any using clauses or disposing of the context myself. Can someone explain to me how to prevent dbContext from dispsoing so I can chain methods.
All the best!
Here is a snippet of the ObjectBuilder Class
class ObjectBuilder
{
readonly GuidObjectBuilder _guidObjectBuilder;
readonly projectviewerContext _db;
bool UpdatedGuidsArray { get; set; }
int UpdatedObjectCount { get; set; }
int CreatedObjectCount { get; set; }
ProjectObjects ActiveObject { get; set; }
public ObjectBuilder(GuidObjectBuilder guidObjectBuilder, projectviewerContext db)
{
this._guidObjectBuilder = guidObjectBuilder;
this._db = db;
this.UpdatedGuidsArray = false;
this.UpdatedObjectCount = 0;
this.CreatedObjectCount = 0;
}
public async Task<dynamic> CreateOrUpdateObject(string projectName, string tag, string pidClass, string guId, string fileName)
{
//SEND ONE ENTRY RETURNS A PROJECT_OBJECT MODEL
if (this._db == null) throw new ArgumentNullException("The object builder class has not been set a database. Set the object with a database");
try
{
//Check for an initial entry
List<ProjectObjects> matchingProjectObjects = (from data in this._db.ProjectObjects.ToList()
where data.ProjectName == projectName &&
data.Tag == tag
select data).ToList();
if (matchingProjectObjects.Any())
{
this.ActiveObject = this.UpdateProjectObject(matchingProjectObjects[0], pidClass, guId, fileName);
this._db.Update(this.ActiveObject);
this.UpdatedObjectCount++;
}
else
{
this.ActiveObject = this.CreateProjectObject(projectName, tag, pidClass, guId, fileName);
this._db.Add(this.ActiveObject);
this.CreatedObjectCount++;
}
await this._db.SaveChangesAsync();
if (this.UpdatedGuidsArray)
{
//Add new guid
await this._guidObjectBuilder.CreateOrUpdateUponModelOpen(this.ActiveObject.Id, guId, fileName);
}
this.UpdatedGuidsArray = false;
return this.ActiveObject;
}
catch (System.Exception error)
{
return error;
}
}
}
Here is a snippet of my test endpoint:
[HttpPost]
[Route("api/objectCreation/test1")]
public async Task<dynamic> TestOne()
{
try
{
projectviewerContext db = new projectviewerContext();
ObjectBuilder objectBuilder = new ObjectBuilder(new GuidObjectBuilder(db), db);
await objectBuilder.CreateOrUpdateObject("Project 1", "VV00011", "Gate Valve", "XXCCBBVVNNDDFFHH", "3D_Model.nwd");
await objectBuilder.CreateOrUpdateObject("Project 1", "VV00012", "Gate Valve", "XXFFGGHHIILLMMNN", "3D_Model.nwd");
await objectBuilder.CreateOrUpdateObject("Project 1", "VV00014", "Gate Valve", "123456789", "PID_drawing.nwd");
return "bang";
}
catch (System.Exception error)
{
return error.Message;
}
}

xamarin how to change the unique id of child in firebase

I'm a beginner in firebase and i'm using nuget FirebaseDatabase.net.
I'm trying to replace the unique id of child with the users uid this is how it looks in the database
i tryed this code but it didnt work
private async void signupbutton_Clicked(object sender, EventArgs e)
{
// the registration part
FirebaseClient firebaseClient = new FirebaseClient("foo");
try
{
var authProvider = new FirebaseAuthProvider(new FirebaseConfig(webApiKey));
var auth = await authProvider.CreateUserWithEmailAndPasswordAsync(UserNewEmail.Text, UserNewPassword.Text);
string getToken = auth.FirebaseToken;
//save user info in database
await firebaseClient.Child("users").Child("some uid").PostAsync(new userinfo
{
firstName = UserFirstName.Text ,
secondName = UsersecondName.Text
}) ;
await App.Current.MainPage.DisplayAlert("Alert", auth.User.LocalId, "Ok");
}
catch (Exception ex)
{
await App.Current.MainPage.DisplayAlert("Alert", "ala " + ex.Message, "OK");
}
}
and this is the opject im trying to send
class userinfo
{
public string firstName { get; set; }
public string secondName { get; set; }
}
pleace let me know if my question needs more Clarificatio thanks in advance.
When you Post to Firebase Realtime Database it always creates a new child node with a generated unique ID. If you want to specify your own ID, specify the entire path you want to write to (including that ID) and then use Put.
// 👇 👇
await firebaseClient.Child("users").Child("some uid").child(getToken).PutAsync(new userinfo
{
firstName = UserFirstName.Text ,
secondName = UsersecondName.Text
}) ;

EF Core with Sqlite Memory Database for testing throws "Collection is read-only" error - why?

I'm writing integration test with ef core using sqlite memory database. Here is the code:
public async Task GetCustomerAndRidesById_When_MultipleCustomersArePresent()
{
var connectionStringBuilder =
new SqliteConnectionStringBuilder { DataSource = ":memory:" };
var connection = new SqliteConnection(connectionStringBuilder.ToString());
var options = new DbContextOptionsBuilder<TravelContext>()
.UseSqlite(connection)
.Options;
var customer = _customerBuilder.WithDefaults();
Customer customerFromRepo;
using (var context = new TravelContext(options))
{
context.Database.OpenConnection();
context.Database.EnsureCreated();
await context.Customers.AddAsync(customer);
await context.SaveChangesAsync();
_output.WriteLine($"Customer ID: {customer.Id}");
//var customerRepository = new CustomerRepository(context);
//customerFromRepo = await customerRepository.GetByIdWithRidesAsync(customer.Id);
}
using (var context = new TravelContext(options))
{
var customerRepository = new CustomerRepository(context);
try
{
customerFromRepo = await customerRepository.GetByIdWithRidesAsync(customer.Id);
}
catch (System.Exception e)
{
throw;
}
}
customerFromRepo.Should().BeEquivalentTo(customer);
customerFromRepo.Rides.Should().HaveCount(customer.Rides.Count);
}
The above code throws following error
Collection is read-only
error. However if I comment out the second using block and uncomment the lines inside first using block, records are retrieved and test passes.
Here is my Customer class:
public class Customer : BaseEntity<Guid>, IAggregateRoot
{
private Customer()
{
// required by EF
}
public Customer(string name, List<Ride> rides)
{
Name = name;
_rides = rides;
}
public string Name { get; set; }
private readonly List<Ride> _rides = new List<Ride>();
public IReadOnlyCollection<Ride> Rides => _rides.AsReadOnly();
}
I'm puzzled. Can anyone explain why?
Thanks
Enabling the below configuration fixes the issue.
var navigation = builder.Metadata.FindNavigation(nameof(Customer.Rides));
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
Credits and Thanks to Ivan Stoev for guidance.

Validating a field in a FormFlow

Code
[Serializable]
public class FAQConversation
{
[Prompt("What product is your concern? {||}")]
public VASetting.SupportedProducts Products { get; set; }
[Prompt("Okay, tell me what is your question. Enter \"back\" to go back to Products Selection.")]
public string Inquiry { get; set; }
public static IForm<FAQConversation> BuildForm()
{
return new FormBuilder<FAQConversation>()
.AddRemainingFields()
.Field(new FieldReflector<FAQConversation>(nameof(Inquiry)).SetValidate(AnswerInquiry))
.Message("Hi this is Test Virtual Assistant")
.Build();
}
private static async Task<ValidateResult> AnswerInquiry(FAQConversation state, object value)
{
var asString = value as String;
var vaConfig = new SmartCareSetting(state.Products);
var result = new ValidateResult() { IsValid = false, Value = value };
if (!string.IsNullOrEmpty(asString))
{
var luisService = new LuisService(new LuisModelAttribute(vaConfig.AppID, vaConfig.SubscriptionKey, domain: vaConfig.HostName));
var luisResult = await luisService.QueryAsync(asString, CancellationToken.None);
result.Feedback = luisResult.TopScoringIntent.Intent.ToString();
}
return result;
}
}
My bot code above shows the conversation below.
I am creating a simple inquiry bot using FormFlow and Bot Framework.
I am validating the Inquiry field through LUIS and returning the intent for processing. I am getting the correct intent, in this case is EXC01. Afterwards, Im wondering why am I still getting prompted the Inquiry prompt.
Questions:
1. How can I finish the FormFlow after validating the Intent of the Inquiry?
2. I want to handle the returned Intent but not show it to the user. I'll be using the Intent string for querying to a Database. Can I do this inside the BuildForm()?
How can I finish the FormFlow after validating the Intent of the Inquiry?
In validation function AnswerInquiry, we can find that IsValid property of ValidateResult would be always false, which cause the issue. You can set IsValid property to true after you assign the returned intent as feedback. The following code snippet works for me, you can refer to it.
private static async Task<ValidateResult> AnswerInquiry(FAQConversation state, object value)
{
var asString = value as String;
var vaConfig = new SmartCareSetting(state.Products);
var result = new ValidateResult() { IsValid = false, Value = value };
if (!string.IsNullOrEmpty(asString))
{
var luisService = new LuisService(new LuisModelAttribute(vaConfig.AppID, vaConfig.SubscriptionKey, domain: vaConfig.HostName));
var luisResult = await luisService.QueryAsync(asString, CancellationToken.None);
result.Feedback = luisResult.TopScoringIntent.Intent.ToString();
//set IsValid to true
result.IsValid = true;
}
return result;
}
I want to handle the returned Intent but not show it to the user. I'll be using the Intent string for querying to a Database. Can I do this inside the BuildForm()?
After you can get the returned intent, if you’d like to query records from your database based on the returned intent, you can do it in your validation function.
Test result:

angularjs data not posting from javascript to C# and also service reference not connecting

I have two problems. 1 is that the c# function does not get the js values. Even though when I step through the javascript, the values are in fact there.
The other problem is that my c# post returns a 404 not found error and I see that the debugger never even goes to my other service on localhost123.
Any advice?
This is my angularjs code below
var AddToGroupIds = [];
var RemoveFromGroupIds = [];
angular.forEach($scope.vm.mailingLists, function(f){
if(f.Selected == true){
AddToGroupIds.push(f.Id);
}
else{
RemoveFromGroupIds.push(f.Id);
}
});
return $http({
method: 'POST',
url: '/Contacts/UpdateSubscription',
data: { AddToGroups: AddToGroupIds, RemoveFromGroups: RemoveFromGroupIds, email: 'test#test.com' }
})
.then(function (data) { return data.data; })
this is my c# code below:
[HttpPost]
public void UpdateSubscription(List<int> AddToGroups, List<int> RemoveFromGroups, string email)
{
HttpWebRequest req = null;
var text = "";
try
{
req = HttpWebRequest.CreateHttp(string.Format("http://localhost:123/api/Api/ImmediateUpload?AddToGroupIds={0}&RemoveFromGroupIds={1}&email={2}", AddToGroups, RemoveFromGroups, email));
req.PreAuthenticate = true;
req.Credentials = new NetworkCredential("123", "123", "123");
var res = req.GetResponse();
using (var sr = new StreamReader(res.GetResponseStream()))
{
text = sr.ReadToEnd();
}
res.Close();
}
catch (Exception e)
{
text = e.ToString();
}
}
You cannot post multiple parameters that way. See this article. You can use JObject as the article mentions, or create a UpdateSubscriptionRequest model containing the parameters:
public class UpdateSubscriptionRequest
{
public List<int> AddToGroups { get; set; }
public List<int> RemoveFromGroups { get; set;}
public string Email { get; set;}
}
And change your controller action to:
public void UpdateSubscription([FromBody]UpdateSubscriptionRequest request)

Categories