The entity used to store these views is called UserQuery and the main properties are:
- Name: Name given to the saved view
- FetchXml: String that specifies the query in Fetch XML language
- OwnerId: Unique identifier of the user or team who owns the saved view
Consider the following simplified scenario:
- CRM has only two users: John (System Administrator role) and Bob (Sales Manager role)
- John has a personal view for the Account Entity (not shared)
- Bob has a personal view for the Contact Entity (not shared)
What if we want to retrieve all the saved views for all the users? A possibility is to impersonate each CRM user, run the query and combine the results.
To implement this solution we rely on the CallerId property of the OrganizationServiceProxy object in combination with the "Act on Behalf of Another User" privilege.
The OrganizationServiceProxy gives us the possibility to impersonate the user by code, the "Act on Behalf of Another User" privilege is required to allow this impersonation.
The following code is a simplified example of the solution:
// url and credentials string organizationUrl = "https://mycompany.crm.dynamics.com/XRMServices/2011/Organization.svc"; string userName = "john@mycompany.onmicrosoft.com"; string password = "JohnPassword"; // authentication code ClientCredentials credentials = new ClientCredentials(); credentials.UserName.UserName = userName; credentials.UserName.Password = password; IServiceManagement<IOrganizationService> orgServiceManagement = ServiceConfigurationFactory.CreateManagement(new Uri(organizationUrl)); AuthenticationCredentials authCredentials = new AuthenticationCredentials(); authCredentials.ClientCredentials = credentials; AuthenticationCredentials tokenCredentials = orgServiceManagement.Authenticate(authCredentials); SecurityTokenResponse organizationTokenResponse = tokenCredentials.SecurityTokenResponse; // IOrganizationService and OrganizationServiceProxy objects OrganizationServiceProxy serviceProxy; IOrganizationService service; using (serviceProxy = new OrganizationServiceProxy(orgServiceManagement, organizationTokenResponse)) { service = (IOrganizationService)serviceProxy; // Dictionary to contain all the saved views Dictionary<Guid, Entity> dictPersonalViews = new Dictionary<Guid, Entity>(); // retrieve first all the CRM Users QueryExpression systemUsers = new QueryExpression("systemuser"); systemUsers.ColumnSet = new ColumnSet(true); EntityCollection userCollection = service.RetrieveMultiple(systemUsers); // for each User we launch the query to retrieve the saved views foreach (Entity systemUser in userCollection.Entities) { QueryExpression personalViews = new QueryExpression("userquery"); personalViews.ColumnSet = new ColumnSet(true); // we set the CallerId property to impersonate the current iteration user serviceProxy.CallerId = systemUser.Id; EntityCollection viewCollection = serviceProxy.RetrieveMultiple(personalViews); foreach (Entity personalView in viewCollection.Entities) { // we want a list without duplicates (shared views or automatically shared to SYSTEM and INTEGRATION users) if (!dictPersonalViews.ContainsKey(personalView.Id)) { dictPersonalViews.Add(personalView.Id, personalView); } } } // we can process the values (Entity objects) of the dictionary foreach (Entity personalView in dictPersonalViews.Values) { string viewName = personalView["name"].ToString(); string viewFetchXml = personalView["fetchxml"].ToString(); EntityReference viewOwnerIdRef = (EntityReference)personalView["ownerid"]; } }
Hello Guido,
ReplyDeleteInteresting point, i'm currently migration from onprem to online and running into issues to migrate the user views.
I agree that your approach is good for existing users.
What if some users are disabled and not in your AD anymore to impersonate them ? (yes i need their views since they shared a lot of them with other users ...)
Thanks,
Clém
tricky situation, probably the easiest way it to recreate them inside AD with the same username and re-activate the users inside CRM (I never did so I don't know if this would work). The alternative because you are onpremise is to extract the fetchxml of these views directly from the CRM DB
Delete