MS CRM 2013 Attribute parentcustomeridtype must not be NULL if attribute parentcustomerid is not NULL - web-services

Dear smart developers out there,
I encounter a problem when I want to create a contact belonging to an organization in Microsoft Dynamics CRM 2013 via web services
client = new OrganizationServiceClient("CustomBinding_IOrganizationService");
var newContactProperties = new Dictionary<string, object> {
{ "lastname", "TestContact"},
{ "firstname", "A"},
{ "fullname", "A TestContact"}
};
/* organizationType is a CRM.CRMWebServices.OptionSetValue
* with ExtensionData null, PropertyChanged null and a valid Value
*
* orgReference is a CRM.CRMWebServices.EntityReference
* with a valid Id
*/
newContactProperties.Add("parentcustomeridtype", organizationType);
newContactProperties.Add("parentcustomerid", orgReference);
var entity = new Entity();
entity.LogicalName = "contact";
entity.Attributes = new AttributeCollection();
entity.Attributes.AddRange(newContactProperties);
client.Create(entity);
This gives me error 'Attribute parentcustomeridtype must not be NULL if attribute parentcustomerid is not NULL'
I am puzzled why this happens and how I can solve this problem. Please help me if you can.
Thank you,
AllWorkNoPlay

You don't need to set "parentcustomeridtype" attribute separately. It's a system field, will be set by platform and in parentcustomerid exists for legacy reason, when it was Customer type in earlier versions of Dynamics CRM.
You need to specify only EntityReference in lookup field.
newContactProperties.Add("parentcustomerid", new EntityReference("account", new Guid("{accountid guid}")));
Also it's not clear what type you use in "orgReference" field. For contact valid entity types should be "account" or "contact".

thank you for the answers, I did not manage to get it right using web services this way.
I tried using Early Bound access with success:
Generated proxy objects using https://xrmearlyboundgenerator.codeplex.com/
Added line [assembly: Microsoft.Xrm.Sdk.Client.ProxyTypesAssemblyAttribute()] to assemblyInfo to have Intellisense available (even for customized fields)
Now I manage to create a contact and assign it to an organization (something like this):
var contact = new Contact()
{
FirstName = "Bob",
LastName = "Dobalina",
Address1_Line1 = "123 Strasse",
Address1_City = "Berlin",
Address1_PostalCode = "32254",
Telephone1 = "425-555-5678",
EMailAddress1 = "bob.dobalina#germany.de"
};
var account = new Account()
{
Name = "Siemens Germany",
};
context.AddObject(contact);
context.AddObject(account);
context.AddLink(account, "contact_customer_accounts", contact);
context.SaveChanges();
}

Related

JSON.NET causes System.TypeAccessException in Dynamics CRM

I get the below error when running a custom workflow action that uses JSON.NET to serialize a dynamics object to JSON.
Is there a restriction on using reflection in CRM Dynamics customer workflow activities / plugins?
Is it because I am using dynamic variables?
System.TypeAccessException: Attempt by method
'DynamicClass.CallSite.Target(System.Runtime.CompilerServices.Closure,
System.Runtime.CompilerServices.CallSite, System.Object,
System.String)' to access type
'Newtonsoft.Json.Linq.JObject+JObjectDynamicProxy' failed. at
CallSite.Target(Closure , CallSite , Object , String ) at
WSWA.CRM.Logic.MyobIntegrationLogic.CreateInvoice(Boolean retry) at
WSWA.CRM.Workflows.MyobJob.MyobIntegrationTester.Execute(CodeActivityContext
context)
dynamic account = new JObject();
account.UID = GetAccount("Undeposited Funds Account");
dynamic job = new JObject();
job.UID = GetJob("JFC Interiors");
dynamic gstTaxCode = new JObject();
gstTaxCode.UID = GetTaxUidByCode("GST");
dynamic customer = new JObject();
customer.UID = GetCustomerUid("Bar001.test");
dynamic line1 = new JObject();
line1.Total = 22.55;
line1.Account = account;
line1.Job = job;
line1.TaxCode = gstTaxCode;
dynamic line2 = new JObject();
line1.Total = 23.55;
line1.Account = account;
line1.Job = job;
line1.TaxCode = gstTaxCode;
var lines = new JArray();
lines.Add(line1);
lines.Add(line2);
dynamic invoice = new JObject();
invoice.Date = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
invoice.Customer = customer;
invoice.CustomerPurchaseOrderNumber = "PO Number";
invoice.Number = "INV-1000";
invoice.Lines = lines;
var content = new StringContent(contact.ToString());
content.Headers.ContentType = MediaTypeHeaderValue.Parse("text/json");
var responseTask = httpClient.PostAsync(url, content);
Task.WaitAll(responseTask);
You can't use dynamic types in Dynamics (ironic isn't it?) CRM Sandboxed plugins. You can use reflection, as long as whatever you're reflecting is publicly available. i.e. You can use reflection to get a list of public properties, but you can't get a list of private fields.
You can always farm your work out to an Azure service and do whatever you'd like there.
There are known issues with dynamic types and using NuGet packages like Microsoft.AspNet.WebApi.Client.
Could you try with a WebClient?
More info here

What is the preferred method of updating Money fields in Dynamics CRM 2013 via Web Services?

I have an entity in CRM that has some Money fields on them. At the time of the creation of the entity there is no value for those fields, so the entity is created and saved. However if I then have values and go to update them (either through the UI or Web Services) I basically get an error stating "The currency cannot be null".
In the UI:
I then get a red circle with an X through it if I go to update the value.
In the code (web service call):
var crmService = new CrmServiceReference.IFAAContext(new Uri(crmWebServicesUrl));
crmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
var crmAccount = crmService.AccountSet.Where(a => a.AccountId == accountId).FirstOrDefault();
crmAccount.myitems_MoneyValueItem.Value = 10.0m;
crmService.UpdateObject(crmAccount);
crmService.SaveChanges()
I then get the "The currency cannot be null" on the .SaveChanges() call.
In the code (second attempt):
var crmService = new CrmServiceReference.IFAAContext(new Uri(crmWebServicesUrl));
crmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
var crmAccount = crmService.AccountSet.Where(a => a.AccountId == accountId).FirstOrDefault();
var crmCurrency = crmService.TransactionCurrencySet.Where(c => c.ISOCurrencyCode == "AUD").First();
crmService.SetLink(crmAccount, "TransactionCurrency_Account", crmCurrency);
//crmService.SaveChanges() /* tried with this uncommented as well to try and "set currency" before setting value */
crmAccount.myitems_MoneyValueItem.Value = 10.0m;
crmService.UpdateObject(crmAccount);
crmService.SaveChanges()
So this attempt fails in the same way, however if I run it a second time (without the currency and SetLink) so that the currency was saved before then it does work - hence the atempt to do a second .SaveChanges() but really need it to sort of work the first time through.
In the code (third attempt):
var crmService = new CrmServiceReference.IFAAContext(new Uri(crmWebServicesUrl));
crmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
var crmAccount = crmService.AccountSet.Where(a => a.AccountId == accountId).FirstOrDefault();
crmAccount.athos_MoneyValueItem= new CrmServiceReference.Money() { Value = 10.0m };
crmService.UpdateObject(crmAccount);
crmService.SaveChanges()
This doesn't appear to work either
When you create a new record containing a Money field (or updating an existing one where no Money fields are filled before) , you need to specify the currency, the right field to set is TransactionCurrencyId (logical name transactioncurrencyid), it's a lookup (so inside the code is an EntityReference) to the currency entity.
assuming you have the Guid of your currency stored inside the currencyId variable:
var crmAccount = crmService.AccountSet.Where(a => a.AccountId == accountId).FirstOrDefault();
crmAccount.TransactionCurrencyId = new EntityReference(TransactionCurrency.LogicalName, currencyId);
crmAccount.myitems_MoneyValueItem = new Money(10.0m); //better to update the money field with this syntax
crmService.UpdateObject(crmAccount);
crmService.SaveChanges()
CRM 2013 expects a Money object for a currency field.
crmAccount.myitems_MoneyValueItem = new Money(10.0m);
You shouldn't have to explicitly declare a currency unless your CRM organization doesn't have a default currency set (and since you need to set this when creating an organization, it should always be set).
It looks like if I do a lookup on currency (shame as an extra data call) and then use that to set the TransactionCurrencyId it then "works" ... seems like I shouldn't have to do this as I do have a default set for the organisation though. But this does appear to be working in that it results in being able to update those fields.
var crmCurrency = crmService.TransactionCurrencySet.Where(c => c.ISOCurrencyCode == currencyCode).First();
var crmService = new CrmServiceReference.IFAAContext(new Uri(crmWebServicesUrl));
crmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
var crmAccount = crmService.AccountSet.Where(a => a.AccountId == accountId).FirstOrDefault();
crmAccount.TransactionCurrencyId = new CrmServiceReference.EntityReference() { Id = crmCurrency.TransactionCurrencyId, LogicalName = "transactioncurrency", Name = crmCurrency.CurrencyName };
crmAccount.myitems_MoneyValueItem.Value = 10.0m;
crmService.UpdateObject(crmAccount);
crmService.SaveChanges();
i am doing the same thing as you but unable to set the money field value during service.create.
I have already put in
entity.Attributes["transactioncurrencyid"] = currencyGuid;
entity.Attributes["new_moneyfield"] = new Money(123.45M);
but in the end, the record is created with the transactioncurrency field populated, while the money field is blank.
Its a custom workflow on CRM online 2016 by the way..

Invoking AX web service via C#

I am trying to connect to the AX web services. What I will do it to fetch the right price given a product and a customer.
I realised the right webservice to use is PriceListServiceClient and I am able to log in to it using windows authentication, but I cannot retrieve any data from it.
Here is my code:
PriceListServiceClient priceListServiceClient = new PriceListServiceClient();
priceListServiceClient.ClientCredentials.Windows.ClientCredential.UserName = "yyy";
priceListServiceClient.ClientCredentials.Windows.ClientCredential.Password = "zzz!";
priceListServiceClient.ClientCredentials.Windows.ClientCredential.Domain = "xxx";
CriteriaElement[] criteriaElement = new CriteriaElement[1];
criteriaElement[0] = new CriteriaElement();
criteriaElement[0].DataSourceName = "SalesPrice";
criteriaElement[0].FieldName = "ItemId";
criteriaElement[0].Operator = Operator.NotEqual;
criteriaElement[0].Value1 = "5637153175";
QueryCriteria queryCriteria = new QueryCriteria();
queryCriteria.CriteriaElement = criteriaElement;
CallContext callContext = new CallContext();
var found = priceListServiceClient.find(callContext, queryCriteria);
Console.WriteLine(found.Currency);
priceListServiceClient.Close();
Any idea about why this is happening?
Try filling in the properties in the CallContext (company and language).
new CallContext { Company = "zzz", Language = "nl" };
I found the answer here: http://community.dynamics.com/ax/f/33/p/118741/246784.aspx
The Ax class for Price List document is AxPriceDiscTmpPrintout Class. This class wraps the TmpPriceDiscPrintout table, which is a TMP table. That's why you are not getting anything in return.

Select new to create complex object with nested new throws cast exception

Has anyone had this issue? I am trying to get objects from the database and create a complex poco but I get a cast issue.
The Account property on the poco message type is a poco account type and it will tell me that whatever the first field type is can't be cast to PocoAccount, so in the example below, AccountID is an int so i'll get int cant' be cast to PocoAccount.
var result = (from a in DbAccount.All()
join m in DbMessage.All() on m.AccountID equals a.AccountID
select new PocoMessage {
Account = new PocoAccount {
AccountID = a.AccountID,
FirstName = a.FirstName,
LastName = a.LastName
},
MessageID = m.MessageID,
Subject = m.Subject,
Body = m.Body
});
If found a similar post that suggested using ToList() which seems to fix the issue however it doesn't feel quite right and I haven't checked out the sql consequence.
var result = (from a in DbAccount.All().ToList()
join m in DbMessage.All().ToList() on m.AccountID equals a.AccountID
select new PocoMessage {
Account = new PocoAccount {
AccountID = a.AccountID,
FirstName = a.FirstName,
LastName = a.LastName
},
MessageID = m.MessageID,
Subject = m.Subject,
Body = m.Body
});

Managed C++ Web reference to WCF service problems

I deveploped a simple WCF service called CLSAPIService that it's Contract contains a method named UpdateLastOpenCloseCall:
[OperationContract(Name = "UpdateLastOpenCloseCall", Action = "http://uniform.com/UpdateLastOpenCloseCall")]
CallResult UpdateLastOpenCloseCall(int iSwitchID, int iAgentID, string strExtension, BusinessDataField[] bdFields);
One of its parameters is a simple DataContract:
[DataContract]
public struct BusinessDataField
{
[DataMember]
public string Name;
[DataMember]
public object Value;
}
Then I created a simple testing project in Managed C++ in Visual .Net 2005, and created web reference for the service:
CLSAPIProxy::CLSAPIService^ service = gcnew CLSAPIProxy::CLSAPIService();
CLSAPIProxy::BusinessDataField ^f1 = gcnew CLSAPIProxy::BusinessDataField();
f1->Name = L"test_string";
f1->Value = L"string";
CLSAPIProxy::BusinessDataField ^f2 = gcnew CLSAPIProxy::BusinessDataField();
f2->Name = L"test_int";
f2->Value = 123;
System::Collections::Generic::List<CLSAPIProxy::BusinessDataField^> ^list = gcnew;
System::Collections::Generic::List<CLSAPIProxy::BusinessDataField^>();
list->Add(f1);
list->Add(f2);
service->UpdateLastOpenCloseCall(1,true,22817,true,L"24319",list->ToArray());
When the BusinessDataField structure arrives to the WCF method, it appears that only the Value property is updated, and the Name property is null, even though I assiged it a value.
What could be the problem?
please add Order to your data member.
[DataMember(Name = "FirstName", IsRequired = true, Order = 2)]
and consult the following article:
Change The Order Of data members