private static void Associate(CrmDbContext context, ContentMap map, EntityReference target, Relationship relationship, EntityReferenceCollection relatedEntities) { target.ThrowOnNull("target"); relationship.ThrowOnNull("relationship"); relatedEntities.ThrowOnNull("relatedEntities"); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Target: LogicalName={0}, Id={1}", EntityNamePrivacy.GetEntityName(target.LogicalName), target.Id)); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Relationship: SchemaName={0}, PrimaryEntityRole={1}", relationship.SchemaName, relationship.PrimaryEntityRole)); foreach (var entity in relatedEntities) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Related: LogicalName={0}, Id={1}", EntityNamePrivacy.GetEntityName(entity.LogicalName), entity.Id)); } // validate that the relationships do in fact exist by querying for the intersects var entities = map.Using(ContentMapLockType.Read, () => RetrieveIntersectEntities(context, map, target, relationship, relatedEntities)); if (entities != null) { // add intersect entities to the content map map.Using(ContentMapLockType.Write, () => map.AddRange(entities)); foreach (var added in entities) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Added: LogicalName={0}, Id={1}", EntityNamePrivacy.GetEntityName(added.LogicalName), added.Id)); } } }
public virtual void Refresh(ContentMap map, List <EntityReference> references) { using (var context = this.CreateContext()) { Refresh(context, map, references); } }
public virtual void Disassociate(ContentMap map, EntityReference target, Relationship relationship, EntityReferenceCollection relatedEntities) { using (var context = this.CreateContext()) { this.Disassociate(context, map, target, relationship, relatedEntities); } }
public virtual EntityNode Refresh(ContentMap map, EntityReference reference) { using (var context = this.CreateContext()) { return(Refresh(context, map, reference)); } }
/// <summary> Select the site marker target page. </summary> /// <param name="siteMarkerName"> The site marker name. </param> /// <param name="contentMap"> The content map. </param> /// <returns> The <see cref="ISiteMarkerTarget"/>. </returns> private ISiteMarkerTarget Select(string siteMarkerName, ContentMap contentMap) { WebPageNode target; if (!this.TryGetPageNodeFromSiteMarkerNode(siteMarkerName, contentMap, out target)) { return(null); } return(this.ToSiteMarkerTarget(target)); }
protected virtual void BuildContentMap(ContentMap map, IEnumerable <Entity> entities) { var sw = Stopwatch.StartNew(); map.AddRange(entities); ApplyBaseSolutionVersionToWebsite(map); sw.Stop(); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Duration: {0} ms", sw.ElapsedMilliseconds)); }
/// <summary> The try get page node from site marker node. </summary> /// <param name="siteMarkerName"> The site marker name. </param> /// <param name="contentMap"> The content map. </param> /// <param name="targetNode"> The target node. </param> /// <returns> The <see cref="bool"/>. </returns> private bool TryGetPageNodeFromSiteMarkerNode(string siteMarkerName, ContentMap contentMap, out WebPageNode targetNode) { var website = HttpContext.Current.GetWebsite().Entity; IDictionary <EntityReference, EntityNode> siteMarkers; targetNode = null; if (!contentMap.TryGetValue("adx_sitemarker", out siteMarkers)) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, "No Sitemarkers found on Content Map"); return(false); } var siteMarkerNode = siteMarkers.Values .Cast <SiteMarkerNode>() .FirstOrDefault(e => e.Website.Id == website.Id && e.Name == siteMarkerName); if (siteMarkerNode == null || siteMarkerNode.WebPage == null) { return(false); } if (!contentMap.TryGetValue(siteMarkerNode.WebPage, out targetNode)) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("No WebPage found on Sitemarker:{0}", siteMarkerNode.Id)); return(false); } if (!this.Language.IsCrmMultiLanguageEnabled) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("WebPage found for Sitemarker:{0} Page:{1}", siteMarkerNode.Id, targetNode.Id)); return(true); } // MLP - Find the content webpage for the current language from the target page var contentWebPage = targetNode.LanguageContentPages.FirstOrDefault(p => p.WebPageLanguage == this.Language.ContextLanguage.WebsiteLanguageNode); if (contentWebPage != null) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("WebPage found for Sitemarker:{0} Language:{1}", siteMarkerNode.Id, this.Language.ContextLanguage.Lcid)); targetNode = contentWebPage; return(true); } ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("No WebPage found for Sitemarker:{0} Language:{1}", siteMarkerNode.Id, this.Language.ContextLanguage.Lcid)); return(false); }
/// <summary> Select site marker target page with read access. </summary> /// <param name="siteMarkerName"> The site marker name. </param> /// <param name="contentMap"> The content map. </param> /// <returns> The <see cref="ISiteMarkerTarget"/>. </returns> private ISiteMarkerTarget SelectWithReadAccess(string siteMarkerName, ContentMap contentMap) { var securityProvider = this.Dependencies.GetSecurityProvider(); var serviceContext = this.Dependencies.GetServiceContext(); WebPageNode target; if (!this.TryGetPageNodeFromSiteMarkerNode(siteMarkerName, contentMap, out target)) { return(null); } if (!securityProvider.TryAssert(serviceContext, target.ToEntity(), CrmEntityRight.Read)) { return(null); } return(this.ToSiteMarkerTarget(target)); }
/// <summary> /// Applies base solution version to website. This should only be called AFTER the ContentMap is completely built. /// </summary> /// <param name="map">ContentMap to apply base solution version.</param> private void ApplyBaseSolutionVersionToWebsite(ContentMap map) { // Apply base solution version to Website const string websiteKey = "adx_website"; if (map.ContainsKey(websiteKey) && map[websiteKey] != null) { var retrieveBaseSolutionCrmVersion = this.PortalSolutions.BaseSolutionCrmVersion; foreach (var node in map[websiteKey]) { var websiteNode = node.Value as WebsiteNode; if (websiteNode != null) { websiteNode.CurrentBaseSolutionCrmVersion = retrieveBaseSolutionCrmVersion; } } } }
private ContentMap GetContentMap(CrmDbContext context) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("LockTimeout={0}", this.LockTimeout)); var sw = Stopwatch.StartNew(); var solution = this.SolutionDefinitionProvider.GetSolution(); var parameters = this.SolutionDefinitionProvider.GetQueryParameters(); var map = new ContentMap(solution) { LockTimeout = this.LockTimeout.GetValueOrDefault(TimeSpan.FromMinutes(1)) }; var entities = this.GetEntities(context, map.Solution, parameters).ToList(); map.Using(ContentMapLockType.Write, () => this.BuildContentMap(map, entities)); sw.Stop(); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Duration: {0} ms", sw.ElapsedMilliseconds)); return(map); }
private void Disassociate(CrmDbContext context, ContentMap map, EntityReference target, Relationship relationship, EntityReferenceCollection relatedEntities) { target.ThrowOnNull("target"); relationship.ThrowOnNull("relationship"); relatedEntities.ThrowOnNull("relatedEntities"); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Target: LogicalName={0}, Id={1}", EntityNamePrivacy.GetEntityName(target.LogicalName), target.Id)); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Relationship: SchemaName={0}, PrimaryEntityRole={1}", relationship.SchemaName, relationship.PrimaryEntityRole)); foreach (var entity in relatedEntities) { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Related: LogicalName={0}, Id={1}", EntityNamePrivacy.GetEntityName(entity.LogicalName), entity.Id)); } var entities = new List <EntityReference>(); if (this.EventHubJobSettings.IsEnabled) { //logic to ignore to get Intersect entity which we already have in eventhub model. EntityReference intersectEntity = new EntityReference(); intersectEntity.LogicalName = target.LogicalName; intersectEntity.Id = target.Id; entities.Add(intersectEntity); } else { // validate that the relationships do in fact not exist by querying for the intersects entities = map.Using(ContentMapLockType.Read, () => RetrieveDisassociatedIntersectEntities(context, map, target, relationship, relatedEntities).ToList()); } if (entities != null) { // add intersect entities to the content map map.Using(ContentMapLockType.Write, () => map.RemoveRange(entities)); } }
private static IEnumerable <EntityReference> RetrieveDisassociatedIntersectEntities(CrmDbContext context, ContentMap map, EntityReference target, Relationship relationship, IEnumerable <EntityReference> relatedEntities) { var solution = map.Solution; // retrieve the intersect entity definition ManyRelationshipDefinition mrd; EntityDefinition ed; if (solution.ManyRelationships != null && solution.ManyRelationships.TryGetValue(relationship.SchemaName, out mrd) && solution.Entities.TryGetValue(mrd.IntersectEntityname, out ed)) { // retrieve the target node EntityNode targetNode; if (map.TryGetValue(target, out targetNode)) { // retrieve the set of existing relationships for validation purposes var entities = RetrieveIntersectEntities(context, map, target, relationship, relatedEntities).Select(e => e.ToEntityReference()).ToList(); // reflexive N:N relationships are not supported var targetRelationship = ed.Relationships.Single(r => r.ForeignEntityLogicalname == target.LogicalName && r.ToMany != null); // retrieve the intersect nodes that point to the target var intersects = targetRelationship.ToMany(targetNode).ToList(); foreach (var related in relatedEntities) { EntityNode relatedNode; if (map.TryGetValue(related, out relatedNode)) { var relatedRelationship = ed.Relationships.Single(r => r.ForeignEntityLogicalname == related.LogicalName && r.ToOne != null); // filter the intersect nodes that point to the related node (as well as the target) // ensure that the intersect does not exist in the collection of retrieved intersects var intersectsToRemove = intersects .Where(i => Equals(relatedRelationship.ToOne(i), relatedNode)) .Select(i => i.ToEntityReference()) .Where(i => entities.All(e => !Equals(e, i))); foreach (var intersect in intersectsToRemove) { yield return(intersect); } } } } } }
private static IEnumerable <Entity> RetrieveIntersectEntities(CrmDbContext context, ContentMap map, EntityReference target, Relationship relationship, IEnumerable <EntityReference> relatedEntities) { var solution = map.Solution; // retrieve the intersect entity definition ManyRelationshipDefinition mrd; EntityDefinition ed; if (solution.ManyRelationships != null && solution.ManyRelationships.TryGetValue(relationship.SchemaName, out mrd) && solution.Entities.TryGetValue(mrd.IntersectEntityname, out ed)) { // build the N:N query to retrieve the intersect entities var fetch = ed.CreateFetch(); // reflexive N:N relationships are not supported var targetRelationship = ed.Relationships.Single(r => r.ForeignEntityLogicalname == target.LogicalName); var filters = fetch.Entity.Filters.FirstOrDefault() ?? new Filter { Conditions = new List <Condition>() }; filters.Conditions.Add(new Condition(targetRelationship.ForeignIdAttributeName, ConditionOperator.Equal, target.Id)); var relatedIds = relatedEntities.Select(related => related.Id).Cast <object>().ToArray(); var firstRelated = relatedEntities.FirstOrDefault(); if (firstRelated != null) { var relatedRelationship = ed.Relationships.Single(r => r.ForeignEntityLogicalname == firstRelated.LogicalName); filters.Conditions.Add(new Condition(relatedRelationship.ForeignIdAttributeName, ConditionOperator.In, relatedIds)); var result = context.Service.RetrieveMultiple(fetch); return(result.Entities); } } return(null); }
/// <summary> /// Test whether or not an Entity's published dates are visible in the current context. /// </summary> /// <param name="context">OrganizationServiceContext</param> /// <param name="entity">CRM Entity</param> /// <param name="right">Entity Right</param> /// <param name="dependencies">Cache Dependency Trace</param> /// <param name="map">Content Map</param> /// <returns></returns> protected override bool TryAssert(OrganizationServiceContext context, Entity entity, CrmEntityRight right, CrmEntityCacheDependencyTrace dependencies, ContentMap map) { if (entity == null || right == CrmEntityRight.Change) { return(false); } dependencies.AddEntityDependency(entity); dependencies.AddEntitySetDependency("adx_webrole"); dependencies.AddEntitySetDependency("adx_websiteaccess"); var entityName = entity.LogicalName; var releaseDate = DateTime.MinValue; var expiryDate = DateTime.MaxValue; if (entityName == "adx_webpage" || entityName == "adx_webfile" || entityName == "adx_event" || entityName == "adx_survey" || entityName == "adx_ad") { releaseDate = entity.GetAttributeValue <DateTime?>("adx_releasedate").GetValueOrDefault(DateTime.MinValue); expiryDate = entity.GetAttributeValue <DateTime?>("adx_expirationdate").GetValueOrDefault(DateTime.MaxValue); } else if (entityName == "adx_weblink") { if (!entity.GetAttributeValue <bool?>("adx_disablepagevalidation").GetValueOrDefault(false)) { var pageReference = entity.GetAttributeValue <EntityReference>("adx_pageid"); if (pageReference != null) { WebPageNode rootPage; if (map.TryGetValue(pageReference, out rootPage)) { var weblinkWebPage = HttpContext.Current.GetContextLanguageInfo().FindLanguageSpecificWebPageNode(rootPage, false); if (weblinkWebPage != null) { return(TryAssert(context, weblinkWebPage.ToEntity(), right, dependencies)); } } } } return(true); } else if (entityName == "adx_shortcut") { if (!entity.GetAttributeValue <bool?>("adx_disabletargetvalidation").GetValueOrDefault(false)) { var pageReference = entity.GetAttributeValue <EntityReference>("adx_webpageid"); var webFileReference = entity.GetAttributeValue <EntityReference>("adx_webfileid"); if (pageReference != null) { WebPageNode rootPage; if (map.TryGetValue(pageReference, out rootPage)) { var shortcutWebPage = HttpContext.Current.GetContextLanguageInfo().FindLanguageSpecificWebPageNode(rootPage, false); if (shortcutWebPage != null) { return(TryAssert(context, shortcutWebPage.ToEntity(), right, dependencies)); } } } else if (webFileReference != null) { WebFileNode webFile; if (map.TryGetValue(webFileReference, out webFile)) { return(TryAssert(context, webFile.ToEntity(), right, dependencies)); } } } var parentPageReference = entity.GetAttributeValue <EntityReference>("adx_parentpage_webpageid"); if (parentPageReference != null) { WebPageNode rootPage; if (map.TryGetValue(parentPageReference, out rootPage)) { var parentPage = HttpContext.Current.GetContextLanguageInfo().FindLanguageSpecificWebPageNode(rootPage, false); return(TryAssert(context, parentPage.ToEntity(), right, dependencies)); } } return(true); } return(UserCanPreview(context, entity) || InnerTryAssert(releaseDate, expiryDate)); }
private static void Refresh(CrmDbContext context, ContentMap map, List <EntityReference> references) { if (references.Count > 0) { references[0].ThrowOnNull("reference"); EntityDefinition ed; Dictionary <Guid, Entity> mapEntities = new Dictionary <Guid, Entity>(); bool getEntityDefinition = map.Solution.Entities.TryGetValue(references[0].LogicalName, out ed); if (getEntityDefinition) { List <Guid> guids = new List <Guid>(); foreach (var reference in references) { reference.ThrowOnNull("reference"); guids.Add(reference.Id); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("LogicalName={0}, Id={1}", EntityNamePrivacy.GetEntityName(reference.LogicalName), reference.Id)); } try { string primaryEntityAttribute = EventHubBasedInvalidation.CrmChangeTrackingManager.Instance.TryGetPrimaryKey(references[0].LogicalName); var entities = RetrieveCRMRecords(context, primaryEntityAttribute, references[0], ed, guids); foreach (var entity in entities) { mapEntities.Add(entity.Id, entity); } ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Retrieve Multiple Response for Entity {0} has Record Count {1} , Refrence Count {2} ", references[0].LogicalName, entities.Count, references.Count)); // check if the entity is inactive according to the definition foreach (var reference in references) { var entity = mapEntities.ContainsKey(reference.Id) ? (Entity)mapEntities[reference.Id] : null; // Check if the entity matches on the defined relationships. if (!ed.ShouldIncludeInContentMap(entity)) { continue; } var option = entity != null?entity.GetAttributeValue <OptionSetValue>("statecode") : null; var isActive = ed.ActiveStateCode == null || (option != null && ed.ActiveStateCode.Value == option.Value); var node = map.Using(ContentMapLockType.Write, () => entity != null ? isActive ? map.Replace(entity) : map.Deactivate(reference) : map.Remove(reference)); } } catch (FaultException <OrganizationServiceFault> ) { // an exception occurs when trying to retrieve a non-existing entity ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("An exception occurs when trying to retrieve a non-existing entity")); } } else { ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Unknown: logicalName={0}", EntityNamePrivacy.GetEntityName(references[0].LogicalName))); } } }
protected override bool TryAssert(OrganizationServiceContext context, Entity entity, CrmEntityRight right, CrmEntityCacheDependencyTrace dependencies, ContentMap map) { switch (entity.LogicalName) { case "adx_weblink": WebLinkNode link; if (map.TryGetValue(entity, out link)) { return(TryAssert(link) || UserCanPreview(context, entity)); } break; case "adx_webpage": WebPageNode page; if (map.TryGetValue(entity, out page)) { return(TryAssert(page.PublishingState) || UserCanPreview(context, entity)); } break; case "adx_weblinkset": WebLinkSetNode linkset; if (map.TryGetValue(entity, out linkset)) { return(TryAssert(linkset.PublishingState) || UserCanPreview(context, entity)); } break; case "adx_webfile": WebFileNode file; if (map.TryGetValue(entity, out file)) { return(TryAssert(file.PublishingState) || UserCanPreview(context, entity)); } break; case "adx_shortcut": ShortcutNode shortcut; if (map.TryGetValue(entity, out shortcut)) { return(TryAssert(shortcut) || UserCanPreview(context, entity)); } break; case "adx_communityforum": ForumNode forum; if (map.TryGetValue(entity, out forum)) { return(TryAssert(forum.PublishingState) || UserCanPreview(context, entity)); } break; } return(this.TryAssert(context, entity, right, dependencies)); }
private static EntityNode Refresh(CrmDbContext context, ContentMap map, EntityReference reference) { reference.ThrowOnNull("reference"); ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("LogicalName={0}, Id={1}", EntityNamePrivacy.GetEntityName(reference.LogicalName), reference.Id)); EntityDefinition ed; if (map.Solution.Entities.TryGetValue(reference.LogicalName, out ed)) { // retrieve a fresh entity which also acts as a backend validation var fetch = ed.CreateFetch(); Entity entity = null; try { string primaryIdAttribute = EventHubBasedInvalidation.CrmChangeTrackingManager.Instance.TryGetPrimaryKey(reference.LogicalName); // The condition for the filter on primary key var primaryAttributeCondition = new Condition { Attribute = primaryIdAttribute, Operator = ConditionOperator.Equal, Value = reference.Id }; var attributes = fetch.Entity.Attributes; var fQuery = new Fetch { Distinct = true, SkipCache = true, Entity = new FetchEntity { Name = reference.LogicalName, Attributes = attributes, Filters = new List <Filter>() { new Filter { Type = LogicalOperator.And, Conditions = new List <Condition>() { primaryAttributeCondition } } } } }; entity = context.Service.RetrieveSingle(fQuery, true, true); } catch (FaultException <OrganizationServiceFault> fe) { // an exception occurs when trying to retrieve a non-existing entity if (!fe.Message.EndsWith("Does Not Exist")) { throw; } } // Check if the entity matches on the defined relationships. if (!ed.ShouldIncludeInContentMap(entity)) { return(null); } // check if the entity is inactive according to the definition var option = entity != null?entity.GetAttributeValue <OptionSetValue>("statecode") : null; var isActive = ed.ActiveStateCode == null || (option != null && ed.ActiveStateCode.Value == option.Value); var node = map.Using(ContentMapLockType.Write, () => entity != null ? (isActive ? map.Replace(entity) : map.Deactivate(reference)) : map.Remove(reference)); return(node); } ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("Unknown: logicalName={0}", EntityNamePrivacy.GetEntityName(reference.LogicalName))); return(null); }