locked
Free Record Counter RRS feed

  • General discussion

  • While i was reading this thread i was thinking - is it hard to write such functionality for me or not. I tried and in some hours i retrieved the result. Code which execute required functionality:

    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;
            }
    
        }
    }
    


    Build library, register it onto Execute message on Post Stage.

    I don't see for what pay something about 500$... May be i'm stupid?
    Истина открывается подготовленному уму. Мой блог - http://a33ik.blogspot.com
    Wednesday, May 6, 2009 12:28 PM
    Moderator

All replies

  • Hi,

    great sample code! Thank you!

    Three additions:

    1.) Is the a special reason not to use something like "ICrmService crmService = context.CreateCrmService(true);"?

    2.) This is not for associated views.

    3.) The result is only written in the Primary Field. It would be nicer to have it in the first column.

    Thank you again for this great sample code!

    Best regards,
    Jürgen


    Jürgen Beck

    Dipl. Kfm./Wirtschaftsinformatik
    MVP, MCSD.NET, MCITP DBA, MCDBA, MCSE
    Microsoft Certified Business Management Solutions Professional
    Microsoft Certified CRM Developer
    Microsoft Certified Trainer

    ComBeck IT Services & Business Solutions
    Microsoft Gold Certified Partner
    Microsoft Small Business Specialist

    Developing & Supporting Business Applications from small business to big enterprises covering scores of sectors

    http://www.combeck.de
    Wednesday, May 6, 2009 1:06 PM
    Moderator
  • Hi, Jürgen

    I wrote this plugin as a sample that to write such plugin isn't a problem.
    Using CrmService - when a began work as CRM Developer - near half year ago - i had some problems with
    "ICrmService crmService = context.CreateCrmService( true ); " code. Don't remember waht problems...

    Code can be modified in any way. Make result to the first field - 15 minutes of work =)

    Истина открывается подготовленному уму. Мой блог - http://a33ik.blogspot.com
    Wednesday, May 6, 2009 1:12 PM
    Moderator
  • Hi,

    there were problems with this because "localhost" was use in Standard what is not alway correct. But this is solved with UR3.

    Best regards,
    Jürgen
    Jürgen Beck

    Dipl. Kfm./Wirtschaftsinformatik
    MVP, MCSD.NET, MCITP DBA, MCDBA, MCSE
    Microsoft Certified Business Management Solutions Professional
    Microsoft Certified CRM Developer
    Microsoft Certified Trainer

    ComBeck IT Services & Business Solutions
    Microsoft Gold Certified Partner
    Microsoft Small Business Specialist

    Developing & Supporting Business Applications from small business to big enterprises covering scores of sectors

    http://www.combeck.de
    Wednesday, May 6, 2009 1:26 PM
    Moderator
  • Hi, Jürgen.

    For assosiated views RetrieveMultiple message plugin can be used. It's a bit different, but it also not difficult =)

    Истина открывается подготовленному уму. Мой блог - http://a33ik.blogspot.com
    Wednesday, May 6, 2009 2:22 PM
    Moderator
  • Can you give a little more info on what this code does?   Is it counting the total records in a view and displaying it somewhere?
    Wednesday, May 6, 2009 3:37 PM
  • Can you give a little more info on what this code does?   Is it counting the total records in a view and displaying it somewhere?
    Hi.

    Look this screenshop . There are total records and pages count on the first row of view.

    Истина открывается подготовленному уму. Мой блог - http://a33ik.blogspot.com
    Wednesday, May 6, 2009 4:11 PM
    Moderator
  • Thank you soo much :-) it will help me alot
    Thanks, Aarch
    Thursday, May 7, 2009 7:26 AM
  • Additionally it is to add that the information is displayed in the Primary Field column.

    When there is no Primary Field column displayed there is no information visible.

    Best regards,
    Jürgen
    Jürgen Beck

    Dipl. Kfm./Wirtschaftsinformatik
    MVP, MCSD.NET, MCITP DBA, MCDBA, MCSE
    Microsoft Certified Business Management Solutions Professional
    Microsoft Certified CRM Developer
    Microsoft Certified Trainer

    ComBeck IT Services & Business Solutions
    Microsoft Gold Certified Partner
    Microsoft Small Business Specialist

    Developing & Supporting Business Applications from small business to big enterprises covering scores of sectors

    http://www.combeck.de
    Thursday, May 7, 2009 8:02 AM
    Moderator
  • Hi,

    there is an error with the automatic lookup resolution. If you type something in a lookup there comes a general error.

    Best regards,
    Jürgen
    Jürgen Beck

    Dipl. Kfm./Wirtschaftsinformatik
    MVP, MCSD.NET, MCITP DBA, MCDBA, MCSE
    Microsoft Certified Business Management Solutions Professional
    Microsoft Certified CRM Developer
    Microsoft Certified Trainer

    ComBeck IT Services & Business Solutions
    Microsoft Gold Certified Partner
    Microsoft Small Business Specialist

    Developing & Supporting Business Applications from small business to big enterprises covering scores of sectors

    http://www.combeck.de
    Friday, May 8, 2009 7:35 AM
    Moderator
  • Hi,

    Thanks a33ik for sharing such a wonderful code !

    You've been very helpful to users out here along with Jurgen!!!


    Even i was facing the issue that Jurgen is facing, in case of automatic lookup resolution!

    Regards,
    Nishant Rana

    http://nishantrana.wordpress.com
    Friday, May 8, 2009 7:52 AM
  • Hi, Jürgen and Nishant
    I found another one bug - Service calendar doesn't work. My code is the base based on which enyone can create, modify and update existing functionality. It's not a release. Just code sample ) It's just attempt to show mighty of MS CRM Core =)

    Истина открывается подготовленному уму. Мой блог - http://a33ik.blogspot.com
    Friday, May 8, 2009 8:25 AM
    Moderator
  • Hi,

    That's true, the code sample is meant for guiding others!!

    Thanks again !

    Regards,
    Nishant Rana
    http://nishantrana.wordpress.com
    Friday, May 8, 2009 8:37 AM
  • We have developed a complete record and page counter solution that seamlessly and easily integrated into CRM. The GI RCO counter supports all CRM views including auto resolve lookup and form assistant.

    I made it publicly available under a very appealing royalty free distribution license so partners will find it worthwhile and won’t waste time and money on trying to recreate this functionality which eventually costs more to develop then acquiring the source code.

    The Counter was already implemented successfully at live customers with hundreds of thousands of records. It works really fast and has minimal performance impact.

    The counter supports associated views and displaying of summery results on any given column.
    You can find more information, a video demonstration and images of supported views at my blog.

     


    Blog: http://mscrm4ever.blogspot.com/ * Website: http://gicrm.upsite.co.il/
    Friday, May 8, 2009 11:43 AM
  • HI,

    interesting sample code.

    Have You figured out how to catch the rollup message to count activities or cases related to an entity?

    Cherrs,
    Norb
    Tuesday, May 12, 2009 6:32 PM
  • Hi, Norbert.

    I've not enough time to solve this task, but it seems that to solve your question  new plugin on RetrieveMultiple message must be created, but i'm not sure...
    Truth opens to prepared mind. My blog - http://a33ik.blogspot.com
    Tuesday, May 12, 2009 6:35 PM
    Moderator
  • Hi, all.

    I've fixed issues for previous version of Record counter and now it is available here .
    Truth is opened the prepared mind My blog - http://a33ik.blogspot.com
    Thursday, September 3, 2009 3:29 PM
    Moderator
  • Hi, all.

    I've fixed issues for previous version of Record counter and now it is available here .
    Truth is opened the prepared mind My blog - http://a33ik.blogspot.com

    Your way of calculating the records is wrong:

    1. If there are more than 5000 record your counter will show only 5000.

    2. Even if it did work, your plugin has major performance issues. You shouldn't retrieve all the entities and count the nodes.  You should manipulate the original query to become a count query and work with that.
    Friday, September 4, 2009 11:57 AM
  • Hi, Moti.

    Thanks for your comment. I've modified code of the plugin and now it works even count of records is greater then 5000.

    One more time - thanks!
    Truth is opened the prepared mind My blog - http://a33ik.blogspot.com
    Sunday, September 6, 2009 11:29 AM
    Moderator
  • You are very welcome.
    Sunday, September 6, 2009 12:46 PM
  • //make sure we don't put this into a status or Guid field as it will error
    XmlNode node=outdoc.SelectSingleNode("//resultset").FirstChild); if (node.Attributes.Count > 0 || node.Name.EndsWith("id"))
    Monday, September 7, 2009 6:07 AM
  • i recommende you to use this code: i use stunwware fetc library http://linqtocrm.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24377 int pageSize; public void Execute(IPluginExecutionContext context) { string originalFetch = context.InputParameters.Properties["FetchXml"].ToString(); var fetchStatement = FetchStatement.FromXml(originalFetch); string entityName = fetchStatement.Entity.EntityName; //This since our call to get the count will cause this method to //get called again, this prevents from getting into an infinite loop bool isRecordcount = originalFetch.Contains("GridRecordCounter"); if (isRecordcount) { return; } pageSize = fetchStatement.PageCount; //Clear all columns, turn off all columsn if specififed. if (fetchStatement.Entity.Columns.AllColumns == false) { fetchStatement.Entity.Columns.Columns.Clear(); } else { fetchStatement.Entity.Columns.AllColumns = false; } //Clear link entity attributes if (fetchStatement.Entity.LinkEntities.Count > 0) { fetchStatement.Entity.LinkEntities.Clear(); } //Clear any order by clauses fetchStatement.Entity.Orders.Clear(); //Change to an aggragate function fetchStatement.PageCount = 0; fetchStatement.Aggregate = true; fetchStatement.PagingCookie = null; //use createdby since all entities should have this field and have it populated fetchStatement.Entity.Columns.Columns.Add("createdby"); fetchStatement.Entity.Columns.Alias = "GridRecordCounter"; fetchStatement.Entity.Columns.Aggregate = FetchAggregate.Count; ICrmService service = context.CreateCrmService(true); string response = service.Fetch(fetchStatement.ToString()); XmlDocument doc = new XmlDocument(); doc.LoadXml(response); doc.LoadXml(response); string recordCountValue = doc.GetElementsByTagName("GridRecordCounter").Item(0).InnerText; if (!string.IsNullOrEmpty(recordCountValue) && recordCountValue != "0") { int recordCount = Convert.ToInt32(recordCountValue); if (recordCount < pageSize) return; XmlDocument resultDoc = new XmlDocument(); string originalResponse = context.OutputParameters.Properties["FetchXmlResult"].ToString(); resultDoc.LoadXml(originalResponse); XmlNode resultSet = resultDoc.SelectSingleNode("resultset"); if (resultSet.HasChildNodes) { XmlNode newNode = resultSet.ChildNodes[0].CloneNode(true); int count = 0; //Clear old data from copied node and put text in first string field bool nodeUsed = false; foreach (XmlNode node in newNode.ChildNodes) { bool nodeUsable = true; //make sure we don't put this into a status or Guid field as it will error if (node.Attributes.Count > 0 || node.Name.EndsWith("id")) { node.Attributes.RemoveAll(); nodeUsable = false; } if (nodeUsable && !nodeUsed && pageSize!=0) { nodeUsed = true; double totalPages = Math.Ceiling(Convert.ToDouble(recordCount / pageSize)); node.InnerText = String.Format("Total Records: {0}, Pages: {1}", recordCount, totalPages); } else { node.InnerText = null; } count++; } if (nodeUsed) { resultSet.InsertBefore(newNode, resultSet.ChildNodes[0]); } context.OutputParameters.Properties["FetchXmlResult"] = resultSet.OuterXml; } } }
    Monday, September 7, 2009 6:13 AM
  • Thank you, Hassan. I will try your code.
    Truth is opened the prepared mind My blog - http://a33ik.blogspot.com
    Monday, September 7, 2009 5:24 PM
    Moderator
  • HI,

    interesting sample code.

    Have You figured out how to catch the rollup message to count activities or cases related to an entity?

    Cherrs,
    Norb

    Hi, Norb.

    I've figured out to handle rollup message but in unsupported meaner. Check this url .

    Truth is opened the prepared mind

    My blog (english)
    Мой блог (русскоязычный)free countersLocations of visitors to this page
    Monday, January 11, 2010 10:47 AM
    Moderator
  • Hi Andriv,

    Nice Stuff.

    Just curious, would you ever considered querying the SQL DB directly for performance reasons and built in features such as sql 'count'? By querying filtered views you would still be using the same security model as when using the web services. Otherwise nice stuff, thanks.

    Karlo
    Karlo Swart - http://www.ver206.com
    Monday, January 11, 2010 11:03 AM
  • Hello all.

    I redeveloped code of record counter and fixed several errors. You can find it here - http://a33ik.blogspot.com/2010/08/record-record-counter-for-microsoft.html


    Microsoft CRM Freelancer

    My blog (english)
    Мой блог (русскоязычный)
    Monday, August 30, 2010 11:13 PM
    Moderator