Calling WCF Rest Service from a Plugin in CRM 2011 (Online)


Let us take a simple rest service example here

http://www.rockycherry.net/services/Photos/photos.svc/photos

It returns the string “You have asked for photos”.

Within the plugin class add references to following assemblies.

The sample code of the plugin


namespace TestPlugin
{
 public class Class1 : IPlugin
 {
 public void Execute(IServiceProvider serviceProvider)
 {
 IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

 if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
 {

// using WebClient
 WebClient webClient1 = new WebClient();
 string data1 = webClient1.DownloadString("http://www.rockycherry.net/services/Photos/photos.svc/photos");

// using WebChannelFactory
 WebChannelFactory<IPhotos> factory = new WebChannelFactory<IPhotos>(new Uri("http://www.rockycherry.net/services/Photos/photos.svc"));
 IPhotos proxy = factory.CreateChannel();
 string photos = proxy.GetPhotos();

 }

 }
 }

[ServiceContract]
 public interface IPhotos
 {
 [WebGet(UriTemplate = "Photos")]
 [OperationContract]
 string GetPhotos();
 }
}


Register the plugin in Sandbox mode for CRM 2011 online.

Check this wonderful post for all the details

http://rockycherry.net/blog/?p=179

Hope it helps.

Enable Sub Grid for Contract Line (ContractDetail) entity in CRM 2011


Hi,

OOB if we try to add\insert sub grid for Contract Line entity in an Entity’s Form we would realize that the Contract Line entity doesn’t show up in the Entity drop down there.

The UNSUPPORTED way to get it enabled is to

Open the OrgName_MSCRM database

Run the following query

update metadataschema.entity

set  IsChildEntity=0

where name=‘contractdetail’

This will let us add the sub grid for the contract line entity.

Bye.

Import User Profile properties in SharePoint 2013 from CRM 2011 using BCS.


For import to work  we will first define our WCF Service.

We could refer to this post first on how to define and use the WCF Service.

https://nishantrana.wordpress.com/2013/06/13/integrating-crm-2011-and-sharepoint-2013-using-bcs-wcf-service-crud-operation/

Here as we are not going to perform update, delete or create operation we don’t have to implement those methods.

Here we would be defining only Read Item, Read List and IdEnumerator Operation of BCS.

IdEnumerator method enables external data search in SharePoint and will be used while defining new profile synchronization connection.

For our scenario we have created a custom entity named Lawyer in our CRM System. These Lawyers are SharePoint user (AD User)

 



[ServiceContract]
 public interface IWCFLawyer
 {

[OperationContract]
 string[] GetLawyerLoginIDs();

[OperationContract]
 IEnumerable<WCFCustomType> ReadList();

[OperationContract]
 WCFCustomType ReadItem(String lawyerLoginID);

 }


 [DataContract]
 public class WCFCustomType
 {
 String lawyerLoginID;
 string practiceDetail;
 DateTime lawyerAvailability;

[DataMember]
 public String LawyerLoginID
 {
 get { return lawyerLoginID; }
 set { lawyerLoginID = value; }
 }

[DataMember]
 public string PracticeDetail
 {
 get { return practiceDetail; }
 set { practiceDetail = value; }
 }

[DataMember]
 public DateTime LawyerAvailability
 {
 get { return lawyerAvailability; }
 set { lawyerAvailability = value; }
 }
 }



public class WCFLawyer : IWCFLawyer
 {
 private IOrganizationService orgService = GetOrganizationService();
 public IEnumerable<WCFCustomType> ReadList()
 {
 try
 {
 QueryExpression queryExpression = new QueryExpression("new_lawyer");
 ConditionExpression conditionExpression = new ConditionExpression("statuscode", ConditionOperator.Equal, 1);
 queryExpression.ColumnSet = new ColumnSet(new String[] { "new_name","new_lawyerid", "new_practicedetail", "new_nextavailability" });
 EntityCollection contactCollection = orgService.RetrieveMultiple(queryExpression);
 List<WCFCustomType> lstLawyerType = new List<WCFCustomType>();
 WCFCustomType lawyerRecord;
 foreach (Entity entity in contactCollection.Entities)
 {
 lawyerRecord = new WCFCustomType();
 lawyerRecord.LawyerLoginID = entity.Attributes["new_name"].ToString();
 if (entity.Contains("new_practicedetail"))
 {
 lawyerRecord.PracticeDetail = entity.Attributes["new_practicedetail"].ToString();
 }
 if (entity.Contains("new_nextavailability"))
 {
 lawyerRecord.LawyerAvailability =(DateTime)entity.Attributes["new_nextavailability"];
 }

lstLawyerType.Add(lawyerRecord);
 }

return lstLawyerType;


 }
 catch (Exception generalException)
 {
 throw new RuntimeException(
 "There was a problem reading lawyer data.",
 generalException);
 }
 }
 public WCFCustomType ReadItem(string lawyerID)
 {
 try
 {
 // get the lawyer record's guid based on lawyer login id
 QueryExpression queryExpression = new QueryExpression("new_lawyer");
 ConditionExpression conditionExpression = new ConditionExpression("new_name", ConditionOperator.Equal, lawyerID);
 queryExpression.Criteria.AddCondition(conditionExpression);
 queryExpression.ColumnSet = new ColumnSet(new String[] { "new_name", "new_lawyerid" });
 EntityCollection contactCollection = orgService.RetrieveMultiple(queryExpression);
 Guid lawyerGuid = Guid.Empty;
 if (contactCollection.Entities.Count > 0)
 {
 Entity lawyerEntity = contactCollection.Entities[0];
 lawyerGuid = new Guid(lawyerEntity.Attributes["new_lawyerid"].ToString());
 }


 ColumnSet cols= new ColumnSet(new String[] { "new_name","new_lawyerid", "new_practicedetail", "new_nextavailability" });
 WCFCustomType lawyerRecord = null;
 Entity entity = orgService.Retrieve("new_lawyer", lawyerGuid, cols);
 if (entity != null)
 {
 lawyerRecord = new WCFCustomType();
 lawyerRecord.LawyerLoginID = entity.Attributes["new_name"].ToString();
 if (entity.Contains("new_practicedetail"))
 {
 lawyerRecord.PracticeDetail = entity.Attributes["new_practicedetail"].ToString();
 }
 if (entity.Contains("new_nextavailability"))
 {
 lawyerRecord.LawyerAvailability = (DateTime)entity.Attributes["new_nextavailability"];
 }

 }

return lawyerRecord;


 }
 catch (InvalidOperationException)
 {
 throw new ObjectNotFoundException(
 "Unable to read data for the lawyer with ID = " +
 lawyerID.ToString() +
 ". The lawyer no longer exists.");
 }
 catch (Exception generalException)
 {
 throw new RuntimeException(
 "There was a problem reading lawyer data.",
 generalException);
 }
 }

 public String[] GetLawyerLoginIDs()
 {

string[] lawyerIDs;

try
 {
 QueryExpression queryExpression = new QueryExpression("new_lawyer");
 ConditionExpression conditionExpression = new ConditionExpression("statuscode", ConditionOperator.Equal, 1);
 queryExpression.ColumnSet = new ColumnSet(new String[] { "new_lawyerid","new_name", "new_practicedetail", "new_nextavailability" });
 EntityCollection contactCollection = orgService.RetrieveMultiple(queryExpression);
 List<WCFCustomType> lstLawyerType = new List<WCFCustomType>();
 WCFCustomType lawyerRecord;
 lawyerIDs = new string[contactCollection.Entities.Count];
 int i = 0;
 foreach (Entity entity in contactCollection.Entities)
 {

lawyerIDs[i] =entity.Attributes["new_name"].ToString();
 i++;
 }

return lawyerIDs;
 }
 catch (Exception generalException)
 {
 throw new RuntimeException(
 "There was a problem reading lawyer data.",
 generalException);
 }


 }
 private IOrganizationService GetOrganizationService()
 {
 Uri organizationUri = new Uri("http://crmserver/orgname/XRMServices/2011/Organization.svc");
 Uri homeRealmUri = null;
 ClientCredentials credentials = new ClientCredentials();
 credentials.Windows.ClientCredential = new System.Net.NetworkCredential("username", "password", "domain");
 OrganizationServiceProxy orgProxy = new OrganizationServiceProxy(organizationUri, homeRealmUri, credentials, null);
 IOrganizationService _service = (IOrganizationService)orgProxy;
 return _service;
 }

}

Here instead of taking Guid of the record we will be taking LoginId (login name of the AD User) of the user as the unique identifier in our BCS, because the same will be used for while defining user profile synchronization with the BCS. The login name of the users and SAMAccountName in the AD will be the connection point between the two. The records in CRM will be identified by the login name of Users in SharePoint.

Here after implementing the Interface and after publishing the service, here we will again create the External Content Type based on it and will define the operations Read List, Read Item. This time we will use the User’s Login Id as Identifier.

Next open the User Profile Service Application à Manage User Properties in Central Administration Site of SharePoint.

Create a new user property named User Login ID (Lawyer Login Id here in our case) that imports the value from SAMAccountName property of the AD. (Note: AD Profile Synchronization Connection should already be set up for the user’s profiles)

Create a new Synchronization Connection for importing profile from BCS

Define the synchronization connection based on Lawyer Login ID property

Create few more user properties e.g. one for Practice Detail field and other for Lawyer Availability field defined as Data Member in the contract in our case.

Open User Profile Application à Manage User Properties

Create a new property named Practice Detail of type String that imports the value from the PracticeDetail attribute of the BCS connection defined.

Create one more property name Next Availability of type date time that imports the value from the LawyerAvailability attribute of the BCS connection defined.

Go to Manage Profile Service à Start Profile Synchronization to start the synchronization

Select Start Full Synchronization


Select Configure Synchronization Timer Job to define the synchronization interval


Open the user profiles record after the synchronization

Select Manage User Profiles in the User Profile Application

Search for the record and open it to confirm the successful user profile import.

Hope it helps.

Integrating CRM 2011 and SharePoint 2013 using BCS (WCF Service – CRUD Operation)


Create a new WCF Service Application in Visual Studio with .NET Framework version as 4.0 (since we will be using CRM 2011’s assembly that are in version 4.0).

Please go through this MSDN article first to get a clear understanding on the BCS Service

http://msdn.microsoft.com/en-us/library/office/ff953200(v=office.14).aspx

Define the Service Contract and the Date Contract in the following manner. Here we would be performing CRUD operation on Date of Birth and Last Name field of the Contact Entity.

Add references to the following assemblies

Microsoft.BusinessData can be found at

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI on the SharePoint Server.


[ServiceContract]
 public interface IService1
 {
 [OperationContract]
 IEnumerable<ContactEntity> ReadList();

[OperationContract]
 ContactEntity ReadItem(Guid contactId);

[OperationContract]
 ContactEntity Create(ContactEntity newContact);

[OperationContract]
 void Update(ContactEntity contact);

[OperationContract]
 void Delete(Guid contactId);
 }

 [DataContract]
 public class ContactEntity
 {
 [DataMember]
 public Guid ContactId { get; set; }

[DataMember]
 public DateTime? DateOfBirth { get; set; }

[DataMember]
 public string LastName { get; set; }
 }


Implement the Service Contract


public class Service1 : IService1
 {
 private readonly IOrganizationService _orgService = GetOrganizationService();

public ContactEntity ReadItem(Guid contactId)
 {
 try
 {
 var cols = new ColumnSet(new[] {"lastname", "birthdate"});
 ContactEntity contactRecord = null;
 Entity entity = _orgService.Retrieve("contact", contactId, cols);
 if (entity != null)
 {
 contactRecord = new ContactEntity();
 contactRecord.ContactId = contactId;
 if (entity.Contains("lastname"))
 {
 contactRecord.LastName = entity.Attributes["lastname"].ToString();
 }
 if (entity.Contains("birthdate"))
 {
 contactRecord.DateOfBirth = (DateTime) entity.Attributes["birthdate"];
 }
 }

return contactRecord;
 }
 catch (InvalidOperationException)
 {
 throw new ObjectNotFoundException(
 "Unable to read data for the conatct with ID = " +
 contactId.ToString() +
 ". The contact no longer exists.");
 }
 catch (Exception generalException)
 {
 throw new RuntimeException(
 "There was a problem reading contact data.",
 generalException);
 }
 }

public IEnumerable<ContactEntity> ReadList()
 {
 try
 {
 var queryExpression = new QueryExpression("contact");
 var conditionExpression = new ConditionExpression("statuscode", ConditionOperator.Equal, 1);
 queryExpression.ColumnSet = new ColumnSet(new[] {"contactid", "lastname", "birthdate"});
 queryExpression.Criteria.AddCondition(conditionExpression);

EntityCollection contactCollection = _orgService.RetrieveMultiple(queryExpression);
 var lstContactType = new List<ContactEntity>();
 ContactEntity contactRecord;
 foreach (Entity entity in contactCollection.Entities)
 {
 contactRecord = new ContactEntity();
 contactRecord.ContactId = new Guid(entity.Attributes["contactid"].ToString());
 if (entity.Contains("lastname"))
 {
 contactRecord.LastName = entity.Attributes["lastname"].ToString();
 }
 if (entity.Contains("birthdate"))
 {
 contactRecord.DateOfBirth = (DateTime) entity.Attributes["birthdate"];
 }

lstContactType.Add(contactRecord);
 }

return lstContactType;
 }
 catch (Exception generalException)
 {
 throw new RuntimeException(
 "There was a problem reading contact data.",
 generalException);
 }
 }

public ContactEntity Create(ContactEntity newContact)
 {
 try
 {
 var returnContact = new ContactEntity();
 returnContact.ContactId = Guid.NewGuid();
 returnContact.DateOfBirth = newContact.DateOfBirth;
 returnContact.LastName = newContact.LastName;

var contactRecord = new Entity();
 contactRecord.LogicalName = "contact";
 contactRecord.Attributes["lastname"] = returnContact.LastName;
 contactRecord.Attributes["contactid"] = returnContact.ContactId;
 contactRecord.Attributes["birthdate"] = returnContact.DateOfBirth;
 newContact.ContactId = _orgService.Create(contactRecord);

return returnContact;
 }
 catch (Exception generalException)
 {
 throw new RuntimeException(
 "There was a problem creating a new contact.",
 generalException);
 }
 }


 public void Update(ContactEntity updateContact)
 {
 try
 {
 var contactRecord = new Entity();
 contactRecord.LogicalName = "contact";
 contactRecord.Attributes["lastname"] = updateContact.LastName;
 contactRecord.Attributes["contactid"] = updateContact.ContactId;
 contactRecord.Attributes["birthdate"] = updateContact.DateOfBirth;

_orgService.Update(contactRecord);
 }
 catch (InvalidOperationException)
 {
 throw new ObjectNotFoundException(
 "Unable to update the contact with ID = " +
 updateContact.ContactId.ToString() +
 ". The contact no longer exists.");
 }
 catch (Exception generalException)
 {
 throw new RuntimeException(
 "There was a problem updating the lawyer with ID = " +
 updateContact.ContactId.ToString() + ".", generalException);
 }
 }

public void Delete(Guid contactId)
 {
 try
 {
 _orgService.Delete("contact", contactId);
 }
 catch (InvalidOperationException)
 {
 throw new ObjectNotFoundException(
 "Unable to delete the contact with ID = " +
 contactId.ToString() +
 ". The contact no longer exists.");
 }
 catch (Exception generalException)
 {
 throw new RuntimeException(
 "There was a problem lawyer the customer with ID = " +
 contactId.ToString() + ".", generalException);
 }
 }

public static IOrganizationService GetOrganizationService()
 {
 var organizationUri = new Uri("http://crmserver/orgname/XRMServices/2011/Organization.svc");
 Uri homeRealmUri = null;
 var credentials = new ClientCredentials();
 credentials.Windows.ClientCredential = new NetworkCredential("username", "password", "domain");
 var orgProxy = new OrganizationServiceProxy(organizationUri, homeRealmUri, credentials, null);
 IOrganizationService _service = orgProxy;
 return _service;
 }

 

Host the Service in the IIS.

Open SharePoint Designer 2013 and connect to the site where we want to create an external content type based on our WCF Service.

Create a new External Content Type

Specify name for the content type and click on the link for defining operations

Click on Add Connection and specify WCF Service as the connection type

Specify the url of the WCF service

For each of the Web Methods, specify the corresponding operation.

For each of the operations define ContactId as Identifier

Once defined, select Create Lists and Form button

Open the SharePoint site and open the list created

Corresponding contact records in CRM

Hope it helps.

“You must provide a value for Potential Customer” error while creating opportunity record through Create Step in Process in CRM 2011 Online


Hi,

Got the below error message while defining the Create Step in Workflow in CRM 2011 online instance. It seems like it is a bug in new online environment that have UR 13 applied.

Check out this thread

http://social.microsoft.com/Forums/en-US/crm/thread/51a63a3e-bd81-471e-a9d8-617bfe033271/

The workaround would be to remove the requirement level, edit and publish the workflow and the set the requirement level back.

Bye.

CRM 2011 Bug – Team Security Roles


Nice post on Team and Security Role. Do check the comments.

crmdeveloper's avatarcrm2011stuff

This appears to be a bug with Security Roles and Teams.  To duplicate the problem, follow these steps:

  1. Create a Custom Entity
  2. Create a Security Role in CRM 2011 to access the Custom Entity
  3. Create a new Team in CRM
  4. Assign the new Security Role to the new Team
  5. Create a new user
  6. Add the user to the Team as a member

Now the new user is supposed to have the permissions granted by the security role assigned to the Team.  Testing will show that you can access everything but the form.

  1. Now assign the new Security Role directly to the new user
  2. Have the new user log in and access the form for the Custom Entity

If you test at this point, everything will work.  Be sure to access the form at least once. 

  1. Remove the role from the new user
  2. Assign the role back to the Team

Now the…

View original post 24 more words