Updating StateCode in Dynamics CRM with web service failes - c#

Im trying to update "StatE Code" (Active|Inactive) to Active through the CRM web service on a product in the database.
...
crmProduct.statecode = new ProductStateInfo() { Value = ProductState.Active };
//crmProduct.statuscode = new Status() { Value = 1 };
crmProduct.name = "...";
service.Update(crmProduct);
It seem to work okay, I get no errors and the name changes, but its still Inactive!
When trying to set "StatUS Code" as well to Active, I get an error saying I cant set status to Active when state is Inactive... but Im setting both to Active at the same time... hmmmm.. dont now whats wrong here...
Any clues?

Setting the state code in an entity has no effect when you save it. You must use an appropriate SetState request. As Matt said, for dynamic entities this is the SetStateDynamicEntityRequest. In your case I am assuming you are using a "product" object, so you need to use the SetStateProductRequest class.
var request = new SetStateProductRequest()
{
EntityId = [GUID of product],
ProductState = ProductState.Active,
ProductStatus = -1
}
var response = (SetStateProductResponse)crmService.Execute(request);
Check out this link: http://msdn.microsoft.com/en-us/library/bb958061.aspx
The -1 for the ProductStatus tells CRM to use to appropriate default statuscode value for the statecode.

You have to use the SetStateDynamicEntityRequest to update the state of a record. You can update the statuscode using the regular update message, but only if the code you're updating to is in the same state that the record is currently in, as you've found.

Related

CRM - SuppressDuplicateDetection for custom entity

My mvc application is updating the status on a custom entity in CRM dynamics 2015. we have a plugin which gets triggered when we update a specific status. We are facing a concurrency issue here, when two different is trying to update the same status at a same time on the entity, the status gets updated twice and system fires the plugin twice.
I tried using in my MVC code but it gives an error. Seems like i cannot use it on custom entity
Portal.abcclaim obj= new Portal.abcclaim ();
obj.Attributes["abcclaimreceiveddate"] = Convert.ToDateTime(DateTime.Now);
obj.Attributes["abcdateclaimsubmitted"] = Convert.ToDateTime(DateTime.Now);
obj.Attributes["abcmodifiedbycontact"] = new EntityReference(Portal.Contact.EntityLogicalName, loggedInId);
obj.Attributes["abcstatus"] = new EntityReference(Portal.abc_status.EntityLogicalName, status);
obj.Attributes["SuppressDuplicateDetection"] = false;
obj.Id = objid;
serviceProxy.Update(obj);
is there any other way to handle this?
You should use dedicated request if you want to set request parameters. In yours case it will be UpdateRequest (https://learn.microsoft.com/en-us/dotnet/api/microsoft.xrm.sdk.messages.updaterequest?view=dynamics-general-ce-9).
var updateRequest = new UpdateRequest()
{
Target = obj,
};
updateRequest["SuppressDuplicateDetection"] = false;
var response = (UpdateResponse)osvc.Execute(updateRequest);
But it doesn't look like duplicate detection will solve concurrency problems. You should check check how to use ConcurrencyBehavior parameter. You can read more about concurrency in Dynamics 365 in this MS docs article: https://learn.microsoft.com/en-us/powerapps/developer/common-data-service/optimistic-concurrency
Hope that helps.

Get related entity statecode value to use as a check

I need to be able to only execute my code upon the condition that the related opportunity has a statecode of 1
In my code I am able to use the GenerateSalesOrderFromOpportunityRequest class provided by the Microsoft Dynamics SDK to create a new sales order when a opportunityclose activity is created.
The drawback of this approach is that an opportunityclose activity is created by the system when an opportunity is closed as won(1) or lost(2). Also, there are no attributes on the opportunityclose activity that say if it was won or lost. So the only way to find it out is to get that attribute from the related opportunity.
In my code I'm able to get other attributes from the related opportunity, like name, but I have not been able to get any other value for statecode other that 0.
Here is my code:
Entity postImageEntity = (context.PostEntityImages != null && context.PostEntityImages.Contains(this.postImageAlias)) ? context.PostEntityImages[this.postImageAlias] : null;
if (postImageEntity.LogicalName == "opportunityclose" && postImageEntity.Attributes.Contains("opportunityid") && postImageEntity.Attributes["opportunityid"] != null)
{
// Create an entity reference for the related opportunity to get the id for the GenerateSalesOrderFromOpportunityRequest class
EntityReference entityRef = (EntityReference)postImageEntity.Attributes["opportunityid"];
// Retrieve the opportunity that the closed opportunity activity was created for.
Entity RelatedEntityRef = service.Retrieve("opportunity", entityRef.Id, new ColumnSet( new String[] {"statecode","statuscode", "name"}));
OptionSetValue StateCode = (OptionSetValue)RelatedEntityRef.Attributes["statecode"];
OptionSetValue StatusCode = (OptionSetValue)RelatedEntityRef.Attributes["statuscode"];
string OppName = (string)RelatedEntityRef.Attributes["name"];
if (entityRef.LogicalName == "opportunity" && StateCode.Value == 1)
{
try
{
GenerateSalesOrderFromOpportunityRequest req = new GenerateSalesOrderFromOpportunityRequest();
req.OpportunityId = entityRef.Id;
req.ColumnSet = new ColumnSet(true);
GenerateSalesOrderFromOpportunityResponse resp = (GenerateSalesOrderFromOpportunityResponse)service.Execute(req);
}
catch (FaultException ex)
{
throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
}
}
}
Recap: For this to work I just need to be able to get the actual statecode value of the opportunity related to the opportunityclose. Currently I have only been able to get 0 even if I know that the state code of the opportunity is 1.
Other Info:
This is for Microsoft Dynamics Online 2013/2015(works with both)
Using SKD v6.1.1
Plugin works, but fires whether the opportunity is won or lost. (not intended)
Can't you view the opportunity to see if the status is won or lost. I
You can retrieve the OpportunityClose and change the status if you need to
https://msdn.microsoft.com/en-us/library/gg334301.aspx
I assume it's setting the opportunityclose to 1 because you are executing GenerateSalesOrderFromOpportunityRequest which you would only do if you won the opportunity (e.g. you wouldn't progress a lost opportunity).

Cannot assign new value to a read-only attribute

I am working with an SDK that can query a set of data as well as update data with a restful web service called VersionOne. We use the web service to document QA testing. Each test has attributes such as "Name", "Status", etc. Most of the attributes have been successfully updating except for "Status".
Here is the method I am calling, when I step through the code I can get the old value but cannot change the attribute value as expected. An error stating "Cannot assign new value to a read-only attribute".
public bool TestInProgress()
{
var testId = Oid.FromToken("Test:26017", _context.MetaModel);
var query = new Query(testId);
var assetType = _context.MetaModel.GetAssetType("Test");
var testStatus = assetType.GetAttributeDefinition("Status.Name");
query.Selection.Add(testStatus);
var result = _context.Services.Retrieve(query);
var test = result.Assets[0];
var oldResult = GetValue(test.GetAttribute(testStatus).Value);
test.SetAttributeValue(testStatus, "Failed");
_context.Services.Save(test);
LogResult(test.Oid.Token, oldResult, GetValue(test.GetAttribute(testStatus).Value));
Console.WriteLine(test.Oid.Token, oldResult, GetValue(test.GetAttribute(testStatus).Value));
return true;
}
https://github.com/versionone/VersionOne.SDK.Net.APIClient#attribute-definition
According to the VersionOne SDK documentation it appears as though "read-only" and is an attribute. I've looked though the different attribute from several different tests and testsets and do not see it. I am authenticated properly and have successfully updated other attributes with many different tests. However, when I attempt to programmatically change the "Status" attribute it says it is read-only.
https://github.com/versionone/VersionOne.SDK.Net.APIClient#learn-by-example-apiclient-setup
How do you change the attribute for an asset in VersionOne programmatically that is currently read-only so you can update the attribute using the restful web service?
Because the Attribute is read-only, you will not be able to change its value. Instead, consider creating a 'new' Asset, set its Attributes, and then save it.
Review the example below and attempt to utilize the idea within your project:
var TestId = Oid.FromToken("Test:26017", _context.MetaModel);
var TestAsset = _context.MetaModel.GetAssetType("Test");
var newTestAsset = _context.Services.New(TestAsset, TestId);
var TestStatusAttr = newTestAsset.GetAttributeDefinition("Status.Name");
newTestAsset.SetAttributeValue(TestStatusAttr, "Failed");
_context.Services.Save(newTestAsset);

CRM 2011 update incident when email arrives

In CRM when emails arrive and have the tracking token in them they automatically set the regarding field to be the incident (or whatever they relate to)
Unfortunately the Record wall isn't updated with this info so even if you are following the case nothing alerts you to the new activity.
I want to write a plugin on email or incident (or both) that updates the record wall and creates a task to follow up on that email with in 3 days.
I'm looking at the SDK and I can't see what the appropriate event in the pipe line would be to work out when an email is/has its regarding field set on arrival in the CRM.
The CRM email creation life-cycle is not well described in the documentation. [shakes fist]
Extra things that are bothering me
I can't seem to include a reference to get a strongly typed Email, Post or Case (driving me crazy)
Testing this is really hard (harder than it should be)
EDIT Here is my current code
namespace Assembly.Plugins
{
using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
/// <summary>
/// PostEmailDeliverIncoming Plugin.
/// </summary>
public class PostEmailDeliverIncoming : Plugin
{
/// <summary>
/// Initializes a new instance of the <see cref="PostEmailDeliverIncoming"/> class.
/// </summary>
public PostEmailDeliverIncoming()
: base(typeof(PostEmailDeliverIncoming))
{
RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(40, "DeliverIncoming", "email", ExecutePostEmailDeliverIncoming));
// Note : you can register for more events here if this plugin is not specific to an individual entity and message combination.
// You may also need to update your RegisterFile.crmregister plug-in registration file to reflect any change.
}
protected void ExecutePostEmailDeliverIncoming(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService = localContext.TracingService;
// Obtain the execution context from the service provider.
IPluginExecutionContext context = localContext.PluginExecutionContext;
// Obtain the organization service reference.
var service = localContext.OrganizationService;
// The InputParameters collection contains all the data passed in the message request.
if (!context.InputParameters.Contains("Target") || !(context.InputParameters["Target"] is Entity))
return;
// Obtain the target entity from the input parmameters.
var target = (Entity)context.InputParameters["Target"];
// Verify that the target entity represents an account.
// If not, this plug-in was not registered correctly.
if (target.LogicalName != "email")
return;
if((string)target["direction"] != "Incoming")
return;
if (target["regardingobjectid"] == null)
return;
try
{
// if its not a case I don't care
var incident = service.Retrieve("incident", (Guid)target["regardingobjectid"], new ColumnSet(true));
if (incident == null)
return;
var post = new Entity("post");
post["regardingobjectid"] = target["regardingobjectid"];
post["source"]=new OptionSetValue(0);
post["text"] = String.Format("a new email has arrived.");
// Create the task in Microsoft Dynamics CRM.
tracingService.Trace("FollowupPlugin: Creating the post.");
service.Create(post);
// Create a task activity to follow up with the account customer in 7 days.
var followup = new Entity("task");
followup["subject"] = "Follow up incoming email.";
followup["description"] = "An email arrived that was assigned to a case please follow it up.";
followup["scheduledstart"] = DateTime.Now.AddDays(3);
followup["scheduledend"] = DateTime.Now.AddDays(3);
followup["category"] = context.PrimaryEntityName;
// Refer to the email in the task activity.
if (context.OutputParameters.Contains("id"))
{
var regardingobjectid = new Guid(context.OutputParameters["id"].ToString());
followup["regardingobjectid"] = new EntityReference("email", regardingobjectid);
}
// Create the task in Microsoft Dynamics CRM.
tracingService.Trace("FollowupPlugin: Creating the task activity.");
service.Create(followup);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in the FollupupPlugin plug-in.", ex);
}
catch (Exception ex)
{
tracingService.Trace("FollowupPlugin: {0}", ex.ToString());
throw;
}
}
}
}
I've just been fighting with this exact same issue and came across this post. I thought I'd post the solution for you (if you still need it) and anyone else who comes across the issue in the future.
Here's the solution I arrived at:
- Using the Plugin Registration Tool register a New Image on the appropriate step( Stage = "40", MessageName = "DeliverIncoming")
- Set the New Image to be a Post Image
- In your plugin fetch the Post Image's entity ID:
Guid emailID = context.PostEntityImages["PostImage"].Id;
Entity emailFromRetrieve = localContext.OrganizationService.Retrieve(
"email",
emailID,
new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
Email email = emailFromRetrieve.ToEntity<Email>();
if (email.RegardingObjectId == null)
{
return;
}
var regardingObject = email.RegardingObjectId;
Hope this helps!
I'm actually working on a very similar plugin at the moment. Mine creates a custom entity upon arrival of an email addressed to a certain email address. It also associates the incoming email with that new record via the Regarding field. I've added a Pre-Operation step on Create of Email and it works great, including incoming email from the router.
What I'm not sure of is when CRM fills in the Regarding field. You might look at Post-Operation and see if it is set there?
One interesting caveat regarding the Regarding field (haha!): Unlike single lookup fields, the Regarding object's name is actually stored in the ActivityPointer table, so when you update the Regarding field, be sure to set the Name on the EntityReference. If you don't, the Regarding lookup will still have a clickable icon but there won't be any text. I do it like this:
email.RegardingObjectId = [yourentity].ToEntityReference();
email.RegardingObjectId.Name = email.Subject;
Hope that helps!
I ended up doing this in a workflow on the email entity
Steps
Create new workflow, I called it 'incoming email workflow'
Scope is Organisation
Choose Email as the entity and check 'Record field changes'
Add a step that checks Regarding (Case):Case Contains Data
if true:
Add a step that creates a Post
Edit the properties in the Post
Text : This case has had {Direction(E-mail)} email activity from {From(E-mail)}
Source : Auto Post
Regarding : {Regarding(E-mail)}
Add a step that creates a Task
Edit the properties in the Task
Subject : Follow up {Subject(E-mail)}
Regarding : {Regarding(E-mail)}
Try to use the following code:
if ((bool)entity["directioncode"] == false)
Instead of your code:
if((string)target["direction"] != "Incoming")

CreateOrganizationProfile error Object reference not set to an instance of an object

I'm using Microsoft code to create a new Organisation in the User Profile Server, as per http://msdn.microsoft.com/en-us/library/ms545122.aspx.
Every time I call CreateOrganizationProfile I get the following:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Office.Server.UserProfiles.OrganizationProfile.set_Parent(ProfileBase value)
The exact code I'm using is:
[WebMethod]
public void CreateOrganisation(string OrganisationName)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(_serverName))
{
// Removing this will cause the error "Operation is not valid due to the current state of the object".
HttpContext.Current = null;
SPServiceContext context = SPServiceContext.GetContext(site);
ProfileSubtypeManager psm = ProfileSubtypeManager.Get(context);
// choose default organization profile subtype as the subtype
string subtypeName = ProfileSubtypeManager.GetDefaultProfileName(ProfileType.Organization);
ProfileSubtype subType = psm.GetProfileSubtype(subtypeName);
OrganizationProfileManager opm = new OrganizationProfileManager(context);
// choose Root Organization as the parent
OrganizationProfile parentOrg = opm.RootOrganization;
// create an organization profile and set its display name
OrganizationProfile profile = opm.CreateOrganizationProfile(subType, parentOrg);
profile.DisplayName = "Test Org1";
// commit to save changes
profile.Commit();
}
});
return;
}
Curiously, somebody else ran into the exact problem here http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/7b5101fd-0ea6-4716-82b1-ac4609b9973c/, but it was never resolved.
I've confirmed the User Profile Service is running and responding. Also, parentOrg and subtypeName are not null when calling CreateOrganizationProfile.
Does anybody have anything I can try, or can anybody spot what might be the problem?
Very grateful!
I had the same problem and I fixed it by changing the line
OrganizationProfile parentOrg = opm.RootOrganization;
To
OrganizationProfile parentOrg = (OrganizationProfile)opm.GetProfile(1);
GetProfile(1) returned the RootOrganization in my case.
Hope this helps someone!
I am no sharepoint expert but this http://msdn.microsoft.com/en-us/library/microsoft.office.server.userprofiles.organizationprofilemanager.createorganizationprofile.aspx states that you need user profile administrative permissions and this http://msdn.microsoft.com/en-us/library/microsoft.office.server.userprofiles.organizationprofile.parent.aspx could be hint that you need user profile manager permission to do what you are trying to do.
EDIT:
since your code try to "write" something this seems relevant http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsecurity.runwithelevatedprivileges.aspx
basically it says you are missing a call to SPUtility.ValidateFormDigest() or SPWeb.ValidateFormDigest() before calling SPSecurity.RunWithElevatedPrivileges

Categories

Resources