CRM Calendar Control Bug – DataValue returns incorrect value

While doing some date verification against a CRM date control with JavaScript I came across a bug. When getting values from CRM UI controls we typically use the [Control].DataValue property. What i’ve found is when users use the actual Calendar control to select the date things work fine. However, if users type in a date into the field and you have code that gets the date via the .DataValue or .DataXml property it will NOT return the updated date.

In order to guarantee getting the latest value, I had to go against the raw HTML .value property while using some of CRM’s date format methods.

var dt = new Date();
dt = new Date(ParseDate([CRM_Date_Control_Id].getElementsByTagName("INPUT")[0].value))

November 16, 2009 at 7:20 pm Leave a comment

Calling WCF service from a CRM Plug-In

I had a requirement to call a WCF service from with a CRM plug-in.  This seemed like this should be straight forward, connecting to the service, building a service reference, setting up the config file and I should be good to go. 

All was fine and good until working with the config file.  When working with a WCF service it expects the configuration properties to be in-process.  For instance, if you’re calling a WCF service from within an ASP.NET web site, then adding something like the snippet below to the web.config will allow you to call service.

<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IContract" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="9000000" maxStringContentLength="9000000" maxArrayLength="9000000"
maxBytesPerRead="9000000" maxNameTableCharCount="9000000" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<!--<message clientCredentialType="UserName" algorithmSuite="Default" />-->
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://[SERVICE_URL]"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IContract"
contract="[CONTRACT]"
name="BasicHttpBinding_IContract" />
</client>
</system.serviceModel&gt

However, the plug-in is registered in the database so an in-process configuration file wasn’t being recognized.  Thankfully the configuration properties are all available via the System.ServiceModel namespace. You can add the code snippet below to setup the configuration when calling the WCF service.

 
using System.ServiceModel;

BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = "BasicHttpBinding_IContract";
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.TransferMode = TransferMode.Buffered;
binding.UseDefaultWebProxy = true;
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

binding.SendTimeout = new TimeSpan(0, 10, 0);
EndpointAddress endPointAddress = new EndpointAddress("http://[SERVICE_URL]");

ContractClient client = new ContractClient(binding, endPointAddress);

client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

client.ChannelFactory.Credentials.Windows.ClientCredential = new System.Net.NetworkCredential([ACCOUNT], [PASSWORD], [DOMAIN]);

client.[METHOD]();

September 29, 2009 at 7:30 pm 5 comments

Dynamic Worksheet – Specified SQL server not found

I was trying to export a dynamic excel sheet from CRM and received the following error on my Windows 7 laptop.

 

Specified SQL server not found
Specified SQL server not found

After some tinkering, found out I needed to allow Excel through the Windows Firewall.  Follow the steps below:

Open up the Control Panel

Control Panel

Control Panel

Select System and Security and Windows Firewall

Windows Firewall

Windows Firewall

Select Allow a program or feature through Windows Firewall

Select Change settings

Browse to the Excel.exe

Allow Excel through Windows Firewall

Allow Excel through Windows Firewall

July 21, 2009 at 6:57 pm 1 comment

CRM Report Timeout

Recently we had a long running CRM report that would timeout occasionally with the error below. 

Error: Request timed out.

 Error Message: Request timed out.

 Error Details: Request timed out.

 Source File: Not available

 Line Number: Not available

 Request URL: [URL]

Stack Trace Info: [HttpException: Request timed out.]

 

#1) SQL Server Report Manager, set Do not timeout… (did not work)

Report Timeout Setting

Report Timeout Setting

#2) Extending timeouts in the RSREPORTSERVER.CONFIG file…(did not work)

<Add Key=”SQLCommandTimeoutSeconds” Value=”60″ />
<Add Key=”DatabaseQueryTimeout” Value=”120″ />

#3) Extend the CRM web.config executionTimeout property <httpRuntime executionTimeout=”300″ maxRequestLength=”8192″ />…(this works!)

July 14, 2009 at 8:59 pm Leave a comment

Mobile Express for CRM 4.0

Download it here.

July 10, 2009 at 4:43 pm Leave a comment

Optimizing and Maintaining Microsoft Dynamics CRM 4.0 Whitepaper

Version 2.0 of the Optimizing and Maintaining CRM 4.0 Whitepaper has been released.  You can download it here.

July 10, 2009 at 4:39 pm Leave a comment

CRM AsyncOperationBase Issue

I worked on a CRM 4.0 system with rollup update #4 that took feeds from SAP and created records in CRM.  Things ran fine until adding a custom audit plug-in that would log modifications to CRM asynchronously.  After installing the plug-ins, the CRM SQL Server would go to 100% usage and start timing out for end users.

After investigating with SQL Profiler, it looked like CRM was trying to write to the AsyncOperationBase, when I took a look at the size of the table, it was over 1 million records for a relatively small CRM system. 

According to this article CRM logs all asynchronous operations to this table, however there is a bug with CRM where it won’t clear the completed operations.  After following the steps of manually clearing the completed records things worked fine.  However over time the table kept growing and would not clear out the completed operations (even though I added the registry node AsyncRemoveCompletedWorkflows). 

I ended up creating a nightly SQL Job that clears out the AsyncOperationBase, WorkflowLogBase, and BulkDeleteFailureBase tables, and broke it into 3 steps.

 

STEP 1: Set recovery mode to simple to prevent logging deletes, this will save you time if the table is large.  Then rebuild the index.

ALTER DATABASE [DATABASE_NAME]

SET RECOVERY SIMPLE
GO
 ALTER INDEX ALL ON AsyncOperationBase REBUILD WITH  
(FILLFACTOR = 80, ONLINE = OFF,SORT_IN_TEMPDB = ON, STATISTICS_NORECOMPUTE = OFF)  

 – Rebuild Indexes & Update Statistics on WorkflowLogBase Table  
ALTER INDEX ALL ON WorkflowLogBase REBUILD WITH  
(FILLFACTOR = 80, ONLINE = OFF,SORT_IN_TEMPDB = ON, STATISTICS_NORECOMPUTE = OFF)

 

STEP 2: Actual delete operations

declare @DeleteRowCount int
Select @DeleteRowCount = 2000
declare @DeletedAsyncRowsTable table (AsyncOperationId uniqueidentifier not null)
declare @continue int, @rowCount int
select @continue = 1
while (@continue = 1)
begin
      begin tran
      insert into @DeletedAsyncRowsTable(AsyncOperationId)
      Select top (@DeleteRowCount) AsyncOperationId
      from AsyncOperationBase
      where OperationType in (1, 9, 12, 25, 27, 10) AND StateCode = 3 AND StatusCode in (30, 32)    
 
      Select @rowCount = 0
      Select @rowCount = count(*) from @DeletedAsyncRowsTable
      select @continue = case when @rowCount <= 0 then 0 else 1 end    
 
        if (@continue = 1)
        begin
            delete WorkflowLogBase from WorkflowLogBase W, @DeletedAsyncRowsTable d
            where W.AsyncOperationId = d.AsyncOperationId
           
delete BulkDeleteFailureBase From BulkDeleteFailureBase B, @DeletedAsyncRowsTable d
            where B.AsyncOperationId = d.AsyncOperationId
 
            delete AsyncOperationBase From AsyncOperationBase A, @DeletedAsyncRowsTable d
            where A.AsyncOperationId = d.AsyncOperationId           
 
            delete @DeletedAsyncRowsTable
      end
 
      commit
end

Step 3: Rebuild the index and set the recovery

 ALTER INDEX ALL ON AsyncOperationBase REBUILD WITH  
(FILLFACTOR = 80, ONLINE = OFF,SORT_IN_TEMPDB = ON, STATISTICS_NORECOMPUTE = OFF)  

 – Rebuild Indexes & Update Statistics on WorkflowLogBase Table  
ALTER INDEX ALL ON WorkflowLogBase REBUILD WITH  
(FILLFACTOR = 80, ONLINE = OFF,SORT_IN_TEMPDB = ON, STATISTICS_NORECOMPUTE = OFF)

ALTER DATABASE [DATABASE_NAME]
SET RECOVERY FULL
GO

July 9, 2009 at 9:28 pm Leave a comment

Permissions to create Price List

I had a plug-in on an opportunity that among other things assigned a price list based on the currency on the opportunity.  Since price list also has a currency on it, it needed to match what’s on the opportunity. 

In order for this to work dynamically, I had the plug-in code look for price lists that had a matching currency and if they didn’t exist create a new one.  Since our system doesn’t use the product catalog or order system, performing these kinds of operations are safe.

The plug-in impersonates the user via the context.InitiatingUserId

ICrmService service = context.CreateCrmService(context.InitiatingUserId);

This was all fine and good, but after testing with less privileged security roles, I found that they didn’t have the prvCreateProduct privilege, so the plug-in would fail on creation of the price list (pricelevel entity).  I had to override the impersonation to use the NETWORK SERVICE account by passing in false to the context.CreateCrmService(false) method in order to get the required privilege. 

private Guid CreatePriceList(IPluginExecutionContext context, Guid currencyId)
        {
            // Need to override the identity of the calling user to SYSTEM, as not everyone has the prvCreateProduct privilege
            // required to create the PriceLevel
            ICrmService crmService = context.CreateCrmService(false);

            // Get the name of the currency and use it for the pricelist
            // Unfortunately we have to make another query
            ColumnSet cols = new ColumnSet();
            cols.AddColumn(“currencyname”);

            transactioncurrency currency = (transactioncurrency)crmService.Retrieve(EntityName.transactioncurrency.ToString(), currencyId, cols);
           
            pricelevel newPriceList = new pricelevel();
            newPriceList.name = currency.currencyname + ” Price List”;
            newPriceList.transactioncurrencyid = new Lookup(EntityName.transactioncurrency.ToString(), currency.transactioncurrencyid.Value);

            return crmService.Create(newPriceList);
        }

I know I could’ve added the the user to a higher privileged OOTB role like Sales Manager, but shouldn’t this privilege be part of the security roles?  If it is perhaps I wasn’t able to find it, does anyone know of a way to add it?

July 7, 2009 at 7:37 pm Leave a comment

Writing to the Windows Event Log

Writing errors to the Windows event log can be tricky, especially with permissions on custom folders.  Here’s a simple method that won’t require special permissions

using System.Diagnostics;

EventLog log = new EventLog();
log.Source = “Application”;
log.WriteEntry(“Your Message”, EventLogEntryType.Error);

If you’re capturing web service exceptions, be sure to capture the SoapException and write the Detail xml node.

July 6, 2009 at 8:35 am Leave a comment

CRM 4.0 and Exchange 2010

I tried installing the e-mail router with forwarding rules from CRM 4.0 to Exchange 2010 (E14). 

The Environment:

CRM Server – Windows Server 2003, Dynamics CRM 4, Rollup Update #4

Exchange Server – Windows Server 2008, Exchange 2010 E14 beta

Some findings:

  1. Outgoing e-mails works fine with the router.  Two things I had to change to make it work though were making sure the Exchange Server name matched the certificate name for the exchange server.  The other was for the Access Credentials when Other Specified was selected to not use theDomain\Administrator account.  This appears to be an account that Exchange does not allow to send e-mails.  I changed this to another service account that had rights to CRM as well (just in case) and got the e-mail router to work.
  2.  

  3. Accessing the Forward Mailbox does not work.  There were two prerequisites for the Forward Mailbox option to work that Exchange 2010 does not have. 
    • One is WebDav, this looks to have been deprecated  (http://social.technet.microsoft.com/Forums/en-US/exchange2010/thread/7aabb536-b226-4d01-ada4-d1271b46fdfa).
    • The other is the existence of legacy IIS virtual directories for Exchange and ExAdmin.  When Testing Access with for the forward mailbox it returns errors repeating 404 or general timeouts when trying to access the mailbox.  When reviewing the IIS logs the router looks like it’s requesting the /Exchange/[Mailbox_Name] and the /ExAdmin/Admin/[Domain]/MBX/[Mailbox_Name] and both of these return a 404.  For Exchange 2007 you can create these via the powershell command new-owavirtualdirectory with the -owaversion parameter.  But this parameter is not available with the current bits.

July 3, 2009 at 9:08 pm Leave a comment

Older Posts


Categories

Feeds


Follow

Get every new post delivered to your Inbox.