Showing posts with label XML. Show all posts
Showing posts with label XML. Show all posts

Aug 29, 2017

Retrieve Multiple - FetchXML with Alias

This is not a complex thing, but though of posting the code snippet since I found it important to explain a bit. When we need to retrieve data in related records few levels away from our current context, best method is using the FetchXML and use ReiveMultiple method. This will avoid us using many server calls to reach our entity.

Reason for writing this post is to explain one point. When we do complex FetchXMLs we definitely need to use Alias for linked entities. So reading the data in the code can be little different.

Check my example; I have an entity called job. Job got a lookup field to Project. Project got a lookup to User. Suppose we need to read the Mobile Number of the user (3 levels ahead) while we have only Job Id in hand, we use FetchXML as below;

internal static EntityCollection RetriveProjectAdminMobileByJobId(IOrganizationService service, Guid Id)
{
var fetchXml = string.Format(@"<fetch mapping='logical' output-format='xml-platform' version='1.0' distinct='false'>  
               <entity name='new_job'>
               <filter type='and'>
               <condition attribute='new_jobid' operator='eq' value='{0}' />
               </filter>
                   <link-entity name='new_project' to='new_jobprojectid' from='new_projectid' alias='PROJ' link-type='outer' visible='false'>
                       <link-entity name='systemuser' to='new_projectadmin' from='systemuserid' link-type='outer' alias ='PROJADMIN'>
                            <attribute name='mobilephone' />
                        </link-entity>
                   </link-entity>
               </entity>
               </fetch>", Id);
            return service.RetrieveMultiple(new FetchExpression(fetchXml));

Please notice, how I have used Aliases meaningfully. Now what we need to keep in mind is resulting fields would come with that Alias. In fact, mobile phone field is like PROJADMIN.mobilephone. Now check how I read it in C#;

var entityCollection = RetriveProjectAdminMobileByJobId(service, workOrderRef.Id);

if (entityCollection == null || entityCollection.Entities == null || entityCollection.Entities.Count <= 0)
    return;

if (entityCollection.Entities[0].Attributes.Contains("PROJADMIN.mobilephone"))
    string AdminMobile = (string)((AliasedValue)entityCollection.Entities[0].Attributes["PROJADMIN.mobilephone"]).Value;

I advice always try the FetchXmls before using. Best tool to do so is FetchXM Tester of XrmToolBox.


There is a one pitfall. I have seen some tools which are not returning the correct field names as expected. For example, I have tested same FetxhXML in DataSet creating tool in SSRS report authering extensions in VS2012 that returned like PROJADMIN-mobilephone, which is WRONG.

Oct 21, 2012

Rule definitions to enable buttons for All RECORDS or SELECTED REDCORDS

This is a handy way of enabling the buttons either for “all records” or “selected once”. I will explain a scenario as below;

Consider an action you need to do against the records populated in a grid/subgrid. Typically we may need to do the action in two ways;

1) We may need to select records and perform the action
2) We may need to perform action for all the records

My solution is to introduce two custom buttons with two rule definitions that work well in terms of useability engineering aspects.

When loading the grid you will see only “All records” button enabled as below. (Pic. A). Idea is, if user interested in executing the action against all record, nothing to worry, just press it.


Suppose, we need to cherry pick the records. Now as soon as we start to select records, we get the view of this. (Pic. B).



Now only “Selected records” button is enabled. There is no confusion; one can execute the action only for selected items. If user deselects everything again, ribbon buttons will get changed to previous state again. (Pic. A)

Now we will see the simple way of defining the enabling rules for both buttons.

<RuleDefinitions>
  <TabDisplayRules />
  <DisplayRules />
  <EnableRules>
    <EnableRule Id="Mscrm.Cu_Selected">
      <SelectionCountRule 
        AppliesTo="SelectedEntity" Maximum="25" Minimum="1">
      </SelectionCountRule>
    </EnableRule>
    <EnableRule Id="Mscrm.Cu_SelectedAll">
      <SelectionCountRule 
        AppliesTo="SelectedEntity" Maximum="0" Minimum="0">
      </SelectionCountRule>
    </EnableRule>
  </EnableRules>
</RuleDefinitions>

Value 25 can be changed as you wish, which marks the maximum number you can select keeping the select button enabled.

Related articles;
How to proceed with All RECORDS (i.e. Scenario A) for Advanced Find results : Click here
How to proceed with SELECTED RECORDS (i.e. Scenario B) : Click here

Oct 14, 2012

Custom Group in Entity Ribbon

It is useful to know how to implement a new group in the ribbon and also to put buttons inside it. Before starting to explain an example I am happy to remind you a basic rule again.

Ribbon modifications can be done in main three ways to distinguish how they should appear in to user. They can be explained as below;

Mscrm.Form.<entityname>change appears when form is opened for selected record.
Mscrm.HomepageGrid.<entityname>change appears when grid is shown (multiple records)
Mscrm.SubGrid.<entityname> - change appears when records appear within a subgid of some other entity OR appears in the result pane of the advanced find

OK, I am here going to do the sample for Subgrid (so my tag naming format will be like Mscrm.SubGrid.<entityname>). In my example I am going to consider a custom entity called new_insurance.

My scenario is to give few buttons to renew insurance. Here I am just implementing one button to create a quote, but I put it in a Group called “Renewal Methods” so I can have other optional buttons for the same need.

This is the main custom action tag. Noticeably, it contains a button tag as we already know. So we can have many as required.

<CustomAction Id="Mscrm.SubGrid.new_insurance.RenewalGroup.CustomAction" 
              Location="Mscrm.SubGrid.new_insurance.MainTab.Groups._children" 
              Sequence="110">
  <CommandUIDefinition>
    <Group Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Group" 
           Command="Mscrm.SubGrid.new_insurance.RenewalGroup.Command" 
           Title="Subscription Renewal" 
           Sequence="51" 
           Template="Mscrm.Templates.Flexible2">
      <Controls Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Controls">
        <Button Id="B_CUSTOM_QuoteCreate" 
                Command="Cmd_CUSTOM_QuoteCreate" 
                LabelText="Create Quote" 
                ToolTipTitle="Create Quotes" 
                ToolTipDescription="Create quotes for renewal subscriptions" 
                TemplateAlias="o1" 
                Image16by16="/_imgs/SFA/ReviseQuote_16.png" 
                Image32by32="/_imgs/SFA/ReviseQuote_32.png" />
      </Controls>
    </Group>
  </CommandUIDefinition>
</CustomAction>

Now we need to add two more custom action tags to define the appearance of the group we are introducing here.

<CustomAction Id="Mscrm.SubGrid.new_insurance.RenewalGroup.MaxSize.CustomAction" 
              Location="Mscrm.SubGrid.new_insurance.MainTab.Scaling._children" 
              Sequence="120">
  <CommandUIDefinition>
    <MaxSize  Id="Mscrm.SubGrid.new_insurance.RenewalGroup.MaxSize" 
              GroupId="Mscrm.SubGrid.new_insurance.RenewalGroup.Group" 
              Sequence="21" 
              Size="LargeLarge" />
  </CommandUIDefinition>
</CustomAction>

<CustomAction Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Popup.CustomAction" 
              Location="Mscrm.SubGrid.new_insurance.MainTab.Scaling._children" 
              Sequence="140">
  <CommandUIDefinition>
    <Scale Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Popup.1" 
           GroupId="Mscrm.SubGrid.new_insurance.RenewalGroup.Group" 
           Sequence="85" 
           Size="Popup" />
  </CommandUIDefinition>
</CustomAction>

Now this is nothing new, we just define a JavaScript method to pass the selected ids when button is clicked.

<CommandDefinition Id="Cmd_CUSTOM_QuoteCreate">
  <EnableRules>
    <EnableRule Id="Mscrm.Cu_Selected" />
  </EnableRules>
  <DisplayRules />
  <Actions>
    <JavaScriptFunction Library="$webresource:new_createquote.js" FunctionName="CreateQuote">
      <CrmParameter Value="SelectedControlSelectedItemIds"></CrmParameter>
    </JavaScriptFunction>
  </Actions>
</CommandDefinition>

Then we define a command definition, actually without any rule since group is to be just viewed.

<CommandDefinition Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Command">
  <EnableRules  />
  <DisplayRules />
  <Actions />
</CommandDefinition>

Then we define a command definition, actually without any rule since group is to be just viewed.
Finally we have an enable rule for the button which is quote smart. In fact, button get enabled only when at least one records selected and not more than 20 records selected. We change this as required.

<EnableRule Id="Mscrm.Cu_Selected">
  <SelectionCountRule 
    AppliesTo="SelectedEntity" Maximum="20" Minimum="1">
  </SelectionCountRule>
</EnableRule>

Once implement, we will see the subgrid Ribbon this;

Feb 8, 2012

Consuming a WCF from JavaScript

This is just to give simple steps to call a WCF from client side.

1) Browse the web service URL. Then you know your web service is available. You will see a page like below one.


2) Now click relevant link in the page. Search for SOAPAction tag relevant to method you wish to use, So that you know the SOAPAction value.


3) Now get the request SOAP envelops.

a) If you have the code of WCF service run the code in Visial Studio that results a pop up of WCF Test Client. Then double click the method you need and pass some values to parameters shown in Formatted tab. Then click the XML tab to grab the Request SOAP envelop. Just omit the Header Tag from the XML you get here.


b) If the web service is provided by some other party, you can simply request the soap envelops.

4) Now we got everything we need, call the relevant method of the Web Service through below code. xmlHttp.ResponseXML will return the result.

        xmlhttp = new XMLHttpRequest();
        xmlhttp.open('POST', 'http://localhost:5555/ISV/PricingWCF/WcfIntermediateService.Service1.svc', false);
        xmlhttp.setRequestHeader('Content-Type', 'text/xml; charset=utf-8');
        xmlhttp.setRequestHeader('SOAPAction', 'http://tempuri.org/IService1/GetSalesRate');

        var data = '';
        data += '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">';
        data += '<s:Body>';
        data += '<GetSalesRate xmlns="http://tempuri.org/">';
        data += '<productcode>AEC0023678</productcode>';
        data += '</GetSalesRate>';
        data += '</s:Body>';
        data += '</s:Envelope>';

        xmlhttp.send(data);

Click this to see how you call WCF service from plug-in.

Jan 29, 2012

Reading a XML configuration file in JavaScript

This is just a simple code sample to read settings kept in XML configuration file, while you are working in client side. Below is the sample of my configuration file. It contains key/value pairs of settings.

<?xml version="1.0"?>
<Configuration xmlns="http://www.abc.com.au">
  <Appsetting Name="httpServer">abc:5555</Appsetting>
  <Appsetting Name="OrgName">abcLtd</Appsetting>
  <Appsetting Name="PriceAccessCode">NUOD66701</Appsetting>
</Configuration>

This is the JavaScript method which could be used to access those.

readConfigFileSettings = function (_url, _reqTag)
{
var objXML = new ActiveXObject("Microsoft.XMLDOM");
objXML.async = false;
objXML.load(_url);
if (objXML.parseError.errorCode != 0)
{
    alert("Error reading file : " + objXML.parseError.reason);
    return null;
}

var config = objXML.selectSingleNode("//Configuration");
var _retrunStr = '';
for (var i = 0; i < config.childNodes.length; i++)
{
 if (config.childNodes[i].attributes[0].nodeTypedValue == _reqTag)
 {
 _retrunStr = config.childNodes[i].nodeTypedValue;
 }
}
if (_retrunStr == '')
{
    _retrunStr = reqTag + ' cannot be found in config file';
}
return _retrunStr;
}

_Url parameter is to give the path of the configuration file (example 'C:\\inetpub\\wwwroot\\AbcAndCompany\\abcAdmin.config';) and _reqTag is the required tag (example: httpServer, OrgName or PriceAccessCode)