I have started to write a workflow assembly for CRM 4.0 that should kill any other running workflows with the given name (in my case, all other workflows except him self).
ConditionExpression ce = new ConditionExpression();
ce.AttributeName = "name";
ce.Values = new Object[]{this.WorkflowName}; // Dependency Property
query.EntityName = EntityName.asyncoperation.ToString();
Has anyone an idea, how to get the current workflow name out of the IContextService or something like that?
Best regards
Its a bit of a long way around, but you could use IWorkflowContext.AsyncOperationId to get the ID of the current workflow.
Using that ID you can then query the asyncoperation to get the name of the workflow.
Related
I am writing a Post PLugin changing the owner. When the owner has a substitution manager, the owner is changed to the substitution manager. I tried a service.Update and an AssignRequest, but these throw an exception.
When I post the request my entity cannot update (and then throws "The request channel time out while waiting for reply after 10:00:00"). But like I see there is no recursion, because when I logged it I have only one repetition of log and it has stopped before or on line with update.
var assignedIncident = new AssignRequest
{
Assignee = substManagerRef, //get it throw another method, alreay checked in test it`s correct
Target = new EntityReference ("incident", incedentId)
};
service.Execute(assignedIncident);
I tried to write target in another way
Target = postEntityImage.ToEntityReference()
I tried to write simple update but the problem is the same.
Entity incident = new Entity("incident" , incidentId);
incident["ownerid"] = substManagerRef:
service.Update(incident);
Can somebody help me with that? Or maybe show the way to solve it)
The plugin is triggering itself and gets in a loop. The system only allows a maximum of 8 calls deep within plugins and that is the reason it throws an error and rolls back the transaction.
To solve this issue redesign your plugin in the following way:
Register your plugin on the Update message of your entity in the PreValidation stage.
In the plugin pick up the Target property from the InputParameters collection.
This is an Entity type. Modify or set the ownerid attribute on this Entity object.
That is all. You do not need to do an update, your modification is now passed into the plugin pipeline.
Note: for EntityReference attributes this technique only works when your plugin is registered in the PreValidation stage. For other regular attributes it also works in the PreOperation stage.
I have the following code:
var propertyInstance = new DynamicPropertyInstance()
{
DynamicPropertyId = new EntityReference(DynamicProperty.EntityLogicalName, Guid.Parse("0ceedfcc-68b2-e711-8168-e0071b658ea1")),
ValueString = jobId.ToString(),
RegardingObjectId = line.ToEntityReference(),
};
crmContext.AddObject(dynamicPropertyInstance);
crmContext.SaveChanges();
It is successfully adding a DynamicPropertyInstance to a SalesOrderLine, but when viewing the Order in the CRM UI it does not pass the validation (as it is a required property). I've not managed to find a way to make this property valid. Editing the property that I've added in the UI (resetting the value) also fails to mark the instance as valid. Adding exactly the same property through the UI does mark it as valid.
The Id of the DynamicProperty is correct, as verified by loading the 2 instance records through the SDK and comparing the properties. Rather strangely, when I load the 2 records through the SDK the one I've created in code has a validationstatus of true (even though it's not) and the one that I've created in the UI has a validationstatus of false and ValueString returns null (which is wrong). All of the other properties either match or have relevant values (such as dates, object Ids etc)
I'm probably missing a method call to recalculate whether the instance is valid or not, but I can't find anything in the documentation to support that. Failing that, it's possibly a bug in CRM
Raised a case with Microsoft support, and was given some workaround code:
//Get DynamicPropertyInstance
UpdateProductPropertiesRequest UpdateRequest = new UpdateProductPropertiesRequest();
UpdateRequest.PropertyInstanceList = new EntityCollection();
UpdateRequest.PropertyInstanceList.EntityName = DynamicPropertyInstance.EntityLogicalName;
Entity dpInstance = new Entity(DynamicPropertyInstance.EntityLogicalName, Dpi.Id);
dpInstance.Attributes.Add(nameof(Dpi.ValueString).ToLower(), "Blarg");
dpInstance.Attributes.Add(nameof(Dpi.DynamicPropertyInstanceid).ToLower(), Dpi.Id);
dpInstance.Attributes.Add(nameof(Dpi.RegardingObjectId).ToLower(), new EntityReference(SalesOrderDetail.EntityLogicalName, line.Id));
dpInstance.Attributes.Add(nameof(Dpi.DynamicPropertyId).ToLower(), new EntityReference(DynamicProperty.EntityLogicalName, dpId));
UpdateRequest.PropertyInstanceList.Entities.Add(dpInstance);
crmContext.Execute(UpdateRequest);
Basically, it looks like you have to re-set or re-attach the entities for CRM to pick it up, so this is a workaround for a bug in CRM
I've got the task of updating a CRM plugin for a system migrating from cm 2013 to 2016. The plugin fails because it tries to set the opportunity state to won, simply by updating the field. And you need to use the WinOpporunityRequest to do so.
The logic is as follows:
When the opportunity is won the plugin executes and runs on the opportunityclose entity
The plugin creates a new custom entity record (project) and updates several other records.
It gets the current opportunity by using the opportunityid of the opportunityclose entity
It updates a field on the opportunity with a reference to the newly created project record.
That update is done through the Update() method.
On 5 it fails because when at 3 it gets the current opportunity it already has the state of won. And if you try to update the record with a new state it fails.
My question is, how can I get the opportunity when acting on the opportunityclose entity and update only the one single field. I do not need to set the state as this is done in the standard CRM flow.
--Edit
The line of code that fetches the opportunity:
Xrm.Opportunity currentOpportunityObjectToUpdate = serviceContext.CreateQuery<Xrm.Opportunity>().First(x => x.Id == entityRef.Id);
The platform allows you to update closed opportunities, I just tried it to verify. What is the error you are getting?
In step #5, make sure you're only sending the attributes you're trying to update (opportunityid and lookup to project). So, when you issue the update, don't use any preexisting opportunity object that you either retrieved or created...doing so sends all attributes that are on the object and the platform will process each attribute as if it were being changed even if the value is unchanged. Instead, create a new opportunity object with just the id and project specified, something like this:
context.AddObject(new Opportunity() {
Id = idOfOpportunity, // you may have to specify id both here...
OpportunityId = idOfOpportunity, // ...and here, can never remember. Doesn't hurt to specify in both places.
new_ProjectId = idOfProject
});
context.SaveChanges();
If you get stuck, you always have an easy workaround option: take the logic from #4 and move it to an async plugin on create of project (even a workflow should work).
I am trying to find a .NET BusinessConnector equivalent call for the below line:
PurchId = NumberSeq::newGetNum(SalesParameters::numRefSalesId()).num();
I am manually entering purchase order information into the purchase order table, which is fine, but the problem lies in the fact that it is the PurchID that ties purchase table (PURCHTABLE) and the individual purchase order lines (PURCHLINE) is the PURCHID field, which is not automatically populated when saving a purchase order.
Currently I am:
ax.TTSBegin();
axRecord.set_Field("ORDERACCOUNT", purchaseOrder.OrderAccount);
(etc)
axRecord.Insert();
However, while this will insert a record into the database, it has no purchID, which has to be generated. You need a purchID to link the purchase line items in. I found the above code (second line) for X++, but does anyone know of a .NET BusinessConnector call that can be used instead?
Any assistance would be greatly appreciated.
Regards,
Steve
I would go for a change in the insert() method of the PurchTable table:
if (!purchTable.PurchId)
purchTable.PurchId = NumberSeq::newGetNum(purchParameters::numRefPurchId()).num();
Placed after the ttsbegin.
This to avoid complicated C# code. You probably could do it in C# code alone using CallStaticClassMethod and cousins, but it is better do put the buisness logic on the X++ side.
See How to: Call Business Logic Using .NET Business Connector.
Be sure to execute inside a TTSBegin/ TTSCommitblock, otherwise you will get error error messages like this one.
// ax is a reference to an "Axapta" business connector object
var numRef = ax.CallStaticRecordMethod("SalesParameters", "numRefSalesId");
var numSeq = (AxaptaObject)ax.CallStaticClassMethod("NumberSeq", "newGetNum", numRef);
var purchId = numSeq.Call("num");
i m currently using Microsoft Visual Studio to create a webpart for MS Sharepoint. May i ask how do i access the Libraries/List where a workflow is implemented to get the Workflow History and Outcome when it is completed?
Currently i have codes to access the individual fields, which is to get the list's different column:
SPSite site = new SPSite("http://win7:8000/RIDepartment/");
SPWeb oweb = site.OpenWeb();
SPList tasklist = oweb.Lists["Innovation workflow list"];
then to get the first item, i use tasklist[0].However i cant get the workflow histroy from there, thanks.
Melvin
Please take a look at the various workflow tutorials https://www.google.com/search?q=sharepoint+2010+workflow+tutorial+c%23
You will need to get the workflow on your list item via SPListItem.Workflows. Once you get your correct SPWorkflow from the returned SPWorkflowCollection you can get the related history list and task list via the HistoryListId and TaskListId properties (see the SPWorkflow doc).
So basically something like this should work:
SPListItem item = tasklist[0];
SPWorkflow workflow = item.Workflows[0];
SPList historyList = workflow.HistoryList;
SPList taskList = workflow.TaskList;
However this code pretty much sucks so just use it as a starting point, also you shouldn't use [0] but get the workflow you really want (e.g. by knowing its name).