ian.blair@softstuff

My technical musings

Writing data to a Won Opportunity

Having recently had a requirement to tag Won opportunities with new data to show that they have been superseded it initially seemed that the only way to do it was to reset the opportunity to draft, update it, then reset it back to Won, which is not an ideal method especially as it then marks the opportunity as Won on the day that you reset it.

It turns out that the method to do this is extremely simple, and is perhaps a little hacky and might not last forever but for now it works.

The simplest way to do it is to

Entity newEntity = new Entity("opportunity");
newEntity.Id = opportunity.Id;
newEntity.Attributes.Add("myfield_toupdate", true);
OrganizationService.Update(newEntity);

That's all there is to it, while you can't update the entity you return in a search, you can create a new one, assign the ID and then update the field and Update that.  Simple.

 

Of course it might be worth while adding a fallback routine in just in case.

try {
     ServiceContext.Trace("First try to just edit the fields");
     Entity newEntity = new Entity("opportunity");
     newEntity.Id = opportunity.Id;
     newEntity.Attributes.Add("myfield_toupdate", true);                                       
     OrganizationService.Update(newEntity);           
    }
catch {                                   
         var statusCode = opportunity.StatusCode;
         var dateClose =  opportunity.ActualCloseDate;
         SetStateRequest setState = new SetStateRequest {
                      EntityMoniker=opportunity.ToEntityReference(),
                      State=OpportunityState.Open.ToOsv()  ,
                      Status = opportunity_statuscode.InProgress.ToOsv()
                      };
         OrganizationService.Execute(setState);
         opportunity["myfield_toupdate"]=true;                                        
         var win = new WinOpportunityRequest {
                      OpportunityClose = new OpportunityClose {
                      OpportunityId = opportunity.ToEntityReference(),
                      ActualEnd = dateClose,  // slight bug in api causes this to ignored
                      ScheduledEnd = dateClose 
                      },
                      Status = statusCode,                                           
                      };
         OrganizationService.Execute(win);                                    
       }

By adding the old school make draft, update, then win code in the try..catch block at least if in future versions this code stops working then at least your code wont get any unexpected surprises, at least apart from the ActualEnd date as that always seems to be set to the date you fire the WinOpportunityRequest even if you set it explicitly.

 

 

Old vs New Connection Methods in CRM2016/Dynamics 365

With the release of the new version of the Crm2016/Dynamics365 SDK the recommended method to connect to CRM in code has changed.

Originally it was (although other methods were available with connection strings)

using Microsoft.Xrm.Sdk;
using System.ServiceModel.Description;

var url = "http://mycrmsystem/XRMServices/2011/Organization.svc";
var username = "myusername";
var password = “mypassword";
var domain = ""
var organizationUri = new Uri(url);            
var credentials = new ClientCredentials();
credentials.UserName.UserName = domain + username;
credentials.UserName.Password = password;
credentials.Windows.ClientCredential.UserName = username;
credentials.Windows.ClientCredential.Password = password;
credentials.Windows.ClientCredential.Domain = domain;

using (OrganizationServiceProxy _service = new OrganizationServiceProxy(organizationUri, null, credentials, null)) {
// code to do stuff goes here
}

With the advent of the tooling connector dll and the other changes in the api this should now be changed to:

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Tooling.Connector;
using System.ServiceModel;

var connectionString = "url=https://mycrmsystem; Username=myusername; Password=mypassword; authtype=Office365";
CrmServiceClient conn = new CrmServiceClient(connectionString);
using (OrganizationServiceProxy orgService = conn.OrganizationServiceProxy) {
     if (conn.IsReady) {
          // code to do stuff goes here
      }else{
         throw new invalidoperationexception(conn.LastCRMError);
      }
}

The key now is the connection string as this determines the connection method with the authtype= parameters.

The example above assumes you are connecting to a Office365 hosted CRM system but if you were connecting to an on-premise active directory system the connection string might be

var connectionString = "url=https://mycrmsystem/myorg; Username=myusername; Password=mypassword; Domain=mydomain; authtype=AD";

 

The other feature is the .IsReady property, if this is set to true the connection has been successful and can be used for further processing, otherwise the properties .LastCRMError and .LastCRMException can be checked to see what went wrong.