Showing posts with label CRM. Show all posts
Showing posts with label CRM. Show all posts

Monday, October 6, 2008

CRM Error: Generic SQL Error Code: 0x80044150

So, I have seen and checked very proposed solution to this error on the web.

The only problem associated with this issue I did not see any record of is of course the error I had with a customer recently...

The issue is complicated-simple issue...

Simple explanation would be:
Once you export and entity, add a new attribute with the same name as an existing one (not case sensitive - meaning 1= new_myattribute 2=New_myattribute) you will get this error.

Simple, Right?

Now, for the complicated way of getting this error...

Normally, the CRM will lower-case all letters in the attribute and add the "new_" prefix for you.

So - when looking for a property to check if it exists I used to have a lower-case case sensitive XML XPath search for it, and if I did not find it - I knew it was safe to add it...

Only that apparently the CRM 3.0 and CRM 4.0 has some inconsistency with the prefix of custom attributes...

One adds new_ while the other adds New_, this means that one of our customers who used the CRM SharePoint connector in CRM 3.0, upgraded the solution to CRM 4.0, and run our solution again - ended up with this error message since he had the old field from the upgrade and we were trying to add it as duplicated in the new version since we could not find it...

Well - complicated enough?

I will keep the conclusion short -
1: Be sure not to add duplicate attributes, or import will fail.
2: When looking for attributes - don't use case-sensitive comparison (although tempting in XML)!
3: Email the CRM developer guys and request nicely for better error messages ( don't tell them I sent you :) )

Well, Please feel free to post here any other problems / solutions related to this very generic error code.

Just for the record - the error code mostly refers to trying to assign data into a field that is too long... so if you didn't check that first - this would be a good time to do so... :)

Friday, June 27, 2008

CRM 4 Web Service 401: Unauthorized error

Hi all,

Been upgrading some of our CRM 3.0 components to CRM 4.0 version, just to find out a lot was changed in the web services access.

For one, now that CRM supports hosted mode, more than one organization could be configured so now you have to set up the organization you are working on with your web services serquests.

This did not took me long to find out - just call the CrmDiscoveryService, create a new RetrieveOrganizationsRequest request, and execute it.
Code:
crmDisco.CrmDiscoveryService ds = new KWizCom.CRM.Utility.crmDisco.CrmDiscoveryService();
ds.Url = CrmWebServicesUrl + "AD/CrmDiscoveryService.asmx";
ds.PreAuthenticate = true;
ds.UseDefaultCredentials = true;
//create request
crmDisco.RetrieveOrganizationsRequest r = new KWizCom.CRM.Utility.crmDisco.RetrieveOrganizationsRequest();
crmDisco.RetrieveOrganizationsResponse rr = (crmDisco.RetrieveOrganizationsResponse)ds.Execute(r);
SetOrganization(rr.OrganizationDetails[0]);


And now that you got your organization (first one in the array), you need to use it when calling all other web service (example: creating CrmService and MetadataService
Code:
crmMeta.CrmAuthenticationToken token = new crmMeta.CrmAuthenticationToken();
token.OrganizationName = this.Organization.OrganizationName;
token.AuthenticationType = Enums.AuthenticationType.AD;

this.metadataService = new crmMeta.MetadataService();
this.metadataService.Url = this.Organization.CrmMetadataServiceUrl;
this.metadataService.CrmAuthenticationTokenValue = token;
this.metadataService.PreAuthenticate = true;
this.metadataService.UseDefaultCredentials = true;

crm.CrmAuthenticationToken token2 = new crm.CrmAuthenticationToken();
token2.OrganizationName = this.Organization.OrganizationName;
token2.AuthenticationType = Enums.AuthenticationType.AD;

this.crmService = new crm.CrmService();
this.crmService.Url = this.Organization.CrmServiceUrl;
this.crmService.CrmAuthenticationTokenValue = token2;
this.crmService.PreAuthenticate = true;
this.crmService.UseDefaultCredentials = true;


Now you are all set for using the web services Under The Current User Account!!!.

What if, like me, you need to call the web service using a user name and password?

The logical to do is impersonation in web services 101:
Create a NetworkCredential Object, and set it to your crmService.Credentials,
like so:
ICredentials WebServiceCredentials = new System.Net.NetworkCredential(userName,password,domain);
this.crmService.UseDefaultCredentials = false;
this.crmService.Credentials = WebServiceCredentials;


Right? Wrong!

CRM web service will return 401 error (unauthorized access) every time you do it.

The solution for this was found in a great msdn post:
http://msdn.microsoft.com/en-us/library/cc151049.aspx

The I found that the web service credentials must not be changed at all.
What needs to be done it to make the request under a user with permissions to the CRM (like administrator or something), and pass the user name and password in the request itself.

For getting the organization, you will need to modify your code like this:
crmDisco.CrmDiscoveryService ds = new KWizCom.CRM.Utility.crmDisco.CrmDiscoveryService();
ds.Url = CrmWebServicesUrl + "AD/CrmDiscoveryService.asmx";
ds.PreAuthenticate = true;
ds.UseDefaultCredentials = true;
//create request
crmDisco.RetrieveOrganizationsRequest r = new KWizCom.CRM.Utility.crmDisco.RetrieveOrganizationsRequest();
if (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password))
{
r.UserId = this.Domain + "\\" + this.UserName;
r.Password = this.Password;
}

crmDisco.RetrieveOrganizationsResponse rr = (crmDisco.RetrieveOrganizationsResponse)ds.Execute(r);

SetOrganization(rr.OrganizationDetails[0]);


And also - you will have to get a ticket for the other web services authentication:
RetrieveCrmTicketRequest ticketRequest = new RetrieveCrmTicketRequest();
ticketRequest.OrganizationName = Organization.OrganizationName;
ticketRequest.UserId = this.Domain + "\\" + this.UserName;
ticketRequest.Password = this.Password;
ticketResponse = (RetrieveCrmTicketResponse)ds.Execute(ticketRequest);


Using the response later when you configure your other web services like so:

crmMeta.CrmAuthenticationToken token = new crmMeta.CrmAuthenticationToken();
token.OrganizationName = this.Organization.OrganizationName;
token.AuthenticationType = Enums.AuthenticationType.AD;
if( ticketResponse != null )
token.CrmTicket = ticketResponse.CrmTicket;

this.metadataService = new crmMeta.MetadataService();
this.metadataService.Url = this.Organization.CrmMetadataServiceUrl;
this.metadataService.CrmAuthenticationTokenValue = token;
this.metadataService.PreAuthenticate = true;
this.metadataService.UseDefaultCredentials = true;

crm.CrmAuthenticationToken token2 = new crm.CrmAuthenticationToken();
token2.OrganizationName = this.Organization.OrganizationName;
token2.AuthenticationType = Enums.AuthenticationType.AD;
if (ticketResponse != null)
token2.CrmTicket = ticketResponse.CrmTicket;

this.crmService = new crm.CrmService();
this.crmService.Url = this.Organization.CrmServiceUrl;
this.crmService.CrmAuthenticationTokenValue = token2;
this.crmService.PreAuthenticate = true;
this.crmService.UseDefaultCredentials = true;


Now, you should be able to call the web services with impersonation to other CRM accounts...

Hope this helps you, I sure got stuck on this for a while.

Thanks, Shai.