.NET AWS SDK CreateInvalidation doesn't work - asp.net

I am using this code to invalidate CloudFront Files using ASP.NET AWS SDK.
public bool InvalidateFiles(string[] arrayofpaths)
{
try
{
var client = AWSClientFactory.CreateAmazonCloudFrontClient(MY_AWS_ACCESS_KEY_ID, MY_AWS_SECRET_KEY);
CreateInvalidationResponse r = client.CreateInvalidation(new CreateInvalidationRequest
{
DistributionId = ConfigurationManager.AppSettings["DistributionId"],
InvalidationBatch = new InvalidationBatch
{
Paths = new Paths
{
Quantity = arrayofpaths.Length,
Items = arrayofpaths.ToList()
},
CallerReference = DateTime.Now.Ticks.ToString()
}
});
}
catch
{
return false;
}
return true;
}
I supplied a path like "/images/1.jpg" but it seems that the invalidation doesn't take place. I've waited half and hour and used hard refresh and cleared the cache and the image is the same. I've changed the image to look different so I can notice the difference if invalidation has occurred.
In the console I see that the invalidation took place, because I have the ID and in the status I see 'completed', but again, nothing changed in the image.
My question is how can I check that the invalidation takes place and make it work, it seems that I am missing something.
Also, is there an option to create is asynchronous, so I won't need to answer from Amazon.
Thanks.

Related

get scaling status using DocumentClient.ReadOfferAsync

I am automatically scaling my cosmosDb using azure.DocumentClient. I want to skip if there is existing scaling in progress and wait for 1 minute and try again.
i have suggestion here "https://learn.microsoft.com/en-us/azure/cosmos-db/set-throughput" that I can use DocumentClient.ReadOfferAsync and see the status of the scaling.
I dont understand what property of the return type I should look for in the return type?
The V3 SDK client provides a way to know the status as part of the ThroughputResponse's property IsReplacePending.
This is obtained when ReadThroughputAsync is called on the Container:
Container container = database.GetContainer(containerId);
var throughputResponse = await simpleContainer.ReadThroughputAsync();
This property is checking for a particular Header in the response. If you are using the V2 SDK you can probably check the headers in the ResourceResponse and look for the same headers to know if the upgrade is still pending.
public bool? IsReplacePending
{
get
{
if (this.Headers.GetHeaderValue<string>(WFConstants.BackendHeaders.OfferReplacePending) != null)
{
return Boolean.Parse(this.Headers.GetHeaderValue<string>(WFConstants.BackendHeaders.MinimumRUsForOffer));
}
return null;
}
}

Changelog method based on project tracker template

Based on the project tracker I have integrated a changelog into my app that relates my UserSettings model to a UserHistory model. The latter contains the fields FieldName, CreatedBy, CreatedDate, OldValue, NewValue.
The relation between both models works fine. Whenever a record is modified, I can see the changes in a changelog table. I now want add an "undo"-button to the table that allows the admin to undo a change he clicks on. I have therefore created a method that is handled by the widget that holds the changelog record:
function undoChangesToUserRecord(changelog) {
if (!isAdmin()) {
return;
}
var fieldName = changelog.datasource.item.FieldName;
var record = changelog.datasource.item.UserSettings;
record[fieldName] = changelog.datasource.item.OldValue;
}
In theory method goes the connection between UserHistory and UserSettings up to the field and rewrites its value. But when I click on the button, I get a "Failed due to circular reference" error. What am I doing wrong?
I was able to repro the issue with this bit of code:
google.script.run.ServerFunction(app.currentPage.descendants.SomeWidget);
It is kinda expected behavior, because all App Maker objects are pretty much complex and Apps Script RPC has some limitations.
App Maker way to implement it would look like this:
// Server side script
function undoChangesToUserRecord(key) {
if (!isAdmin()) {
return;
}
var history = app.models.UserHistory.getRecord(key);
if (history !== null) {
var fieldName = history.FieldName;
var settings = history.UserSettings;
settings[fieldName] = history.OldValue;
}
}
// Client side script
function onUndoClick(button) {
var history = widget.datasource.item;
google.script.run
.undoChangesToUserRecord(history._key);
}

setting IsEditable=false for item disables save/close button but not save button?

I developed a data extender class that acts on GetItem and CheckOutItem commands to do some business-specific validation to determine whether the user should have access to modify the item or not (basically if it's past the initial "author" task in workflow, no one can edit it. by default Tridion allows "reviewers" in workflow to edit the item, which is a no-no in our business).
I am relatively certain this worked at one point, but now does not. I'm exploring what might have changed, but I thought I'd ask here in case anyone has an idea.
If the item can't be modified, I'm setting the IsEditable attribute to false. This does in fact disable the Save and Close button and Save and New button, but for some reason the Save button is enabled. I don't quite understand why there could be a difference. (I'm looking to see if someone extended the save button somehow, but I don't see that being done). Any thoughts on how the Save button would enable when the others aren't?
thanks for any suggestions,
~Warner
public override XmlTextReader ProcessResponse(XmlTextReader reader, PipelineContext context)
{
using (new Tridion.Logging.Tracer())
{
string command = context.Parameters["command"].ToString();
if (command == CHECKOUT_COMMAND || command == GETITEM_COMMAND)
{
XmlDocument xmlDoc = ExtenderUtil.GetExtenderAsXmlDocument(reader);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("tcm", Constants.TcmNamespace);
try
{
//is this a page or component?
XmlNode thisItemNode = null;
thisItemNode = xmlDoc.SelectSingleNode("//tcm:Component", nsmgr) ?? xmlDoc.SelectSingleNode("//tcm:Page", nsmgr);
if (thisItemNode == null) return ExtenderUtil.GetExtenderAsXmlTextReader(xmlDoc);
// need to impersonate system admin in order to get workflow version of item later
Session sessionSystemAdmin = Util.SystemAdminSession;
XmlAttribute idAttribute = thisItemNode.Attributes.GetNamedItem("ID") as XmlAttribute;
//if ID attribute is null, we don't have the actual object being used (just a referenced item. so, we'll ignore it)
if (idAttribute != null)
{
string itemId = idAttribute.Value;
VersionedItem tridionObject = Util.ObtainValidTridionIdentifiableObject(sessionSystemAdmin, itemId) as VersionedItem;
//logic has been moved to separate method, just for maintainablility...
//the logic may change when workflow code is finished.
bool allowSave = IsItemValidForEdit(tridionObject, nsmgr);
if (!allowSave)
{
//not the WIP ("author") task... make item read-only
Logger.WriteVerbose("setting iseditable to false for item: " + itemId);
XmlAttribute isEditableAttribute = thisItemNode.Attributes.GetNamedItem("IsEditable") as XmlAttribute;
isEditableAttribute.Value = "false";
}
}
}
catch (Exception e)
{
Logger.WriteError("problem with get item data extender", ErrorCode.CMS_DATAEXTENDER_GETITEM_FAILURE, e);
}
return ExtenderUtil.GetExtenderAsXmlTextReader(xmlDoc);
}
else
{
return reader;
}
}
}
Most of the Tridion GUI probably bases the options it presents on the so-called Allowed Actions. This is a combination of the Allow and Deny attributes that are present in list-calls (if requested) and item XML.
So at the very least you will have to remove the CheckIn and Edit action from the Allow attribute (and probably add them to the Deny attribute). If you look at the Core Service documentation (or any other Tridion API documentation: these values haven't changed in a long time) you can find an Enum called Actions that hold the possible actions and their corresponding values. The Allow and Deny attributes are simply additions of these numbers.
The CheckIn action I mention is number 2, Edit is 2048.
Update:
I have a little command line program to decode the AllowedActions for me. To celebrate your question, I quickly converted it into a web page that you can find here. The main work horse is below and shows both how you can decode the number and how you can manipulate it. In this case it's all subtraction, but you can just as easily add an allowed action by adding a number to it.
var AllowedActionsEnum = {
AbortAction: 134217728,
ExecuteAction: 67108864,
FinishProcessAction: 33554432,
RestartActivityAction: 16777216,
FinishActivityAction: 8388608,
StartActivityAction: 4194304,
BlueprintManagedAction: 2097152,
WorkflowManagedAction: 1048576,
PermissionManagedAction: 524288,
EnableAction: 131072,
CopyAction: 65536,
CutAction: 32768,
DeleteAction: 16384,
ViewAction: 8192,
EditAction: 2048,
SearchAction: 1024,
RePublishAction: 512,
UnPublishAction: 256,
PublishAction: 128,
UnLocalizeAction: 64,
LocalizeAction: 32,
RollbackAction: 16,
HistoryListAction: 8,
UndoCheckOutAction: 4,
CheckInAction: 2,
CheckOutAction: 1
};
function decode() {
var original = left = parseInt(prompt('Specify Allow/Deny actions'));
var msg = "";
for (var action in AllowedActionsEnum) {
if (left >= AllowedActionsEnum[action]) {
msg += '\n' + action + ' ('+AllowedActionsEnum[action]+')';
left -= AllowedActionsEnum[action];
}
}
alert(original+msg);
}
The solution is to really look over the entire solution and be absolutely positive that nobody snuck something in recently that messes with the Save button and is magically enabling it behind the scenes. I've re-edited the code to show how I initially had it. And it does work. It will disable the save, save/close, save/new buttons and make all fields disabled. I'm sorry that I wasted Frank's time. Hopefully having this here for historical purposes may come in handy for someone else with similar requirements in the future.

Flex mobile : how to know it is the very first time running the application

I googled but didn't find a post for Flex mobile..
All I want for now is display an user agreement popup from TabbedViewNavigatorApplication when the user uses the app for the first time
var agreementView: UserAgreement = new UserAgreement();
PopUpManager.addPopUp(agreementView, this,true);
PopUpManager.centerPopUp(agreementView);
but maybe more later.
Please help..
What i did in my desktop air app;
I guess this will work at a mobile app also.
Make sure you have write access;
open yourproject-app.mxml scroll down to the end of the document. In the section, uncomment the following permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Now you can create files like for example an sqlite database.
At the applicationcomplete call the function checkFirstRun:
// functions to check if the application is run for the first time (also after updates)
// so important structural changes can be made here.
public var file:File;
public var currentVersion:Number;
private function checkFirstRun():void
{
//get the current application version.
currentVersion=getApplicationVersion();
//get versionfile
file = File.applicationStorageDirectory;
file= file.resolvePath("Preferences/version.txt");
if(file.exists)
{
checkVersion();
}
else
{
firstRun(); // create the version file.
}
}
public function getApplicationVersion():Number
{
var appXML:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = appXML.namespace();
var versionnumber:Number =Number(appXML.ns::versionNumber);
return versionnumber;
}
private function checkVersion():void
{
var stream:FileStream= new FileStream();
stream.open(file,FileMode.READ);
var prevVersion:String = stream.readUTFBytes(stream.bytesAvailable);
stream.close();
if(Number(prevVersion)<currentVersion)
{
// if the versionnumber inside the file is older than the current version we go and run important code.
// like alternating the structure of tables inside the sqlite database file.
runImportantCode();
//after running the important code, we set the version to the currentversion.
saveFile(currentVersion);
}
}
private function firstRun():void
{
// at the first time, we set the file version to 0, so the important code will be executed.
var firstVersion:Number=0;
saveFile(firstVersion);
// we also run the checkversion so important code is run right after installing an update
//(and the version file doesn't exist before the update).
checkFirstRun();
}
private function saveFile(currentVersion:Number):void
{
var stream:FileStream=new FileStream();
stream.open(file,FileMode.WRITE);
stream.writeUTFBytes(String(currentVersion));
stream.close();
}
private function runImportantCode():void
{
// here goes important code.
// make sure you check if the important change previously has been made or not, because this code is run after each update.
}
Hope this helps.
Greets, J.
Some you need to store whether the user has agreed to the agreement or not. IF they haven't agreed, then show it.
One way to do this would be to store a value in a shared object. Another way to do this would be to use a remote service and store such data in a central repository. I assume you'll want the second; so you can do some form of tracking against the number of users using your app.

Multiple TrackingParticipants not working, have funny side effects?

We are rying to use WF with multiple tracking participants which essentially listen to different queries - one for activity states, one for custom tracknig records which are a subclass of CustomTrackingRecord.
The problem is that we can use both TrackingParticipants indivisually, but not together - we never get our subclass from CustomTrackingRecord but A CustomTrackingRecord.
If I put bopth queries into one TrackingParticipant and then handle everythign in one, both work perfectly (which indicates teh error is not where we throw them).
The code in question for the combined one is:
public WorkflowServiceTrackingParticipant ()
{
this.TrackingProfile = new TrackingProfile()
{
ActivityDefinitionId = "*",
ImplementationVisibility = ImplementationVisibility.All,
Name = "WorkflowServiceTrackingProfile",
Queries = {
new CustomTrackingQuery() { Name = "*", ActivityName = "*" },
new ActivityStateQuery() {
States = {
ActivityStates.Canceled,
ActivityStates.Closed,
ActivityStates.Executing,
ActivityStates.Faulted
}
},
}
};
}
When using two TrackingParticipants we have two TrackingProfile (with different names) that each have one of the queries.
in the track method, when using both separate, the lines:
protected override void Track(TrackingRecord record, TimeSpan timeout)
{
Console.WriteLine("*** ActivityTracking: " + record.GetType());
if (record is ActivityBasedTrackingRecord)
{
System.Diagnostics.Debugger.Break();
}
never result in the debugger hitting, when using only the one to track our CustomTrackingRecord subclass (ActivityBasedTrackingRecord) then it works.
Anyone else knows about this? For now we have combined both TrackingParticipants into one, but this has the bad side effect that we can not dynamically expand the logging possibilities, which we would love to. Is this a known issue with WWF somewhere?
Version used: 4.0 Sp1 Feature Update 1.
I guess I encounterad the exact same problem.
This problem occurs due to the restrictions of the extension mechanism. There can be only one instance per extension type per workflow instance (according to Microsoft's documentation). Interesting enough though, one can add multiple instances of the same type to one workflow's extensions which - in case of TrackingParticipant derivates - causes weird behavior, because only one of their tracking profiles is used for all participants of the respective type, but all their overrides of the Track method are getting invoked.
There is a (imho) ugly workaround to this: derive a new participant class from TrackingParticipant for each task (task1, task2, logging ...)
Regards,
Jacob
I think that this problem isn't caused by extension mechanism, since DerivedParticipant 1 and DerivedParticipant 2 are not the same type(WF internals just use polymorphism on the base class).
I was running on the same issue, my Derived1 was tracking records that weren't described in its profile.
Derived1.TrackingProfile.Name was "Foo" and Derived2.TrackingProfile.Name was null
I changed the name from null to "Bar" and it worked as expected.
Here is a WF internal reference code, describing how is the Profile selected
// System.Activities.Tracking.RuntimeTrackingProfile.RuntimeTrackingProfileCache
public RuntimeTrackingProfile GetRuntimeTrackingProfile(TrackingProfile profile, Activity rootElement)
{
RuntimeTrackingProfile runtimeTrackingProfile = null;
HybridCollection<RuntimeTrackingProfile> hybridCollection = null;
lock (this.cache)
{
if (!this.cache.TryGetValue(rootElement, out hybridCollection))
{
runtimeTrackingProfile = new RuntimeTrackingProfile(profile, rootElement);
hybridCollection = new HybridCollection<RuntimeTrackingProfile>();
hybridCollection.Add(runtimeTrackingProfile);
this.cache.Add(rootElement, hybridCollection);
}
else
{
ReadOnlyCollection<RuntimeTrackingProfile> readOnlyCollection = hybridCollection.AsReadOnly();
foreach (RuntimeTrackingProfile current in readOnlyCollection)
{
if (string.CompareOrdinal(profile.Name, current.associatedProfile.Name) == 0 && string.CompareOrdinal(profile.ActivityDefinitionId, current.associatedProfile.ActivityDefinitionId) == 0)
{
runtimeTrackingProfile = current;
break;
}
}
if (runtimeTrackingProfile == null)
{
runtimeTrackingProfile = new RuntimeTrackingProfile(profile, rootElement);
hybridCollection.Add(runtimeTrackingProfile);
}
}
}
return runtimeTrackingProfile;
}

Resources