Saturday, April 27, 2019

Asp.Net MVC (5) - Exception Filter - HandleError


Applicable on Asp.Net MVC5

HandleError Filter

This belongs to Exception Filters category (Authentication Filter, Authorization Filter, Action Filter, Result Filter & Exception Filter) . This is out of the box filter provided by .Net MVC team. We can develop our customized exception filter by extending the IException interface and overriding its method, the way other customized filters are created.

By default HandleError filter redirects to "Error" view placed in Views/Shared folder. This filter can be placed on controller level as well as on Action level. Whenever exception occurred this filter redirect to Error view (by default / custom view if specified in filter). 
Developer can place the error details on Error view. 

Scenario: In below situation there is some exception occurred (SQL connectivity / divide by zero / Null reference exception). In this case the system redirects to Error view showing the details of error. 

Wednesday, April 17, 2019

_Viewstart Page in ASP.NET MVC


_Viewstart is a special page to embed layout page with views.
  • The _ViewStart.cshtml page is a special view page containing the statement declaration to include the Layout page.
  • Instead of declaring the Layout page in every view page, we can use the _ViewStart page.
  • When a View Page Start is running, the “_ViewStart.cshtml” page will assign the Layout page for it.
  • This make very easy to maintainable application


㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤ Ali Hamza Wadood  | Software Engineer - Microsoft Technologies| LinkedIn

Wednesday, March 20, 2019

Web.Config with separate sections for DEV, STAG & PROD - Asp.Net / Dynamics CRM

Hi,
In this post I am going to show how to have separate sections for development, staging and production environment in web.config in asp.net / dynamics CRM Plugin. Same can be put in dynamics crm record with multi line field in (for instance custom configuration entity)

Below are steps to achieve this functionality

1) Web.config

Web.config will look like this

<configuration>

  <configSections>

    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->

    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

    <section name="MyConfigs" type="MyConfigs.ABCGroupConfigsSection" />



  </configSections>

  <appSettings>

    <add key="CurrentEnvironment" value="DEV" />

  </appSettings>

  <MyConfigs>

  <DEV>

    <add key="crmconnection" value="https://samplecrm4.dynamics.com" />

  <add key="logFolderPath" value="E:\Log\" />

  <add key="key1" value="blahblahblah" />

  <add key="key2" value="blahblahblah" />

  <add key="key3" value="blahblahblah" />

  <add key="key4" value="blahblahblah" />




  </DEV>

  <STAG>

  <add key="crmconnection" value="https://samplecrm4.dynamics.com" />

  <add key="logFolderPath" value="E:\Log\" />

  <add key="key1" value="blahblahblah" />

  <add key="key2" value="blahblahblah" />

  <add key="key3" value="blahblahblah" />

  <add key="key4" value="blahblahblah" />


  </STAG>

  <PROD>

   <add key="crmconnection" value="https://samplecrm4.dynamics.com" />

  <add key="logFolderPath" value="E:\Log\" />

  <add key="key1" value="blahblahblah" />

  <add key="key2" value="blahblahblah" />

  <add key="key3" value="blahblahblah" />

  <add key="key4" value="blahblahblah" />


  </PROD>

    </MyConfigs>

<!-- Other configurations here -->

</configuration>


2) Code

 public class ABCGroups
    {
     
        public static ABCGroupConfigsSection _Config = ConfigurationManager.GetSection("MyConfigs") as ABCGroupConfigsSection;
        public static ABCElementCollection GetSection(string name)
        {
            try
            {
             
                if (name == "DEV")
                    return _Config.DEVGroups;
                else if (name == "STAG")
                    return _Config.STAGGroups;
                else if (name == "PROD")
                    return _Config.PRODGroups;
            }
            catch (Exception ex) {
         
                throw new Exception(ex.Message);
            }

            return null;
        }
    }
     
        public class ABCGroupConfigsSection : ConfigurationSection
        {
            //Fill the property with the tag of respective collection.
            [ConfigurationProperty("DEV")]
            public ABCElementCollection DEVGroups
            {
                get { return (ABCElementCollection)this["DEV"]; }
            }

        //Fill the property with the tag of respective collection.
        [ConfigurationProperty("STAG")]
        public ABCElementCollection STAGGroups
        {
            get { return (ABCElementCollection)this["STAG"]; }
        }

        //Fill the property with the tag of respective collection.
        [ConfigurationProperty("PROD")]
            public ABCElementCollection PRODGroups
            {
                get { return (ABCElementCollection)this["PROD"]; }
            }
    }

   
        [ConfigurationCollection(typeof(ABCGroupElement))]
        public class ABCElementCollection : ConfigurationElementCollection
        {
            public ABCGroupElement this[int index]
            {
                get { return (ABCGroupElement)BaseGet(index); }
                set
                {
                    if (BaseGet(index) != null)
                        BaseRemoveAt(index);
                    BaseAdd(index, value);
                }
            }
            protected override ConfigurationElement CreateNewElement()
            {
                return new ABCGroupElement();
            }
            protected override object GetElementKey(ConfigurationElement element)
            {
                return ((ABCGroupElement)element).key;
            }


        }
   
        public class ABCGroupElement : ConfigurationElement
        {
            [ConfigurationProperty("key", IsRequired = true)]
            public string key
        {
                get { return (string)this["key"]; }
                set { this["key"] = value; }
            }
            [ConfigurationProperty("value", IsRequired = true)]
            public string value
        {
                get { return (string)this["value"]; }
                set { this["value"] = value; }
            }
       
        }

Sunday, January 20, 2019

Working With Word Templates

I was involved with world template requirements for different entities. There were different things / hacks and bugs / problems I found during implementing Word Templates. I am trying to cover and list these things in this post. This might help any one else in understanding word templates and its issues.

1) Repeat Tag giving Null records in table

Repeat Tag is used for child entity records to list multiple records for parent records. For instance Invoice -> Invoice Detail. For repeat tag to work we have to use the same publisher  prefix / same solution where we have created the child entity. Let me explain

Suppose you create custom child entity in solution "My Solution" having publisher with prefix "dev". Now this custom entity should have relation with Account Entity. Suppose we are capturing different Events data dynamically for the accounts.
Now if I made the relationship between Account and Events (custom entity) in default solution with prefix "new_" what will happen is the entity is created with prefix "dev_" but the relationship between account and envent is something like new_account_event_xxxxx.
This will lead word templates not to show the records for event entity. You will expect word tempates to populate / map records in table using repeating tag and even if there is data for that particular account in event entity in Dynamics, still when you generate word template for that account, word template will always give you null table and no events data will gen reflected in word file.

So to avoid null child records, must have to create the relationship from within the solution "My Solution" i.e. using prefix dev


2) Getting Updated / New fields for the entity

Suppose you have generated the word template from dynamics for Account entity and you have included all fields, relationships (1:N, N:1 & N:N) and you are using the template. Later there was new / existing requirement for which you need to add another field on account. But this new field is not available in your word template. In this scenario the solution is below

Download new template file from Dynamics
Remove .docx extension and changed it to zip
Export the zip
Now in customxml folder there will xml file(s), select the larger one.
Now in word template of your template "Select Add new part" in XML mapping in Custom XML Part:
Now you have another xml schema with same name, select the last one.
This will have updated / new fields and relationships within word file.
Below is same process with visual representation copied from (https://dynamicscrmpros.com/update-existing-word-templates-dynamics-365-crm/)

Add Updated Fields / Entities (XML) to an existing template:

1.    In your CRM environment, navigate to the Templates area under Settings
2.    Click on Document Templates
3.    Click + New to create a new Word Template
4.    Select the primary entity you will be pulling data from to use in the word template
1.    If you’re updating an existing template, make sure to choose the same primary entity as the exiting
2.    If you’re creating a new word template for an already created word document, select the necessary primary entity the word template will be ran from.
5.    If necessary, select any necessary relationships that you’d like pull from the related entities of the primary entity
6.    Download the template and save on your local PC
7.    In Windows Explorer, navigate to the location the template was saved
– I recommend creating a folder and putting the document in this folder. You’ll see why in the next couple of steps
8.    Rename the file and replace the file extension from .docx to .zip


9.    Right click on the file and use a compression tool such as 7-Zip or WinZip to extract the file in the folder the file resides in



10.  You should now see the extracted files like the example


11.  Take note of this file location

12.  On your PC, navigate to and open the word template that needs updated
13.  You will need to enable the Developer tab in Word to bring in the Custom XML Part. If you have already enabled the Developer tab in Word, skip to step 18. If you have not, continue with the below steps to enable
14.  In Word, navigate to File > Options > Customize Ribbon.

15.  Check the box next to Developer
16.  Click ok
17.  You should now see the Developer tab in the ribbon
18.  Click on the Developer tab > XML Mapping Pane
19.  The XML Mapping pane should appear

20.  Click the drop down under Custom XML Part

21.  Click Add new part…

22.  Navigate to the file location from Step 10 and open the customXml folder
23.  Select the xml file. If you have two, select the one that is larger in size and click open.


24.  In the Custom XML Part drop down, you should now see two parts that start with urn. One is the original one from when the template was created, the other is the new one with the latest fields and/or relationships.


25.  Add the updates to the word template and save the document
26.  Upload the updated template to CRM and test your updates


Tuesday, September 18, 2018

Order Product Bundle Items


In this post, I am going to describe how to retrieve Sales Order Product items for a particular Product Bundle. If a bundle has 10 products and this bundle is added in sales order lines. This will make 11 sales order lines one header with bundle title and rest as bundle products.
So if we want to get quantity of all bundle items excluding header bundle item then we need to find the relationship and data values insert by Dynamics 365 in backed.
In below plugin, I am demonstrating how to get the bundle item id (sales order line item). Then we can query (fetchxml / query expression) to retrieve all lines having the bundle id in Parent Bundle Id.

Plugin (In this plugin I am showing how to  retrieve bundle id)

using Microsoft.Xrm.Sdk;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test.Plugins
{
    public class BundleProductQtyCheck : IPlugin
    {
        bool IsDebug = false;
       
        public void Execute(IServiceProvider serviceProvider)
        {
            IsDebug = false;
            Entity DebugEntity = new Entity("new_plugindebug");
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = factory.CreateOrganizationService(context.UserId);
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
           
            string DebugDesc = " Started...";
           
            try
            {

           
               


                string strGcTest = "";
                string NEWLINE = "";
                strGcTest = " Plugin Debug started... at " + DateTime.Now + NEWLINE;
               


                string entityName = "";

                Entity OrderLine = null;
                Entity RetrievedOrderLine = null;
                OrderLine = (Entity)context.InputParameters["Target"];
                entityName = OrderLine.LogicalName;

                if (context.MessageName == "Update")
                {
                    if (OrderLine.Attributes.Contains("shipto_telephone"))
                        return;
                    RetrievedOrderLine = service.Retrieve(OrderLine.LogicalName, OrderLine.Id, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));
                    if (RetrievedOrderLine.Attributes.Contains("parentbundleid")) {
                        OrderLine["shipto_telephone"] = ((Guid)RetrievedOrderLine["parentbundleid"]).ToString();
                        service.Update(OrderLine);

                    }
                }

            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex.InnerException);
                tracingService.Trace(ex.Message);
                if (IsDebug)
                {
                    DebugEntity["new_name"] = this.ToString();
                    DebugEntity["new_description"] = DebugDesc + "\n" + DebugEntity.GetAttributeValue<string>("new_description") + ex.Message + "\n" + ex.ToString();
                    service.Create(DebugEntity);
                }
            }
        }

    }
}








㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤ Ali Hamza Wadood Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC) LinkedIn

Tuesday, September 4, 2018

Auto No Dynamics 365 V8.2

I was involved in project using Microsoft Dynamics 365 V8.2. I downloaded the auto number solution, one available for Dynamics CRM 2016 and previous releases. This solution was working fine on previous versions but on Dynamics 365 V8.2, there was error using this solution. I searched and tried to find some alternatives but was not able to find any one. So I thought to develop my own Auto-Number utility / solution for Microsoft Dynamics 365 V8.2.

Below are screen shots for the entity holding configurations for auto number.


At this time Auto No Length is fixed to 5. I will make that dynamic later. Below are details of configuration
Name: Put whatever name you want
Auto No Length: Put 5 (Fix at this time)
Auto No Value: Put value from where you want auto no to increment (First number is 0)
Entity Name: Name of entity
Mapping Field: Field schema name which will hold the auto number value
Prefix / Sufix: Will update in next versions
Zero Pad: Currently zeros are displayed with length of 5 i.e. for number 1 four zeros will be added. This is not changeable int current version

Currently Plugin is also not dynamic (Based on configuration value to fire plugin). Customization Consultant / Developer has to manually register plugin for desired entity and message.

Below is plugin step screen shot.























This is Auto No Solution for Dynamics 365 V8.2 (Uploading soon....)


㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤ Ali Hamza Wadood Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC) LinkedIn

Monday, September 3, 2018

Web API Invoke Roll up Field Update

In this post I am sharing the solution to requirement of updating Roll up field using Web API.

Tested on: Dynamics 365 V9.0 Online
Entity Name = new_projects
Field Name = new_totalactualduration


function UpdateRollUp(){
var id ="";
var url = "https://WebAPIAddress/api/data/v9.0/CalculateRollupField(Target=@tid,FieldName=@field)?@tid={%27@odata.id%27:%27new_projects()%27}&@field=%27new_totalactualduration%27"

}




㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤ Ali Hamza Wadood Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC) LinkedIn

Check User Specific Role - Web API (1 API Call) - Dynamics CRM 365

I was working in a requirement where ribbon customization was required based on user role. Many ribbon buttons were hidden / visible based on different roles assigned to user. There was also custom button on ribbon bind with custom JavaScript function.

 Due to more buttons bind with Enable Rules to set their visibility result in slow page load and increase user wait for Ribbon Buttons.

Previously, I was getting user roles ids from XRM method and then checking the name of roles by getting role name through Web API retrieve request and passing guid of role as parameter. This means if there are 7 roles assigned to user then system will make 7 API Calls.
Also on custom button trigger, System was again loading the webresource and as API Calls were made outside any function therefore system also made API Calls before triggering custom ribbon button function. There were separate web resource for Enable Rules of Ribbon Buttons. There were methods which were used in Entity Main web resource and in Enble Rules web resource.
What I did was that I create another web-resource and write a class of Dynamics CRM Roles. This class contain method and an array to load all roles from Dynamics CRM 365. So I loaded the array with role name and role guid using the Web API retrieve request for roles. This technique loaded the array with all roles and made the API Call only once.
Now in my logic and other areas where I was checking with role name whether user is assigned that or not, I was using the roles array to match.
So this result in making Web API Call only once.

Here is my code logic.

Updating shortly ....






㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤
Ali Hamza Wadood Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC) LinkedIn

Custom Workflow to send Email to All Team members

There was a requirement in project to send email to all Team members of a certain Queue, whenever a new item is added to that Queue.
To achieve this requirement, I have developed custom workflow so that configuration can be done from the Dynamics Workflow interface / window.

Below is Dynamics Workflow screen
For Beginners: Solution -> Processes -> Create New Process as workflow



















































Saturday, March 31, 2018

Check User Specific Role - Web API - Dynamics CRM 365

In this post, I am going to demonstrate how to check that current logged in user has specific role or not in Dynamics CRM 365 using JavaScript & Web API.


function IsRoleExist(RoleName) {
    var currentUserRoles = Xrm.Page.context.getUserRoles();
    for (var i = 0; i < currentUserRoles.length; i++) {
        var userRoleId = currentUserRoles[i];
        if (GetRoleName(userRoleId) == RoleName) {
            return true;
        }
    }
    return false;

}

function GetRoleName(RoleId) {
    var select = "roles(" + RoleId + ")?$select=name";

    var result = AWXRM.WebAPISelectVersion(select, "8.2");
    var Rolename = result["name"];
    return Rolename;

}

function OnLoad() {

var Role_Admin = "System Admin_1";
var IsRoleExist = null;

   if (IsRoleExist(Role_Admin))
            IsRoleExist = true;
        else
            IsRoleExist = false;
}

Dependency:
Need this library to be included in form load / page load
AWXRMLibrary


㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤
Ali Hamza Wadood 
Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC)
LinkedIn



Enable Rule for Default Buttons - Ribbon Workbench - Dynamics CRM 365


1) Install Ribbon Workbench from here
2) Import solution in your Dynamics CRM 365 instance
3) A button "RIBBON WORKBENCH 2016" is created in Solution Page. Click on it
























4) Now new window is opened. Select your desired solution containing entity to be customized. It is better to create a separate solution to be used for ribbon customization and contains only desired entity. In this scenario I have created a new solution "Ribbon Solution" contain only Case entity. Here I am selecting solution Ribbon Solution

























5) Now solution is opened in ribbon workbench. Select your desired entity and on button right mouse click. Now select Customize Command. (In my case as button is already customized therefore this command is shown disabled)























6) Now in command section, select the generated command and click on Add Enable Rule. Now select Add New Enable Rule.




























7) Now click on Add Step & select CustomRule. There are others rules to apply enable rules on button. Here I am only showing the CustomRule.























Friday, March 30, 2018

Object Oriented Javascript - Dynamics CRM 365

I have done lot of work using javascript in Dynamics 365 (CRM) / CRM Projects. During many routine tasks I always used to think about how to optimize my code?, so able to do more with less code. Therefore achieve code reuse-ability, extensiveness and object oriented style. In below Javascript technique I am trying to demonstrate this approach.






function Customer() {

    this.name =  AWXRM.GetXRMAttributeGetVal("name");
    this.custid = AWXRM.GetXRMAttributeGetVal("accountnumber");
    this.address = AWXRM.GetXRMAttributeGetVal("wtr_plot");
    this.customertype = AWXRM.GetXRMAttributeGetText("wtr_customertype");
    this.cnic = AWXRM.GetXRMAttributeGetVal("wtr_cnic");
    this.phone = AWXRM.GetXRMAttributeGetVal("telephone2");
    this.cell = AWXRM.GetXRMAttributeGetVal("telephone1");
    this.guid = Xrm.Page.data.entity.getId();
    this.guidplan = this.guid.replace("{", "");
    this.guidplan = this.guid.replace("}", "");
    this.invoices = {};
    this.invoices.invoicedetails = {};

}

function OnSave(){

   var customer = new Customer();

}




㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤
Ali Hamza Wadood 
Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC)
LinkedIn

Saturday, March 24, 2018

Calling REST Web Service in Plugin


I was involved in a project where I have to consume REST Web services to integrate with Dynamics CRM 2016. Below plugin was used to perform this operation.

The web service used POST operation. and retrieved a specific authentication string present in response headers.



























Wednesday, January 17, 2018

Custom Workflow vs Plugin


Workflow / Custom Workflow:
1) Can be triggered on less than 10 actions (Create, Edit etc)
2) Have Input, Output Parameters
3) Provide Administrators interface / window to configure the parameters or triggers configurations.




Plugins
1) Run on 200+ Messages
2) Don't provide interface to configure parameters
3) Provide Plugin Registration tool to register and configure attributes and plugin to be ran on.



I wrote in hurry, I will update the plugin part later. If you can add for me, that will be great!!!


㉺㉼㉴㉳㉽㉾㈕㈔㈆㈅㈄㈄㈃㈁㈀㉤
Ali Hamza Wadood 
Microsoft Dynamics CRM Developer | Software Engineer - Microsoft Technologies(Asp.Net, Asp.Net MVC)
LinkedIn

Tuesday, October 10, 2017

Dynamics CRM Development using Object Oriented Design Techniques

#CompositeDesignPattern
Dynamics CRM development can be much easier and efficient using "Object Oriented Design" techniques. Let me explain.

Suppose the case study of dynamics CRM is such that xyz business is having customers as companies each company has sub branches which is again customers. Customers have people representing contacts for the business.

If I say that customers are accounts then sub branches means self relationship with accounts so there is 1-n  self relation between accounts. Now for representatives of company, we have contacts entity in CRM. so there is 1-n relation between accounts and contacts.

Means
1 - N relation : Accounts -> Accounts
1 - N relation : Accounts -> Contacts

Now suppose I want to get all such information, logic and relationships in terms of object oriented design, what I should do is. Firstly I will identify the objects in this case study.

I have two objects Accounts and Contacts.



So now I will surely and definitely  define classes for these objects. i.e. the pillar of object oriented design.
I have Account class and Contact class. Should I start writing these classes and adding properties for the respective objects? But what if I have properties which are same in both objects. Or I will prefer to make and identify properties similar for both classes and all other classes which can be added later for CRM case studies.

So for the purpose of adding similar properties I will like to define an Abstract class. This class will hold the parent class properties and act as base class to share the properties and methods for all child classes (entities of CRM).


Model: (Objects) 


using Microsoft.Xrm.Sdk;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Account
{
    class Model
    {
    }

    /// <summary>
    /// Abstract Entity Class
    /// </summary>
    public abstract class CRMEntity
    {   
        public Entity Entity;
        public EntityReference EntityReference;
        public string EntityDisplayName;
        public string Href;
        public string CurrentAttributeName;
        //Other Common Properties


        public CRMEntity(Entity entity)
        {
            this.Entity = entity;
            this.EntityReference = new EntityReference(entity.LogicalName, entity.Id);
            this.Href = "https://datainvent-sandbox.crm3.dynamics.com/main.aspx?etn=" + Entity.LogicalName + "&id=" + Entity.Id.ToString() + "&newWindow=true&pagetype=entityrecord";
            //     https://datainvent-sandbox.crm3.dynamics.com/main.aspx?etn=insr_inspectionelement&id=60a3e6da-5584-e711-8125-480fcff44541&newWindow=true&pagetype=entityrecord


        }

        public CRMEntity(Entity entity, string EntityDisplayName) : this(entity)
        {

            SetName(EntityDisplayName);
        }

        public void SetName(string EntityDisplayName)
        {
            this.EntityDisplayName = EntityDisplayName;
            this.Entity.Attributes.Add("EntityName", this.EntityDisplayName);

        }

        public bool IsValidAttribute(string name)
        {
            if (this.Entity.Attributes.Contains(name))
                return true;

            return false;
        }

    }

    public class Account : CRMEntity
    {
        public Account ParentAccount { get; set; }
        public List<Account> SubAccounts = new List<Account>();
        public List<Contact> Contacts = new List<Contact>();

        public Account() : base(new Entity(EntityNames.Account)) { }

        public Account(Entity entity) : base(entity) { }

        public Account(Entity entity, Account ParentAccount) : base(entity) {
            this.ParentAccount = ParentAccount;
        }

        public string Name
        {
            get
            {
                CurrentAttributeName = "name";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<string>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "name";
                this.Entity[CurrentAttributeName] = value;
            }


        }

        public Guid AccountId
        {

            get
            {
                CurrentAttributeName = "accountid";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<Guid>(CurrentAttributeName);
                }

                return Guid.Empty;
            }
            set
            {
                CurrentAttributeName = "accountid";
                this.Entity[CurrentAttributeName] = value;
            }

        }

        public string AccountNo
        {
            get
            {
                CurrentAttributeName = "accountno";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<string>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "accountno";
                this.Entity[CurrentAttributeName] = value;
            }


        }

    }

    public class Contact : CRMEntity
    {
        public Account ParentAccount { get; set; }

        public Contact() : base(new Entity(EntityNames.Account)) { }

        public Contact(Entity entity) : base(entity) { }

        public string FirstName
        {
            get
            {
                CurrentAttributeName = "firstname";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<string>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "firstname";
                this.Entity[CurrentAttributeName] = value;
            }


        }

        public string LastName
        {
            get
            {
                CurrentAttributeName = "lastname";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<string>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "lastname";
                this.Entity[CurrentAttributeName] = value;
            }


        }

        public Guid ContactId
        {

            get
            {
                CurrentAttributeName = "contactid";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<Guid>(CurrentAttributeName);
                }

                return Guid.Empty;
            }
            set
            {
                CurrentAttributeName = "contactid";
                this.Entity[CurrentAttributeName] = value;
            }

        }

        public EntityReference ParentAccountId
        {

            get
            {
                CurrentAttributeName = "parentcustomerid";
                if (this.IsValidAttribute(CurrentAttributeName))
                {
                    return this.Entity.GetAttributeValue<EntityReference>(CurrentAttributeName);
                }

                return null;
            }
            set
            {
                CurrentAttributeName = "parentcustomerid";
                this.Entity[CurrentAttributeName] = value;
            }

        }

    }

    public class AccountHierarchy
    {
        public List<Account> Accounts { get; set; }
        public List<Contact> Contacts { get; set; }

        public AccountHierarchy() {
            Accounts = new List<Account>();
            Contacts = new List<Contact>();
        }
    }


    public class EntityNames
    {
        public static string Account = "account";
        public static string Contact = "contact";
    }

}

Saturday, October 7, 2017

X-Frame-Options = Same Origion

This case is about adding iframe in Dynamics CRM and setting asp.net web form / mvc page to show. One error which can prevent page to load is X-Frame-Options = Same Origion. This occur if there is below line in code

 @Html.AntiForgeryToken()



Also this can occur because off AntiForgeryConfig or similar methods. Usually this is present to not allowed suspicious scripts to run. But anti forgery code add header of x-frame-options and sets value equal to 'same origion'. Which means that no cross domain script is allowed to run. If you have Ajax requests from other servers / domains, then chrome show error of

Refused to display from ..... because of X-Frame-Options = Same Origion

Tuesday, September 26, 2017

Custom Dynamics CRM Integration with SharePoint (Tested on Dynamics 365 Online)


Scenario:
Requirement is that there must be Document type with each document, so that when document is uploaded from crm to sharepoint the document type can be tracked.
One solution can be to create a field (text field / option set) in CRM & SharePoint and mapped so that when document is uploaded the filed can be filled. But this solution was not found after hours of effort and searching for SharePoint.

One solution can be to create folder as per each Document Type in respective record. This will give option to upload document using CRM in respective site location which will represent respective folder in SharePoint.

Thursday, September 21, 2017

Custom XRM Library: Enhance functions

Custom XRM Library to enhance the functionality of xrm functions. This library is a small effort from my side. This includes validations and avoid null reference exceptions in javascript.

I am improving it and planning to add more functions and improvements.

Download

Web API retrieve Specific Account all fields


   var customerid = ""; // Pass account guid here or get from context as per your logic.

    // replacing brackets if found in id

        customerid = customerid.replace("{", "");
        customerid = customerid.replace("}", "");

Sunday, June 25, 2017

CRM 365 Online - Discovery Service

Hi,

Today I was writing code in order to use CRM Discovery Service to retrieve my CRM organizations list for Dynamics 365 Online. To find out Web Application URL  (CRM Application Url), Organization Service Url and Organization data service URL






Casting Error of DiscoveryServiceProxy in CRM 365 Online







Problem Solution:
To solve Discovery Service Proxy casting error on Dynamics 365, I have used Microsoft.Xrm.Tooling.Connector


Below is the solution code.


OrganizationDetailCollection orgDet = Microsoft.Xrm.Tooling.Connector.CrmServiceClient.DiscoverOrganizations(CRMService.DiscoveryUri, null, CRMService.CRMcredentials, null);

Debug.Write(orgDet[0].Endpoints[EndpointType.OrganizationService]);


Explanation:

I tried using Microsoft.Xrm.Sdk.Client.DiscoveryServiceProxy as used to do in previous versions of CRM  (Online / On-Premises). Every thing works fine but when the program reached at line where DiscoveryResponse object is casted to its derived class RetrieveOrganizationsResponse, program throw exception as shown.




Asp.Net MVC (5) - Exception Filter - HandleError

Applicable on Asp.Net MVC5 HandleError Filter This belongs to Exception Filters category (Authentication Filter, Authoriz...