DynamoDB for .net: Table name in data model - amazon-web-services

I am using Dynamodb.net in my application.
I have the following code.
var creds = new BasicAWSCredentials(awsId, awsPassword);
var dynamoClient = new AmazonDynamoDBClient(creds,
awsDynamoDbRegion);
var context = new DynamoDBContext(dynamoClient);
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition("Id", ScanOperator.Equal, myId));
var response = await context.ScanAsync<Data>(conditions).GetRemainingAsync();
return response;
My Data Model is as:
[DynamoDBTable("MyTable")]
public class Data
{
[DynamoDBHashKey]
public string Id{ get; set; }
public string Name { get; set; }
}
We are harcoding the table table name in our model "Data" as
[DynamoDBTable("MyTable")]
How can we not hardcode this. Is it possible to apply the table name in my actual code itself instead of giving in the model?
Thanks

Is OverrideTableName in DynamoDBOperationConfig what you are looking for ?
Description:
Property that indicates the table to save an object to overriding the
DynamoDBTable attribute declared for the type.
Example:
var x = await DbContext.LoadAsync<T>("hash", new DynamoDBOperationConfig {
OverrideTableName = "NewTableName",
IndexName = indexName
});
Also what you are looking for might be table prefix for every request of DbContext. It will append this prefix to every table. Useful if you want to isolate application specific tables like AppName-MyTable...
Example:
return new DynamoDBContextConfig
{
TableNamePrefix = "MyAppIdentifier",
ConsistentRead = false,
};

another option is to use different prefixes for the tables via
Amazon.DynamoDBv2.DataModel.DynamoDBContextConfig.TableNamePrefix
Property that directs DynamoDBContext to prefix all table names with a specific string. > If property is null or empty, no prefix is used and default table names are used.
https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TDynamoDBContextConfig.html
e.g.:
var credentials = new StoredProfileAWSCredentials("default");
var client = new AmazonDynamoDBClient(credentials, RegionEndpoint.USEast1);
var config = new DynamoDBContextConfig{
TableNamePrefix = "Test."
};
var ctx = new DynamoDBContext(client, config);
await ctx.SaveAsync(item);

Related

How to get current filters from PowerBi embedded export report

I am using powerbi embedded and I would like an export button similar to the one used on powerbi.com, that asks if you want to apply the current filters or not.
How can I get the current filters in javaScript in such a way that these can be passed to the back end, or to the javascript api to generate a PDF?
I am using the following code to generate the PDF currently, I just don't know how to get the current configuration current filters and current page selected in javaScript
public PowerBiExportViewModel CreateExport(Guid groupId,
Guid reportId,
IEnumerable<PowerBiReportPage> reportPages,
FileFormat fileFormat,
string urlFilter,
TimeSpan timeOut)
{
var errorMessage = string.Empty;
Stream stream = null;
var fileSuffix = string.Empty;
var securityToken = GetAccessToken();
using (var client = new PowerBIClient(new Uri(BaseAddress), new TokenCredentials(securityToken, "Bearer")))
{
var powerBiReportExportConfiguration = new PowerBIReportExportConfiguration
{
Settings = new ExportReportSettings
{
Locale = "en-gb",
IncludeHiddenPages = false
},
Pages = reportPages?.Select(pn => new ExportReportPage { PageName = pn.Name }).ToList(),
ReportLevelFilters = !string.IsNullOrEmpty(urlFilter) ? new List<ExportFilter>() { new ExportFilter(urlFilter) } : null,
};
var exportRequest = new ExportReportRequest
{
Format = fileFormat,
PowerBIReportConfiguration = powerBiReportExportConfiguration
};
var export = client.Reports.ExportToFileInGroupAsync(groupId, reportId, exportRequest).Result;
You can go to PowerBi playground and play around with their sample report. Next to "Embed" button you have "Interact" and option to get filters. In response you get JSON with filters. If you are too lazy to go there, here is the code it created for me
// Get a reference to the embedded report HTML element
var embedContainer = $('#embedContainer')[0];
// Get a reference to the embedded report.
report = powerbi.get(embedContainer);
// Get the filters applied to the report.
try {
const filters = await report.getFilters();
Log.log(filters);
}
catch (errors) {
Log.log(errors);
}

Has anyone got a guide on how to upgrade from PowerBi Embeded v2 to v3? Or a tutorial for v3?

This appears to be a nightmare, sure its easy to upgrade the nuget package to 3.11 I think the latest is, but then nothing at all compiles. So you fix the compile errors, and then it doesn't work. I'm getting an error when it tries to create the PowerBI client.
Getting the token and also creating the client appears to be totally different to v2.
This is my code:
public PowerBiConfig GetPowerBiConfig(string reportId)
{
var result = new PowerBiConfig();
try
{
if (!Guid.TryParse(reportId, out var _))
{
result.ErrorMessage = $"Invalid report guid: {reportId}";
return result;
}
var credential = new UserPasswordCredential(_powerBiProMasterUsername, _powerBiProMasterPassword);
var authenticationContext = new AuthenticationContext(AuthorityUrl);
// Taken from https://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously
var authenticationResult = authenticationContext.AcquireTokenAsync(ResourceUrl, dataArchiverSettings.PowerBiApplicationId, credential).GetAwaiter().GetResult();
if (authenticationResult == null)
{
result.ErrorMessage = "Authentication Failed.";
return result;
}
var tokenCredentials = new TokenCredentials(authenticationResult.AccessToken, "Bearer");
using (var client = new PowerBIClient(new Uri(ApiUrl), tokenCredentials))
{
var report = client.Reports.GetReportInGroup(dataArchiverSettings.PowerBiWorkspaceId, reportId);
if (report == null)
{
result.ErrorMessage = $"No report with the ID {reportId} was found in the workspace.";
return result;
}
var datasets = client.Datasets.GetDatasetById(dataArchiverSettings.PowerBiWorkspaceId, report.DatasetId);
result.IsEffectiveIdentityRequired = datasets.IsEffectiveIdentityRequired;
result.IsEffectiveIdentityRolesRequired = datasets.IsEffectiveIdentityRolesRequired;
GenerateTokenRequest tokenRequest;
if (datasets.IsEffectiveIdentityRequired == true)
{
var username = UserHelper.GetCurrentUser();
var roles = _userService.GetRolesForUser(username);
tokenRequest = new GenerateTokenRequest(accessLevel: "view",
identities: new List<EffectiveIdentity>
{
new EffectiveIdentity(username: username,
roles: new List<string> (roles.Select(x=> x.RoleName)),
datasets: new List<string> {datasets.Id})
});
}
else
{
tokenRequest = new GenerateTokenRequest(accessLevel: "view");
}
var tokenResponse =
client.Reports.GenerateTokenInGroup(dataArchiverSettings.PowerBiWorkspaceId, report.Id,
tokenRequest);
if (tokenResponse == null)
{
result.ErrorMessage = "Failed to generate embed token.";
return result;
}
// Generate Embed Configuration.
result.EmbedToken = tokenResponse;
result.EmbedUrl = report.EmbedUrl;
result.Id = report.Id.ToString();
result.WorkloadResourceName = dataArchiverSettings.PowerBiWorkloadResourceName.Trim();
}
}
catch (HttpOperationException exc)
{
result.ErrorMessage =
$"Status: {exc.Response.StatusCode} ({(int)exc.Response.StatusCode})\r\n" +
$"Response: {exc.Response.Content}\r\n" +
$"RequestId: {exc.Response.Headers["RequestId"].FirstOrDefault()}";
}
catch (Exception exc)
{
result.ErrorMessage = exc.ToString();
}
return result;
}
The closest to "upgrade guide" is the announcement in Power BI blog. It looks like your code is using v2 (e.g. reportId is string, while in v3 it should be Guid).
Here is a brief summary of the changes:
What you should know about v3
Here are the key changes with this version update:
Namespaces renaming:
Microsoft.PowerBI.Api.V2 was changed to Microsoft.PowerBI.Api
Microsoft.PowerBI.Api.Extensions.V2 was changed to Microsoft.PowerBI.Api.Extensions
Microsoft.PowerBI.Api.V1 namespace was removed.
SetAllConnections and SetAllConnectionsInGroup operations are deprecated and marked as obsolete. You should use UpdateDatasources or UpdateParameters APIs instead.
PowerBI artifacts IDs typing was changed* from string to Guid, we recommend to work with Guid when possible.
*Dataset ID is an exception and it’s typing will remain string.
ODataResponse[List[Object]] types was changed to Objects, thus returning an objects collection on responses. For example, a response of ODataResponse[List[Report]] type will now return Reports collection as the return type.
New credentials classes allow easier build of credentialDetails. The new classes include: BasicCredentials, WindowsCredentials, OAuth2Credentials, and more.
Read Configure credentials article to learn more.
New encryption helper classes for easier encryption when creating CredentialDetails.
For example, using AsymmetricKeyEncryptor class with a gateway public key:
GatewayPublicKey publicKey = new GatewayPublicKey
{
Exponent = "...",
Modulus = "..."
};
CredentialsBase credentials = new BasicCredentials("<USER>", "<PASSWORD>");
var credentialsEncryptor = new AsymmetricKeyEncryptor(publicKey);
var credentialDetails = new CredentialDetails(credentials, PrivacyLevel.None, EncryptedConnection.Encrypted, credentialsEncryptor);
Read Configure credentials article to learn more.
Consistency on field names.
For example, reportKey, datasetKey, dashboardKey and tileKey was changed to reportId, datasetId, dashboardId and tileId.
Consistency on operations names.
For example, use GetDataset instead of GetDatasetById. The effected opertation names are imports, datasets, gateways and datasources.
Use enum class instead of string for enumerated types.
For example, In the generateTokenRequest, we recommend to use TokenAccessLevel.View, and not explicitly use “view” as value.
Required fields was marked – some fields was changed to required fields are not nullable anymore.
Examples
Change in Get Reports call if WorkspaceId is a string:
var reports = await client.Reports.GetReportsInGroupAsync(WorkspaceId);
var reports = await client.Reports.GetReportsInGroupAsync(new Guid( WorkspaceId ) );
Change in response handling if a string is expected:
report = reports.Value.FirstOrDefault(r => r.Id.Equals(ReportId, StringComparison.InvariantCultureIgnoreCase));
report = reports.Value.FirstOrDefault(r => r.Id .ToString() .Equals(ReportId, StringComparison.InvariantCultureIgnoreCase));
Change in Generate token:
var tokenResponse = await client.Reports.GenerateTokenInGroupAsync(WorkspaceId, report.Id, generateTokenRequestParameters);
var tokenResponse = await client.Reports.GenerateTokenInGroupAsync( new Guid( WorkspaceId ), report.Id, generateTokenRequestParameters);
Change in Generate token response handling if a string is expected:
m_embedConfig.Id = report.Id;
m_embedConfig.Id = report.Id .ToString() ;
Required fields are not nullable, i.e. Expiration is not nullable and the Value property should be removed:
var minutesToExpiration = EmbedToken.Expiration .Value – DateTime.UtcNow;
var minutesToExpiration = EmbedToken.Expiration – DateTime.UtcNow;
Consistency on operations names, i.e. use GetDataset instead of GetDatasetById:
var datasets = await client.Datasets.GetDataset ById InGroupAsync(WorkspaceId, report.DatasetId);
var datasets = await client.Datasets.GetDatasetInGroupAsync(new Guid(WorkspaceId), report.DatasetId);

How to get list of items from DynamoDB with HashKey while using HashKey+RangeKey combination?

I have my table with UserId(hashkey)+id(Rangekey). they are only together unique as expected.
[DynamoDBTable("Item")]
public class Item
{
[DynamoDBHashKey]
public string UserId { get; set; }
[DynamoDBRangeKey]
public string id { get; set; }
}
now I want to get all the table items for a UserId. I tried as below using xamarin sdk loadasync function with parameter of an existing UserId.
var client = new
Amazon.DynamoDBv2.AmazonDynamoDBClient(AWS.DynamoDBhelper.Credentials,
Amazon.RegionEndpoint.USEast1);
Amazon.DynamoDBv2.DataModel.DynamoDBContext context = new
Amazon.DynamoDBv2.DataModel.DynamoDBContext(client);
Items= await context.LoadAsync<List<Item>>("14354365");
But i get exception as below, it looks like It expects not list because it assumes there should be table with table with list.
How can I achieve this?
There is also QueryAsync function but I am not sure what is the difference between LoadAsync.
ex = {System.InvalidOperationException: Must have one hash key defined
for the table List`1
at Amazon.DynamoDBv2.DataModel.DynamoDBContext.MakeKey (System.Object
hashKey, System.Object rangeKey,
Amazon.DynamoDBv2.DataModel.ItemStorageConfig storageConfig, Amaz...
Your code:
var client = new Amazon.DynamoDBv2.AmazonDynamoDBClient(
AWS.DynamoDBhelper.Credentials,
Amazon.RegionEndpoint.USEast1
);
Amazon.DynamoDBv2.DataModel.DynamoDBContext context = new
Amazon.DynamoDBv2.DataModel.DynamoDBContext(client);
Items= await context.LoadAsync<List<Item>>("14354365");`
Should read:
var client = new Amazon.DynamoDBv2.AmazonDynamoDBClient(
AWS.DynamoDBhelper.Credentials,
Amazon.RegionEndpoint.USEast1
);
Amazon.DynamoDBv2.DataModel.DynamoDBContext context = new
Amazon.DynamoDBv2.DataModel.DynamoDBContext(client);
items= await context.QueryAsync<Item>("14354365").GetRemainingAsync();
You should be able to use LoadAsync to get an object by both its hash + range key.
The .NET library has this:
public Task<T> LoadAsync<T>(
object hashKey,
object rangeKey,
DynamoDBOperationConfig operationConfig,
CancellationToken cancellationToken = default(CancellationToken))
Use Load when the method requires only the primary key of the item you want to retrieve.

How to use boosting in solrnet while using default query?

I am using SolrNet to do query on my default search field and not on any specific field. How can I use Boost on a specific field in that case? Below is the code snippet.
List filter = BuildQuerySingleLine(arrParams);
var customer = solr.Query(parameters.SingleLineSearch, new QueryOptions
{
FilterQueries = filter,
SpellCheck = new SpellCheckingParameters { Collate = true },
OrderBy = new[] { new SortOrder("score", Order.DESC), SortOrder.Parse("score DESC") },
StartOrCursor = new StartOrCursor.Start(parameters.StartIndex),
Rows = parameters.NumberOfRows
});
At last I found the solution to this problem. For this I have used dismax request handler and passed the qf param value through SOLRNET.
With this you can pass the dynamic boost value to the SOLR query, on different fields.
var extraParams = new Dictionary<string, string> { { "qt", "dismax" }, { "qf", "fieldName^1 FieldName^0.6" } };
var customer = solr.Query(parameters.SingleLineSearch, new QueryOptions
{
StartOrCursor = new StartOrCursor.Start(parameters.StartIndex),
Rows = parameters.NumberOfRows,
},
ExtraParams = extraParams
});
According to this document: Querying and The DisMax Query Parser
var extraParams = new List<KeyValuePair<string, string>>();
extraParams.Add(new KeyValuePair<string, string>("bq", "SomeQuery^10"));
extraParams.Add(new KeyValuePair<string, string>("bq", "SomeOtherQuery^10"));
var options new new QueryOptions();
options.ExtraParams = extraParams; //Since my List implements the right interface
solr.Query(myQuery, options)
the bq parameter should be used to boost the Query. #Abhijit Guha has an excellent answer, to use the same idea on the Field: qf (Query fields with optional boosts)
QueryOptions options = new QueryOptions
{
ExtraParams = new KeyValuePair<string, string>[]
{
new KeyValuePair<string,string>("qt", "dismax"),
new KeyValuePair<string,string>("qf", "title^1")
},
Rows = 10,
Start = 0
};
Thank You!

Listing Activities via Web Services

I'm trying to reproduce the Activities page in Microsoft CRM 4.0 via web services. I can retrieve a list of activities, and I believe I need to use ActivityPointers to retrieve the entities but have so far been unsuccessful. Would I need to loop through every single entity returned from the first query to retrieve the ActivityPointer for it? And if so, how would I then get the "Regarding" field or Subject of the activity (eg: email).
The code to retrieve the activities is:
var svc = GetCrmService();
var cols = new ColumnSet();
cols.Attributes = new[] { "activityid", "addressused", "scheduledstart", "scheduledend", "partyid", "activitypartyid", "participationtypemask", "ownerid" };
var query = new QueryExpression();
query.EntityName = EntityName.activityparty.ToString();
query.ColumnSet = cols;
LinkEntity link = new LinkEntity();
//link.LinkCriteria = filter;
link.LinkFromEntityName = EntityName.activitypointer.ToString();
link.LinkFromAttributeName = "activityid";
link.LinkToEntityName = EntityName.activityparty.ToString();
link.LinkToAttributeName = "activityid";
query.LinkEntities = new[] {link};
var activities = svc.RetrieveMultiple(query);
var entities = new List<ICWebServices.activityparty>();
RetrieveMultipleResponse retrieved = (RetrieveMultipleResponse) svc.Execute(request);
//var pointers = new List<activitypointer>();
foreach (activityparty c in activities.BusinessEntities)
{
entities.Add(((activityparty)c));
//the entities don't seem to contain a link to the email which they came from
}
Not sure if I understand your problem, but the field "activityid" in the activitypointer object is the same activityid as the underlying activity (email, task, phonecall, etc). The regardingobjectid is the link to the regarding entity.
Heres what you need to get the equivalent of the Activities page
ColumnSet cols = new ColumnSet()
{
Attributes = new string[] { "subject", "regardingobjectid", "regardingobjectidname", "regardingobjectidtypecode", "activitytypecodename", "createdon", "scheduledstart", "scheduledend" }
};
ConditionExpression condition = new ConditionExpression()
{
AttributeName = "ownerid",
Operator = ConditionOperator.Equal,
Values = new object[] { CurrentUser.systemuserid.Value } //CurrentUser is an systemuser object that represents the current user (WhoAmIRequest)
};
FilterExpression filter = new FilterExpression()
{
Conditions = new ConditionExpression[] { condition },
FilterOperator = LogicalOperator.And
};
QueryExpression query = new QueryExpression()
{
EntityName = EntityName.activitypointer.ToString(),
ColumnSet = cols,
Criteria = filter
};
BusinessEntityCollection activities = svc.RetrieveMultiple(query);
foreach (activitypointer activity in activities)
{
//do something with the activity
//or get the email object
email originalEmail = (email)svc.Retrieve(EntityName.email.ToString(), activity.activityid.Value, new AllColumns());
}