CRM 2016 Version stamp associated with the client has expired - dynamics-crm

With CRM 2016, I use RetrieveEntityChangesRequest to get changed data from CRM:
var request = new RetrieveEntityChangesRequest
{
EntityName = entityLogicalName,
DataVersion = dataToken,
Columns = columnSet,
PageInfo = new PagingInfo { Count = Constants.DefaultCRMChunkSize, PageNumber = 1, ReturnTotalRecordCount = false }
};
It worked for me before, but today after a period of time I have not run, it's suddently throw an exception: System.ServiceModel.FaultException`1[Microsoft.Xrm.Sdk.OrganizationServiceFault]: Version stamp associated with the client has expired. Please perform a full sync. (Fault Detail is equal to Microsoft.Xrm.Sdk.OrganizationServiceFault).
In my case the dataToken is empty, as I want to get all data for the first time.
Any idea about the problem? And please tell me how to solve it. Thank you.

As described in this article https://msdn.microsoft.com/en-us/library/jj863599.aspx, the problem can caused by putting empty of datatoken to the RetrieveEntityChangesRequest, instead, you should pass null value and retreive the latest token from the response.

Related

Is it possible to track changes to Entity Metadata in Dynamics CRM?

Is there any way to track changes to Metadata, like new fields, new entities and so on?
It is difficult to control a very large project in the same environment, so sometimes there are some customization that should not be deployed to productions (Mostly are mistakes or test in a development environment).
And there is a way to know who did that customization?
I am looking to know every possible change, not any in particular.
You have to use the RetrieveMetadataChangesRequest and it is not possible to know who made the change.
This is available only from Microsoft Dynamics CRM 2011 Update Rollup 12
This request is intended to be used to cache information from the metadata and be able to work offline, but we can use it to track changes to metadata in complex projects and complex teams
Examples on internet are not very friendly so this is how you can use the request:
The request can be completed only with filling one parameter
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
ClientVersionStamp = null
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
The first time you executed this request ClientVersionStamp needs to be null, because there was no request made to the metadata before and there is no ClientVersionStamp. This parameter is the last time you query for metadata changes and if it is null it will bring all customization from all time, so probably this request won't complete on time so we need to tune up.
var EntityFilter = new MetadataFilterExpression(LogicalOperator.And);
EntityFilter.Conditions.Add(new MetadataConditionExpression("SchemaName", MetadataConditionOperator.Equals, "ServiceAppointment"));
var entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter
};
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = null
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
This will query all metadata changes for "ServiceAppointment", feel free to use the entity you want, but what we need is the ServerTimeStamp from the response, it will looks like "22319800!09/13/2017 16:17:46", if you try to send this time stamp first, it will throw an exception, so it is necessary to query first to get a server time stamp.
Now you can use the request and the time stamp to retrieve all new changes since "22319800!09/13/2017 16:17:46"
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = #"22319800!09/13/2017 16:17:46"
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
You can filter the query to match your needs, only search for specific entities, labels, relationship, keys and attributes or specific properties.
EntityQueryExpression entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter,
Properties = EntityProperties,
RelationshipQuery = new RelationshipQueryExpression()
{
Properties = RelationshipProperties,
Criteria = RelationshipFilter
},
AttributeQuery = new AttributeQueryExpression()
{
Properties = AttributeProperties,
Criteria = AttributeFilter
}
};
Use this request and implement it the way you need.
A couple more options:
Register a plugin on Publish and Publish All, and track who did
the publish and when. That may help you narrow down who was making
changes, although someone could technically make a change without
publishing it, so not perfect information.
If you're using Dynamics OnPremise, the Metadata tables sometimes store information about who made a change that is not visible through a Metadata retrieve. I've found this to be very spotty though, not all Metadata has a Modified By user stored.

XrmServiceContext object is not getting the latest data from CRM

i have a wcf which connects to crm (on prem) to retrieve an account record. i can see when the entity is retrieved it does not hold the current record i.e. some field will still hold the old column value. i tried with various merge option with no avail. please see the code below
using (XrmServiceContext cContext = new XrmServiceContext(con))
{
Entity ent = cContext.Retrieve(ConstantKVP.AccountSchema.ENTITY_LOGICAL_NAME, AccountId, new ColumnSet(true));
}
any suggestions?
Is it possible the data is being cached?
cContext.TryAccessCache(cache => cache.Mode = OrganizationServiceCacheMode.Disabled);
I took this approach for a CrmOrganizationServiceContext, so perhaps the same theory applies.
After save use clear changes cContext.ClearChanges();
For retrieves use MergeOption.OverwriteChanges
Or
Create a new XrmServiceContext object by passing a newed up organizationservice:
var uncachedOrganizationService = new OrganizationService("Xrm");
var uncachedXrmServiceContext = new XrmServiceContext(uncachedOrganizationService);
var ent = uncachedXrmServiceContext.Retrieve(ConstantKVP.AccountSchema.ENTITY_LOGICAL_NAME,AccountId,new ColumnSet(true));

How can I determine the revision of a calendar item in EWS when using a PullSubscription

I am trying to do some synchronization work with and Exchange Calendar. I want to keep another external calendar in sync with Exchange. Currently when the other app triggers a creation or update of some sort in Exchange, that change is then sent back to the other calendar creating an endless loop.
I had hoped to use the AppointmentSequenceNumber property when binding the Appointment item, but it always has the value of 0 no matter how many times it is updated. I am including AppointmentSequenceNumber in my PropertySet.
If anyone knows of a way to catch these updates and keep them from being sent back, that would be very helpful.
Thank you.
PropertySet pSet = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Subject, ItemSchema.Body, AppointmentSchema.Start, AppointmentSchema.End,AppointmentSchema.ArchiveTag, AppointmentSchema.InstanceKey, AppointmentSchema.AppointmentSequenceNumber);
ChangeCollection<ItemChange> changes = null;
.....
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013)
{
Url = new Uri(exInfo.ServiceURL),
Credentials = new WebCredentials(exInfo.UserName, exInfo.Password)
};
//Pull Subscription Info
Microsoft.Exchange.WebServices.Data.PullSubscription sub = service.SubscribeToPullNotifications(
new FolderId[] { WellKnownFolderName.Calendar }, 30, "",
EventType.Created, EventType.Modified, EventType.Deleted);
syncState = exInfo.SyncState;
//Pull Changes
while (!syncComplete )//&& Count < MaxItems)
{
changes = service.SyncFolderItems(new FolderId(WellKnownFolderName.Calendar),
PropertySet.FirstClassProperties, null, 100, SyncFolderItemsScope.NormalItems, syncState);
foreach (ItemChange change in changes)
{
if (change.ChangeType != ChangeType.Delete) { eventItem = Appointment.Bind(service, change.ItemId, pSet); }
switch (change.ChangeType)
{
case ChangeType.Update:
...
break;
case ChangeType.Create:
...
break;
case ChangeType.Delete:
...
break;
}
Count++;
}
syncState = changes.SyncState;
syncComplete = !changes.MoreChangesAvailable;
}...
The AppointmentSequenceNumber would only be valid for Meetings; on normal Appointments it isn't used.
I had hoped to use the AppointmentSequenceNumber property when binding the Appointment item
That wouldn't work even if it was incrementing. Exchange will always provide you with the current version and the only things valid in a Bind is the EWSId of the appointment (or the Recurrence Sequence).
If anyone knows of a way to catch these updates and keep them from being sent back, that would be very helpful.
Synchronization is complicated but (from a notification perspective) if you modify an item in Exchange it's going to fire a notification and the ChangeKey attribute on the Item will be updated (quote):
"When you work with items in Exchange, another value to keep in mind is the ChangeKey attribute. This value, in addition to the item ID, is used to keep track of the state of an item. Any time an item is changed, a new change key is generated. When you perform an UpdateItem operation, for example, you can use the ChangeKey attribute to let the server know that your update is being applied to the most current version of the item. If another application made a change to the item you’re updating, the change keys won’t match and you will not be able to perform the update."

RavenDB Service Session.Query not returning results

I have a RavenDB Service instance set up on localhost:8080 and am using the OAuth plugin to store a simple user document for authentication. I am using a guid for the id and the users email as the name. The following code is functioning properly to store the user
public AccountUserDocument CreateUser(RegisterModel model)
{
using (IDocumentSession session = DataDocumentStore.Instance.OpenSession())
{
Guid userId = Guid.NewGuid();
session.Store(new AccountUserDocument
{
Name = model.Email,
Id = String.Format("Raven/Users/{0}", userId),
AllowedDatabases = new[] { "*" },
Email = model.Email,
FirstName = model.FirstName,
LastName = model.LastName,
FacebookId = 0,
Expires = DateTime.Now.AddMonths(1),
AccessToken = string.Empty
}.SetPassword(model.Password));
session.SaveChanges();
return session.Load<AccountUserDocument>
(String.Format("Raven/Users/{0}", userId));
}
}
and returns a valid user object. However, when i call
return session.Query<AccountUserDocument>()
.Customize(x => x.WaitForNonStaleResults())
.Where(x => x.Name == email)
.SingleOrDefault();
I get nothing. It had been working a week ago but now it just doesn't. If I open up RavenDB studio, I can see the user and the name is exactly how I am entering it (i have even copy and pasted it into the text field).
I have tried stopping and restarting the service hoping that would solve the problem but it did not.
I was wondering if someone could point me in the direction of how I might debug what is going on here. The full code repository can be found here
https://github.com/jamesamuir/MVC_Facebook_Auth
if anyone is inclined to download it.
Thanks in advance.
Well, I see a lot of things wrong with the code sample you provided - such as mismatched versions of client and server. Also, the Authentication Bundle was a 1.0 feature that has been deprecated in 2.0 which is almost final, so you're writing code you will eventually have to replace.
But to answer your question, the specific reason that you can't get results from your query is that you chose to use a document key starting with "Raven/", which is the convention for RavenDB system documents - which don't get indexed.
If you remove "Raven/" from your id, it will work.
Also, you should not be using .WaitForNonStaleResults() - that's only for unit tests, and is dangerous in production. If you really feel like you need to wait, use .WaitForNonStaleResultsAsOfNow() - which is safer because it provides a cutoff.

How do you read system jobs in Dynamics CRM?

The CRM SDK says this is possible but the following code fails. Does anyone know why?
var request = new RetrieveMultipleRequest();
var query = new QueryExpression(EntityName.asyncoperation.ToString());
query.ColumnSet = new AllColumns();
request.Query = query;
var response = _connection.Execute(request);
The error is:
<error>\n
<code>0x80040216</code>
<description>An unexpected error occurred.</description>
<type>Platform</type>
</error>
If I change the entity name to account, it works fine.
Found the answer. It appears that it doesn't like the "new AllColumns()" bit. If I specify a column list it works.

Resources