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 режиме.

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