Wednesday, May 06, 2009

Счётчик записей в MS CRM

Прочитав этот топик немного возмутился, потому что даже за мелочи наши заокеанские друзья готовы брать деньги. Мне, как немного работавшим и писавшим под MS CRM сходу было видно чем исполнители пользовались для создания такого функционала и сходу написание такого функционала я оценил в день работы. В этом сообщении я опишу, как и что надо сделать, чтобы получить такого рода функциональность.

Итак сердцем всего решения будет написание плагина на Execute сообщение, который в результирующую выборку будет добавлять запись, в которой будет отображаться количество страниц и записей.

Дальше код плагина - есть комментарии на английском. Если будут вопросы - задавайте.


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Win32;
using System.Xml;
using Microsoft.Crm.SdkTypeProxy.Metadata;
using Microsoft.Crm.Sdk.Metadata;

namespace TestPlugin
{
public class ExecuteHandler : IPlugin
{
public ExecuteHandler(string config, string secureConfig)
{
}

#region IPlugin Members

public void Execute(IPluginExecutionContext context)
{
if (context.Depth != 1) //To calculate count of pages and records another one fetch will be executed
return;//so to avoid infinite loops i need to check the depth of request - if it more then 2 - return

if (context.MessageName == "Execute" && context.InputParameters.Contains("FetchXml"))
{
XmlDocument indoc = new XmlDocument();
indoc.LoadXml((string)context.InputParameters["FetchXml"]);

//Retrieve name of entity to display
string entityName = indoc.SelectSingleNode("//fetch/entity").Attributes["name"].InnerText;
//Creation of Metadata service - it will be need for retrieving of main attribute of entity
MetadataService mservice = GetMetadataService(context.OrganizationName);

RetrieveEntityRequest request = new RetrieveEntityRequest();
request.RetrieveAsIfPublished = false;
request.LogicalName = entityName;
request.EntityItems = EntityItems.EntityOnly;
string primaryFieldName = ((RetrieveEntityResponse)mservice.Execute(request)).EntityMetadata.PrimaryField;

CorrelationToken ct = new CorrelationToken(context.CorrelationId, context.Depth, context.CorrelationUpdatedTime);

//CrmService Creation
CrmService crmService = GetCrmService(context.OrganizationName, ct);
crmService.CrmAuthenticationTokenValue.CallerId = context.InitiatingUserId;

//Count of records by page - for calculation of pages count
int pagecount = int.Parse(indoc.DocumentElement.Attributes["count"].InnerText);

//I remove this attributes for retrieve of all records in current view
indoc.DocumentElement.Attributes.Remove(indoc.DocumentElement.Attributes["count"]);
indoc.DocumentElement.Attributes.Remove(indoc.DocumentElement.Attributes["page"]);

//Xml of full result (without paging)
string fullResult = crmService.Fetch(indoc.OuterXml);

XmlDocument fullResultDocument = new XmlDocument();
fullResultDocument.LoadXml(fullResult);

//Total record count by fetch
int totalRecordCount = fullResultDocument.SelectNodes("//resultset/result").Count;
int totalPageCount = (totalRecordCount / pagecount) + ((totalRecordCount % pagecount) == 0 ? 0 : 1);

string result = string.Format("Total records = {0}, Total pages = {1}", totalRecordCount, totalPageCount);

//Result XML which is the result shown in Grid
XmlDocument outdoc = new XmlDocument();
outdoc.LoadXml((string)context.OutputParameters["FetchXmlResult"]);

//Creation of record which will show totals
XmlNode resResult = outdoc.CreateNode(XmlNodeType.Element, primaryFieldName, null);
resResult.InnerText = result;

XmlNode res = outdoc.CreateNode(XmlNodeType.Element, "result", null);
res.AppendChild(resResult);

//Adding record with label of count of pages and records as a first record in recordset
outdoc.SelectSingleNode("//resultset").InsertBefore(res, outdoc.SelectSingleNode("//resultset").FirstChild);
context.OutputParameters["FetchXmlResult"] = outdoc.OuterXml;
}
}

#endregion

private CrmService GetCrmService(string OrgName, CorrelationToken ct)
{
CrmAuthenticationToken token = new CrmAuthenticationToken();
token.AuthenticationType = AuthenticationType.AD;
token.OrganizationName = OrgName;

CrmService crmService = new CrmService();
crmService.UseDefaultCredentials = true;
crmService.Url = (string)(Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\MSCRM").GetValue("ServerUrl")) + "/2007/crmservice.asmx";
crmService.CrmAuthenticationTokenValue = token;
crmService.CorrelationTokenValue = ct;

return crmService;
}

private MetadataService GetMetadataService(string OrgName)
{
MetadataService result = new MetadataService();
result.Url = (string)(Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\MSCRM").GetValue("ServerUrl")) + "/2007/MetadataService.asmx";
result.Credentials = System.Net.CredentialCache.DefaultCredentials;

CrmAuthenticationToken token = new CrmAuthenticationToken();
token.OrganizationName = OrgName;
token.AuthenticationType = 0;

result.CrmAuthenticationTokenValue = token;
result.UnsafeAuthenticatedConnectionSharing = true;

return result;
}
}
}

Регистрировать плагин надо на сообщение Execute в Post режиме.

Вот что получилось после его паблиша:

1 comment:

  1. Thank you for your row count post. We have used your code to develop a clean, fast solution to the row count issue that displays the total row count on the status bar of the grid view. Basically, it transforms the fetch XML into an aggregate query, writes the count to a cookie, reads the cookie in grid.htc, and writes the count to the status bar of the grid view. If you are interested, we would like to share the code with your readers. You can contact me at mcgill@ardms.org. I am a senior software engineer with ARDMS, 51 Monroe St, Rockville, MD, USA.

    ReplyDelete