Request a topic or
contact an Arke consultant
404-812-3123
CRM

Arke Systems Blog

Useful technical and business information straight from Arke.

About the author

Author Name is someone.
E-mail me Send mail

Recent comments

Archive

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2024

Parsing and Validating Phone Numbers in CRM 2011

First off, I would like to thank Joe Gill for getting me started down the right path.  In fact, I'm going to suggest that everyone click that link so you can use his helpful screenshots to navigate where to put the JS I'm about to post. 

In any case, I had not seen a full example of parsing a phone number in CRM 2011 as I had with CRM 4.0.  Since it is such a common need, I decided to make my own.  The following code will strip out all special characters, check and make sure it's a valid set of numbers, and then push it back to the field, parsed properly.  This is limited to 10-digit phone numbers at the moment, but the core structure should be easily expanded if you need different types of validation.

The nice thing is, this can point at any entity, and any attribute that holds a phone number.  I strongly recommend adding this to your standard JS library for all CRM 2011 projects.

function validatePhone(context)
{

var phone =context.getEventSource().getValue();
var sTmp = phone.replace(/[^0-9]/g, "");
phoneRegex = /^\d{10}$/;

if( !sTmp.match( phoneRegex ) )
   {
   event.returnValue = false;
   alert("Phone must contain 10 numbers.") ;
   }
else
  {
   var sTmpClean =  "(" + sTmp.substr(0, 3) + ") " + sTmp.substr(3, 3) + "-" + sTmp.substr(6, 4);
   context.getEventSource().setValue(sTmpClean);
  }
}


Posted by Wayne Walton on Wednesday, June 22, 2011 4:34 PM
Permalink | Comments (0) | Post RSSRSS comment feed

CRM 4.0 Deletion Service

Today I had an issue where I had deleted a number of records from CRM during my loads of testing through Scribe.  After deleting these records, CRM updated those records to have a deletestatecode = 2.  Therefore, every subsequent scribe job would no longer work properly as the address still existed in the database.  Those of you used to CRM 3.0, there used to be a MSCRMDeletionService you could restart in your running services and it would force the job to run through all your records.  That is now wrapped in the Async Service of CRM 4.0 which you can restart.  For those of you who don't/can't restart that service for any reason, try this here:

USE MSCRM_CONFIG

UPDATE dbo.ScaleGroupOrganizationMaintenanceJobs SET
NextRunTime = getdate() -- Now
WHERE OperationType = 14
-- Deletion Service

This was found on an old archive site, posted by Aaron Elder.  Hope this helps others find it.  Be patient.  I fumed for a few minutes thinking it wasn't working but just give it some time. ;)

 

When all else fails.....

There are other ways going directly to the database level, but I cannot stress how bad of an idea that is and how much it should never be done.  Exhaust all other options CRM provides you before going to the database level and modifying it by hand.  'Because it would be faster' should never be a good enough excuse!!  If you have no other options of using CRM to it's full abilities and must do it by hand, something went horribly wrong and needs to be re-evaluated immediately after you clean up your data.

 

 

you're still reading....*sigh* ok but I warned you.

 CRM gurus correct me if I'm wrong, but from the understanding I have at this moment, every entity in CRM has two tables:

  • [YourEntity]base - table that holds all the default out of the box attributes of your entity
  • [YourEntity]extensionbase - table that holds all your 'new_' custom attributes for your entity

So if you have a 'Contact' with a 'new_foo' attribute and someone adds a new 'Contact' to your CRM instance, 

  •  1 row added to your 'Contactbase' table - holds address1_line1, name, firstname, etc (all defaults)
  •  1 row added to your 'Contactextensionbase' table - holds new_foo (all custom)

The BOTH have the same ContactID because they ARE the same contact.  So if you have to delete at the database level you MUST delete from the extensionbase table first and foremost.  The smartest thing to do is to first find out exactly which contacts you need to delete.  Whether its on IDs or a certain field state, get a select statement as correct and accurate as possible.  Once you have that select, I like to make a temp table of those records but this is purely optional.  The reason I like to do this is because sometimes the field I care to do my search on is a 'new_' attribute.  Where 'new_foo' = null.  But if I run my delete query on extensionbase where 'new_foo' = null, I just shot off my own foot.  The reason?  I just deleted all the rows who had any knowledge that 'new_foo' existed.  How do I know what rows I just deleted to now clear out the base table?   With a temp table, I can capture all that data and include a 'contactid' so I never am without a reference of what fields need to be deleted.

 As always, BACKUP before attempting this.  Run your delete on extensionbase.  Write down the number deleted.  Run your delete on base.  Match number deleted.  If it doesn't match, Panic.  Restore you database and refine your search until those numbers match.  Re-evaluate your process and NEVER DO IT AGAIN!

 


Categories: CRM
Posted by Nicole Rodriguez on Thursday, June 16, 2011 2:19 PM
Permalink | Comments (0) | Post RSSRSS comment feed

CRM 4.0 Bulk Delete Tool

I found this tool out on the web.  It’s a bulk delete tool for CRM 4.0 since it doesn’t have a bulk delete option.  (As far as I’ve been told, CRM 4.0 Online does, but CRM 4.0 does not).  Anyways, you run the executable and it gives you a very simple UI.  All you need to do is create a view for the entity with all the records you want to bulk delete.

 

1.       Run the executable

 

 

2.       The bottom corner shows you’re not connected.  Click the drop down and ‘Create a new Connection…’

3.       You will get the connection information screen

 

 

4.       Give it all your information and click ‘OK’.

5.       You’ll now see you’re connected at the bottom of your screen.  And in the future, you will have that connection information available to you in that small dropdown as shown below:

 

 

6.       NOTE: for this to work as you want it to, you need to create a view on that entity for the records you want to delete.  If this is going to be routine, perhaps a CRM job plugin might be better, but we’ve had several instances where we loaded a CRM instance with a test data and want to dump it all, so here’s a fun tool for it.  Create your view. (I’m assuming here you know how to do that).

7.       After your view is created, enter your entity in the textbox and click ‘Retrieve Views’.  You’ll now get a list of those views. 

 

 

8.       You can schedule it to run in the future or recur but, again, I think a plugin would be more beneficial for that.  You can also have it send you an email after the job is done deleting.  It’s not perfect but it’s out there. 

 

Enjoy.


Tags: ,
Categories: CRM
Posted by Nicole Rodriguez on Tuesday, April 26, 2011 4:54 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Loading a CRM page from a post-build event

CRM uses NTLM authentication, so you can’t just pull down a page using any simple thing.

Luckily, “curl” is a nice command-line tool for loading webpages that supports NTLM.

The only tricky part is, not all builds support the “--ntlm” and ”-u :” features you need for NTLM to work.  The Win32 Generic 7.21.2 binary build at http://curl.haxx.se/download.html is working for me (the MSVC build supports ntlm but “-u :” silently doesn’t work. You can tell it failed because you get back a 401.)

So, I now put a copy of curl in my project’s references folder, and have added to my post-build events that bounce IIS:

SETLOCAL ENABLEDELAYEDEXPANSION
set URL=http://localcrm/orgname/loader.aspx

. . .

set loop=0
:TRYCURL
rem Load front page to get app pool started up again
set /a loop=%loop%+1
echo Loading site to initialize app pool %URL%
rem curl should use --ntlm -u : to pull user from the environment.
"$(SolutionDir)\references\curl\curl" --user-agent "Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)" --location --location-trusted --ntlm -u : --silent --show-error -w"%%{http_code}" "%URL%"  > NUL
if !ERRORLEVEL! NEQ 0 GOTO CURLFAIL
goto DONE
:CURLFAIL
if %LOOP% LEQ 4 GOTO TRYCURLSLEEP
goto FAIL
:TRYCURLSLEEP
echo sleeping before retry
sleep 1
goto TRYCURL
:DONE
echo OK at %TIME%


Posted by David Eison on Sunday, November 28, 2010 2:14 AM
Permalink | Comments (0) | Post RSSRSS comment feed

CRM API – Picklist details

Just thought I’d share a bug I ran into with everyone and hope it helps you avoid it.

I see plenty of code that sets picklist values.  You might do this in javascript, or in the CRM API.  Set a new value, submit the update, picklist value is changed. 

But, it’s easy to miss that picklist has two fields: a Name, and a Value.  Value is something boring like 2, name is something to show to the user, like “Critical”. 

You would think that writing code like this was great:

Picklist prop = source.Properties[attribute] as Picklist;
if (prop == null || prop.IsNull)
{
    return defaultvalue;
}
return prop.name;

However, a problem crops up when dealing with client code written by people who didn’t understand that the name field is important.  If you put that code into a plugin, you get passed straight the name + value that the API client specified – so you could run into javascript code that only changed the value, or into other CRM API code that only changed the value, and name can either be completely not set, or worse, set to an old previous value.

So, when writing server side code that handles data submitted by the client, it looks like you’ll need to only trust the value and ignore the name.  It’s possible you could audit your client code and make sure that everywhere a new value is set a new name is set too.. but one day somebody will find some code from another project, add it to yours, and your picklist handling will be wrong.

Happy Thanksgiving!


Posted by David Eison on Saturday, November 27, 2010 11:57 PM
Permalink | Comments (0) | Post RSSRSS comment feed

CRM 2011 - Living in Outlook

Right now, the Microsoft CRM Team is posting videos about CRM 2011.  The most recent one is Living in Outlook.  If you use Outlook and/or CRM at all, prepare to have your mind blown.  The level of integration between CRM 2011 and Outlook is absolutely amazing!  and the best thing is, since it uses Outlook's features to expose CRM data, as Outlook is updated, you get more features in CRM. Of course, that's a double-edged sword.  If you're struck on Outlook 2003, you're not going to get a lot of these cool features, as they disn't exist in Outlook 2003. Here is their full blog post as well: http://blogs.msdn.com/b/crm/archive/2010/10/04/microsoft-dynamics-crm-2011-living-in-outlook.aspx

 
 

Posted by Wayne Walton on Monday, October 4, 2010 4:27 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Internet Explorer 9 Beta and Dynamics CRM

With the release of the Internet Explorer 9 Beta today, I just wanted to make sure that everyone knows not to install IE9 on any machine using CRM Online, CRM 4.0 or testing out the CRM 2011 Beta.  IE9 Beta is currently unsupported for all three CRM environments, and if the IE8 Beta is any indication, it will break things in a big way.

So enjoy testing the Internet Explorer 9 Beta, just don't do it on a machine that uses Dynamics CRM. 


Posted by Wayne Walton on Wednesday, September 15, 2010 12:24 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Elmah and SoapException

A web app I’m working on which uses web service calls a lot is using Elmah for error logging.

Unfortunately web service calls consistently result in the useless ‘Server was unable to process request.’ message.

Originally I thought I could patch Elmah to log session variables then log the detail in the session in a Global.asax application_error handler.  Unfortunately, the Elmah error handler appears to consistently run before the application_error handler, so that doesn’t work (although it’s still nice to have session variables logged).

So I did some quick hacking on Elmah to get it to pull out the useful SoapException.Detail message. 

In Elmah’s Error.cs file, after:

if (httpException != null)
{
    _statusCode = httpException.GetHttpCode();
    _webHostHtmlMessage = Mask.NullString(httpException.GetHtmlErrorMessage());
}

I added:

// If this is a SOAP exception, then replace the message information with more useful info
System.Web.Services.Protocols.SoapException soapException = baseException as System.Web.Services.Protocols.SoapException;
if (soapException != null && soapException.Detail != null)
{
    _detail = baseException.Message 
        + System.Environment.NewLine + System.Environment.NewLine 
        + "Soap Detail: " + Mask.NullString(soapException.Detail.InnerText) 
        + System.Environment.NewLine + System.Environment.NewLine 
        + "Regular detail: " + System.Environment.NewLine + _detail;
    _message = Mask.NullString(soapException.Detail.InnerText);
    // not sure how big these detail strings get, so arbitrarily cap the size on the short message
    if (_message.Length > 100)
    {
        _message = _message.Substring(0, 100);
    }
}

And now I get Elmah error logs like:

elmah_log_new

Instead of:

elmah_log_old

And detail messages like:

elmah_log_newdetail

Instead of:

elmah_log_olddetail


Posted by David Eison on Thursday, August 19, 2010 2:33 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Microsoft Dynamics CRM 4.0 – Guids ToString – Even simple things can be complicated

One common need when working with CRM is to convert GUIDs to String.  Say, you want to build up some fetchxml.  No problem, .ToString(), right?

Well, Guids can actually be converted to strings in many different ways – even just the hexadecimal string can be with brackets, without brackets, uppercase, lowercase, with or without hyphens, etc. 

To keep your code as reliable and readable as possible, you’ll want to do this consistently – CRM uses uppercase hexadecimal, with brackets.  Guid has a ToString that takes a format string that you can pass it several different options.  “B” is closest to what we want, but not quite right, because it returns lowercase.  So you should convert to uppercase… but you’ll want to be careful, because converting to uppercase behavior can vary depending on the locale of the box running the code.  Usually your code will run on a server and it won’t matter, but what if you are writing a plugin which is running offline on an outlook client?  I don’t actually know if there is a locale where the hexadecimal characters A-F don’t convert right, but I know that in Turkey the uppercase of i is not I, so I don’t want to push my luck that no culture does something similar with A-F (update: Writing culture-safe managed code says Turkish and Azeri are the only languages with single character case differences, but this points out there may be multiple character case differences, such as Ff in welsh, and then there are some languages that don’t have some letters, such as Cryllic has no C for example…).  So, to be as safe as possible, specify the ‘InvariantCulture’ for any string comparisons or conversions that should deal with strings in a program-readable consistent manner.

Finally, to make this easily accessible to all of your code, you can add a utility method directly to the Guid class as an Extension Method

using System;
using System.Globalization;

namespace arkesystems.crm
{
    public static class CRMUtilExtensionmethods
    {
        public static string ToStringForCRM(this Guid guid)
        {
            return guid.ToString("B", CultureInfo.InvariantCulture).ToUpper(CultureInfo.InvariantCulture);
        }
    }
}

 

Now whenever I want to turn a guid into a string, I just have to have

using arkesystems.crm;

at the top of the class, and my extension method is available directly on the Guid itself (handily also in the autocomplete dropdown):

Guid taskGuid = crmservice.Create(t);
string strTaskGuid = taskGuid.ToStringForCRM();

Posted by David Eison on Friday, August 6, 2010 6:44 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Update Rollup 12 for Dynamics CRM has been released

First off, here's the Knowledge Base Article and the Download page.

A couple of big issues have been resolved with this update. The first of which is the Email Router Rule Deployment Wizard now supports Exchange 2010.  Also, the Quick Find should be faster, as it no longer occasionally runs the search twice.

For those of you having trouble with Report Wizard Reports, the issue where the error  "Query execution failed for data set DSMain." has been resolved!

A lot of good updates in this Rollup, I highly recommendinstalling it soon.


Posted by Wayne Walton on Tuesday, August 3, 2010 9:38 AM
Permalink | Comments (0) | Post RSSRSS comment feed