Plugin on Retrieve Multiple in CRM.

Filtering records using javascript in subgrid or a view is unsupported and doesnt work hence here is how you can/should filter subgrid records using a plugin.

Nishant Rana's Weblog

Recently we had a requirement to filter sub grid on one of the forms. We thought of using Plugin on Retrieve Multiple for this.

Here we were showing Opportunity Sub Grid on Account form.

So we created a view for Opportunity that will be used as Sub Grid. Used it as Related Record Sub Grid so that we can have the GUID of the Account record being passed to the plugin.

The problem we faced à Sorting and Paging stopped working for the Sub Grid.

http://crmtipoftheday.com/2015/10/05/limitations-of-retrieve-plugins/v

Hope it helps..

View original post

Advertisement

Create Auto-Number Attribute In Dynamics CRM 365 Using Organization Service + Simple Console Application

With the Dynamics 365 v9, you can add an auto-number attribute for any entity. Currently, you can add the attribute programmatically. There is no user interface to add this type of attribute.

There are actually two ways of doing this one is using c# code which you can use a console application and other being Web API request.

In  this blog, I will cover the 1st one, and by default this blog will also help you in connecting dynamics CRM 365 with console application.


Create a simple console application

 

  1. Open Visual Studio and click on new project and select console application project type and give it a name as “AutoNumber” and click on OK.



  2. From your solution manager , right click on “References” and click on “Manager nuget package”:




  3. In the search box enter the name as “Microsoft.CrmSdk.CoreAssemblies” , when result comes > select an click on install. It will install the dynamics crm core assemblies reference needed in the application.



  4. Now from your solution explorer click on add references and again select “System.Configuration” , “System.ServiceModel“and “System.Runtime.Serialization assmeblies“.


  5. Use below namespaces:
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Client;
    using Microsoft.Crm.Sdk.Messages;
    using System.Configuration;
    using System.Net;
    using System.ServiceModel.Description;
    using Microsoft.Xrm.Sdk.Messages;
    using Microsoft.Xrm.Sdk.Metadata;
  6. Copy paste below code in the application:
 IOrganizationService organizationService = null;

            try
            {
                ClientCredentials clientCredentials = new ClientCredentials();
                clientCredentials.UserName.UserName = ConfigurationManager.AppSettings["Username"];
                clientCredentials.UserName.Password = ConfigurationManager.AppSettings["Password"];

                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                
                organizationService = (IOrganizationService)new OrganizationServiceProxy(new Uri(ConfigurationManager.AppSettings["CRMUrl"]),
                 null, clientCredentials, null);

                if (organizationService != null)
                {
                    Guid userid = ((WhoAmIResponse)organizationService.Execute(new WhoAmIRequest())).UserId;

                    if (userid != Guid.Empty)
                    {
                        Console.WriteLine("Connected to dynamics crm");

                        CreateAttributeRequest widgetSerialNumberAttributeRequest = new CreateAttributeRequest
                        {
                            EntityName = "new_autonumber",
                            Attribute = new StringAttributeMetadata
                            {
                                //Define the format of the attribute
                                AutoNumberFormat = "DPR-{SEQNUM:5}-{RANDSTRING:6}-{DATETIMEUTC:yyyyMMddhhmmss}",
                                LogicalName = "new_serialnumber",
                                SchemaName = "new_SerialNumber",
                                RequiredLevel = new AttributeRequiredLevelManagedProperty(AttributeRequiredLevel.None),
                                MaxLength = 100, // The MaxLength defined for the string attribute must be greater than the length of the AutoNumberFormat value, that is, it should be able to fit in the generated value.
                                DisplayName = new Label("Serial Number", 1033),
                                Description = new Label("Serial Number of the widget.", 1033)
                            }
                        };
                        organizationService.Execute(widgetSerialNumberAttributeRequest);                      
                        Console.WriteLine("Created the autonumber attribute successfully..");
                    }
                }
                else
                {
                    Console.WriteLine("Failed to Established Connection!!!");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception caught - " + ex.Message);
            }
            Console.ReadKey();
        }

 

        7.  In the code above:

            A. change the entitylogical to the name of the entity where you want to create an autonumber field.  
            B. Give the required logical name of the attribute(which you would like to create).
            C. notice the  code line —-   

AutoNumberFormat = "DPR-{SEQNUM:5}-{RANDSTRING:6}-{DATETIMEUTC:yyyyMMddhhmmss}" 


         In the code above you can actually define what should be the format of your auto number as in example below : 

( Taken from docs.microsoft here : AutoNumber  Format Options)
        
     8. Now in your app.config put below( Insert the correct organization URL , username , password):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="CRMUrl" value="https://organame.api.crm8.dynamics.com/XRMServices/2011/Organization.svc" />
<add key="Username" value="Username" />
<add key="Password" value="Password" />
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup>
</configuration>


     9.  Build your console application( right click on solution and click “Build Solution” and then Run(Start) it:
        

    10. If it gets excuted fine , go to your dynamics CRM and open the entity fields from Settings > customizations > customize the system > entityname> fields. You will notice the field is created:
       
    


   11. Customize the form and add this field to the form post which try to create a record in dynamics crm. I have create two records and could see below:

      


 

     12. Note that you can always update this attrubute if it is created incorrectly by using code given here and using the same application we created :  Update AutoNumber attribute


Conclusion:
We can utilize this feature very well for creating an autonumber field in crm. before this we needed created a plugin which will trigger everytime or a workflow with very complex configuration.

Transaction handling:

“SEQNUM” which is The sequential segment is generated by SQL and hence uniqueness is guaranteed by SQL.

In my next blog – we will create an auto number field with more simpler approach of Web API request.



       
 
          

How To Access Master & Duplicate Record In Merge Operation Plugin

Here is a quick blog on how to access master & child records during a Merge operation in a plugin.

I recently had to develop a plugin where in I needed to do some manipulation with the records being merged.

You can access three entities in your plugin when a record is merged from Context.InputParameter : 

       1. SubordinateId – the duplicate record
       2. Target – the master record
       3. UpdateContent   – a temp entity contains the final attribute as outcome of the merge operation.


To Access them in the code simply do this:


Entity duplicate = context.InputParameters[“SubordinateId“]; // To access the duplicate record simply retrieve the attributes using service.retrieve and by proving the duplicate.Id.

EntityReference
target= (EntityReference)context.InputParameters[“Target“];

Entity
finalRecord = context.InputParameters[“UpdateContent“]; //To access the final record simply retrieve the attributes using service.retrieve and by proving the finalRecord.Id.

I hope it makes sense:
Cheers!



Get Most Recent Created On Record from Retrieved Entity Collection In Plugin

Sometimes, you may have a requirement to get the most recently created on record from the entity collection you have retrieved.

Instead of playing around a lot with coding and .net stuff, Dynamics CRM fetch XML and QueryExpression provides a way to sort records Ascending or descending.

Therefore, While retrieving records in FetchXML, do this :

<entity name='entityname'>
 <attribute name='atrributename1' /> 
   <attribute name='atrributename2' />    
    <attribute name ='attributename3' />                       
      <order attribute='createdon' descending='true' /> 
     <filter type='and'>                                  
     <condition attribute='statecode' operator='eq' value='0' />
   </filter>
</entity>

Or in Query Expression:

QueryExpression qe = new QueryExpression(entityName);
FilterExpression fe = new FilterExpression();
qe.ColumnSet = new ColumnSet(true);
qe.Orders.Add(new OrderExpression(columnname, ordertype)); 
service.RetrieveMulti ple(qe);

 

when Execute them , you will get the desired record on the top which can be access by simply by doing retrievedResult[0] or :

firstRecord= retrievedResult.Entities.First(); //first method.

firstrecord

I hope this helps!

cheers!

 

Retrieve Audit History Changes For A Particular Field/Attribute Of A Record

Description:

Sometimes we have a requirement to retrieve audit history changes for a particular field in CRM which may be for the purpose of checking if for e.g field A value which is at the moment set to “10”, was ever “5” or may be “3” or may be use old those values of fields to create a new CRM Record. In the below Image , you can easily retrieve old and new values at any given time on birthday field by looping on each audit record:

audit1

I have taken the reference from Dynamics CRM SDK & MSDN to figure out how this can be achieved.

Please note : To be able to use this you must have Auditing enabled on all three areas of CRM.

1. Auditing for whole Organization should be already turned on.

2. Auditing for Entity Should be already turned on.

3. Auditing for that Field should already be turned on.

Solution Code:

I have accomplished this on a console application , you can do it in plugins or custom workflows as per the requirement.

Required :

Namespace:   Microsoft.Crm.Sdk.Messages

Assembly:  Microsoft.Crm.Sdk.Proxy (in Microsoft.Crm.Sdk.Proxy.dll)

try
   {
//initiate a new retrieve request & add entity logical name + Guid of the record to retrieve
    RetrieveRecordChangeHistoryRequest changeRequest = new RetrieveRecordChangeHistoryRequest();
    changeRequest.Target = new EntityReference("contact", Id);                RetrieveRecordChangeHistoryResponse changeResponse =

//Execute the request, the "details" variable will have the audit data. 
    (RetrieveRecordChangeHistoryResponse)_service.Execute(changeRequest);
    AuditDetailCollection details = changeResponse.AuditDetailCollection;

// Retrieve Particular attribute change history by passing entity logical
//name and guid of the record, finally execute using RetrieveRecordChangeHistoryResponse
    var attributeChangeHistoryRequest = new RetrieveAttributeChangeHistoryRequest
      {
           Target = new EntityReference("contact", Id),
           AttributeLogicalName = "birthday"

       };

     var attributeChangeHistoryResponse = (RetrieveAttributeChangeHistoryResponse)_service.Execute(attributeChangeHistoryRequest);
     details = attributeChangeHistoryResponse.AuditDetailCollection;

//Details will have many records for example birthday change records, loop through all of them
       foreach (var detail in details.AuditDetails)
         {
             var detailType = detail.GetType();
             if (detailType == typeof(AttributeAuditDetail))
                  {
// retrieve old & new value of each action of each audit change from AttributeAuditDetail
                var attributeDetail = (AttributeAuditDetail)detail;
                foreach (KeyValuePair<string, object> attribute in attributeDetail.NewValue.Attributes)

                        {

                        string oldValue = "(no value)", newValue = "(no value)";
                        if (attributeDetail.OldValue.Contains(attribute.Key))

                       oldValue = attributeDetail.OldValue[attribute.Key].ToString();
                       newValue = attributeDetail.NewValue[attribute.Key].ToString();

                       if (oldValue !=null & newValue!=null)
                            {
                             // Do Something here!
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
}

I hope this helps!

Simplified Connection To Dynamics CRM 2016 Onpremise Using Console Application

Here is the quick code that i use when i have to build a console application that connects to dynamics crm onpremise version with AD/IFD Authentication.

Main Class:

ClientCredentials _clientCreds = new ClientCredentials();
_clientCreds.Windows.ClientCredential.UserName = ConfigurationManager.AppSettings["username"];
_clientCreds.Windows.ClientCredential.Password = ConfigurationManager.AppSettings["password"];
_clientCreds.Windows.ClientCredential.Domain = ConfigurationManager.AppSettings["domain"];
var organizationUri = ConfigurationManager.AppSettings["CRMUrl"];

_service = (IOrganizationService)new OrganizationServiceProxy(new Uri(organizationUri), null, _clientCreds, null);

OrganizationServiceContext _orgContext = new OrganizationServiceContext(_service);

App.Config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="AppSettings" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<appSettings>
<add key="CRMUrl" value="https://Oranization.com/XRMServices/2011/Organization.svc" />
<add key="Username" value="rawishkumar" />
<add key="Password" value="password" />
<add key="Domain" value ="exampledomain"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup>
</configuration>

 

Required Assemblies:

using System.ServiceModel.Description;

using System.Configuration;

using Microsoft.Xrm.Sdk;

using Microsoft.Xrm.Sdk.Client;

Hope this helps!

SQL Connection to CRM Database

Dynamics CRM has very efficient web services using which you can retrieve data such as Organization service Or WebApi. However if you still need to retrieve data from database here is a quick code helper – which i am using in a console application.

//Initiate the connection
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLServerConnection"].ConnectionString))
{
//create a command variable
using (var command = connection.CreateCommand())
{
//add query to your command
command.CommandText = "your SQLquery goes here";

// open the connection first and then execute the query using Execute Reader
connection.Open();
result = command.ExecuteReader();

here is the app.config which i have used , i am using the windows authentication hence you donot need to mention credentials.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="SQLServerConnection" connectionString="Server=.;Database=events.website;Trusted_Connection=True;"/>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup>
</configuration>

By Now you will have your dataset in “result”; here is another piece of code to read the data:

 if (result.HasRows)
{
 while (result.Read())
{
string contactid= result["columnName"].ToString();
string contact = result["columnName"].ToString();
DateTime createdonDate= (DateTime)result["createdon"];
string type = result["columnName"].ToString();
}

}
// close the result
 if (result != null)
result.Close();


 

I hope this helps!

Cheers!

How to connect to Dynamics CRM Onpremises AD/IFD from a Windows Form Application

Being a CRM developer, you often need to develop some external application. In this blog i will talk about and provide the code to connect to dynamics CRM Onpremises in a windows form application.

Login

public static ConnectToCrm(string username, string password, string domain, string Url)
{

ClientCredentials _clientCreds = new ClientCredentials();
_clientCreds.Windows.ClientCredential.UserName = username;
_clientCreds.Windows.ClientCredential.Password = password;
_clientCreds.Windows.ClientCredential.Domain = domain;

if (username == "" || password == "" || domain == "" || Url == "")
{
MessageBox.Show("Please Enter All Details To Login!");
}

_service = (IOrganizationService)new OrganizationServiceProxy(new Uri(Url), null, _clientCreds, null);

OrganizationServiceContext _orgContext = new OrganizationServiceContext(_service);
Guid orgId = ((WhoAmIResponse)_service.Execute(new WhoAmIRequest())).OrganizationId;

if (orgId != null)
{
MessageBox.Show("Successfully Connected to CRM. Click OK");
}
else if(orgId==null)
{
MessageBox.Show("Could Not Connect to CRM. Click OK & Try Again!");
}
}

The _service can be utilized in your methods to retrieve the data and perform actions in dynamics CRM. i.e, below:

var fetchExpression = new FetchExpression(fetchXml);
EntityCollection fetchResult = _service.RetrieveMultiple(fetchExpression);

hope this helps!

cheers!

Create Text log file – Simplest way possible

We all need to log errors, information, warnings when writing your console application.

while there are several third party tools/methods available which you use in your solution such as Nlog, Log4net… etc. I would still prefer to create my custom code to generate the log file and capture all details as those tools might work on some machine and on some wont also depends badly on the permissions on the system.

below is simple code that i use :

using System;
using System.IO;

namespace YourNameSpace
{
 public static class ErrorLog
 {

public static void Logger(string ErrorCode, string ErrorMsg)
 {
 try
 {
 string path = Directory.GetCurrentDirectory();
 path = path + "\\Logs\\";

// check if directory exists
 if (!Directory.Exists(path))
 {
 Directory.CreateDirectory(path);
 }
 path = path + DateTime.Today.ToString("dd-MMM-yy") + ".log";
 // check if file exist
 if (!File.Exists(path))
 {
 File.Create(path).Dispose();
 }
 // log the error now
 using (StreamWriter writer = File.AppendText(path))
 {
 string error = "\n" + DateTime.Now.ToString() + ":" + ErrorCode + ":" + ErrorMsg;
 writer.WriteLine(error);
 writer.Flush();
 writer.Close();
 }

}
 catch (Exception ex)
 {
 throw new Exception(ex.Message);
 }
 }
 }
}

add this file to your code and later you can use it in your solution anywhere like below :

 ErrorLog.Logger("Info","yourtexthere");

kindly note that this will generate the logs file on your directory where the code is running in that case in the “BIN” folder. You can tweak the code to put it somewhere else if you need.

logs

Hope this helps!

Cheers!