问题
I'm receiving an error while trying to retrieve systemuser information from Dynamics CRM 2011. The following Code works:
public List<CrmUser> GetAllCrmUsers()
{
List<CrmUser> CrmUsers = new List<CrmUser>();
using (CrmSdk.OrganizationServiceClient myCrm = new CrmSdk.OrganizationServiceClient("CustomBinding_IOrganizationService1"))
{
try
{
// this will need to be changed... the address to a key in the app.config and the credentials will need to be whatever is correct for the
// end server to hit the CRM WCF service
myCrm.Endpoint.Address = new System.ServiceModel.EndpointAddress("https://devcrm.removed/XRMServices/2011/Organization.svc");
myCrm.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
CrmSdk.ColumnSet colsPrincipal = new CrmSdk.ColumnSet();
colsPrincipal.Columns = new string[] { "lastname", "firstname", "domainname", "systemuserid" };
CrmSdk.QueryExpression queryPrincipal = new CrmSdk.QueryExpression();
queryPrincipal.EntityName = "systemuser";
queryPrincipal.ColumnSet = colsPrincipal;
CrmSdk.EntityCollection myAccounts = myCrm.RetrieveMultiple(queryPrincipal);
foreach (CrmSdk.Entity myEntity in myAccounts.Entities)
{
//create new crm users and add it to the list
CrmUser thisOne = new CrmUser();
thisOne.firstName = myEntity.Attributes[0].Value.ToString();
thisOne.lastName = myEntity.Attributes[1].Value.ToString();
thisOne.userId = myEntity.Attributes[2].Value.ToString();
thisOne.userGuid = myEntity.Attributes[3].Value.ToString();
CrmUsers.Add(thisOne);
}
}
catch (Exception ex)
{
CrmUser thisOne = new CrmUser();
thisOne.firstName = "Crap there was an error";
thisOne.lastName = ex.ToString();
CrmUsers.Add(thisOne);
}
}
return CrmUsers;
}
However if I try to add "businessunitid" to the ColumnSet when I invoke the service I get an error stating:
"Error in line 1 position 1879. Element \ 2004/07/System.Collections.Generic:value\' contains data from a type that maps to the name \'/xrm/2011/Contracts:OptionSetValue\'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to \'OptionSetValue\' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.\'"
This error is because the data being returned is the type "Lookup" according to the metadata information. I tried adding [KnownType(typeof(OptionSetValue))] just under the [Data Contract] tag to no avail and I've been Googling and Binging(?) this for two days now so if it's already been answered I apologize.
回答1:
Just leverage Microsoft.Xrm.Client. It provides you with CrmConnection, a simplified way to connect to the system.
I also suggest (but it's probably more a matter of taste/needs) to always read attributes through GetAttributeValue<> for more readable code.
Full working sample including BU id:
// helper class
public static class CommonCrm
{
public static readonly CrmConnection crmConnection = null;
public static readonly OrganizationService crmService = null;
public static readonly CrmOrganizationServiceContext crmContext = null;
static CommonCrm()
{
try
{
CommonCrm.crmConnection = new CrmConnection("Crm");
// "Crm" is a connection string which goes like this in Web.config:
//<connectionStrings>
// <add name="Crm" connectionString="Url=http://orgUrl; Domain=X; Username=Y; Password=Z;" />
//</connectionStrings>
CommonCrm.crmService = new OrganizationService(crmConnection);
CommonCrm.crmContext = new CrmOrganizationServiceContext(crmService);
}
catch (Exception ex)
{
//Log exception (code removed)
throw;
}
}
}
public class CrmUser
{
public string firstName { get; set; }
public string lastName { get; set; }
public string userId { get; set; }
public Guid userGuid { get; set; }
public Guid buId { get; set; }
public static List<CrmUser> GetAllCrmUsers()
{
List<CrmUser> CrmUsers = new List<CrmUser>();
try
{
ColumnSet colsPrincipal = new ColumnSet("lastname", "firstname", "domainname", "systemuserid", "businessunitid");
QueryExpression queryPrincipal = new QueryExpression();
queryPrincipal.EntityName = "systemuser";
queryPrincipal.ColumnSet = colsPrincipal;
var myAccounts = CommonCrm.crmContext.RetrieveMultiple(queryPrincipal);
foreach (var myEntity in myAccounts.Entities)
{
//create new crm users and add it to the list
CrmUser thisOne = new CrmUser();
thisOne.firstName = myEntity.GetAttributeValue<string>("firstname");
thisOne.lastName = myEntity.GetAttributeValue<string>("name");
thisOne.userId = myEntity.GetAttributeValue<string>("domainname");
thisOne.userGuid = myEntity.GetAttributeValue<Guid>("systemuserid");
thisOne.buId = myEntity.GetAttributeValue<EntityReference>("businessunitid").Id;
// and so on and so forth...
CrmUsers.Add(thisOne);
}
}
catch (Exception ex)
{
CrmUser thisOne = new CrmUser();
thisOne.firstName = "Crap there was an error";
thisOne.lastName = ex.ToString();
CrmUsers.Add(thisOne);
}
return CrmUsers;
}
}
回答2:
I finally found it. You have to open the auto generated Reference.cs code. Do a search for the entity class:
public partial class Entity : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
Go to the line above it and add the known type stuff so the entity can de-serialize it.
[System.Runtime.Serialization.KnownTypeAttribute(typeof(EntityReference))]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(OptionSetValue))]
public partial class Entity : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
来源:https://stackoverflow.com/questions/16921425/error-when-trying-to-receive-information-from-crm-2011-webservice