{Bookmarklet} Refresh Form Data

{Bookmarklet} Refresh Form Data

Recently I was developing a plugin in which, whenever a record updated some of the fields were updated and for reflecting those fields I need to refresh the page. I was tired to refresh the page again and again.so I come up with a solution that would also increase productivity.

I made a small bookmarklet that will help me to refresh form data without refreshing the entire page.

Here is code

javascript: (function () { debugger;(document.querySelectorAll(‘iframe’)).forEach(function (frame, v) { if (frame.style.visibility !== ‘hidden’) { if (frame) { var Xrm = frame.contentWindow.Xrm; Xrm.Page.data.refresh(); alert(‘Form Data Refreshed…’) } else { alert(‘Entity form not detected’); } } }) })();

Note: Before using the above code please update single quotation mark.

For adding this bookmarklet on chrome , refer below link

https://crmdynamicsblog.wordpress.com/2016/06/10/bookmarklet-get-current-record-guid-from-crm-form/

Hope it’ll help someone.

 

Advertisements
Add custom fetch XML to subgrid lookup

Add custom fetch XML to subgrid lookup

In this blog, I am going to show how we can change subgrid lookup behavior. Basically, I want to control custom N:N contact subgrid lookup, depend on company lookup that is on the contact form.

e.g. A.Datum company have five contacts and if I select contact lookup (custom N:N subgrid inline lookup ) on one of contact form so it’ll only show four contacts in subgrid lookup excluding this contact.

I have an N:N subgrid and company lookup on the contact form.

2

What’s the tricky part for getting subgrid lookup ?

Inspecting DOM

For add event on subgrid lookup, we need to inspect the DOM for subgrid and look out for lookup object.

Have a look below image, It clearly shows how we can find lookup , object by object.(if object key, not the same like below then find lookup with help of object name.)

FYI I am using Dynamics 365 online.

3

After inspecting the DOM structure of the subgrid and carefully understand the mechanics of the lookup filter,we can set filter criteria like in the JavaScript below:

 var RelatedContact = Xrm.Page.getControl('RelatedContact');
 var RelatedContactLookup = RelatedContact.$0_3.$1m_4.$O_4.$38_3.$3_6;
 RelatedContactLookup.addPreSearch(function ()
 {
 if (Xrm.Page.getAttribute("parentcustomerid").getValue())
 {
 var parentCustomer = Xrm.Page.getAttribute("parentcustomerid").getValue()[0].id;
 var strVar = "";
 strVar += "<filter type=\"and\" >";
 strVar +=" <condition attribute=\"statecode\" operator=\"eq\" value=\"0\" />"
 strVar += " <condition attribute=\"parentcustomerid\" 
               operator=\"eq\" value=\"" + parentCustomer + "\" \/>";
 strVar += " <\/filter>";
 strVar += "";
 RelatedContactLookup.addCustomFilter(strVar, "contact");
 }
 })

 

Get the company id from Xrm.Page library  and passes in fetchXML for search criteria.

Our filter criteria code is done but for triggering the above code, we need to attach click function to the subgrid add button, like in JavaScript below :

var RelatedContact_Button = window.parent.document.getElementById("RelatedContact_addImageButton");
 RelatedContact_Button.addEventListener("click", function ()
 {
 ///put your filter code here  
 }

Here is complete code for JavaScript web resource that we need to add on a contact form.

You can also write this code inside a function and call it onload, here I am using self invoking JS function.

(function ()
{
 setTimeout(function ()
 {
 var RelatedContact_Button = window.parent.document.getElementById("RelatedContact_addImageButton");
 RelatedContact_Button.addEventListener("click", function ()
 {
 var RelatedContact = Xrm.Page.getControl('RelatedContact');
 var RelatedContactLookup = RelatedContact.$0_3.$1m_4.$O_4.$38_3.$3_6;
 RelatedContactLookup.addPreSearch(function ()
 {
 if (Xrm.Page.getAttribute("parentcustomerid").getValue())
 {
 var parentCustomer = Xrm.Page.getAttribute("parentcustomerid").getValue()[0].id;
 var strVar = "";
 strVar += "<filter type=\"and\" >";
 strVar += " <condition attribute=\"parentcustomerid\" operator=\"eq\" value=\"" + parentCustomer + "\" \/>";
 strVar += " <\/filter>";
 strVar += "";
 RelatedContactLookup.addCustomFilter(strVar, "contact");
 }
 })
 })
 }, 2000)
}())

You can also download from here.

animation

 

That’s it , Please try and comment below If you found any problem.

Hope it’ll help someone.

 

Note: This is an unsupported way if you really want to go with a supported way then use custom web resource HTML for showing your grid with filter criteria.

{Custom activity workflow Debug error} Syntax error in cast operator; two arguments separated by comma are required.

{Custom activity workflow Debug error} Syntax error in cast operator; two arguments separated by comma are required.

Recently I tried to debug a custom activity workflow and I was facing below error.

Unhandled Exception: System.Activities.InvalidWorkflowException: The following errors were encountered while processing the workflow tree:

‘DynamicActivity’: The private implementation of activity ‘1: DynamicActivity’ has the following validation error:   Compiler error(s) encountered processing expression “DirectCast(CustomActivityStep3: Get Url_1_converted, System.String)”.

Basically, I am using two input parameters in my custom activity workflow.

2

So for debugging after above error I have figured out two options to solve my problem.

  1. Remove Input parameters when you are debugging your activity workflow, later you will add for dynamic values.
  2. Or add default values for input parameters.
3
after trying one of the above options I am able to debug my workflow.
For debugging custom activity workflow please refer below links
Hope it’ll help someone.

 

 

Multiple views inside a tab on CRM dashboard

Multiple views inside a tab on CRM dashboard

In this blog, we’re going to implement multiple views inside a tab with the help of web resource.

we are showing Active Accounts, Active Contacts, and Open Opportunities views into a tab of a dashboard.

for this, I used Javascript Tabifier library, you can download JS and CSS from below link

Javascript Tabifier library

let’s upload and publish Tabbler.js and their CSS on our CRM Organization.we can use XrmToolbox for maintaining CRM web resources.

create a new HTML web resource i.e. MultiViews. Inside this, we’ll write our code for showing three different views in a web resource.

crmweb.PNG

For showing views in Iframe we need views URL’s.For more info about how to get URL please refer below link

Copy the URL for a View

email

Here is code for HTML page

<!DOCTYPE html>

<html lang=”en” xmlns=”http://www.w3.org/1999/xhtml”&gt;
<head>
<meta charset=”utf-8″ />
<title></title>
http://../../ClientGlobalContext.js.aspx
http://../content_/js/tabber_minimized.js
<link rel=”stylesheet” href=”../content_/css/example.css” type=”text/css” media=”screen”>

/* Optional: Temporarily hide the “tabber” class so it does not “flash”
on the page as plain HTML. After tabber runs, the class is changed
to “tabberlive” and it will appear. */

document.write(‘.tabber{display:none;}’);

</head>
<body>

Note: Iframe tag is not supported as a text in WordPress so please download the source code from here

In the above code, we’re using Active Accounts, Active Contacts, and Open Opportunities views URL.Now let just add this web resource on dashboard or use a web resource whatever.

m1.PNG

tabbler

That’s it . Now we can see multiple views inside a single web resource.

Here is the link for source code

https://1drv.ms/f/s!AvWbcg6Nl97LiU1kl6GQg1snKfgr

Thanks for visiting my blog.

Change currency symbol using JS script without refreshing CRM form

Change currency symbol using JS script without refreshing CRM form

Recently I having a requirement in which I need to change a transaction currency at CRM form using JS. I was able to change the currency but currency symbol is not reflected for all currency attribute on form, for changing we need to refresh explicit the form.

Here is the previous code

var lookupReference = [];
lookupReference[0] = {};
lookupReference[0].id = ‘{TransactionCurrencyId}’;
lookupReference[0].entityType = “transactioncurrency”;
lookupReference[0].name = ‘{CurrencyName}’;
Xrm.Page.getAttribute(“transactioncurrencyid”).setValue(lookupReference);
Xrm.Page.data.save();
Xrm.Utility.openEntityForm(“contact”, Xrm.Page.data.entity.getId());

so after spending some time I came with a way , that we use for change currency symbol on CRM form without refreshing the CRM form.

This is an unsupported way so please careful before using this.

Here is the updated code

var obj= {
id: ‘{TransactionCurrencyId}’,
entityType: ‘transactioncurrency’,
type: 9105,
name: ‘{CurrencyName}’,
keyValues: {
currencysymbol: { name: ‘currencysymbol’, value: ‘{CurrencySymbol}’ },
currencyprecision: { name: ‘currencyprecision’, value: “1” }
}
};
Xrm.Page.getControl(‘transactioncurrencyid’).get_editControlBehavior().handleAfterLookup({ items: [obj] });

 

 

CurrencyChange1

Note : All the curly variable needs dynamic value

e.g.{TransactionCurrencyId}=90300F9F-5560-E611-80EA-005056A93B8D

 

Thanks for visiting my blog.

 

 

 

CRM Web Portal with Token Based authentication -Part 1

CRM Web Portal with Token Based authentication -Part 1

Sometime we have a requirement to make a web portal with using CRM as back end e.g. ticket management portal. A portal is a custom application that allows external users to access and edit data that is stored in Microsoft Dynamics CRM (a.k.a CRUD – Create, Read, Update and Delete operations). A CRM portal application can be developed with different technologies along with the Dynamics CRM Web Services for data access.

In this article we’ll discuss how we can implement token based authentication in CRM web portal.I’ll divided this article into two parts

  1. CRM Web Portal with JWT authentication -Part 1
  2. Intregate CRM web portal with AngularJS-Part 2(coming soon..)

Token Based Authentication

As I stated before we’ll use token based approach to implement authentication between the front-end application and the CRM API, as we all know the common and old way to implement authentication is the cookie-based approach were the cookie is sent with each request from the client to the server, and on the server it is used to identify the authenticated user.

1. Create a web application (webapi) project in visual studio with no authentication.

create_new_project

create_new_project1

create_new_project2

2.Remove Global.asax from our project and add owin starup class i.e. startup.cs

using System;
using Microsoft.Owin;
using Owin;
using Microsoft.Owin.Security.OAuth;
using Microsoft.Owin.Security;
using System.Web.Http;
using System.Web.Routing;
using System.Web.Mvc;
using System.Net.Http.Headers;
using Microsoft.AspNet.Identity.Owin;

[assembly: OwinStartup(typeof(MSCRMjwtAuth.Startup))]

namespace MSCRMjwtAuth
{
public class Startup
{

public void Configuration(IAppBuilder app)
{
HttpConfiguration httpconfig = new HttpConfiguration();
WebApiConfig.Register(httpconfig);
RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
app.UseWebApi(httpconfig);
httpconfig.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(“text/html”));

// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
}
}
}

3.After that install below nuget packages

Install-Package Microsoft.AspNet.WebApi.Owin

Install-Package Microsoft.Owin.Host.SystemWeb

Install-Package Microsoft.Owin.Security.OAuth

Install-Package Microsoft.AspNet.Identity.Owin

Install-Package Microsoft.CrmSdk.CoreAssemblies

In this blog we’re authenticating user with contact entity, emailaddress1 field as username and custom attribute am_password  for password and we also store password in encrypted format.

4.Create a new solution i.e. JWTaunthentication for all our schema customization.

create_solution

5. CRMHelper class

CRMhelper class contains functions that check user and password from our existing CRM contact records on behalf of input that user provided.

/// <summary>
/// This class contains all crm functions
/// </summary>
public class CRMHelper
{
//Variable
public IOrganizationService _orgService;

//CRM dynamics Connection
CrmConnection connection = CrmConnection.Parse(ConfigurationManager.ConnectionStrings[“CRMConnectionString”].ConnectionString);

public CRMHelper()
{
_orgService = new OrganizationService(connection);
}

/// <summary>
/// Login Function for parent
/// </summary>
/// <param name=”arry”>array of login id and password</param>
/// <returns>Datacollection of contact entity</returns>
public DataCollection<Entity> tryLogin(string[] arry)
{
try
{
QueryExpression parentQuery = new QueryExpression()
{
EntityName = “contact”,
ColumnSet = new ColumnSet(“firstname”, “lastname”),
Criteria =
{
Filters =
{
new FilterExpression(LogicalOperator.And)
{
Conditions={
new ConditionExpression(“emailaddress1”,ConditionOperator.Equal,arry[0].ToString()),
new ConditionExpression(“am_password”,ConditionOperator.Equal,StringCipher.Encrypt(arry[1].ToString()))
}
}
}
}
};
return _orgService.RetrieveMultiple(parentQuery).Entities;
}
catch (Exception ex)
{
throw;
}
}

/// <summary>
/// Get all Cases related to logged in user
/// </summary>
/// <param name=”customerid”>Contact Entity guid</param>
/// <returns>Datacollection of Incident Entity</returns>
public DataCollection<Entity> getCases(Guid customerid)
{
try
{
// Instantiate QueryExpression QEincident
var QEincident = new QueryExpression(“incident”);

// Add columns to QEincident.ColumnSet
QEincident.ColumnSet.AddColumns(“title”);

// Define filter QEincident.Criteria
QEincident.Criteria.AddCondition(“customerid”, ConditionOperator.Equal, customerid);
return _orgService.RetrieveMultiple(QEincident).Entities;
}
catch (Exception ex)
{

throw;
}
}

}

5. OAuth Bearer Tokens Generation

Add a new class i.e. ApplicationOAuthProvider.cs in our web application that support for OAuth Bearer Tokens Generation.

public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
CRMHelper helper = new CRMHelper();
if (context.UserName != null && context.Password != null)
{
var collection = helper.tryLogin(new string[] { context.UserName, context.Password });
if (collection.Count > 0)
{
context.OwinContext.Response.Headers.Add(“Access-Control-Allow-Origin”, new[] { “*” });
var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
oAuthIdentity.AddClaim(new Claim(ClaimTypes.Email, context.UserName));
var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
context.Validated(ticket);
}

}
//return base.GrantClientCredentials(context);
}
}

6. Encryption and Decryption class

public static class StringCipher
{
// This constant string is used as a “salt” value for the PasswordDeriveBytes function calls.
// This size of the IV (in bytes) must = (keysize / 8). Default keysize is 256, so the IV must be
// 32 bytes long. Using a 16 character string here gives us 32 bytes when converted to a byte array.
private static readonly byte[] initVectorBytes = Encoding.ASCII.GetBytes(“tu89geji340t89u2”);

// This constant is used to determine the keysize of the encryption algorithm.
private const int keysize = 256;
private const string passPhrase = “contact”;
public static string Encrypt(string plainText)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}

public static string Decrypt(string cipherText)
{
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
}

7. Create CRM contact record

Also create a record for contact entity in CRM with amankothari@outlook.com as Email and ChHTqB6783q4J/b5BHD7vQ==  as Password (we stored password in encrypted form).

ContactForm.png

8. Add secured controller for Incident

[RoutePrefix(“api/cases”)]
public class CasesController : ApiController
{
CRMHelper helper = new CRMHelper();
[Authorize]
[HttpGet]
[Route(“”)]
public DataCollection<Entity> Getcases()
{
try
{
var identity = (ClaimsIdentity)User.Identity;
foreach (var a in identity.Claims)
{
if (a.Type == “contactid”)
{
return helper.getCases(new Guid(a.Value));
}}
return null;

}
catch (Exception ex)
{
return null;
}
}
}

Notice how we added the “Authorize” attribute on the method “Get” so if you tried to issue HTTP GET request to the end point “http://localhost:port/api/cases&#8221; you will receive HTTP status code 401 unauthorized because the request you send till this moment doesn’t contain valid authorization header.

9.Modified our startup.cs code for support for OAuth Bearer Tokens.

using System;
using Microsoft.Owin;
using Owin;
using Microsoft.Owin.Security.OAuth;
using Microsoft.Owin.Security;
using System.Web.Http;
using System.Web.Routing;
using System.Web.Mvc;
using System.Net.Http.Headers;
using Microsoft.AspNet.Identity.Owin;

[assembly: OwinStartup(typeof(MSCRMjwtAuth.Startup))]

namespace MSCRMjwtAuth
{
public class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpconfig = new HttpConfiguration();
ConfigureOAuth(app);
WebApiConfig.Register(httpconfig);
RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
app.UseWebApi(httpconfig);
httpconfig.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(“text/html”));

// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString(“/oauth/token”),
Provider = new ApplicationOAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
AllowInsecureHttp = true,
};

// Token Generation
app.UseOAuthBearerTokens(OAuthOptions);
}
}
}

Assuming that you saved the username “amankothari@outlook.com”  with password “ChHTqB6783q4J/b5BHD7vQ==” (123456) in CRM. In the step below, we’ll use the same username to generate token, so to test this out open your favorite REST client application in order to issue HTTP requests to generate token for user “amankothari@outlook.com”. For me I’ll be using PostMan.

Now we’ll issue a POST request to the endpoint http://localhost:57205/oauth/token the request will be as the image below:

Postman1.PNG

If the username and password are not same then we sent bad request in response.

invalid_token_postman

If all is correct we’ll receive HTTP status 200 along with the secured data in the response body, if you try to change any character with signed token you directly receive HTTP status code 401 unauthorized.

Casescaseresponse

Now our back-end API is ready to be consumed from any front end application or native mobile app.

In my next blog we’ll consumed this API with angularJS application.

Below are the links of solution and web project code respectively.

https://1drv.ms/u/s!AvWbcg6Nl97LiUsVexaWI0gZV2TP

https://1drv.ms/u/s!AvWbcg6Nl97LiUyciNWPn4ehGpNH

 

 

 

 

 

{Bookmarklet} Get current record Guid from CRM form

{Bookmarklet} Get current record Guid from CRM form

Most of the time when we developed some new functionality in crm, we need current entity record GUID for debugging and checking our modification using advanced find , Odata query etc.

In this blog I am going to create a simple bookmarklet for getting current enity record GUID.

What is Bookmarklet?

A small software application stored as a bookmark in a web browser, which typically allows a user to interact with the currently loaded web page in some way.

(definition from google)

For more details on bookmarklet creation refer below link

http://code.tutsplus.com/tutorials/create-bookmarklets-the-right-way–net-18154

Let’s write a JavaScript code that we use for our bookmarklet.

javascript;
(function () {
(document.querySelectorAll(‘iframe’)).forEach(function (frame, v) {
if (frame.style.visibility !== ‘hidden’) {
if (frame) {
var Xrm = frame.contentWindow.Xrm;
prompt(“Copy GUID for the current record”, Xrm.Page.data.entity.getId());
} else {
alert(‘Entity form not detected’);
}

}
})
})();

Now add a new page on chrome from bookmark bar

2

In name give some meaning name like ‘GETID’ and in URL paste our JavaScript code

1

Now try this on Entity Form, we’ll get the GUID of current record.

GIF

 

That’s it. Hope it’ll help someone 🙂

Thanks for visiting my blog!!!