How should I get one item from Cosmos using the v3 API? - azure-cosmosdb

I want to retrieve one item from Cosmos DB and there must be a better way than what I am doing here.
I've tried other commands, but this seems to actually work.
public async Task<ToDoItem> GetAsync(string id)
{
FeedIterator<ToDoItem> results = container.GetItemQueryIterator<ToDoItem>("select top 1 * from Items i where i.id = '" + id + "'");
FeedResponse<ToDoItem> item = await results.ReadNextAsync();
return item.Resource.FirstOrDefault();
}
I expect to be able to do this with one line that executes on the
server and doesn't force me to look at a set of items.

Here is an example from the official document to query,
using (ResponseMessage responseMessage = await container.ReadItemStreamAsync(
partitionKey: new PartitionKey("Account1"),
id: "SalesOrder1"))

The SDK is still in development - this may help:
using (ResponseMessage response = await _container.ReadItemStreamAsync(id: pageId, partitionKey: partitionKey))
{
if (!response.IsSuccessStatusCode)
{
//Handle and log exception
}
await using (Stream stream = response.Content)
{
using (var streamReader = new StreamReader(stream))
{
string content = streamReader.ReadToEnd();
}
}
}

Related

How to read data from CosmosDb when i only have the partitionkey but not the id of the document

When trying to read from CosmosDb i can select a document via:
Id Query
Id + PartitionKey Query
but how do i select data from CosmosDb when i only have the PartitionKey?
using Microsoft.Azure.Cosmos;
public class CosmosDbService : ICosmosDbService
{
private Container _container;
public CosmosDbService(
CosmosClient cosmosDbClient,
string databaseName,
string containerName)
{
_container = cosmosDbClient.GetContainer(databaseName, containerName);
}
public async Task<Error> GetItemAsync(string partitionKey)
{
// selection only via partitionKey - does not work
var response = await _container.ReadItemAsync<Error>(partitionKey, new PartitionKey(partitionKey));
return response.Resource;
// below one works as i am passing the Id (internally generated by CosmosDB)
var id = "2e4e5727-86ff-4c67-84a6-184b4716d744";
var response = await _container.ReadItemAsync<Error>(id, new PartitionKey(partitionKey));
return response.Resource;
}
}
Question:
Are there any other methods in CosmosDB client which can return the document using the PartitionKey ONLY without the need of Id which I don't know ?
When selecting documents you could try to use QueryDefinition + QueryAsync:
var query = new QueryDefinition("select top 1 * from c");
var partitionKey = "PARTITIONKEY";
var resultSet = container.GetItemQueryIterator<ModelObject>(query, null, new QueryRequestOptions { PartitionKey = new PartitionKey(partitionKey) });
var result = new List<ModelObject>();
while (resultSet.HasMoreResults)
{
var item = await resultSet.ReadNextAsync(ct /* CancellationToken */).ConfigureAwait(false);
var itemList = item.ToList();
result.AddRange(itemList);
}
Instead of a top 1 select you could also do a select * (for example)

Error with EF when trying to save changes

I have an angular 8 app with .net core web api 2.1 and MS SQL SERVER.
I have login and logout implementation for users.
After the user logins, he can add or delete programming langugages.
When I perform a delete operation, I get the error
database operation expected to affect 1 row(s) but actually effected
5 rows
But the code works properly for finding that particular user and the ID of the programming language that he wants to delete.
Here is the image from the table: https://imgur.com/a/taZtJ7d
As you can see there are no duplicates.
I think it is something about Concurrency Conflicts. That's why I added a try-catch block with DbUpdateConcurrencyException.
It works sometimes and sometimes not.
Here, you can find the definiton for the table https://imgur.com/a/YMCYkNy
When I try the following method to delete Users from MS SQL, it works as it should:
public async Task<IActionResult> DeleteProgrammingLanguage(string userId, int plId)
{
UserPL ps = new UserPL();
try
{
ps = await _context.PlUsers.Where(x => x.UserId == userId && x.ProgrammingLanguageId == plId).SingleAsync();
_context.PlUsers.Remove(ps);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
throw ex;
}
return Ok(ps);
}
I solved my problem with this solution.
public IActionResult DeleteProgrammingLanguage(string userId, int plId)
{
using (_context)
{
// Fetch a person from database and change phone number
var ps = _context.PlUsers.FirstOrDefault(x => x.UserId == userId && x.ProgrammingLanguageId == plId);
// Change the person's name in the database to simulate a concurrency conflict
_context.PlUsers.Remove(ps);
var saved = false;
while (!saved)
{
try
{
// Attempt to save changes to the database
_context.SaveChanges();
saved = true;
}
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
if (entry.Entity is UserPL)
{
var proposedValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
foreach (var property in proposedValues.Properties)
{
var proposedValue = proposedValues[property];
var databaseValue = databaseValues[property];
// TODO: decide which value should be written to database
// proposedValues[property] = <value to be saved>;
}
// Refresh original values to bypass next concurrency check
entry.OriginalValues.SetValues(databaseValues);
}
else
{
throw new NotSupportedException(
"Don't know how to handle concurrency conflicts for "
+ entry.Metadata.Name);
}
}
}
}
}
return NoContent();
}

.NET Already Open DataReader

I get this error when running this code. I have looked for solution though I don't like the idea of using MARS as people have suggested as it may contain a lot of data, is there any other option here? Also can I edit a variable in a database without rewriting all of them as I do here, will this save server power or make no difference?
There is already an open DataReader associated with this Command which must be closed first.
public ActionResult CheckLinks(Link model)
{
var userId = User.Identity.GetUserId();
var UserTableID = db.UserTables.Where(c => c.ApplicationUserId == userId).First().ID;
foreach (var item in db.Links.Where(p => p.UserTable.ID == UserTableID))
{
string pageContent = null;
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(item.Obdomain);
HttpWebResponse myres = (HttpWebResponse)myReq.GetResponse();
using (StreamReader sr = new StreamReader(myres.GetResponseStream()))
{
pageContent = sr.ReadToEnd();
}
string live = "";
if (pageContent.Contains(item.Obpage))
{
live = "Yes";
}
else { live = "No"; }
var link = new Link { Obdomain = item.Obdomain, ClientID = item.ClientID, Obpage = item.Obpage, BuildDate = item.BuildDate, Anchor = item.Anchor, IdentifierID = item.IdentifierID, live = (Link.Live)Enum.Parse(typeof(Link.Live), live), UserTableID = item.UserTableID };
db.Entry(link).State = EntityState.Modified;
db.SaveChanges();
}
return RedirectToAction("Index");
}
Entity Framework allows only one active command per context at a time. You should add .ToList() at the end of the following statement:
db.Links.Where(p => p.UserTable.ID == UserTableID).ToList();
So your code could look like this:
var items = db.Links.Where(p => p.UserTable.ID == UserTableID).ToList();
foreach (var item in items)

Result of the "R Script" without ColumnNames

I'm going crazy!
I'm using Azure Machine Learning and R Script. I deploy it as Web Service. I use sample code based on HttpClient.
using (var client = new HttpClient())
{
var scoreRequest = new
{
Inputs = new Dictionary<string, StringTable>() {
{
"input1",
new StringTable()
{
ColumnNames = new string[] {
"experts_estimates",
"experts_share_of_unique_information",
"avg_correlation",
"point_a",
"point_b",
"is_export_mode"
},
Values = new string[,] {
{
expertsEstimatesStr,
expertsShareOfUniqueInformationStr,
avgCorrelationStr,
pointAStr,
pointBStr,
isExportModeStr
},
}
}
},
},
GlobalParameters = new Dictionary<string, string>()
{
}
};
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
client.BaseAddress = new Uri(apiUrl);
// WARNING: The 'await' statement below can result in a deadlock
// if you are calling this code from the UI thread of an ASP.Net application.
// One way to address this would be to call ConfigureAwait(false)
// so that the execution does not attempt to resume on the original context.
// For instance, replace code such as:
// result = await DoSomeTask()
// with the following:
// result = await DoSomeTask().ConfigureAwait(false)
HttpResponseMessage response = await client.PostAsJsonAsync("", scoreRequest);
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
return result;
}
else
{
// Print the headers - they include the requert ID and the timestamp,
// which are useful for debugging the failure
var headers = response.Headers.ToString();
string responseContent = await response.Content.ReadAsStringAsync();
throw new Exception(responseContent, new Exception(headers));
}
}
and when I run code from Visual Studio I get:
but when I run code from Azure App Service I get:
Any ideas?
One solution is adding "edit metadata" module inside the model and rename the output columns. It'll be easy than using the code to name the columns.

Generating PDFs using Phantom JS on .NET applications

I have been looking into phantomJS and looks like it could be a great tool to use generating PDFs. I wonder if anyone have successfully used it for their .NET applications.
My specific question is: how would you use modules like rasterize.js on the server, receive requests and send back generated pdfs as a response.
My general question is: is there any best practice for using phantomJS with .NET Applications. What would be the best way to achieve it?
I am fairly new in .NET World and I would appreciate the more detailed answers. Thanks everyone. :)
I don't know about best practices, but, I'm using phantomJS with no problems with the following code.
public ActionResult DownloadStatement(int id)
{
string serverPath = HttpContext.Server.MapPath("~/Phantomjs/");
string filename = DateTime.Now.ToString("ddMMyyyy_hhmmss") + ".pdf";
new Thread(new ParameterizedThreadStart(x =>
{
ExecuteCommand("cd " + serverPath + #" & phantomjs rasterize.js http://localhost:8080/filetopdf/" + id.ToString() + " " + filename + #" ""A4""");
})).Start();
var filePath = Path.Combine(HttpContext.Server.MapPath("~/Phantomjs/"), filename);
var stream = new MemoryStream();
byte[] bytes = DoWhile(filePath);
return File(bytes, "application/pdf", filename);
}
private void ExecuteCommand(string Command)
{
try
{
ProcessStartInfo ProcessInfo;
Process Process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/K " + Command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
}
catch { }
}
public ViewResult FileToPDF(int id)
{
var viewModel = file.Get(id);
return View(viewModel);
}
private byte[] DoWhile(string filePath)
{
byte[] bytes = new byte[0];
bool fail = true;
while (fail)
{
try
{
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
}
fail = false;
}
catch
{
Thread.Sleep(1000);
}
}
System.IO.File.Delete(filePath);
return bytes;
}
Here is the action flow:
The user clicks on a link to DownloadStatement Action. Inside there, a new Thread is created to call the ExecuteCommand method.
The ExecuteCommand method is responsible to call phantomJS. The string passed as an argument do the following.
Go to the location where the phantomJS app is and, after that, call rasterize.js with an URL, the filename to be created and a print format. (More about rasterize here).
In my case, what I really want to print is the content delivered by the action filetoupload. It's a simple action that returns a simple view. PhantomJS will call the URL passed as parameter and do all the magic.
While phantomJS is still creating the file, (I guess) I can not return the request made by the client. And that is why I used the DoWhile method. It will hold the request until the file is created by phantomJS and loaded by the app to the request.
If you're open to using NReco.PhantomJS, which provides a .NET wrapper for PhantomJS, you can do this very succinctly.
public async Task<ActionResult> DownloadPdf() {
var phantomJS = new PhantomJS();
try {
var temp = Path.Combine(Path.GetTempPath(),
Path.ChangeExtension(Path.GetRandomFileName(), "pdf")); //must end in .pdf
try {
await phantomJS.RunAsync(HttpContext.Server.MapPath("~/Scripts/rasterize.js"),
new[] { "https://www.google.com", temp });
return File(System.IO.File.ReadAllBytes(temp), "application/pdf");
}
finally {
System.IO.File.Delete(temp);
}
}
finally {
phantomJS.Abort();
}
}
Here's some very basic code to generate a PDF using Phantom.JS but you can find more information here: https://buttercms.com/blog/generating-pdfs-with-node
var webPage = require('webpage');
var page = webPage.create();
page.viewportSize = { width: 1920, height: 1080 };
page.open("http://www.google.com", function start(status) {
page.render('google_home.pdf, {format: 'pdf', quality: '100'});
phantom.exit();
});

Resources