Table.PutItemAsync of AWSSDK.DynamoDBv2 always returns null - asp.net-core

In .net core 2.1 application I am adding a new record into DynamoDB table using Table.PutItemAsync of AWSSDK.DynamoDBv2 (v3.3.101.18) library:
var doc = await _table.PutItemAsync(document);
I can see that the record is successfully added in AWS Console, but it always returns null whereas the expected return value should be a Document:
public Task<Document> PutItemAsync(Document doc, CancellationToken cancellationToken = default);
I wonder if I am missing something obvious?

You need to specify the ReturnValues enum type in your PutItemOperationConfig and include this config in your request. The default is to return None. If you specify ReturnValues.AllOldAttributes (the only other option for this request), then you will get back a document with the old item's attributes if you overwrote an item or an empty item if you added a new item.
var putItemOperationConfig = new PutItemOperationConfig()
{
ReturnValues = ReturnValues.AllOldAttributes
};

Related

Is there a Session-unique identifier that can be used as a cache key name?

I'm porting a legacy ASP.NET WebForms app to Razor. It had stored an object in the Session collection. Session storage is now limited to byte[] or string. One technique is to serialize objects and store as a string, but there are caveats. Another article suggested using one of the alternative caching options, so I'm trying to use MemoryCache.
For this to work as a Session replacement, I need a key name that's unique to the user and their session.
I thought I'd use Session.Id for this, like so:
ObjectCache _cache = System.Runtime.Caching.MemoryCache.Default;
string _keyName = HttpContext.Session.Id + "$searchResults";
//(PROBLEM: Session.Id changes per refresh)
//hit a database for set of un-paged results
List<Foo> results = GetSearchResults(query);
if (results.Count > 0)
{
//add to cache
_cache.Set(_keyName, results, DateTimeOffset.Now.AddMinutes(20));
BindResults();
}
//Called from multiple places, wish to use cached copy of results
private void BindResults()
{
CacheItem cacheItem = _cache.GetCacheItem(_keyName);
if (cacheItem != null) //in cache
{
List<Foo> results = (List<Foo>)cacheItem.Value;
DrawResults(results);
}
}
...but when testing, I see any browser refresh, or page link click, generates a new Session.Id. That's problematic.
Is there another built-in property somewhere I can use to identify the user's session and use for this key name purpose? One that will stay static through browser refreshes and clicks within the web app?
Thanks!
The answer Yiyi You linked to explains it -- the Session.Id won't be static until you first put something into the Session collection. Like so:
HttpContext.Session.Set("Foo", new byte[] { 1, 2, 3, 4, 5 });
_keyName = HttpContext.Session.Id + "_searchResults";
ASP.NET Core: Session Id Always Changes

Cosmos DB "Partial Update"/Patch, cant set new property value to null

I'm trying out the Cosmos DB SDK's new Patch/Partial Update-functionality (for .NET)
When adding a new property I use
var patchOperations = new List<PatchOperation>(){
PatchOperation.Add<string>("/FavoriteColor", **null**)
};
await container.PatchItemAsync<T>(
id: myId,
partitionKey: new PartitionKey(myPk),
patchOperations: patchOperations);
The problem is, that it throws at the PatchOperation-Add() if I set second parameter to null (with message "Value cannot be null"). I can set any non-null string and it works well. I just wonder if this isn't supported yet or if I missed something.
Thanks to github user rvdvelden (source), this work around appears to work perfectly:
private JToken NullValue { get { return new JProperty("nullValue", null).Value; } }
Used in this way:
operations.Add(PatchOperation.Set("\customer", value ?? NullValue));
Remove is one alternative if the intent is to remove field/property.
This is not supported with Patch yet,
However, if you want to remove the entire property you need to use Remove Operation

Set value configuration.GetSection("").Value from header request

I need to set in my asp.net core configuration a value from the header in every request.
I'm doing like so:
public async Task Invoke(HttpContext context)
{
var companyId = context.Request.Headers["companyid"].ToString().ToUpper();
configuration.GetSection("CompanyId").Value = companyId;
await next(context);
}
It works fine. But is this the proper way? In case of multiple request at same time is there a risk of messing the values? I've searched around but couldn't find an answer.
I'm using .Net 3.1.
As far as I know, the appsetting.json value is a global setting value, you shouldn't be modifying global state per request, this action is not thread safe. At some point, you will face a rice condition.
If you still want to use this codes, I suggest you could try to add a lock. Notice: This will make your Invoke method very slowly.
Details, you could refer to below codes:
private static Object _factLock = new Object();
lock (_factLock)
{
Configuration.GetSection("CompanyId").Value = "";
}

Appending instead of overwriting table in BiqQuery API

I currently use bigquery.tabledata().insertAll() to put data into BigQuery. However it overwrites all previous content instead of appending it. Is there a way to change default behaviour or should I use another method to do so?
Code below:
GoogleCredential credential = GoogleCredential.fromStream(...);
if (credential.createScopedRequired()) {
credential = credential.createScoped(BigqueryScopes.all());
}
bigquery = new Bigquery.Builder(new NetHttpTransport(), new GsonFactory(), credential).setApplicationName("Bigquery Samples").build();
TableDataInsertAllRequest.Rows r = new TableDataInsertAllRequest.Rows();
r.setInsertId("123");
ObjectMapper m = new ObjectMapper();
Map<String,Object> props = m.convertValue(person, Map.class);
r.setJson(props);
TableDataInsertAllRequest content =
new TableDataInsertAllRequest().setRows(Arrays.asList(r));
content.setSkipInvalidRows(true);
content.setIgnoreUnknownValues(true);
TableDataInsertAllResponse execute = bigquery.tabledata().insertAll("", "", "", content).execute();
Solution is to assign [globally] unique ID as an InserID.
BigQuery uses InsertId property to detect duplicate insertion requests on a best-effort basis.
If you will ignore this - you might end up with having unwanted duplicate rows!
See more in https://cloud.google.com/bigquery/streaming-data-into-bigquery#dataconsistency
Oh, found the answer.
Inserts with same (if set) id by setInsertId(id) are overridden by next with same id.
Solution: do not set InsertId.
EDIT: see #Mikhail Berlayant response and why you should care about InsertId.

vaadin access session attribute that was put in filter

I've got multiple filters.
In one of the filters I've got this code
HttpServletRequest request = (HttpServletRequest) req;
String url = request.getRequestURI();
HttpSession session = request.getSession();
if (request.getParameter("xxxx") != null)
session.setAttribute("xxxx", request.getParameter("xxxx"));
chain.doFilter(req, res);
For UI I use VAADIN 7.
And I decided to display the value of the parameter xxxx in the table.
So I wanted to do it like this
Table table = new Table("Data.");
table.setSizeFull();
table.addContainerProperty("Field", String.class, null);
table.addContainerProperty("Value", String.class, null);
table.setStyleName("wordwrap-table");
table.setStyleName("user-table");
Object attribute = VaadinSession.getCurrent().getAttribute("xxxx");
However attribute value is null.
Why? And how to resolve this problem?
You need another getSession() in there:
Object attribute = VaadinSession.getCurrent().getSession().getAttribute("xxxx");
The result of VaadinSession.getCurrent() is the current Vaadin Session. The next getSession() gets you the HTTP session, which is where your attributes live.