Tuesday, July 6, 2010

Plug-ins vs. Workflows in MS CRM 4.0

First of all, remember than both workflows and plug-ins can attach to exactly the same events. Well, plug-ins have available a couple of more events but essentially both work on top of the same event model.Remember also that workflows always run asynchronous and hence, the Asynchronous Processing Service must be running on the server in order to run.

Workflows are more suitable if:

1)you want to achieve simple tasks faster, such as sending an e-mail or creating / updating assigning records. These actions can be set up very quickly with a workflow without any need of writing code.

2)you want to easily scale things to managers (if they were setup for user records), as it is possible to assign records to them.

you want to allow an advanced user to make changes to logic. As using the integrated workflow designer is user-friendly, an advanced user would be able to edit an existing workflow and change some rules according to business changes.

3)the logic should be available to be run on demand. I mean, when you are within an entity and navigates to “workflows” option in the left pane, all workflows marked as available to run on demand can be executed making them independent of an event trigger.

4)you want to send emails making use of templates and attaching files.

Workflows also allow running child workflows which may make a lot of sense in some scenarios. Nevertheless, be careful if you need the child workflow results in order to make decisions on your main workflow, as child workflows always run asynchronous, which means that it will trigger the child workflow and continue. If you need your primary workflow to wait until child ends, you will need to write a custom activity.

On the other hand, plug-ins are more suitable if:

1)you need to manipulate data before is saved.

2)you need to make validations before submitting the operation.

3)you want to be able to cancel an operation based on your validations.

4)immediate response to the user is needed.

5)you need retrieve values and/or take actions after operation has been completed (i.e. getting and autogenerated id)

It is important to note that since Dynamics CRM 4, plug-ins can also be configured to run asynchronous (Mode attribute while registering plug-in). Nevertheless, pre-event asynchronous plug-ins are not supported. In this case, you will have to set it up as synchronous mode.

Another important thing about plug-ins is the Deployment option which says if the plug-in is going to be executed on the server and/or Outlook client. If both executions are set up and client goes offline and online, plug-in calls are triggered after synchronization so be prepared in this case to execute your code twice!

Regarding to security:

1)Workflows triggered automatically will run under the security context of the workflow owner. On the contrary, if executed on demand, the security context of the user who executed the workflow will be used.

2)Plug-ins execute under the security context of the CRM Web application pool identity (typically NETWORK SERVICE). As this account typically maps to generic CRM SYSTEM user this typically works fine.

However, within plug-ins you can make use of impersonation to work under the credentials of the user who is making the request. For doing so, you just need to pass True to the CreatCrmService method under the context object.If you need to always impersonate with a specific user, you can do that by passing True as above and setting impersonatinguserid attribute while registering the plug-in.It is important to know that plug-in impersonation does not work offline. The logged on user credentials are always used in this case.

referred from Here

How to get currently authenticated user in MSCRM SQL queries?

During developing SQL queries for MSCRM, it’s often required to fetch the currently authenticated user.
SUSER_SNAME() is a special function in SQL that returns the currently authenticated user. If your code doesn’t authenticate to SQL Server by using Windows authentication, your queries will never return any data, because all of the filtered views perform an inner join using systemuserid. Here is the query to fetch currently authenticated user in SQL server.

select SystemUserId, FullName from SystemUserBase
where SystemUserBase.DomainName = SUSER_SNAME()

above code referred from http://ayazahmad.wordpress.com/page/5/

Get Current User Roles through JavaScript in CRM

If you need to find businessunitid and name from role entity of current logged in user in JavaScript then for this you need to access WebService of CRM through JavaScript and privide logged in user id through system variable "EqualUserId".

In the below code you can access role entity attribute after liked other two entities with name "systemuserroles" and "systemuser" with "role" entity.

var xml = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
GenerateAuthenticationHeader() +
" <soap:Body>" +
" <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
" <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
" <q1:EntityName>role</q1:EntityName>" +
" <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
" <q1:Attributes>" +
" <q1:Attribute>businessunitid</q1:Attribute>" +
" <q1:Attribute>name</q1:Attribute>" +
" </q1:Attributes>" +
" </q1:ColumnSet>" +
" <q1:Distinct>false</q1:Distinct>" +
" <q1:LinkEntities>" +
" <q1:LinkEntity>" +
" <q1:LinkFromAttributeName>roleid</q1:LinkFromAttributeName>" +
" <q1:LinkFromEntityName>role</q1:LinkFromEntityName>" +
" <q1:LinkToEntityName>systemuserroles</q1:LinkToEntityName>" +
" <q1:LinkToAttributeName>roleid</q1:LinkToAttributeName>" +
" <q1:JoinOperator>Inner</q1:JoinOperator>" +
" <q1:LinkEntities>" +
" <q1:LinkEntity>" +
" <q1:LinkFromAttributeName>systemuserid</q1:LinkFromAttributeName>" +
" <q1:LinkFromEntityName>systemuserroles</q1:LinkFromEntityName>" +
" <q1:LinkToEntityName>systemuser</q1:LinkToEntityName>" +
" <q1:LinkToAttributeName>systemuserid</q1:LinkToAttributeName>" +
" <q1:JoinOperator>Inner</q1:JoinOperator>" +
" <q1:LinkCriteria>" +
" <q1:FilterOperator>And</q1:FilterOperator>" +
" <q1:Conditions>" +
" <q1:Condition>" +
" <q1:AttributeName>systemuserid</q1:AttributeName>" +
" <q1:Operator>EqualUserId</q1:Operator>" +
" </q1:Condition>" +
" </q1:Conditions>" +
" </q1:LinkCriteria>" +
" </q1:LinkEntity>" +
" </q1:LinkEntities>" +
" </q1:LinkEntity>" +
" </q1:LinkEntities>" +
" </query>" +
" </RetrieveMultiple>" +
" </soap:Body>" +
"</soap:Envelope>" +
"";
var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");

xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction"," http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);

var resultXml = xmlHttpRequest.responseXML;

if (resultXml != null)
{
var entityNode = resultXml.selectSingleNode("//RetrieveMultipleResult/BusinessEntities/BusinessEntity");
var RoleName = entityNode.selectSingleNode("q1:name").text;
var BUentityNode = resultXml.selectSingleNode("//RetrieveMultipleResult/BusinessEntities/BusinessEntity/q1:businessunitid");
var BUName = BUentityNode.getAttribute("name");
}

Get Regarding Activity Status from activitypointer Entity

Here you can find activityid and statecode from activitypointer entity through WebService in JavaScript after passing one parameter "crmForm.ObjectId", parameter return current entitt GUID.

var xml = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
GenerateAuthenticationHeader() +
" <soap:Body>" +
" <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
" <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
" <q1:EntityName>activitypointer</q1:EntityName>" +
" <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
" <q1:Attributes>" +
" <q1:Attribute>activityid</q1:Attribute>" +
" <q1:Attribute>statecode</q1:Attribute>" +
" </q1:Attributes>" +
" </q1:ColumnSet>" +
" <q1:Distinct>false</q1:Distinct>" +
" <q1:Criteria>" +
" <q1:FilterOperator>And</q1:FilterOperator>" +
" <q1:Conditions>" +
" <q1:Condition>" +
" <q1:AttributeName>activitytypecodename</q1:AttributeName>" +
" <q1:Operator>Equal</q1:Operator>" +
" <q1:Values>" +
" <q1:Value xsi:type=\"xsd:string\">Task</q1:Value>" +
" </q1:Values>" +
" </q1:Condition>" +
" <q1:Condition>" +
" <q1:AttributeName>regardingobjectid</q1:AttributeName>" +
" <q1:Operator>Equal</q1:Operator>" +
" <q1:Values>" +
" <q1:Value xsi:type=\"xsd:string\">"+crmForm.ObjectId+"</q1:Value>" +
" </q1:Values>" +
" </q1:Condition>" +
" </q1:Conditions>" +
" </q1:Criteria>" +
" </query>" +
" </RetrieveMultiple>" +
" </soap:Body>" +
"</soap:Envelope>" +
"";

var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");

xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);

var objResult = xmlHttpRequest.responseXML;

var buNodes = objResult.selectNodes("//BusinessEntity/q1:statecode"); // CRM 4.0

if(buNodes != null )
{
/*get values*/
for( i = 0; i < buNodes.length; i++)
{
switch(buNodes[i].text)
{
//Put your logic here
}
}
}

Include Javascript files in CRM (load custom javascript file)

Some time user required to do same type of work at multiple place in JavaScript, for this user have two options either place a same type of code at all the places or store the same code at one place in JavaScript file and name it with "xyz.js", now the question is how to use this JS file in different entities from CRM.

Some steps are there:
1) create one folder with name "myscripts" in ISV in CRM server.
2) place the "xyz.js" file in above named folder.
3) use the following JavaScript code at the OnLoad event of the entity.

var script = document.createElement('script');
script.language = 'javascript';
script.src = '/ISV/myscripts/xyz.js';
document.getElementsByTagName('head')[0].appendChild(script);

var f = function()
{
if (event.srcElement.readyState == "loaded")
{
//perform onload scripts
FunctionfromJavaScriptFile();
// some function from your custom js file
}
}
script.attachEvent("onreadystatechange", f);

After using above three defined steps you are ready to call custom JavaScript file.

Disable Menu Buttons from any entity in CRM

Some time user is not interested to show some buttons from menu items, for this user required to hide these buttons. You can do this if you have ID of that button, but in CRM the ID of these buttons not standard these are created at the time of loading, but some part of the ID is unique every time, so find this unique id name from source control of entity.After this use following JavaScript to Hide these buttons.

function DisableButtons()
{
//Get all of the List Elements
var lis = document.getElementsByTagName('LI');
var i = 0;
//Loop through the list items
while (i < lis.length)
{
if (lis[i].getAttribute('id').indexOf( 'provide unique id name')!=-1)
{
var lnkmenuApproveDiscount = lis[i].getAttribute('id');
var menuApproveDiscountButton = document.getElementById(lnkmenuApproveDiscount);
menuApproveDiscountButton.style.display='none';
}
if (lis[i].getAttribute('id').indexOf( 'provide unique id name')!=-1)
{
var lnkmenuRejectDiscount = lis[i].getAttribute('id');
var menuRejectDiscountButton = document.getElementById(lnkmenuRejectDiscount);
menuRejectDiscountButton.style.display='none';
}
i = i + 1;
}
}

Hide associated view buttons(Buttons those are showing in related entity)

Some time user not required some buttons to be shown in associated (related entity view) grid menu.To hide associated(related entity view) buttons we are required to Add JavaScript on the form OnLoad event of entity, in which this assicated view is shown.

For example:- I have add entity with name Audit in CRM and associate it with Account, Now I tried to hide Audit assiciated button's Add New and Add Existing Item from Audit entity, but I saw ID's of these buttons not exist in Account entity source becuase associated entity open in Iframe, so for this we requried to add following JavaScript on Account form load event.

function HideAssociatedViewButtons(loadAreaId, buttonTitles) {
var navElement = document.getElementById('nav_' + loadAreaId);
if (navElement != null) {
navElement.onclick = function LoadAreaOverride() {
// Call the original CRM method to launch the navigation link and create area iFrame
loadArea(loadAreaId);
HideViewButtons(document.getElementById(loadAreaId + 'Frame'), buttonTitles);
}
}
}

function HideViewButtons(Iframe, buttonTitles) {
if (Iframe != null) {
Iframe.onreadystatechange = function HideTitledButtons() {
if (Iframe.readyState == 'complete') {
var iFrame = frames[window.event.srcElement.id]; var liElements = iFrame.document.getElementsByTagName('li'); for (var j = 0; j < buttonTitles.length; j++) {
for (var i = 0; i < liElements.length; i++) {
if (liElements[i].getAttribute('title') == buttonTitles[j]) {
liElements[i].style.display = 'none';
break;
}
}
}
}
}
}
}

HideAssociatedViewButtons function requires loadAreaId, buttonTitles as a parameters.
We can find this loadAreaID, by viewing source code of Account form. and buttonTitles means ToolTip of that button.

for Example:- HideAssociatedViewButtons('new_lead_custom_audit', ['Add existing Audit to this record', 'Add a new Audit to this record']);

Content refereed from http://mahadeomatre.blogspot.com/2009/07/hide-associated-view-buttons.html

Split the String values with a special character in MS Flow to convert this into Array

 Many times we have a requirement to prepare the Mailing address for some of the documents, suppose there are Address Line1, Address Line2, ...