Query Camel case json documents in Azure CosmosDB - json

I have created collections with camelcase partition keys like \locationId instead of \LocationId. Also when inserting / updating documents in cosmosdb, i have added them as camelcase using below code :
T entity = null;
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var messageBody = JsonConvert.SerializeObject(entity, Formatting.Indented, settings);
using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(messageBody)))
{
var res = Resource.LoadFrom<Document>(memoryStream);
await _client.UpsertDocumentAsync((await _collection).SelfLink, res, option);
}
However, when retriving any document using linq condition, the result is always null. I have decorated all CosmosDB T types with [JsonProperty(PropertyName = "id")]
Am i missing something here?

Related

ASP.NET Core CSV text output formatter using CsvHelper

I'm looking to write custom ASP.NET Core TextOutputFormatter so I can throw any IEnumerable as an action result and it will produce comma separated list as an output. I don't want to save the results to a file or anything like it, just serve it as a response directly. CsvHelper seems to be very intuitive to use but I don't know how to write to response body. Any help will be much appreciated!
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var response = context.HttpContext.Response;
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
NewLine = Environment.NewLine,
Encoding = selectedEncoding,
};
if (context.Object is IEnumerable<object> list)
{
using var writer = new StreamWriter(response.Body);
using var csv = new CsvWriter(writer, config);
await csv.WriteRecordsAsync(list); // does not work
}
}
Edit:
When I replace
using var writer = new StreamWriter(response.Body);
with
StringBuilder sb = new();
using var writer = new StringWriter(sb);
I can see my sb is being built just as expected so it's not a problem with my IEnumerable<object> or with CsvWriter. I just don't know how to write results it produce to HttpContext.Response.Body
I'm not sure if this will be the best answer, but I was able to make this work using StringBuilder and replacing StreamWriter with StringWriter
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var response = context.HttpContext.Response;
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
NewLine = Environment.NewLine,
Encoding = selectedEncoding,
};
if (context.Object is IEnumerable<object> list)
{
StringBuilder sb = new();
using var writer = new StringWriter(sb);
using var csv = new CsvWriter(writer, config);
await csv.WriteRecordsAsync(list);
await response.WriteAsync(sb.ToString(), selectedEncoding);
}
}
WriteAsync requires adding Microsoft.AspNetCore.Http namespace

Why 2 Different JSON Results with String Parameter Search using RestSharp?

If I hard code the band name in my client request with RestSharp I get the results I expect. If I pass in the String I get a different result set. I checked the url it formed and they are the same. Any ideas? I don't use both, I will comment one out and use the other for testing this scenario.
ArtistInfoResponse IMusicRepository.GetArtistResponse(string artistName)
{
var client = new RestClient($"https://api.deezer.com/search?q=artist:{artistName}");
// returns this as url https://localhost:44343/Home/ArtistInformation?artistName=Dave%20Matthews%20Band
var client = new RestClient($"https://api.deezer.com/search?q=artist:\"Dave Matthews Band\"");
// returns this in url https://localhost:44343/Home/ArtistInformation?artistName=Dave%20Matthews%20Band
var request = new RestRequest(Method.GET);
var cancellationTokenSource = new CancellationTokenSource();
IRestResponse response = client.Execute(request);
if (response.IsSuccessful)
{
// Deserialize the string content into JToken object
var content = JsonConvert.DeserializeObject<JToken>(response.Content);
// Deserialize the JToken object into our ArtistInfoResponse Class
return content.ToObject<ArtistInfoResponse>();
}
return null;
}

Submitting File and Json data to webapi from HttpClient

I want to send file and json data from HttpClient to web api server.
I cant seem to access the json in the server via the payload, only as a json var.
public class RegulationFilesController : BaseApiController
{
public void PostFile(RegulationFileDto dto)
{
//the dto is null here
}
}
here is the client:
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["ApiHost"]);
content.Add(new StreamContent(File.OpenRead(#"C:\\Chair.png")), "Chair", "Chair.png");
var parameters = new RegulationFileDto
{
ExternalAccountId = "1234",
};
JavaScriptSerializer serializer = new JavaScriptSerializer();
content.Add(new StringContent(serializer.Serialize(parameters), Encoding.UTF8, "application/json"));
var resTask = client.PostAsync("api/RegulationFiles", content); //?ApiKey=24Option_key
resTask.Wait();
resTask.ContinueWith(async responseTask =>
{
var res = await responseTask.Result.Content.ReadAsStringAsync();
}
);
}
}
this example will work:HttpClient Multipart Form Post in C#
but only via the form-data and not payload.
Can you please suggest how to access the file and the submitted json And the file at the same request?
Thanks
I have tried many different ways to submit both file data and metadata and this is the best approach I have found:
Don't use MultipartFormDataContent, use only StreamContent for the file data. This way you can stream the file upload so you don't take up too much RAM on the server. MultipartFormDataContent requires you to load the entire request into memory and then save the files to a local storage somewhere. By streaming, you also have the benefit of copying the stream into other locations such as an Azure storage container.
This solves the issue of the binary data, and now for the metadata. For this, use a custom header and serialize your JSON into that. Your controller can read the custom header and deserialize it as your metadata dto. There is a size limit to headers, see here (8-16KB), which is a large amount of data. If you need more space, you could do two separate requests, one to POST the minimum need, and then a PATCH to update any properties that needed more than a header could fit.
Sample code:
public class RegulationFilesController : BaseApiController
{
public async Task<IHttpActionResult> Post()
{
var isMultipart = this.Request.Content.IsMimeMultipartContent();
if (isMultipart)
{
return this.BadRequest("Only binary uploads are accepted.");
}
var headerDto = this.GetJsonDataHeader<RegulationFileDto>();
if(headerDto == null)
{
return this.BadRequest("Missing X-JsonData header.");
}
using (var stream = await this.Request.Content.ReadAsStreamAsync())
{
if (stream == null || stream.Length == 0)
{
return this.BadRequest("Invalid binary data.");
}
//save stream to disk or copy to another stream
var model = new RegulationFile(headerDto);
//save your model to the database
var dto = new RegulationFileDto(model);
var uri = new Uri("NEW URI HERE");
return this.Created(uri, dto);
}
}
private T GetJsonDataHeader<T>()
{
IEnumerable<string> headerCollection;
if (!this.Request.Headers.TryGetValues("X-JsonData", out headerCollection))
{
return default(T);
}
var headerItems = headerCollection.ToList();
if (headerItems.Count() != 1)
{
return default(T);
}
var meta = headerItems.FirstOrDefault();
return !string.IsNullOrWhiteSpace(meta) ? JsonConvert.DeserializeObject<T>(meta) : default(T);
}
}

accessing dynamic property when calling Action....MVC

I have an Action method that returns JSON, for brevity, I excluded code. :
public ActionResult SetMasterLocation(string masterValue)
{
json = new JavaScriptSerializer().Serialize(masterLocation);
return Json(json, JsonRequestBehavior.AllowGet);
}
I need to call this method and access the JSON string that gets returned:
var jVendors = SetMasterLocation(masterValue);
When I run it and inspect the output, I see the JSON string in a dynamic property called Data:
But if I try to access data like this, the app will not compile because the compiler says Cannot resolve symbol 'Data':
var jVendors = SetMasterLocation(masterValue);
var data = jVendors.Data;
How do I access the Data property at runtime?
Return JsonResult
return new JsonResult()
{
Data = someData,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
Then, you can access Data property of the result

Salesforce JSON POST works for standard objects by not custom object

I am using the Salesforce REST API. I have created a new custom object within SFDC and want to POST data to it. I can happily POST JSON documents to the standard SFDC objects such as Account or Contact. However, when I try posting to my custom object I receive a timeout from SFDC.
Here is the method I am using to perform all POSTS (whether standard or custom)
public static BsonDocument PostJSONToSFDC(string uri, BsonDocument postDoc, string method, HPSUtilities.Transformation.Transformation transformation)
{
string accessToken = transformation.sfdcAccess.accessToken;
string instanceUri = transformation.sfdcAccess.instanceUri;
string uri2 = instanceUri + uri;
System.Net.WebRequest req = System.Net.WebRequest.Create(uri2);
req.ContentType = "application/json";
req.Method = method;// "POST" or "PATCH"; // a PATCH alternative uses POST with url parm="?_HttpMethod=PATCH"
req.Headers.Add("Authorization: Bearer " + accessToken);
string postDocAsString = postDoc.ToJson();
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(postDocAsString);
req.ContentLength = bytes.Length;
System.IO.Stream os = req.GetRequestStream();
os.Write(bytes, 0, bytes.Length); //Push it out there
os.Close();
System.Net.WebResponse resp = req.GetResponse();
if (resp == null) return null;
System.IO.StreamReader sr =
new System.IO.StreamReader(resp.GetResponseStream());
string rs = sr.ReadToEnd().Trim();
MongoDB.Bson.BsonDocument doc2;
if (rs.Equals("") && method.Equals("PATCH", StringComparison.CurrentCultureIgnoreCase))
{
// For successful PATCHs (updates), SFDC mysteriously returns a completely empty response.
// In this case let's create something more meaningful!
doc2 = new BsonDocument();
doc2.Add("success", "true");
}
else
{
doc2 = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<MongoDB.Bson.BsonDocument>(rs);
}
return doc2;
}
Given that this code works when POSTing or PATCHing to SFDC I believe that I must be hitting some sort of SFDC restriction for custom objects. Is it necessary to mark SFDC custom objects as API-enabled? Is anyone aware of any other issues that might be causing my timeout?