I am trying to get values from form and print those value in windows form but whenever I try to save the values it failed showing the error An unexpected error occurred from ISV code.
public void Execute(IServiceProvider serviceProvider) {
// Get the context and organization service
IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof (IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory) serviceProvider.GetService(typeof (IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
Entity target = context.InputParameters["Target"] as Entity;
try {
EntityReference lookupValue = target.GetAttributeValue < EntityReference > ("new_contact");
EntityReference lookupValue2 = target.GetAttributeValue < EntityReference > ("new_account");
// string contactname = target.GetAttributeValue<string>("new_contact");
// string accountname = target.GetAttributeValue<string>("new_account");
MessageBox.Show("" + lookupValue + " " + lookupValue2);
} catch (Exception ex) {
throw new InvalidPluginExecutionException(ex.Message);
}
}
Related
As the title suggests, I do not know how to convert entity.attributes ["subgrid"] as a list of entities, on which to run the multiretrieve:
My code for now:
protected override void Execute(CodeActivityContext executionContext)
{
ITracingService tracingService = executionContext.GetExtension<ITracingService>();
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
var entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "account")
{
return;
}
var currentAccountId = entity.Id;
try
{
if (!entity.Contains("Subgrid"))
{
return;
}
var itemsOnSubgrid = entity.Attributes["Subgrid"];
if(itemsOnSubgrid == null)
{
return;
}
else
{
//if subgrid exist and is not null
//List of entities needed
}
}
catch (Exception ex)
{
tracingService.Trace("MyWorkflow: {0}", ex.ToString());
throw new InvalidPluginExecutionException(ex.Message);
}
}
As you are writing code in a custom workflow assembly - the entity at this point does not know anything about the form it is being called from, and does not have a "Subgrid" property to allow you to access the related records.
You will need to do a sperate query to retrieve related contacts (as an example) using the target entity's "accountid" property to relate to the contacts' "parentcustomerid" property.
Assume you are looking for a method to get all associated records for a particular record.
If that is the case, I would have written something like this. Hope that helps.
private EntityCollection GetAssociatedRecords(string relationshipName, string relatedEntityName, string entityName, Guid entityId,OrganizationService service)
{
EntityCollection result = null;
try
{
QueryExpression query = new QueryExpression();
query.EntityName = relatedEntityName;
query.ColumnSet = new ColumnSet(false);
Relationship relationship = new Relationship();
relationship.SchemaName = relationshipName;
relationship.PrimaryEntityRole = EntityRole.Referencing;
RelationshipQueryCollection relatedEntity = new RelationshipQueryCollection();
relatedEntity.Add(relationship, query);
RetrieveRequest request = new RetrieveRequest();
request.RelatedEntitiesQuery = relatedEntity;
request.ColumnSet = new ColumnSet(true);
request.Target = new EntityReference
{
Id = entityId,
LogicalName = entityName
};
RetrieveResponse response = (RetrieveResponse)service.Execute(request);
RelatedEntityCollection relatedEntityCollection = response.Entity.RelatedEntities;
if (relatedEntityCollection.Count > 0)
{
if (relatedEntityCollection.Values.Count > 0)
{
result = (EntityCollection)relatedEntityCollection.Values.ElementAt(0);
}
}
}
catch (Exception exception)
{
throw exception;
}
return result;
}
In that based on the role of the other entity change the Primary Entity Role between Referencing and Referenced.
Hope that helps. Let me know if my assumption is wrong.
I have a parent entity and child entity. I'm creating a plugin to count number of child entities for each parent entity and display the number in noOfProduct field in parent entity. So every time when I created a new child entity, the value of number in noOfProduct will be increment to 1. But when I deleted the child entity, my plugin is not triggering, hence the value remain the same.
I registered my plugin,
step: create
primary entity: child_entity
event_pipeline: post-operation
synchronous
Plugin Images: post-image
This is my complete code.
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Description;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Client;
using System.Net;
using System.Web.Services;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NoOfProductsPlugin
{
public class NoOfProducts : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//for create and update event
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parmameters.
Entity targetEntity = (Entity)context.InputParameters["Target"];
// Verify that the entity represents a connection.
if (targetEntity.LogicalName != "child_entity")
{
return;
}
else
{
try
{
//triggered upon create or update message
if (context.MessageName == "Create" || context.MessageName == "Update")
{
Entity postMessageImage;
Guid oppId = new Guid();
if (context.PostEntityImages.Contains("postMessageImage") && context.PostEntityImages["postMessageImage"] is Entity)
{
postMessageImage = (Entity)context.PostEntityImages["postMessageImage"];
oppId = ((EntityReference)postMessageImage.Attributes["lookup_fieldtoParent"]).Id;
}
//throw new InvalidPluginExecutionException
queryOppProd(service, oppId);
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred :-" + ex.Message, ex);
}
//</snippetFollowupPlugin3>
catch (Exception ex)
{
tracingService.Trace("An error occurred : {0}" + ex.Message, ex.ToString());
throw;
}
}
}
//for delete event use entityreference
else if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is EntityReference)
{
// Obtain the target entity from the input parmameters.
EntityReference targetEntity = (EntityReference)context.InputParameters["Target"];
// Verify that the entity represents a connection.
if (targetEntity.LogicalName != "child_entity")
{
return;
}
else
{
try
{
//triggered upon delete message
if (context.MessageName == "Delete")
{
Guid oppProdId = targetEntity.Id;
// retrieve oppid guid
Entity oppProd = new Entity("child_entity");
ColumnSet columns_ = new ColumnSet(new string[] { "lookup_fieldtoParent" });
oppProd = service.Retrieve(oppProd.LogicalName, oppProdId, columns_);
Guid oppId = new Guid();
oppId = ((EntityReference)oppProd["lookup_fieldtoParent"]).Id;
//throw new InvalidPluginExecutionException(
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred :-" + ex.Message, ex);
}
//</snippetFollowupPlugin3>
catch (Exception ex)
{
tracingService.Trace("An error occurred: {0}" + ex.Message, ex.ToString());
throw;
}
}
}
}
public void queryOppProd(IOrganizationService service, Guid oppId)
{
int noOfProduct = 0;
QueryExpression oppProdQuery = new QueryExpression { EntityName = "child_entity", ColumnSet = new ColumnSet("child_entityid", "lookup_fieldtoParent") };
oppProdQuery.Criteria.AddCondition("lookup_fieldtoParent", ConditionOperator.Equal, oppId); // to search for child_entity that linked to the selected parent_entity
EntityCollection oppProdQueryRetrieve = service.RetrieveMultiple(oppProdQuery);
if (oppProdQueryRetrieve != null && oppProdQueryRetrieve.Entities.Count > 0)
{
for (var i = 0; i < oppProdQueryRetrieve.Entities.Count; i++)
{
noOfProduct++;
}
}
//declare table used to retrieve the field and update
Entity opportunity = new Entity("parent_entity");
ColumnSet columns = new ColumnSet(new string[] { "new_noofproducts" });
opportunity = service.Retrieve(opportunity.LogicalName, oppId, columns);
opportunity["new_noofproducts"] = noOfProduct;
service.Update(opportunity);
}
public void queryOppProdOnDel(IOrganizationService service, Guid oppId, Guid oppProdId)
{
int noOfProduct = 0;
//query opportunityProduct by using opportunity guid
QueryExpression oppProdQuery = new QueryExpression { EntityName = "child_entity", ColumnSet = new ColumnSet("child_entityid", "lookup_fieldtoParent") };
FilterExpression oppProdQueryFilter = oppProdQuery.Criteria.AddFilter(LogicalOperator.And);
oppProdQueryFilter.AddCondition("child_entityid", ConditionOperator.NotEqual, oppProdId);
oppProdQueryFilter.AddCondition("lookup_fieldtoParent", ConditionOperator.Equal, oppId); // to search for child_entity that linked to the selected parent_entity
EntityCollection oppProdQueryRetrieve = service.RetrieveMultiple(oppProdQuery);
if (oppProdQueryRetrieve != null && oppProdQueryRetrieve.Entities.Count > 0)
{
for (var i = 0; i < oppProdQueryRetrieve.Entities.Count; i++)
{
noOfProduct++;
}
}
//throw new InvalidPluginExecutionException
//declare table used to retrieve the field and update
Entity opportunity = new Entity("parent_entity");
ColumnSet columns = new ColumnSet(new string[] { "new_noofproducts" });
opportunity = service.Retrieve(opportunity.LogicalName, oppId, columns);
service.Update(opportunity);
}
}
}
You forgot to call the method queryOppProdOnDel.
When you register your Plugin assembly & Step on Delete message, replace the below snippet in your code.
//triggered upon delete message
if (context.MessageName == "Delete")
{
Guid oppProdId = targetEntity.Id;
// retrieve oppid guid
Entity oppProd = new Entity("child_entity");
ColumnSet columns_ = new ColumnSet(new string[] { "lookup_fieldtoParent" });
oppProd = service.Retrieve(oppProd.LogicalName, oppProdId, columns_);
Guid oppId = new Guid();
oppId = ((EntityReference)oppProd["lookup_fieldtoParent"]).Id;
//throw new InvalidPluginExecutionException(
queryOppProdOnDel(service, oppId, oppProdId);
}
Update:
This line is missing in queryOppProdOnDel:
opportunity["new_noofproducts"] = noOfProduct;
Couple of points:
step: create You should register on delete.
Pretty sure post-image is not supported on delete. You need to use pre's. "The create operation doesn’t support a pre-image and a delete operation doesn’t support a post-image."
Your basic design has a flaw. If lots of changes occur at the same time, they could all execute concurrently on seperate threads, this means the count could be incorrect in some circumstances.
How to obtain the list (or e.g. collection) of guids of all notes associated with current entity?
I know that it is in some way connected with service.Retreive(...), but can't make working code.
Attach 1:
public void Execute(IServiceProvider serviceProvider)
{
Entity entity = null;
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
if (entity.Contains("new_parentopportunity"))
{
try
{
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
Guid projectGuid = entity.Id;
Guid oppGuid = ((EntityReference)entity["new_parentopportunity"]).Id;
for (int i = 0; i < 100; i++) //Instead of 100, I'll place obtained collection.Length
{
Entity opp = service.Retrieve("", oppGuid, new Microsoft.Xrm.Sdk.Query.ColumnSet(true)); //RETREIVE ENTITY NOTE HERE
var temop = CreateNoteAttachment(opp);
service.Create(temp);
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
}
}
}
private Entity CreateNoteAttachment(Entity oppNote)
{
//some code here
}
Update 1:
I also write it in queries, can you look at this, whethere everything fine there?
PasteBin
Two ways to query for related notes:
Early Bound:
var notes =
service.AnnotationSet.Where(annotation => annotation.Opportunity_Annotation.Id == entity.Id)
.Select(annotation => annotation.Id)
.ToList();
FetchXml:
var fetchXml = string.Format("<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
"<entity name='annotation'>" +
"<attribute name='annotationid' />" +
"<filter type='and'>"+
"<condition attribute='objectid' operator='eq' value='{0}'/>"+
"</filter>"+
"</entity>" +
"</fetch>", entity.Id);
var response = service.RetrieveMultiple(new FetchExpression(fetchXml));
var notes = response.Entities;
I have a C# program that manages Sharepoint lists using the Sharepoint Client Object Model. Occasionally we will have server issues which will prevent the program from accessing the sharepoint server. I am using a helper class to run the ExecuteQuery method and have exception handling to continue to execute until there is no exception.
private void ExecuteContextQuery(ref ClientContext siteContext)
{
int timeOut = 10000;
int numberOfConnectionErrors = 0;
int maxNumberOfRetry = 60;
while (numberOfConnectionErrors < maxNumberOfRetry)
{
try
{
siteContext.ExecuteQuery();
break;
}
catch (Exception Ex)
{
numberOfConnectionErrors++;
Service.applicationLog.WriteLine("Unable to connect to the sharepoint site. Retrying in " + timeOut);
Service.applicationLog.WriteLine("Exception " + Ex.Message + " " + Ex.StackTrace);
System.Threading.Thread.Sleep(timeOut);
if (numberOfConnectionErrors == maxNumberOfRetry)
{
throw Ex;
}
}
}
}
However I getting an error messages
The property or field 'LoginName' has not been initialized.
and
collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
The error messages seem to be related to methods where I call the Load method. here is an example of my code that calls the method above.
List sharepointList = siteContext.Web.Lists.GetByTitle(this._listName);
CamlQuery query = CamlQuery.CreateAllItemsQuery();
items = sharepointList.GetItems(query);
siteContext.Load(items);
//siteContext.ExecuteQuery();
ExecuteContextQuery(ref siteContext);
Do I need to reload the site context with every call to ExecuteQuery? Is that why I am seeing the error message above?
Here is the function I am using for getting the Login ID which is generating the error
public String getLoginIDbyUserId(int userID)
{
ClientContext siteContext = getClientContextObject();
User _getUser = siteContext.Web.SiteUsers.GetById(userID);
siteContext.Load(_getUser);
//siteContext.ExecuteQuery();
ExecuteContextQuery(ref siteContext);
String loginID = String.Empty;
String formatedLoginID = String.Empty;
loginID = _getUser.LoginName;
if (loginID.Contains('|'))
{
formatedLoginID = loginID.Substring(loginID.IndexOf('|') + 1);
}
siteContext.Dispose();
return formatedLoginID;
}
Please try to load LoginName property of user while loading user object. And after excutequery method, try to consume LoginName property of User
siteContext.Load(_getUser, u => u.LoginName);
And after this change your code should look like this
public String getLoginIDbyUserId(int userID)
{
ClientContext siteContext = getClientContextObject();
User _getUser = siteContext.Web.SiteUsers.GetById(userID);
siteContext.Load(_getUser, u => u.LoginName);
//siteContext.ExecuteQuery();
ExecuteContextQuery(ref siteContext);
String loginID = String.Empty;
String formatedLoginID = String.Empty;
loginID = _getUser.LoginName;
if (loginID.Contains('|'))
{
formatedLoginID = loginID.Substring(loginID.IndexOf('|') + 1);
}
siteContext.Dispose();
return formatedLoginID;
}
Am having a plugin that moves the activities of lead to opportunity on qualify. I have registered the plugin on "Create" of opportunity and the following is the code
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
Entity entity;
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
entity = (Entity)context.InputParameters["Target"];
if (entity.Attributes.Contains("originatingleadid") == false) return;
}
else
{
return;
}
try
{
//.....
EntityReference Lead = (EntityReference)entity.Attributes["originatingleadid"];
Guid LeadGuid = Lead.Id;
MoveActivitiesFromLeadToOpportunity(service, LeadGuid, Opportunityid);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException(
"An error occurred in the plug-in.", ex);
}
}
private void MoveActivitiesFromLeadToOpportunity(IOrganizationService service, Guid LeadID, Guid OpportunityID)
{
ConditionExpression condition = new ConditionExpression();
condition.AttributeName = "regardingobjectid";
condition.Operator = ConditionOperator.Equal;
condition.Values.Add(LeadID.ToString());
var query = new QueryExpression("activitypointer");
query.Criteria.AddCondition(condition);
//query.Conditions.Add("reagrdingobjectid", ConditionOperator.Equal, theIdOfTheRelatedRecord);
query.ColumnSet = new ColumnSet(true);
var activities = service.RetrieveMultiple(query).Entities;
foreach (var activity in activities)
{
var castedActivity = (ActivityPointer)activity;
if (castedActivity.ActivityTypeCode == "email")
{
castedActivity.Id = Guid.NewGuid();
castedActivity["regardingobjectid"] = new EntityReference("opportunity", OpportunityID);
//service.Create(castedActivity);--->Exception thrown
//service.Update(castedActivity);---->Tried this one too.Exception is thrown stating method not supported on "ActivityPointer"
}
}
Can somebody shed light on this? Am i missing something here? Thank you
You need to query for the exact entity type, because you can't update an activitypointer
private void MoveEmailsFromLeadToOpportunity(IOrganizationService service, Guid LeadID, Guid OpportunityID)
{
ConditionExpression condition = new ConditionExpression();
condition.AttributeName = "regardingobjectid";
condition.Operator = ConditionOperator.Equal;
condition.Values.Add(LeadID.ToString());
var query = new QueryExpression("email");
query.Criteria.AddCondition(condition);
query.ColumnSet = new ColumnSet(true);
var emails = service.RetrieveMultiple(query).Entities;
foreach (var email in emails)
{
email["regardingobjectid"] = new EntityReference("opportunity", OpportunityID);
service.Update(email);
}
}
you can also write a method that will retrieve first all the activities (as you already did) check the ActivityTypeCode after retrieve and update each single record depending on activity type (email, fax, ...)
Try commenting out this line:
castedActivity.Id = Guid.NewGuid();
And then just do your Update:
service.Update(castedActivity)
You are just updating the RegardingObjectId, not creating a new activity, so you shouldn't change the Id and you shouldn't use Create.