<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://customerfx.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">CRM Developer</title><subtitle type="html">Ryan Farley on CRM Development for SalesLogix, SageCRM, MSCRM, .NET - and all things geek</subtitle><id>http://customerfx.com/pages/crmdeveloper/atom.aspx</id><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/default.aspx" /><link rel="self" type="application/atom+xml" href="http://customerfx.com/pages/crmdeveloper/atom.aspx" /><generator uri="http://communityserver.org" version="3.0.20611.960">Community Server</generator><updated>2008-05-21T21:30:00Z</updated><entry><title>Extracting Reports from the SalesLogix Plugin Table from External Applications</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/05/29/extracting-reports-from-the-saleslogix-plugin-table-from-external-applications.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/05/29/extracting-reports-from-the-saleslogix-plugin-table-from-external-applications.aspx</id><published>2009-05-29T20:09:00Z</published><updated>2009-05-29T20:09:00Z</updated><content type="html">&lt;p&gt;There are many reasons why extracting a SalesLogix Report from the SalesLogix database might be useful. There are possibilities of integration, automated running of reports, as well as the need to generate a PDF from some code on a server using a SalesLogix Crystal report.&lt;/p&gt;
&lt;p&gt;SalesLogix stores reports in the DATA field, which is a binary (BLOB) field in the PLUGIN table. Not just the report, but the SalesLogix report &lt;i&gt;plugin&lt;/i&gt;, which contains not only the report itself but also the plugin info for the report. All together in a single BLOB field. This BLOB field is the serialized Delphi class named TCRWReportWrapper with the report file bytes appended to the end of the serialized class bytes. &lt;/p&gt;
&lt;p&gt;Luckily, a serialized Delphi class will always end in two consecutive NULL bytes (0x00, 0x00) and will never contain two consecutive NULL bytes internally. This makes out job a bit easier in knowing where the serialized Delphi class ends and the bytes making up the report file begin. We can read out the bytes from PLUGIN.DATA for the report record and then read through them until we find the two consecutive NULL bytes, when write out everything following to a file and we&amp;#39;ll have the report itself.&lt;/p&gt;
&lt;p&gt;Here is some C# code to do just that:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Blue;"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span style="color:Blue;"&gt;using&lt;/span&gt; System.Data;&lt;br /&gt;&lt;span style="color:Blue;"&gt;using&lt;/span&gt; System.Data.OleDb;&lt;br /&gt;&lt;span style="color:Blue;"&gt;using&lt;/span&gt; System.IO;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:Blue;"&gt;namespace&lt;/span&gt; FX.SalesLogix.Utility&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; ReportExtractor&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:Blue;"&gt;public&lt;/span&gt; ReportExtractor(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; ConnectionString)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.ConnectionString &lt;span style="color:Navy;"&gt;=&lt;/span&gt; ConnectionString;&lt;br /&gt;        }&lt;br /&gt; &lt;br /&gt;        &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ConnectionString { &lt;span style="color:Blue;"&gt;get&lt;/span&gt;; &lt;span style="color:Blue;"&gt;set&lt;/span&gt;; }&lt;br /&gt; &lt;br /&gt;        &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; GetReport(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; PluginID, &lt;span style="color:Blue;"&gt;string&lt;/span&gt; DestinationFile)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (OleDbConnection conn &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; OleDbConnection(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.ConnectionString))&lt;br /&gt;            {&lt;br /&gt;                conn.Open();&lt;br /&gt;                &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (OleDbCommand cmd &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; OleDbCommand(&lt;span&gt;&amp;quot;SELECT DATA FROM PLUGIN WHERE PLUGINID = ?&amp;quot;&lt;/span&gt;, conn))&lt;br /&gt;                {&lt;br /&gt;                    cmd.Parameters.Add(&lt;span style="color:Blue;"&gt;new&lt;/span&gt; OleDbParameter(&lt;span&gt;&amp;quot;PLUGINID&amp;quot;&lt;/span&gt;, PluginID));&lt;br /&gt; &lt;br /&gt;                    &lt;span style="color:Green;"&gt;// Get the plugin byte array&lt;br /&gt;&lt;/span&gt;                    byte[] data &lt;span style="color:Navy;"&gt;=&lt;/span&gt; (byte[])cmd.ExecuteScalar();&lt;br /&gt;&lt;br /&gt;                    &lt;span style="color:Green;"&gt;// Look for the two consecutive null bytes&lt;br /&gt;&lt;/span&gt;                    &lt;span style="color:Blue;"&gt;int&lt;/span&gt; idx &lt;span style="color:Navy;"&gt;=&lt;/span&gt; 0;&lt;br /&gt;                    &lt;span style="color:Blue;"&gt;for&lt;/span&gt; (&lt;span style="color:Blue;"&gt;int&lt;/span&gt; i &lt;span style="color:Navy;"&gt;=&lt;/span&gt; 0; i &amp;lt; data.Length; i++)&lt;br /&gt;                    {&lt;br /&gt;                        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; ((&lt;span style="color:Blue;"&gt;int&lt;/span&gt;)data[ i ] == 0 &amp;amp;&amp;amp; (&lt;span style="color:Blue;"&gt;int&lt;/span&gt;)data[i &lt;span style="color:Navy;"&gt;+&lt;/span&gt; 1] == 0)&lt;br /&gt;                        {&lt;br /&gt;                            idx &lt;span style="color:Navy;"&gt;=&lt;/span&gt; i &lt;span style="color:Navy;"&gt;+&lt;/span&gt; 2;&lt;br /&gt;                            &lt;span style="color:Blue;"&gt;break&lt;/span&gt;;&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt; &lt;br /&gt;                    &lt;span style="color:Green;"&gt;// Get everything after the two consecutive bytes&lt;br /&gt;&lt;/span&gt;                    byte[] rpt &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; byte[data.Length];&lt;br /&gt;                    Array.Copy(data, idx, rpt, 0, data.Length &lt;span style="color:Navy;"&gt;-&lt;/span&gt; idx);&lt;br /&gt; &lt;br /&gt;                    &lt;span style="color:Green;"&gt;// Write out to an RPT file &lt;br /&gt;&lt;/span&gt;                    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (FileStream f &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; FileStream(DestinationFile, FileMode.CreateNew))&lt;br /&gt;                    {&lt;br /&gt;                        f.Write(rpt, 0, rpt.Length);&lt;br /&gt;                        f.Close();&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;To use the code you&amp;#39;d do something like the following:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Green;"&gt;// Extract report to C:\MyReportFile.rpt&lt;br /&gt;&lt;/span&gt;ReportExtractor rptextractor &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; ReportExtractor(MyConnectionString);&lt;br /&gt;rptextractor.GetReport(&lt;span&gt;&amp;quot;pDEMOA0000HQ&amp;quot;&lt;/span&gt;, &lt;span&gt;@&amp;quot;C:\MyReportFile.rpt&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Now you can do whatever you&amp;#39;d like with the report such as open it in an RDC object and generate a PDF from it. &lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40572" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="Development" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Development/default.aspx" /><category term="SalesLogix" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix/default.aspx" /><category term="C#" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/C_2300_/default.aspx" /></entry><entry><title>Determining the Page Mode at Runtime in SalesLogix Web</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/04/20/determining-the-page-mode-at-runtime-in-saleslogix-web.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/04/20/determining-the-page-mode-at-runtime-in-saleslogix-web.aspx</id><published>2009-04-20T18:42:00Z</published><updated>2009-04-20T18:42:00Z</updated><content type="html">&lt;p&gt;One of the keys to reusing a form for both inserting new records and displaying existing record detail is the ability to determine if the form is currently in insert mode or detail mode. There are several ways to determine this at runtime so you can take the necessary steps depeding on the current form mode.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;&lt;i&gt;Out of the box, there are three defined form types: Detail, Insert, &amp;amp; List&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some of the code we&amp;#39;ll use will differ whether you&amp;#39;re using a C# Snippet Action (where the code is added to the form itself) or a Code Snippet Action (where the code is added to a separate assembly and you&amp;#39;re passed an adapter object to access limited form properties).&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;font size="4"&gt;&lt;b&gt;From a C# Snippet Action &lt;/b&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Use the following code to access the exposed EntityForm property of the form and determine the form mode.&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;&lt;span style="color:Blue;"&gt;if&lt;/span&gt; (EntityPage.IsInsertMode)&lt;br /&gt;    labelMode.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Insert Mode&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:Blue;"&gt;else&lt;/span&gt;&lt;br /&gt;    labelMode.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Not insert mode&amp;quot;&lt;/span&gt;;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;span style="color:Green;"&gt;// or&lt;br /&gt;&lt;/span&gt; &lt;br /&gt; &lt;br /&gt;&lt;span style="color:Blue;"&gt;if&lt;/span&gt; (EntityPage.ViewMode == Sage.Platform.Orm.Entities.EntityViewMode.Insert)&lt;br /&gt;    labelMode.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Insert Mode&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:Blue;"&gt;else&lt;/span&gt;&lt;br /&gt;    labelMode.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Not insert mode&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;


&lt;p&gt;&lt;br /&gt;&lt;font size="4"&gt;&lt;b&gt;From a Code Snippet Action&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;For a Code Snippet Action, you&amp;#39;ll need to do things a little differently. In a Code Snippet Action you&amp;#39;re only passed an adapter, or a wrapper, for the form, not the form itself. So, the problem is that you cannot access the page&amp;#39;s EntityPage reference. You can still get to it however, you&amp;#39;ll just have a few extra steps to dig through. Luckily, the form adapter exposes the SmartPart via the NativeForm property.&lt;br /&gt;&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;&lt;span style="color:Green;"&gt;// First get a reference to the underlying SmartPart itself&lt;br /&gt;&lt;/span&gt;Sage.Platform.WebPortal.SmartParts.SmartPart smartpart &lt;span style="color:Navy;"&gt;=&lt;/span&gt; form.NativeForm as Sage.Platform.WebPortal.SmartParts.SmartPart;&lt;br /&gt;&lt;span style="color:Green;"&gt;// Now get the SmartPart&amp;#39;s parent page and use it as an EntityPage&lt;br /&gt;&lt;/span&gt;Sage.Platform.WebPortal.EntityPage page &lt;span style="color:Navy;"&gt;=&lt;/span&gt; smartpart.Page as Sage.Platform.WebPortal.EntityPage;&lt;br /&gt;&lt;span style="color:Green;"&gt;// Now you can proceed as normal...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:Blue;"&gt;if&lt;/span&gt; (page.IsInsertMode)&lt;br /&gt;    form.labelMode.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Insert Mode&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:Blue;"&gt;else&lt;/span&gt;&lt;br /&gt;    form.labelMode.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Not insert mode&amp;quot;&lt;/span&gt;;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;span style="color:Green;"&gt;// or&lt;br /&gt;&lt;/span&gt; &lt;br /&gt; &lt;br /&gt;&lt;span style="color:Blue;"&gt;if&lt;/span&gt; (page.ViewMode == Sage.Platform.Orm.Entities.EntityViewMode.Insert)&lt;br /&gt;    form.labelMode.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Insert Mode&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:Blue;"&gt;else&lt;/span&gt;&lt;br /&gt;    form.labelMode.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Not insert mode&amp;quot;&lt;/span&gt;;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;&amp;nbsp;&lt;br /&gt;&lt;font size="4"&gt;&lt;b&gt;Checking the Entity&amp;#39;s ID Property&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;One last way you can use to check to see if the page is in Insert mode is to check the entity&amp;#39;s Id property. If it is null then you have a new entity, not yet persisted to the database.&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Blue;"&gt;if&lt;/span&gt; (myentity.Id == &lt;span style="color:Blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;    &lt;span style="color:Green;"&gt;// this is a new entity&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;The problem is that it is possible that this won&amp;#39;t infer the correct mode. That is telling you that the object hasn&amp;#39;t yet been persisted to the database, which might be enough, but you might want different behavior for new objects on the form vs the form being in insert mode itself. Just make sure that if you use this method to determine the page mode that you understand the differences so you know what you&amp;#39;re really checking.&lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40457" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Entity Model" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Entity+Model/default.aspx" /><category term="SmartParts" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SmartParts/default.aspx" /><category term="Quick Forms" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Quick+Forms/default.aspx" /></entry><entry><title>Accessing the Current Parent Entity from a Code Snippet Action</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/04/08/accessing-the-current-parent-entity-from-a-code-snippet-action.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/04/08/accessing-the-current-parent-entity-from-a-code-snippet-action.aspx</id><published>2009-04-08T15:00:00Z</published><updated>2009-04-08T15:00:00Z</updated><content type="html">
&lt;p&gt;The transition from using pre-version 7.5.1 &amp;quot;C# Snippet Actions&amp;quot;, where the code is placed inline in the form, and the new &amp;quot;Code Snippet Actions&amp;quot;, where the code is compiled into a separate DLL and a psudo-form reference is passed in, can be frustrating at times. I ran into yet another instance of that today. Before, we were spoiled using the C# Snippet Actions. We had access to everything on the form. Everything. That&amp;#39;s no longer the case with Code Snippet Actions. While in a Code Snippet Action, I needed a reference to the current parent entity (not the current entity that is exposed via form.CurrentEntity, but it&amp;#39;s parent). This Code Snippet Action was on a LoadAction of an Insert screen so the parent had not yet been set. Let&amp;#39;s take a look at how to solve that.&lt;/p&gt;

&lt;p&gt;Before you go on, read a previous post of mine where I discuss the differences between C# Snippet Actions and Code Snippet Actions if you&amp;#39;ve not done so already: &lt;a href="http://customerfx.com/pages/crmdeveloper/2009/03/26/setting-the-default-sort-for-a-datagrid-in-saleslogix-web-revisited.aspx"&gt;Setting the Default Sort for a DataGrid in SalesLogix Web REVISITED&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;font size="4"&gt;&lt;b&gt;The Problem &lt;/b&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;The problem I needed to solve was get the current entity&amp;#39;s parent from a LoadAction on an insert screen. At that time the parent had not yet been set so we couldn&amp;#39;t just use myentity.ParentEntity to get it. If this were an older C# Snippet Action then I could have simply used the following:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;IMyParentEntity myparent &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.GetParentEntity() as IMyParentEntity;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;That would have been great. But this wasn&amp;#39;t in a C# Snippet Action and &amp;quot;this&amp;quot; in a Code Snippet Action is an entirely different thing where GetParentEntity did not exist. My first thought was to use the form.NativeForm and cast it as an EntityBoundSmartPart. That seemed logical. The cast worked, however when I attempted to call GetParentEntity it failed due to it&amp;#39;s protection level. Doh! It is protected so I can&amp;#39;t call it from another assembly. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;font size="4"&gt;&lt;b&gt;The Solution&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Thankfully, one of the most useful things the form referenced that is passed in has is the page&amp;#39;s WorkItem. Through the WorkItem you can get a reference to one of the many useful services in the portal. In this case, the EntityContextService. The EntityContextService has a method named GetEntity that will give you the currently accessed entity. Not the child entity that my dialog was for, but the entity the page itself is for, my parent entity. I wired up the following code:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Green;"&gt;// Get a reference to the EntityContextServce&lt;br /&gt;// and call GetEntity() &lt;br /&gt;&lt;/span&gt;IMyParentEntity myparent &lt;span style="color:Navy;"&gt;=&lt;/span&gt; form.WorkItem.Services.Get&amp;lt;Sage.Platform.Application.IEntityContextService&amp;gt;().GetEntity() as IMyParentEntity; &lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;That is it. It works and it isn&amp;#39;t so bad. However, I do miss the C# Snippet Actions as well. I realize I can still use them even though they are marked as obsolete, however, I think there is also value in learning the new way to do things and living with the changes.&lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40391" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Application Architect" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Application+Architect/default.aspx" /></entry><entry><title>Adding a Default Sort to the Add Opportunity Products List in SalesLogix Web</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/04/07/adding-a-default-sort-to-the-add-opportunity-products-list-in-saleslogix-web.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/04/07/adding-a-default-sort-to-the-add-opportunity-products-list-in-saleslogix-web.aspx</id><published>2009-04-07T14:27:00Z</published><updated>2009-04-07T14:27:00Z</updated><content type="html">
&lt;p&gt;Usually by the third time I see a question asked, I realize it needs to be a blog post. I&amp;#39;ve been asked by a couple of customers how to add a default sort to the products list on the Add Opportunity Products form in the SalesLogix Web client. The question of how to add a default sort to the list of products in the Add Opportunity Products form in the web client surfaced again today so I am posting the answer here.&lt;/p&gt;

&lt;p&gt;The approach to sorting the products list on the Add Opportunity products form is different than &lt;a href="http://customerfx.com/pages/crmdeveloper/2009/03/26/setting-the-default-sort-for-a-datagrid-in-saleslogix-web-revisited.aspx"&gt;what I have outlined before for simply sorting a grid&lt;/a&gt;. The opportunity products list is not a DataGrid, but a Tree control. &lt;/p&gt;

&lt;p&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/AddOppProduct_ProductsList.png" border="1" alt="" /&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;To sort the products list, instead of telling the control to sort, we will just sort the list of objects that it is bound to. &lt;/p&gt;

&lt;p&gt;First, locate the AddOpportunityProduct SmartMart. This is a custom SmartPart, not a QuickForm, so you won&amp;#39;t find this under the Opportunity entity itself, but instead in the Sage SalesLogix Portal in following location (we&amp;#39;ll just need the code-behind, or &amp;quot;cs&amp;quot; file for this, not the &amp;quot;ascx&amp;quot; file):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;i&gt;Support Files\SmartParts\Opportunity\AddOpportunityProduct.ascx.cs&lt;/i&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Double-click that file to open it in the Application Architect. In the code, look for the method named &lt;b&gt;GetProductList&lt;/b&gt;. You&amp;#39;ll see the following two lines at the very end of that method:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;List&amp;lt;Product&amp;gt; ProductList &lt;span style="color:Navy;"&gt;=&lt;/span&gt; criteriaProduct.List&amp;lt;Product&amp;gt;() as List&amp;lt;Product&amp;gt;;&lt;br /&gt;&lt;span style="color:Blue;"&gt;return&lt;/span&gt; ProductList;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Right &lt;u&gt;&lt;b&gt;before&lt;/b&gt;&lt;/u&gt; those two lines, add the following line (in this case, we&amp;#39;ll sort the list by family):&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;criteriaProduct.AddOrder(expProduct.Asc(&lt;span&gt;&amp;quot;Family&amp;quot;&lt;/span&gt;));&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Obviously, you can replace &amp;quot;Family&amp;quot; with any other valid property name on the Opportunity entity to sort the results by. &lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40396" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Customization" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Customization/default.aspx" /><category term="SmartParts" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SmartParts/default.aspx" /><category term="Application Architect" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Application+Architect/default.aspx" /></entry><entry><title>Filtering a DataGrid in SalesLogix Web at Runtime</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/04/02/filtering-a-datagrid-in-saleslogix-web-at-runtime.aspx" /><link rel="enclosure" type="application/zip" length="24568" href="http://customerfx.com/pages/crmdeveloper/attachment/40380.ashx" /><id>http://customerfx.com/pages/crmdeveloper/2009/04/02/filtering-a-datagrid-in-saleslogix-web-at-runtime.aspx</id><published>2009-04-02T17:22:00Z</published><updated>2009-04-02T17:22:00Z</updated><content type="html">&lt;p&gt;Binding a DataGrid at runtime is something that many SalesLogix developers are used to doing while working in the LAN client. This task is every bit as easy in the web platform as well. Let&amp;#39;s take a look at how to put this together.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;Scenario&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;For this example, we will put together a tab on the account page. We&amp;#39;ll call this tab &amp;quot;Related Accounts&amp;quot;. It will have a Picklist, showing the Account Types picklist, and a DataGrid. As the user selects an account type value in the picklist we will display all accounts with that account type. Not a really useful customization, but one that will allow us to see how to bind the grid up at runtime using a user selected value.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p style="font-weight:bold;"&gt;&lt;font size="4"&gt;Building the Solution&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;To put this together, let&amp;#39;s start with building a busioness rule that we&amp;#39;ll use to return the data for the grid. You can read more about using GetByMethod to bind a grid to a rule in my previous articles: &lt;a href="http://customerfx.com/pages/crmdeveloper/2008/05/22/creating-a-business-rule-to-return-a-list-of-objects.aspx"&gt;Creating a Business Rule to Return a List of Objects&lt;/a&gt; and &lt;a href="http://customerfx.com/pages/crmdeveloper/2008/05/27/binding-a-grid-to-a-list-returning-business-rule-using-getbymethod.aspx"&gt;Binding a Grid to a List Returning Rule using GetByMethod&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our business rule will return a list of accounts and will take in one parameter, which will be the user selected account type value. The rule will look like this:&lt;/p&gt;

&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Name:&lt;/span&gt; GetRelatedAccounts&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Return Type:&lt;/span&gt; System.Collections.Generic.IList&amp;lt;Sage.Entity.Interfaces.IAccount&amp;gt;&lt;/p&gt;

&lt;p&gt;Add a parameter as follows (click on the Add link in the Parameters section):&lt;/p&gt;

&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Parameter Name:&lt;/span&gt; TypeValue&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Type:&lt;/span&gt; String&lt;/p&gt;

&lt;p&gt;Now for the code:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; GetRelatedAccountsStep(IAccount account, &lt;span style="color:Blue;"&gt;string&lt;/span&gt; TypeValue, out System.Collections.Generic.IList&amp;lt;Sage.Entity.Interfaces.IAccount&amp;gt; result)  &lt;br /&gt;{&lt;br /&gt;    IRepository&amp;lt;IAccount&amp;gt; repository &lt;span style="color:Navy;"&gt;=&lt;/span&gt; EntityFactory.GetRepository&amp;lt;IAccount&amp;gt;();&lt;br /&gt;    IQueryable qry &lt;span style="color:Navy;"&gt;=&lt;/span&gt; (IQueryable)repository;&lt;br /&gt;    IExpressionFactory ef &lt;span style="color:Navy;"&gt;=&lt;/span&gt; qry.GetExpressionFactory();&lt;br /&gt;&lt;br /&gt;    ICriteria criteria &lt;span style="color:Navy;"&gt;=&lt;/span&gt; qry.CreateCriteria();&lt;br /&gt;    criteria.Add(ef.Eq(&lt;span&gt;&amp;quot;Type&amp;quot;&lt;/span&gt;, TypeValue));&lt;br /&gt;&lt;br /&gt;    result &lt;span style="color:Navy;"&gt;=&lt;/span&gt; criteria.List&amp;lt;IAccount&amp;gt;();&lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Now, we&amp;#39;ll need one more business rule. The SalesLogix DataGrid control itself will throw an error if it does not have a DataSource set at build time. We&amp;#39;re not going to really use the SalesLogix DataSource component at all since we&amp;#39;ll be binding up the grid at runtime. However, it still requires this or it won&amp;#39;t build. To get around this we will have to add a DataSource component to the form as well. Now, we&amp;#39;ll also get errors if we have a DataSource component that is not set to return some data. We can&amp;#39;t use GetByMethod with our new rule we created since our rule takes a param and there is no way to set that for the DataSource. What we will do is create another business rule that returns a blank, empty list of accounts and we&amp;#39;ll use that for the DataSource, just so things compile.&lt;/p&gt;

&lt;p&gt;This is what our empty rule will look like:&lt;/p&gt;

&lt;p&gt;&lt;span style="font-weight:bold;"&gt;Name:&lt;/span&gt; GetEmptyAccountList &lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Return Type:&lt;/span&gt; System.Collections.Generic.IList&amp;lt;Sage.Entity.Interfaces.IAccount&amp;gt;&lt;/p&gt;

&lt;p&gt;The code will be as follows:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; GetEmptyAccountListStep( IAccount account, out System.Collections.Generic.IList&amp;lt;Sage.Entity.Interfaces.IAccount&amp;gt; result)  &lt;br /&gt;{&lt;br /&gt;    result &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; System.Collections.Generic.List&amp;lt;IAccount&amp;gt;();&lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Now you can use that rule that returns an empty list to set up as the GetByMethod for the DataSource component and then wire the DataSource to the grid. Also throw a Picklist onto the form using the Account Type picklist.&lt;/p&gt;

&lt;p&gt;The picklist will have some code in the OnChange action. Add a &amp;quot;Code Snippet Action&amp;quot; to the OnChange of the Picklist control. The code for that will look as follows:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; picklistType_OnChangeStep(IRelatedAccounts form, EventArgs args)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Green;"&gt;// Get a reference to the underlying ASP.NET GridView control&lt;br /&gt;&lt;/span&gt;    System.Web.UI.WebControls.GridView grid &lt;span style="color:Navy;"&gt;=&lt;/span&gt; (System.Web.UI.WebControls.GridView)form.gridAccounts.NativeControl;  &lt;br /&gt;&lt;br /&gt;    &lt;span style="color:Green;"&gt;// Make sure a value was selected in the Picklist&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (form.picklistType.PickListValue !&lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; form.picklistType.PickListValue !&lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt;.Empty)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:Green;"&gt;// Get a reference to the account and call the rule, passing the picklist value&lt;br /&gt;&lt;/span&gt;        IAccount account &lt;span style="color:Navy;"&gt;=&lt;/span&gt; form.CurrentEntity as IAccount;                &lt;br /&gt;        grid.DataSource &lt;span style="color:Navy;"&gt;=&lt;/span&gt; account.GetRelatedAccounts(form.picklistType.PickListValue);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color:Blue;"&gt;else&lt;/span&gt;&lt;br /&gt;        grid.DataSource &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:Green;"&gt;// Call the DataBind method of the GridView to set the binding &lt;br /&gt;&lt;/span&gt;    grid.DataBind();&lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;That is it. The key is to get a reference to the native underlying ASP.NET GridView control and then do the binding just as you would normally with that control. The end result will look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/RelatedAccountsScreenshot.png" border="1" alt="" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I&amp;#39;ve also included a bundle of the code and form for this sample as an attachment to this article. Have fun.&lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40380" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Customization" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Customization/default.aspx" /><category term="ASP.NET" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/ASP.NET/default.aspx" /><category term="Controls" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Controls/default.aspx" /></entry><entry><title>Relationship Property Names and Case</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/03/27/relationship-property-names-and-case.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/03/27/relationship-property-names-and-case.aspx</id><published>2009-03-27T18:38:00Z</published><updated>2009-03-27T18:38:00Z</updated><content type="html">&lt;p&gt;In today&amp;#39;s &lt;a href="http://customerfx.com/pages/events/pages/developer-training-building-solutions-for-saleslogix-web.aspx"&gt;SalesLogix Web Developer class&lt;/a&gt;, we discussed an issue that
someone in the class was having at runtime with a relationship that had a property that started with lower-case letters. Here are the details of that issue and
the fix:&lt;/p&gt;&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;Scenario&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Create a entity named
&amp;quot;testProject&amp;quot; and then relate it to the Account entity. In the
relationship, the Account will have a collection named &amp;quot;testProjects&amp;quot;
(notice the property name starts lower case). You&amp;#39;ll then use that
relationship when you wire up your lookup on a form.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;Problem&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;Every
things builds fine, however at runtime you get an error saying &amp;quot;Could
not find field &amp;#39;_TestProjects&amp;#39; in class
Sage.SalesLogix.Entities.Account&amp;quot;. Notice that the error refers to the
property with an uppercase &amp;quot;T&amp;quot;.&lt;/p&gt;&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;Solution&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;&lt;/b&gt;&lt;/font&gt;To fix this you just need to simply delete (or change) the relationship property to &lt;b&gt;NOT&lt;/b&gt; start lower-case. Always name your relationship properties Proper-case, starting with an upper case letter always. 

&lt;/p&gt;&lt;p&gt;&lt;br /&gt;I don&amp;#39;t know why this problem occurs. Seem that somewhere in the system an assumption is being made that the property name will be proper-cased (starting with an upper-case letter). However, I can tell you that you don&amp;#39;t see the problem if you use the first letter upper-cased for the properties created in the relationship. Weird.&lt;br /&gt;&lt;/p&gt;&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40359" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="Issues and Bugs" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Issues+and+Bugs/default.aspx" /><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /></entry><entry><title>Setting the Default Sort for a DataGrid in SalesLogix Web REVISITED</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/03/26/setting-the-default-sort-for-a-datagrid-in-saleslogix-web-revisited.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/03/26/setting-the-default-sort-for-a-datagrid-in-saleslogix-web-revisited.aspx</id><published>2009-03-26T21:28:00Z</published><updated>2009-03-26T21:28:00Z</updated><content type="html">&lt;p&gt;A while back I &lt;a href="http://customerfx.com/pages/crmdeveloper/2008/03/07/setting-the-default-sort-for-a-datagrid-in-saleslogix-web.aspx"&gt;wrote an article on setting the sort for a DataGrid in SalesLogix Web&lt;/a&gt; at runtime. That solution worked great in SalesLogix 7.2. However, things changed in SalesLogix 7.5 so I thought it was time for an update to that original post. Let&amp;#39;s see what changed and how to make it work again.&lt;/p&gt;
&lt;p style="font-weight:bold;"&gt;&lt;font size="3"&gt;&lt;a href="http://customerfx.com/pages/crmdeveloper/2008/03/07/setting-the-default-sort-for-a-datagrid-in-saleslogix-web.aspx"&gt;Take a look at the original article&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;In the original article, I mentioned that all this was possible because the SalesLogix DataGrid (Real class name SlxGridView) inherited from the ASP.NET GridView control. That hasn&amp;#39;t changed. However, here is what has changed:&lt;/p&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;span style="font-weight:bold;"&gt;Change #1: Where you LoadAction code is located&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-weight:bold;"&gt;&lt;/span&gt;The original &amp;quot;&lt;span style="font-weight:bold;font-style:italic;"&gt;C# Snippet Action Item&lt;/span&gt;&amp;quot; has been deprecated. This is what was used before. Now there is a &amp;quot;&lt;span style="font-weight:bold;font-style:italic;"&gt;Code Snippet Action Item&lt;/span&gt;&amp;quot; is what is used for code in LoadActions. The reason why this is significant is that the deprecated &amp;quot;C# Snippet Action Item&amp;quot; was placed inline in the SmartPart/ASCX file. So, you could rely on the fact that you could easily just reference controls on the form since the code also existed on the form. Now, with the new &amp;quot;Code Snippet Action Item&amp;quot;, the code is compiled into a separate assembly, much like the code in business rules. You are passed a reference to the form - which is not really a reference to the SmartPart class itself, but instead via an object that implements IForm and IEntityForm. &lt;/p&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;span style="font-weight:bold;"&gt;Change #2: In LoadAction code, you no longer get a direct reference to the controls&lt;/span&gt;&lt;/font&gt; &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;This form object mentioned above exposes the controls on the form, however, not as the real control type, but as an adapter that wraps the control - only exposing certain things. For example, instead of exposing a reference to your SlxGridView (the datagrid), you get a reference to a faux-grid the implements IDataGridControl. This interface only provides access to a few handful of properties of the grid and the columns. The IDataGridControl implements IControl, which provides a few additional things, most notably, it provides a reference to the actual underlying control via an object property named NativeControl.&lt;/p&gt;
&lt;p&gt;&lt;font size="4"&gt;&lt;span style="font-weight:bold;"&gt;How do we make this work?&lt;/span&gt;&lt;/font&gt; &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Using the IControl interface, you can take the control adapter you are passed in the LoadAction code and get to the native control. That is a simple task and then you&amp;#39;ll be able to do anything you need with the native control reference. Here&amp;#39;s some sample code that get&amp;#39;s a reference to the native control and then does the sorting, just like before:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; partial &lt;span style="color:Blue;"&gt;class&lt;/span&gt; RelatedAccountsEventHandlers&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Step(IAccountTickets form,  EventArgs args)&lt;br /&gt;    {&lt;br /&gt;        System.Web.UI.WebControls.GridView grid &lt;span style="color:Navy;"&gt;=&lt;/span&gt; (System.Web.UI.WebControls.GridView)form.grdAccountTickets.NativeControl;  &lt;br /&gt;        grid.Sort(&lt;span&gt;&amp;quot;ReceivedDate&amp;quot;&lt;/span&gt;, SortDirection.Descending);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Not so bad. The trick is knowing how to get to the underlying control from the adapter reference you are passed. One thing to note is that the code in the original article will still work in code in the now deprecated &amp;quot;C# Snippet Action Item&amp;quot;, so if you&amp;#39;ve used the code prior to 7.5, it will still work in the C# action. However, for new systems you need to use the new code above.&lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40350" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Application Architect" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Application+Architect/default.aspx" /><category term="SalesLogix 7.5" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+7.5/default.aspx" /><category term="Controls" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Controls/default.aspx" /></entry><entry><title>Presentation of the Infusionsoft Outlook Integration at InfusionCon</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/03/11/presentation-of-the-infusionsoft-outlook-integration-at-infusioncon.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/03/11/presentation-of-the-infusionsoft-outlook-integration-at-infusioncon.aspx</id><published>2009-03-12T00:19:00Z</published><updated>2009-03-12T00:19:00Z</updated><content type="html">&lt;p&gt;I was out at &lt;a href="http://infusioncon.com/" target="_blank"&gt;InfusionCon&lt;/a&gt; today, the annual user conference for &lt;a href="http://infusionsoft.com/" target="_blank"&gt;Infusionsoft&lt;/a&gt;, for the public unveiling of the Infusionsoft Outlook Integration with &lt;a href="http://editweapon.com/" target="_blank"&gt;Patrick Sullivan&lt;/a&gt;. I&amp;#39;ve been really excited for the Outlook integration to get into the hands of the Infusionsoft masses because, frankly, it is so completely cool. Patrick and I met up early to make sure all was working and ran through the demo several times.&lt;/p&gt;&lt;p&gt;Flash forward to the actual demo. Things started well. There was even loud applause and cheering. That&amp;#39;s when things went downhill. Doh! Patrick&amp;#39;s Outlook started to try to connect to Exchange and sync up folders via the wireless at the resort (something that it wasn&amp;#39;t doing via Patrick&amp;#39;s Verizon wireless that we were rehearsing with). The connection to his Exchange server just wasn&amp;#39;t happening via the wireless connection from the resort so the result was that Outlook started freezing up while trying to sync the folders. Needless to say this made it, er, difficult for Patrick to continue demoing the integration. To be honest, it was disappointing to not get to show more than what we did, not because we were struggling through getting Outlook to behave, but because I think the Outlook integration rocks and I wanted for the Infusionsoft users to get to see all that it can do.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;However, it was surprising that despite the difficulties in demoing the integration that there was so much positive feedback about the integration. I guess people saw enough before the problems started to know that they liked what they saw. When it comes to knowing how software and UI &lt;span style="font-style:italic;"&gt;should work&lt;/span&gt;, Patrick is king. I think we&amp;#39;ve captured a completely unique yet intuitive experience in the integration. Best of all, this is just the beginning. If you&amp;#39;ve seen the integration or you&amp;#39;re using it already, be prepared to have your socks knocked off throughout this year. There is some mind-blowing stuff that will be coming in the integration. It&amp;#39;s great already, but we&amp;#39;re going to be &lt;a href="http://en.wikipedia.org/wiki/Up_to_eleven" target="_blank"&gt;taking it up to 11&lt;/a&gt; :-)&lt;/p&gt;&lt;p&gt;For those of you who have not yet seen it, you can see a short demo (the one that Patrick was &lt;span style="font-style:italic;"&gt;intending&lt;/span&gt; to do at InfusionCon) &lt;a href="http://www.screencast.com/users/editweapon/folders/Jing/media/6410d372-ff47-4483-8d58-991d378ac50a" target="_blank"&gt;here&lt;/a&gt; (be sure to click the &amp;quot;Full Size&amp;quot; button for full effect). &lt;span style="font-style:italic;"&gt;However, keep in mind that Patrick is using a new untested build (not the same publically available version) so there are a couple of very quick nasties that pop up in the video.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.screencast.com/users/editweapon/folders/Jing/media/6410d372-ff47-4483-8d58-991d378ac50a" target="_blank"&gt;&lt;font size="4"&gt;&lt;span style="font-weight:bold;"&gt;View Patrick&amp;#39;s Quick Video Demo of the Infusionsoft Outlook Integration&lt;/span&gt;&lt;/font&gt;&lt;/a&gt;&lt;br /&gt;&lt;font size="1"&gt;&lt;span style="font-style:italic;"&gt;(Be sure to click the &amp;quot;Full Size&amp;quot; button)&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;All in all, it was great to be at InfusionCon with the guys from Infusionsoft. What a completely exciting company.&lt;br /&gt;&lt;/p&gt;&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40277" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="Infusionsoft" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Infusionsoft/default.aspx" /><category term="Outlook Integration" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Outlook+Integration/default.aspx" /></entry><entry><title>Determining if a User is a Member of a Team in SalesLogix Web</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/02/04/determining-if-a-user-is-a-member-of-a-team-in-saleslogix-web.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/02/04/determining-if-a-user-is-a-member-of-a-team-in-saleslogix-web.aspx</id><published>2009-02-04T21:13:00Z</published><updated>2009-02-04T21:13:00Z</updated><content type="html">
&lt;p&gt;Five years ago I wrote &lt;a href="http://customerfx.com/pages/crmdeveloper/2003/11/19/39084.aspx"&gt;a post about how to determine if a user is a member of a team&lt;/a&gt; in SalesLogix LAN scripts that is still referred to today. I&amp;#39;ve been asked on occasion how one would go about doing the same in the SalesLogix Web platform, so I thought it was time for a follow up post. In this post I will demonstrate how to use a &lt;a href="http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/queryhql.html" target="_blank"&gt;HQL query&lt;/a&gt; to create a reusable function in the SalesLogix Web platform to determine whether a user is a member of a specified team.&lt;/p&gt;

&lt;p&gt;We will be creating this as a reusable method that we&amp;#39;ll pass a User object to as well as the team name we want to check. Let&amp;#39;s look at the code first and then we&amp;#39;ll look at how to use it and where you might create this reusable code:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;bool&lt;/span&gt; IsUserOnTeam(Sage.Entity.Interfaces.IUser user, &lt;span style="color:Blue;"&gt;string&lt;/span&gt; team)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (NHibernate.ISession session &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sage.Platform.Orm.SessionScopeWrapper())&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 &amp;lt; Convert.ToInt32(session.CreateQuery(&lt;span&gt;&amp;quot;select count(*) from OwnerRights r where r.Owner.OwnerTypeChar = :type and r.Owner.OwnerDescription = :teamname and r.User.Id = :accessid&amp;quot;&lt;/span&gt;)&lt;br /&gt;                   .SetAnsiString(&lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;, Sage.SalesLogix.Security.StringEnum.GetStringValue(Sage.SalesLogix.Security.OwnerType.Team))&lt;br /&gt;                   .SetAnsiString(&lt;span&gt;&amp;quot;teamname&amp;quot;&lt;/span&gt;, team)&lt;br /&gt;                   .SetAnsiString(&lt;span&gt;&amp;quot;accessid&amp;quot;&lt;/span&gt;, user.Id.ToString())&lt;br /&gt;                   .UniqueResult());&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;The code above queries the SalesLogix entity model, looking at the OwnerRight entity specifically (this maps to the SECRIGHTS table in the database), and then limits that with conditions that the OwnerTypeChar property has the corresponding value for a team, the OwnerDescription has the correct team name, and to limit that to the OwnerRight entity instance where the UserId matches the Id of the User we pass in.&lt;/p&gt;

&lt;p&gt;The code to use it might look something like this:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;Sage.SalesLogix.Security.SLXUserService usersvc &lt;span style="color:Navy;"&gt;=&lt;/span&gt; (Sage.SalesLogix.Security.SLXUserService)Sage.Platform.Application.ApplicationContext.Current.Services.Get&amp;lt;Sage.Platform.Security.IUserService&amp;gt;();&lt;br /&gt;Sage.Entity.Interfaces.IUser user &lt;span style="color:Navy;"&gt;=&lt;/span&gt; usersvc.GetUser();&lt;br /&gt; &lt;br /&gt;&lt;span style="color:Blue;"&gt;if&lt;/span&gt; (IsUserOnTeam(user, &lt;span&gt;&amp;quot;Midwest&amp;quot;&lt;/span&gt;))&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Green;"&gt;// user is on the Midwest team&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;span style="color:Blue;"&gt;else&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Green;"&gt;// user is NOT on the Midwest team&lt;br /&gt;&lt;/span&gt;}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;Now, where might we implement something like this? Personally, I would create this as a separate assembly in Visual Studio and plug in where needed. However, you could also implement this in a business rule as well. If you implemented this code in a business rule, you&amp;#39;ll need to make sure the rule has the correct references. Otherwise it will produce an error when you build the web platform saying something about &amp;quot;are you sure you are not missing an assembly reference?&amp;quot;.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;By default, the rule will have references to the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sage.Entity.Interfaces.dll&lt;/li&gt;

&lt;li&gt;Sage.Form.Interfaces.dll&lt;/li&gt;

&lt;li&gt;Sage.Platform.dll&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the code I outlined above, you&amp;#39;ll also need to have references for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;nbsp;NHibernate.dll&lt;/li&gt;

&lt;li&gt;Sage.SalesLogix.Security.dll&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I won&amp;#39;t go into a whole lot of details now about how to add these references, I&amp;#39;ll have those steps outlined in a future post. However, while in the rule editor, open the Property pane (F4), click the drop-down at the top of the Properties pane and select &amp;quot;Sage.Platform.Orm.Entities.CodeSnippetHeader&amp;quot;. Then you&amp;#39;ll see properties for the CodeSnippetHeader for your code. You can bring up the AssemblyReferences and add the ones I mention above to that dialog. Things should complile fine now and you could shorten the code a bit too since you can add usings for these namespaces and drop the fully-qualified names of the objects. Just make sure you don&amp;#39;t try to add this rule to the User or other Security entities (See &lt;a href="http://customerfx.com/pages/crmdeveloper/2009/01/30/accessing-user-and-security-entity-properties-in-saleslogix-web.aspx"&gt;Accessing User and Security Entity Properties in SalesLogix Web&lt;/a&gt;)&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;One that thing I wanted to point out as well. The Owner object in Sage.SalesLogix.Security also has a similar function that will return a List&amp;lt;Owner&amp;gt; of all teams a specified user belongs to. That can come in handy as well. Here&amp;#39;s a sample that you could add to a LoadAction on a form to display a list of the teams the current user belongs to in a multi-line TextBox on the form called QFTextBox (Note: for this code, you do need a Sage.SalesLogix.Security.User object, not just a Sage.Entity.Interfaces.IUser reference since the method specifically takes a User, not IUser, parameter):&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;Sage.SalesLogix.Security.SLXUserService usersvc &lt;span style="color:Navy;"&gt;=&lt;/span&gt; (Sage.SalesLogix.Security.SLXUserService)Sage.Platform.Application.ApplicationContext.Current.Services.Get&amp;lt;Sage.Platform.Security.IUserService&amp;gt;();&lt;br /&gt;Sage.SalesLogix.Security.User user &lt;span style="color:Navy;"&gt;=&lt;/span&gt; usersvc.GetUser();&lt;br /&gt; &lt;br /&gt;System.Collections.Generic.IList&amp;lt;Sage.SalesLogix.Security.Owner&amp;gt; teamlist &lt;span style="color:Navy;"&gt;=&lt;/span&gt; Sage.SalesLogix.Security.Owner.GetTeamsByUser(user);&lt;br /&gt; &lt;br /&gt;&lt;span style="color:Blue;"&gt;string&lt;/span&gt; list &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt;.Empty;&lt;br /&gt;&lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (Sage.SalesLogix.Security.Owner team &lt;span style="color:Blue;"&gt;in&lt;/span&gt; teamlist)&lt;br /&gt;{&lt;br /&gt;    list += team.OwnerDescription &lt;span style="color:Navy;"&gt;+&lt;/span&gt; &lt;span&gt;&amp;quot;\r\n&amp;quot;&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;QFTextBox.Text &lt;span style="color:Navy;"&gt;=&lt;/span&gt; list;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;This code could also be used to check if a member is on a given team. However, the implementation of the method used in the Owner object will also return all the data in the List as well (and if I would have just used that I couldn&amp;#39;t have shown you the example using the HQL query). &lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40156" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="Development" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Development/default.aspx" /><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Entity Model" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Entity+Model/default.aspx" /></entry><entry><title>Accessing User and Security Entity Properties in SalesLogix Web</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/01/30/accessing-user-and-security-entity-properties-in-saleslogix-web.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/01/30/accessing-user-and-security-entity-properties-in-saleslogix-web.aspx</id><published>2009-01-30T23:34:00Z</published><updated>2009-01-30T23:34:00Z</updated><content type="html">
&lt;p&gt;There are likely many cases in SalesLogix Web where you need to access properties on the User and Security related entities that are not included in the entity by default, meaning that there is no public property exposing the value. For example, the IsManager property on the User entity. A co-worker of mine ran into just this problem this week (See &lt;a href="http://customerfx.com/pages/integrationblog/2009/01/29/retrieving-the-manager-in-saleslogix-7-5-web.aspx"&gt;Retrieving the Manager in SalesLogix 7.5 Web&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;The Problem&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;The root of the problem is that there are some often necessary properties on the User &amp;amp; Security related entities that are not included in the entity. See the image below:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/User-SecurityProperties-IsManager.jpg" width="618" border="1" height="362" alt="" /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Notice in the image above that the &amp;quot;Include&amp;quot; checkbox is not checked for the IsManager property on the User entity. What the Include value means is whether to include a public accessor property for this when the entity is built. So, you might think that checking this checkbox and doing a build will make it available to you at runtime. You build &amp;amp; deploy and get no errors. However, when you attempt to access the site you get a runtime error that states the following:&lt;/p&gt;

&lt;p style="margin-left:40px;"&gt;&lt;span style="font-style:italic;"&gt;System.TypeLoadException: Method &amp;#39;get_ManagerId&amp;#39; in type &amp;#39;Sage.SalesLogix.Security.User&amp;#39; from assembly &amp;#39;Sage.SalesLogix.Security, Version=7.5.0.1484, Culture=neutral, PublicKeyToken=null&amp;#39; does not have an implementation&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Here is why you are getting this error; the &amp;quot;Packages&amp;quot; in the entity model are more than just for the sake of organization. The &amp;quot;SalesLogix Security Support&amp;quot; package of entities does not just exist to separate these entities from the others. Each package is built to a separate assembly. They can have different templates for code generation. They can also have properties to indicate whether they are built into an assebmly at build time at all. This is the case with the User and Security entities in the SalesLogix Security Support package. If you open the package itself and &amp;quot;Build Settings&amp;quot; tab you will see something different about this package.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/User-SecurityProperties-Package.jpg" width="458" border="1" height="157" alt="" /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;You can see in the screenshot above that the SalesLogix Security Support package isn&amp;#39;t event built when you build the web platform. However, it&amp;#39;s interface is. When you check the Include checkbox on the IsManager property it is added to the interface. This is why you don&amp;#39;t get a compile error when you use it in a code snippet because you&amp;#39;re likely using the User entity via it&amp;#39;s interface. However, since the assembly is not built as well there is no implementation for the IsManager property that now exists in the IUser interface, hence the &amp;quot;does not have an implementation&amp;quot; error. Checking the box for &amp;quot;Generate Assembly&amp;quot; on the package won&amp;#39;t fix the problem. If you do, you&amp;#39;ll get compile errors. These User and Security entities are available in the Application Architect so you can create relationships to them from other entities, however their implementation is quite different and the standard code generation templates will not account for all the extra things they do. So, what is the solution?&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p style="font-weight:bold;"&gt;&lt;font size="4"&gt;The Solution&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Knowing why you&amp;#39;re getting the errors and what the problem is does not exactly help in getting to these not-included values that you need from these entities. However, there is hope. When you access any entity in SalesLogix code, you&amp;#39;re likely accessing the entity via it&amp;#39;s interface (as you should). However, I mentioned above that there is a lot more to the implementation of the User and Security entities. That is where you&amp;#39;ll find what you need.&lt;/p&gt;

&lt;p&gt;Normally, you would access a User, such as the current user, like this:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;Sage.SalesLogix.Security.SLXUserService usersvc &lt;span style="color:Navy;"&gt;=&lt;/span&gt; (Sage.SalesLogix.Security.SLXUserService)Sage.Platform.Application.ApplicationContext.Current.Services.Get&amp;lt;Sage.Platform.Security.IUserService&amp;gt;();&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Sage.Entity.Interfaces.IUser&lt;/span&gt; user &lt;span style="color:Navy;"&gt;=&lt;/span&gt; usersvc.GetUser();&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;Note that you are accessing the User via the IUser interface. Now, the IUser interface is just a standard entity interface. Since the interface is being built when you do a &amp;quot;Build Web Platform&amp;quot; (note, the checkbox to build it&amp;#39;s interface is checked for the package) it is a true representation of what you see in the Application Architect. However, there is quite a bit more to it&amp;#39;s implementation found in the User class. Fire up Reflector and take a look at some of the things available in Sage.SalesLogix.Security.User:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/User-SecurityProperties-Reflector.jpg" border="0" alt="" /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Notice all the extra goodies there to use? For example, the Manager property, that returns a Manager object. The Manager class simply inherits from User, meaning that it has all the properties and methods that a User object has as well as a few more. To use this property, as well as the others in the User class, you just need to use the reference via the User class instead of via the IUser interface. Something like this:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Green;"&gt;// get the current user as a User (not IUser)&lt;br /&gt;&lt;/span&gt;Sage.SalesLogix.Security.SLXUserService usersvc &lt;span style="color:Navy;"&gt;=&lt;/span&gt; (Sage.SalesLogix.Security.SLXUserService)Sage.Platform.Application.ApplicationContext.Current.Services.Get&amp;lt;Sage.Platform.Security.IUserService&amp;gt;();&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Sage.SalesLogix.Security.User&lt;/span&gt; user &lt;span style="color:Navy;"&gt;=&lt;/span&gt; usersvc.GetUser();&lt;br /&gt;&lt;br /&gt;&lt;span style="color:Green;"&gt;// now get the user&amp;#39;s Manager&lt;br /&gt;&lt;/span&gt;Sage.SalesLogix.Security.Manager manager &lt;span style="color:Navy;"&gt;=&lt;/span&gt; user.Manager;&lt;br /&gt;&lt;span style="color:Blue;"&gt;string&lt;/span&gt; manageremail &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Manager e-mail: &amp;quot;&lt;/span&gt; &lt;span style="color:Navy;"&gt;+&lt;/span&gt; manager.UserInfo.Email;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Note that the code is basically the same as when you accessed the User via the IUser interface. You just use the actual implementation class instead and you can get to what you need.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p style="font-weight:bold;"&gt;&lt;font size="4"&gt;A Solution for All Cases?&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;This is not a solution for every case. There will without question be some properties that you just can&amp;#39;t get to. The &amp;quot;last resort&amp;quot; solution to access these inaccessible properties is to go to the database. You can easily get a connection to the underlying database and use that to query for the value you&amp;#39;re after. Here&amp;#39;s an example:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Green;"&gt;// get the manager&amp;#39;s e-mail address using a connection to the database&lt;br /&gt;//&lt;br /&gt;// Note: this is just for example purposes, instead of doing this&lt;br /&gt;// use the user.Manager property available on Sage.SalesLogix.Security.User&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:Blue;"&gt;string&lt;/span&gt; manageremail &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt;.Empty;&lt;br /&gt;&lt;span style="color:Green;"&gt;// get the DataService to get a connection string to the database&lt;br /&gt;&lt;/span&gt;Sage.Platform.Data.IDataService datasvc &lt;span style="color:Navy;"&gt;=&lt;/span&gt; Sage.Platform.Application.ApplicationContext.Current.Services.Get&amp;lt;Sage.Platform.Data.IDataService&amp;gt;();&lt;br /&gt;&lt;span style="color:Blue;"&gt;using&lt;/span&gt; (System.Data.OleDb.OleDbConnection conn &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; System.Data.OleDb.OleDbConnection(datasvc.GetConnectionString()))&lt;br /&gt;{&lt;br /&gt;    conn.Open();&lt;br /&gt;    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (System.Data.OleDb.OleDbCommand cmd &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; System.Data.OleDb.OleDbCommand(&lt;span&gt;&amp;quot;select u1.email from userinfo u1 inner join usersecurity u2 on u1.userid = u2.managerid where u2.userid = &amp;#39;&amp;quot;&lt;/span&gt; &lt;span style="color:Navy;"&gt;+&lt;/span&gt; user.Id.ToString() &lt;span style="color:Navy;"&gt;+&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;, conn))&lt;br /&gt;    {&lt;br /&gt;        object o &lt;span style="color:Navy;"&gt;=&lt;/span&gt; cmd.ExecuteScalar();&lt;br /&gt;        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (o !&lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;null&lt;/span&gt;) manageremail &lt;span style="color:Navy;"&gt;=&lt;/span&gt; o.ToString();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;This is not an ideal solution, and isn&amp;#39;t meant to be.In my opinion, accessing the database directly should absolutely be a last resort and avoided if possible. Why, the entity model is rich and complete in most cases. The majority of times I&amp;#39;ve seen someone go direct to the database it is more than likely because of a lack of knowledge of how to do something in the entity model, not because the entity model could not provide what was needed. Business rules that might be in place in the entity model will not apply to things you do in the database (unless they are implemented in Process Orchestration). &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Ideally these properties in the implementation that are hidden by their absence in the interface would just be included in the interface. However, knowing that some of these things are there, and how to get to them, will definitely save you some headaches.&lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40150" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="Development" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Development/default.aspx" /><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="C#" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/C_2300_/default.aspx" /><category term="Entity Model" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Entity+Model/default.aspx" /><category term="Application Architect" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Application+Architect/default.aspx" /></entry><entry><title>Programatically Adding a New Record in SalesLogix Web</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/01/29/programatically-adding-a-new-record-in-saleslogix-web.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/01/29/programatically-adding-a-new-record-in-saleslogix-web.aspx</id><published>2009-01-29T20:55:00Z</published><updated>2009-01-29T20:55:00Z</updated><content type="html">&lt;p&gt;Something that is a common task in development, yet one that I get a lot of questions about, is how to programatically add a new record in SalesLogix Web using the entity model. This is an easy task, but unless you have some examples to learn from you might not know where to start. Let&amp;#39;s take a look.&lt;/p&gt;

&lt;p&gt;The EntityFactory is something you need to get familiar with. Get &lt;a href="http://www.red-gate.com/products/reflector/" target="_blank"&gt;Reflector&lt;/a&gt; and dig around the Sage.Platform.dll to take a look. You&amp;#39;ll use the EntityFactory to Create &amp;amp; Delete data. You can also use it to get a record by ID and to get a repository to query data in the entity model. Let&amp;#39;s just take a look at using it to Create a new entity instance that we can save (which will add the new record to the database).&lt;/p&gt;

&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;Scenario&lt;/b&gt;&lt;/font&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s say we have an entity named Certification, which has a 1:M relationship to the Contact. We&amp;#39;ll create a form under the contact where the user can choose a &amp;quot;certification&amp;quot; from a picklist and click an &amp;quot;add&amp;quot; button. We&amp;#39;ll also put a DataGrid on the Form to display the certifications for the contact. When the &amp;quot;add&amp;quot; button is clicked we&amp;#39;ll programatically create the certification record using the value the user selected in the picklist. Since the only selection to make is the certification, I like to do things like this instead of using a separate &amp;quot;add&amp;quot; form in a dialog that only contains a single control (the picklist). We&amp;#39;ve done away with the need to use an add dialog by just placing the picklist and add button controls right above the grid on the form itself.&lt;/p&gt;

&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;The Code&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;The code that we&amp;#39;ll execute on the Click of the add button would look as follows:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Green;"&gt;// make sure the user has selected a certification in the picklist&lt;br /&gt;&lt;/span&gt;&lt;span style="color:Blue;"&gt;if&lt;/span&gt; (picklistCert.PickListValue !&lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt;.Empty)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Green;"&gt;// get a reference to the current Contact&lt;br /&gt;&lt;/span&gt;    Sage.Entity.Interfaces.IContact contact &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.BindingSource.Current as Sage.Entity.Interfaces.IContact;&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:Green;"&gt;// programatically create a Certification and save it.&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:Green;"&gt;// use the EntityFactory to create a new instance of the Certification entity&lt;br /&gt;&lt;/span&gt;    &lt;b&gt;Sage.Entity.Interfaces.ICertification certification &lt;span style="color:Navy;"&gt;=&lt;/span&gt; Sage.Platform.EntityFactory.Create&amp;lt;Sage.Entity.Interfaces.ICertification&amp;gt;(); &lt;/b&gt;&lt;br /&gt;    &lt;span style="color:Green;"&gt;// now just set the properties &amp;amp; save&lt;br /&gt;&lt;/span&gt;    certification.Contact &lt;span style="color:Navy;"&gt;=&lt;/span&gt; contact;&lt;br /&gt;    certification.CertificationName &lt;span style="color:Navy;"&gt;=&lt;/span&gt; picklistCert.PickListValue;&lt;br /&gt;    certification.Save();&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:Green;"&gt;// add the certification to the contact&amp;#39;s Certification collection. &lt;br /&gt;&lt;/span&gt;    &lt;span style="color:Green;"&gt;// this is only needed to cause the grid bound to contact.Certifications to refresh&lt;br /&gt;&lt;/span&gt;    contact.Certifications.Add(certification);&lt;br /&gt;    &lt;br /&gt;    picklistCert.PickListValue &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt;.Empty;&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:Blue;"&gt;else&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Green;"&gt;// if the user clicked the add button without first choosing a certification display a message&lt;br /&gt;&lt;/span&gt;    &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.DialogService.ShowMessage(&lt;span&gt;&amp;quot;You must first select a certification to add. Please try again&amp;quot;&lt;/span&gt;);    &lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;You can see that the only tricky part is knowing how to create the new entity instance using the EntityFactory (I&amp;#39;ve bolded that line in the code above). Once you have that it is just a matter of setting the needed properties and saving it. Much easier than using a SQL INSERT statement or even adding a new record to an updateable ADO Recordset like how you would do this in the LAN client.&lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=40145" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="C#" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/C_2300_/default.aspx" /><category term="Entity Model" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Entity+Model/default.aspx" /><category term="EntityFactory" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/EntityFactory/default.aspx" /></entry><entry><title>Last Chance to Register for SalesLogix Web Developer Training</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2009/01/09/last-chance-to-register-for-saleslogix-web-developer-training.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2009/01/09/last-chance-to-register-for-saleslogix-web-developer-training.aspx</id><published>2009-01-09T17:03:00Z</published><updated>2009-01-09T17:03:00Z</updated><content type="html">
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;There is still time to register for my SalesLogix Web Developer training class starting this Monday. I am getting excited to start the class, we&amp;#39;ll be covering how to develop a complete solution in the SalesLogix 7.5 Web platform. You can see the entire class detail &lt;a href="http://customerfx.com/pages/events/pages/developer-training-building-solutions-for-saleslogix-web.aspx"&gt;here&lt;/a&gt; and register &lt;a href="http://customerfx.com/pages/events/2008/11/19/Jan-12_2C00_-2009-_2D00_-Developer-Training-_2D00_-Building-Solutions-for-SalesLogix-Web.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p style="font-weight:bold;"&gt;This is why you should register for the class:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You&amp;#39;ll learn what you need to know to develop complete solutions in SalesLogix Web&lt;/li&gt;

&lt;li&gt;You&amp;#39;ll learn it from someone who has developed many solutions for SalesLogix Web that are in production today&lt;br /&gt;&lt;/li&gt;

&lt;li&gt;You&amp;#39;ll end up with a working solution that you can use yourself or sell to customers (if you really follow along in the class in your own system)&lt;/li&gt;

&lt;li&gt;You&amp;#39;ll have a lot of fun :-)&lt;/li&gt;
&lt;/ol&gt;
I hope to see you in the class. It starts Monday and there are still seats available, but not many - so register quick.
&lt;p&gt;&lt;a href="http://customerfx.com/pages/events/2008/11/19/Jan-12_2C00_-2009-_2D00_-Developer-Training-_2D00_-Building-Solutions-for-SalesLogix-Web.aspx"&gt;&lt;font size="3"&gt;&lt;span style="font-weight:bold;"&gt;Register for Building Solutions for SalesLogix Web starting January 12!&lt;/span&gt;&lt;/font&gt;&lt;/a&gt; &lt;br /&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=39837" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Training" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Training/default.aspx" /></entry><entry><title>Public SalesLogix Developer Classes Revamped</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2008/10/27/public-saleslogix-developer-classes-revamped.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2008/10/27/public-saleslogix-developer-classes-revamped.aspx</id><published>2008-10-27T23:51:00Z</published><updated>2008-10-27T23:51:00Z</updated><content type="html">
&lt;p&gt;&lt;a href="http://customerfx.com/pages/crmdeveloper/2008/09/02/public-saleslogix-web-developer-classes-on-the-way.aspx"&gt;I announced&lt;/a&gt; a while ago that we will be offering some public developer training classes for SalesLogix Web. We will be making some changes to the class outline I posted earlier. &lt;/p&gt;&lt;p&gt;The new classes we will be offering will be as follows:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Building Solutions for SalesLogix Web&lt;/b&gt;&lt;br /&gt;This is the all-inclusive web developer class that uses the concept of building a complete solution to train around. We will go from start to finish in building a solution that covers all typical development scenarios when developing for SalesLogix Web.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Process Orchestration&lt;/b&gt;&lt;br /&gt;This is a full class that will focus on working with and developing for process orchestration (Windows Workflow) with SalesLogix 7.5 (Web or LAN).&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;SData &amp;amp; Integration&lt;/b&gt;&lt;br /&gt;This class will focus on building solutions using the SalesLogix SData &amp;amp; REST services layer for both reading SalesLogix data and writing to SalesLogix (creating new records, updating, &amp;amp; deleting), focusing on integration and external application scenarios.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;SalesLogix .NET Extensions&lt;/b&gt;&lt;br /&gt;This class will focus on developing .NET Extensions for the SalesLogix v7 and higher LAN client. We will take an in-depth look at building, debugging, &amp;amp; managing .NET Extensions as well as look at cases when to use .NET Extensions vs. standard SalesLogix customizations. &lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Beginning C# &amp;amp; .NET Development for SalesLogix&lt;/b&gt;&lt;br /&gt;We are also considering a &amp;quot;Beginning C# for SalesLogix&amp;quot; class that will cover the basics of C# and the .NET Framework from the perspective of working with SalesLogix.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;I will be posting the complete class outlines and schedules to this site &amp;amp; RSS feed shortly. Stay tuned.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=39683" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="Development" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Development/default.aspx" /><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term=".NET Extensions" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/.NET+Extensions/default.aspx" /><category term="SalesLogix" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix/default.aspx" /><category term="C#" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/C_2300_/default.aspx" /><category term="REST" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/REST/default.aspx" /><category term="Training" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Training/default.aspx" /></entry><entry><title>SalesLogix Group Explorer Added to Labs</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2008/09/13/saleslogix-group-explorer-added-to-labs.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2008/09/13/saleslogix-group-explorer-added-to-labs.aspx</id><published>2008-09-13T08:06:00Z</published><updated>2008-09-13T08:06:00Z</updated><content type="html">
&lt;p&gt;I added a new utility to the Customer FX Labs tonight, the SalesLogix Group Explorer. This utility allows you to dig deeper into the definition of SalesLogix groups than you ever thought possible. You can see the group&amp;#39;s layout, included columns, conditions, sort order, and way more. Not only that, but you can also see the SQL query behind the group and view the data that makes up the group, all from outside of SalesLogix. The Group Explorer also gives you the ability to quickly export group data, exporting 100,000 records in a fraction of a second.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Take a look at the SalesLogix Group Explorer (more images in the &lt;a href="http://customerfx.com/pages/beta/2008/09/13/saleslogix-group-explorer.aspx"&gt;Labs page&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="http://customerfx.com/blogs/beta/GroupExplorer/GroupExplorer2.jpg" target="_blank"&gt;&lt;img src="http://customerfx.com/blogs/beta/GroupExplorer/th_GroupExplorer2.jpg" border="0" alt="" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;i&gt;&lt;font color="#606060" size="1"&gt;(click for larger view)&lt;/font&gt;&lt;/i&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;The Group Explorer is currently in beta, but a free utility and downloadable in the labs. I&amp;#39;ve only tested this on versions 7.2 and higher so far (might or might not work with earlier versions).&lt;/p&gt;
&lt;p&gt;Download it and give it a whirl.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://customerfx.com/pages/beta/2008/09/13/saleslogix-group-explorer.aspx"&gt;&lt;font size="4"&gt;&lt;span style="font-weight:bold;"&gt;Visit the SalesLogix Group Explorer in the Labs&lt;/span&gt;&lt;/font&gt;&lt;/a&gt;&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=39624" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="New Finds" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/New+Finds/default.aspx" /><category term="General" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/General/default.aspx" /><category term="SalesLogix" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix/default.aspx" /><category term="Tools" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Tools/default.aspx" /></entry><entry><title>Custom Format Columns in SalesLogix Web (and Linking to External Sites in a DataGrid)</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2008/09/11/Custom-Format-Columns-in-SalesLogix-Web-and-Linking-to-External-Sites-in-a-DataGrid.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2008/09/11/Custom-Format-Columns-in-SalesLogix-Web-and-Linking-to-External-Sites-in-a-DataGrid.aspx</id><published>2008-09-11T23:12:00Z</published><updated>2008-09-11T23:12:00Z</updated><content type="html">&lt;p&gt;There might be times when you need to do some custom formatting in SalesLogix DataGrids that goes way beyond just simple formatting. A perfect example of this is taking a simple value, such as an indentifier from another external system where you want the value in the DataGrid to be a part of a hyperlink to this other system. In this scenario, you might have a value like &amp;quot;12345&amp;quot;, which identifies a matching record in another system and you want this to become a value like the following in the grid:&lt;br /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;font color="#000099" face="courier new,courier"&gt;&amp;lt;a href=&amp;quot;http://theothersystem.com/something?id=12345&amp;quot;&amp;gt;12345&amp;lt;/a&amp;gt;&lt;/font&gt;&lt;/pre&gt;
&lt;p&gt;This is where the CustomFormatColumn column type comes in. The problem is that this column type can be a little confusing and not well documented.&lt;/p&gt;

&lt;p&gt;In this scenario, we&amp;#39;ll just use a sample of adding a hyperlink into the Account Contacts grid to do a Google search on the contact&amp;#39;s full name. Not really useful, I know, but it will serve the purpose of demonstrating how to use a CustomFormatColumn.&lt;/p&gt;

&lt;p&gt;Basically, the way that a CustomFormatColumn works is you create your own custom C# function. The value, from each row, in the grid is passed into your function. You do whatever you need to do with the value in your code and then return the result, which is what will appear in the grid. &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;In the DataGrid on the AccountContacts QuickForm, add a CustomFormatColumn. There are four properties we&amp;#39;ll need to make sure we set. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;b&gt;ColumnHeading&lt;/b&gt; = The title or caption for the column.&lt;/li&gt;

&lt;li&gt;&lt;b&gt;DataField&lt;/b&gt; = This is field/property on the entity that you want passed into your function. For our example, we&amp;#39;ll pass in the contact&amp;#39;s FullName property.&lt;br /&gt;&lt;/li&gt;

&lt;li&gt;&lt;b&gt;FormatMethodName&lt;/b&gt; = This is the name that you&amp;#39;ll be calling your function. For our example, we&amp;#39;ll call our function &amp;quot;GoogleLink&amp;quot;&lt;/li&gt;

&lt;li&gt;&lt;b&gt;FormatCode&lt;/b&gt; = This is the C# code to do what is needed to the value so it displays the way you want in the grid. See the code for our example below:&lt;/li&gt;
&lt;/ol&gt;

&lt;pre&gt;&lt;span style="color:Blue;"&gt;protected&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; GoogleLink(&lt;span style="color:Blue;"&gt;object&lt;/span&gt; name)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt;.Format(&lt;span&gt;&amp;quot;&amp;lt;a href=\&amp;quot;http://www.google.com/search?q={0}\&amp;quot; target=_blank&amp;gt;{0}&amp;lt;/a&amp;gt;&amp;quot;&lt;/span&gt;, name);&lt;br /&gt;}&lt;/pre&gt;
&lt;p&gt;One thing to point out here, the parameter getting passed in will need to be an object and you&amp;#39;ll be returning a string. Also, you &lt;b&gt;must&lt;/b&gt; include the complete function signature with the method name matching (case-sensitive) the name you have in the FunctionMethodName property. The properties for our CustomFormatColumn will look as follows:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/CustomFormatColumn1.jpg" border="0" alt="" /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;The thing that will look weird, is the code in the Format Code property. As I mentioned before, you must include the complete signature of the function. The code window, however, will try to tell you that the code is not valid and it will appear as if you&amp;#39;re adding a function into a function, but you&amp;#39;re not. The code you type into this window will get added to the SmartPart and the grid column will wrap itself in the function call. You can see the weirdness I am referring to in the screenshot:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/CustomFormatColumn2.jpg" border="0" alt="" /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Notice the red squigglies and the apparent method signature at the top of the window. Ignore those. You&amp;#39;re doing just fine. After deploying, you can see the final result. A link in our grid that will launch a new window and take you to a search results page on Google. &lt;/p&gt;
&lt;p&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/CustomFormatColumn3.jpg" border="0" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A bit more real world, this would be another web app showing some details for that contact, like maybe products purchased or something from an accounting system. You can go far beyond simple formatting with this. If we wanted, we could pass in some identifier from the other system and then grab a value from that system&amp;#39;s database or via a web service call to get some value to show in the grid. However, beware, that while that is possible, keep in mind that this will execute for each row in the grid, delaying the load time for the grid and SmartPart so use discretion when moving beyond simple formatting.&lt;br /&gt;&lt;/p&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=39616" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Customization" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Customization/default.aspx" /><category term="Application Architect" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Application+Architect/default.aspx" /><category term="Quick Forms" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Quick+Forms/default.aspx" /></entry><entry><title>Public SalesLogix Web Developer Classes On The Way</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2008/09/02/public-saleslogix-web-developer-classes-on-the-way.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2008/09/02/public-saleslogix-web-developer-classes-on-the-way.aspx</id><published>2008-09-02T22:08:00Z</published><updated>2008-09-02T22:08:00Z</updated><content type="html">&lt;p&gt;Ever since the new SalesLogix 7.2 Web client and platform was released, I&amp;#39;ve had numerous requests for development training. Until now, I&amp;#39;ve done that on a very individualized basis, providing web training to single companies at a time. I&amp;#39;ve decided that it is time to make my web development training classes public, and I&amp;#39;d like your feedback.&lt;/p&gt;&lt;p&gt;The training classes will be done online, in short easy to digest chunks. The class will basically consist of 3 full days of training, spread out across three weeks. There will be approximately three sessions per week, each session lasting around 2+ hours each. To get the most out of the class, it will be expected that you spend some time working on the assigned practice examples in-between sessions. &lt;/p&gt;&lt;p&gt;The basic outline, for now, will consist of the following:&lt;/p&gt;&lt;p style="font-weight:bold;"&gt;&lt;font size="4"&gt;Beginner Track&lt;/font&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&amp;nbsp;Application Architect walk-through and terminology&lt;/li&gt;&lt;ol&gt;&lt;li&gt;QuickForms&lt;/li&gt;&lt;li&gt;SmartParts&lt;/li&gt;&lt;li&gt;Entity model and relationships&lt;/li&gt;&lt;li&gt;Interfaces&lt;/li&gt;&lt;li&gt;Portals and pages&lt;/li&gt;&lt;li&gt;Looking under the hood and understanding how it all comes together&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Setting up new portals and development environments&lt;/li&gt;&lt;ol&gt;&lt;li&gt;IIS configuration&lt;/li&gt;&lt;li&gt;Deployment configuration &amp;amp; process&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;QuickForm customization&lt;/li&gt;&lt;li&gt;Creating new 1:1 QuickForms &amp;amp; entity level tabs&lt;/li&gt;&lt;li&gt;Creating new 1:Many QuickForms with grids and edit/detail forms&lt;/li&gt;&lt;li&gt;Creating and installing bundles&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style="font-weight:bold;"&gt;&lt;font size="4"&gt;Intermediate Track&lt;/font&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Creating new entities&lt;/li&gt;&lt;li&gt;Creating new MainView pages&lt;/li&gt;&lt;li&gt;Creating entity insert screens&lt;/li&gt;&lt;li&gt;Creating simple business rules&lt;/li&gt;&lt;li&gt;Creating simple entity event handlers&lt;/li&gt;&lt;li&gt;Troubleshooting &amp;amp; debugging&lt;/li&gt;&lt;ol&gt;&lt;li&gt;A look at troubleshooting both out of the box issues and your own customizations&lt;/li&gt;&lt;li&gt;Best practices for optimal development debugging and testing&lt;/li&gt;&lt;li&gt;Using tools such as Visual Studio, Reflector, Firebug, etc&lt;/li&gt;&lt;/ol&gt;&lt;/ol&gt;&lt;font size="4"&gt;&lt;span style="font-weight:bold;"&gt;Advanced Track&lt;/span&gt;&lt;/font&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Creating complex business rules&lt;/li&gt;&lt;li&gt;Writing code for the entity model, repositories, &amp;amp; NHibernate queries&lt;/li&gt;&lt;li&gt;Creating business rules in Visual Studio&lt;/li&gt;&lt;li&gt;Creating custom SmartParts (visual UI elements) in Visual Studio&lt;/li&gt;&lt;li&gt;Creating and using mashups&lt;/li&gt;&lt;li&gt;Using mashups in custom SmartParts&amp;nbsp;&lt;/li&gt;&lt;/ol&gt;The expert track below will likely be a completely separate class (or classes) that will not be a part of the timeline mentioned for the developer class above.&lt;br /&gt;&lt;p style="font-weight:bold;"&gt;&lt;font size="4"&gt;Expert Track&lt;/font&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;SData &amp;amp; REST&lt;/li&gt;&lt;ol&gt;&lt;li&gt;Consuming SData feeds from external applications&lt;/li&gt;&lt;li&gt;Creating and updating entity data via REST&lt;/li&gt;&lt;li&gt;Integrating SalesLogix with other systems using SData/REST&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Process Orchestration (workflow)&lt;br /&gt;&lt;/li&gt;&lt;ol&gt;&lt;li&gt;Using process orchestration&lt;/li&gt;&lt;ol&gt;&lt;li&gt;Sequential, event driven processes&lt;/li&gt;&lt;li&gt;Goal driven processes&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Creating new process orchestration tasks in Visual Studio&lt;/li&gt;&lt;li&gt;Integrating SalesLogix with other systems using process orchestration&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/ol&gt;&lt;p&gt;&lt;br /&gt;Cost of the classes to follow at a later date. Obviously, we can&amp;#39;t offer Sage certification, the training is meant to provide an inexpensive, easy to attend, and &lt;span style="font-style:italic;"&gt;quick&lt;/span&gt; way to get developing for SalesLogix web &lt;span style="font-style:italic;"&gt;now&lt;/span&gt;. The class will also focus on 7.5. Attendees will be given access to forums where discussions from class can continue, code shared, etc, to help while working through practice examples.&lt;br /&gt;&lt;/p&gt;&lt;p style="font-weight:bold;font-style:italic;"&gt;&lt;font size="5"&gt;I&amp;#39;d love to hear your feedback &lt;/font&gt;&lt;/p&gt;&lt;p&gt;What topics would &lt;span style="font-style:italic;"&gt;you&lt;/span&gt; like to see covered? What things have caused you frustration when working with SalesLogix Web that would be helpful in a training class? Let me know in the comments below or via the &amp;quot;Contact&amp;quot; link to the right.&lt;br /&gt;&lt;/p&gt;&lt;img src="http://customerfx.com/aggbug.aspx?PostID=39608" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="Development" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Development/default.aspx" /><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Customization" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Customization/default.aspx" /><category term="SalesLogix 7.5" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+7.5/default.aspx" /><category term="Training" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Training/default.aspx" /></entry><entry><title>Building Interfaces, Building Web Platform, and Deployment Explained</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2008/08/22/building-interfaces-building-web-platform-and-deployment-explained.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2008/08/22/building-interfaces-building-web-platform-and-deployment-explained.aspx</id><published>2008-08-22T16:03:00Z</published><updated>2008-08-22T16:03:00Z</updated><content type="html">&lt;p&gt;When you&amp;#39;re developing for SalesLogix Web in the Application Architect, there are three actions that a developer must use during the process: building interfaces, building the web platform, and deployment. For someone starting out with the Application Architect, the reasons behind each of these actions can be confusing. Even more confusing can be when one is used vs another. This post will attempt to explain these three actions and when/why they are used.&lt;br /&gt;&lt;/p&gt;
&lt;p style="font-weight:bold;"&gt;&lt;font size="5"&gt;Building Interfaces&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;If you think about how the entities are used in code, you&amp;#39;ll know that it is always via it&amp;#39;s interface. Basically, an interface is a sort of &amp;quot;contract&amp;quot; that another class that implements the interface must abide by. The interface has no implementation code, it only defines what the implementing class must have. The reason why the entities in SalesLogix all implement an interface, and also why these interfaces are used to reference the entities in the AA and in code, is to provide a level of abstraction from the actual implementation of the entities. This way, when &amp;quot;future&amp;quot; SalesLogix can be deployed to web, windows, or mobile, the implementation of the entities can differ if needed yet all still implement the same interface, and the code that uses them via the interfaces will still work.&lt;/p&gt;
&lt;p&gt;So, what does that have to do with using the Application Architect? Just as your own code will use the entities via their interface, the QuickForms and other areas in the AA will use the interface as well. When you make a change to an entity, such as add a new entity, or add/change a property or relationship on and entity, the rest of the Application Architect will not know about this change until you&amp;#39;ve built the interfaces - which will cause the interface to show the change you&amp;#39;ve made. If you add a new property to an entity and then want to add it to a QuickForm, the QuickForm designer won&amp;#39;t know about the new property unless you&amp;#39;ve rebuilt the interfaces.&lt;/p&gt;
&lt;p&gt;As a rule of thumb, you should rebuild interfaces after doing the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a new entity&lt;/li&gt;
&lt;li&gt;Add or change properties on an entity&lt;/li&gt;
&lt;li&gt;Add or change relationships for entities&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, remember this: &lt;span style="font-weight:bold;font-style:italic;"&gt;building interfaces is only needed if you want to immediately use an entity you&amp;#39;ve added or changed in the Application Architect&lt;/span&gt;. The whole purpose of building interfaces is to make an entity change immediately available for use in the Application Architect. If you&amp;#39;re not going to use that change in a QuickForm or something right away, then you don&amp;#39;t need to build the interfaces. As you&amp;#39;ll learn in the next section, &lt;span style="font-weight:bold;font-style:italic;"&gt;building the web platform also builds the interfaces&lt;/span&gt; (so if you&amp;#39;re going to be doing that anyway, no need to take this step).&lt;/p&gt;
&lt;p&gt;In newer versions of SalesLogix (I think this came in 7.2.1 or 7.2.2) the Application Architect will attempt to recognize when a build is required for the interfaces and will run the build for you. I don&amp;#39;t really like this since you&amp;#39;ll attempt something like open up a QuickForm, it looks like the AA has locked up, but what it is really doing is running the build interfaces step in the background, when it&amp;#39;s done it will open up the form. Instead, I like to do my own build of the interfaces when it is required.&lt;br /&gt;&lt;/p&gt;
&lt;p style="font-weight:bold;"&gt;&lt;font size="5"&gt;Building Web Platform&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;When you build the web platform, what you&amp;#39;re essentially doing is getting the entity model ready for a web environment. All of the business rules and event code is compiled so it is usable by the entities, the QuickForms are converted to SmartParts (ASP.NET UserControls, ascx files), and so forth. This is a required step if you&amp;#39;ve made any changes at all in the entity model, that means entities, QuickForms, relationships, business rules, etc. &lt;span style="font-weight:bold;font-style:italic;"&gt;Remember, this step also builds interfaces, so no need to do that too&lt;/span&gt;. Before a deployment can happen, this must occur first to prepare the entity model by getting it into a web usable format.&lt;/p&gt;
&lt;p&gt;As a rule, you must build the web platform after you&amp;#39;ve done the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Anything listed above in the building interfaces section&lt;/li&gt;
&lt;li&gt;Created/modified a QuickForm&lt;/li&gt;
&lt;li&gt;Created/modified a business rule, event code, or code snippet. &lt;br /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you&amp;#39;ve changed anything in the entity model then you must do this step. Be clear about this, however, &lt;span style="font-weight:bold;font-style:italic;"&gt;this is only needed with changes to the &lt;span style="text-decoration:underline;"&gt;entity model&lt;/span&gt; only&lt;/span&gt;. Making changes in the portal manager, such as adding a SmartPart to a page, adding a new page, adding navigation menus, etc, are not part of the entity model, so there&amp;#39;s no need to build the web platform, only deployment.&lt;br /&gt;&lt;/p&gt;
&lt;p style="font-weight:bold;"&gt;&lt;font size="5"&gt;Deployment&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;The deployment is the step that pushes everything out to the website itself. The deployment process will check for the files that have changed and will push out accordingly. The deployment is needed after you do basically &lt;span style="font-style:italic;"&gt;anything&lt;/span&gt; in the Application Architect to get the changes out to the website. There are some things you can do in the AA which only require a deployment with no builds or anything else. If the only changes you&amp;#39;ve are in the portal manager, such as adding a SmartPart to a page, changing where a SmartPart loads on a page or anything like that, then all you need to do is a deployment. No builds are needed. Make sense?&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Yes, a lot to take in. Remember this:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Make changes to entity model and want to use the changes right away, build interfaces (unless you&amp;#39;ll also be building web platform for other reasons)&lt;/li&gt;&lt;li&gt;Any change to the entity model, build the web platform&lt;/li&gt;&lt;li&gt;Any change mentioned in 1 or 2, deploy.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Any change to the portal manager, deploy.&amp;nbsp;&lt;/li&gt;&lt;/ol&gt;Worse case, it doesn&amp;#39;t hurt to to more than what is necessary. If a build ins&amp;#39;t needed and you do it anyway, it won&amp;#39;t hurt anything. However, you&amp;#39;ve realized by now that the build and deployment for SalesLogix web takes a &lt;span style="font-style:italic;"&gt;long time&lt;/span&gt;. Anything to cut down on that time, and only perform exactly what is necessary is always helpful.&lt;br /&gt;
&lt;img src="http://customerfx.com/aggbug.aspx?PostID=39594" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Application Architect" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Application+Architect/default.aspx" /></entry><entry><title>Error Opening InsertOpportunity.aspx in SalesLogix 7.2 Web</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2008/07/28/error-opening-insertopportunity-aspx-in-saleslogix-7-2-web.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2008/07/28/error-opening-insertopportunity-aspx-in-saleslogix-7-2-web.aspx</id><published>2008-07-28T23:54:00Z</published><updated>2008-07-28T23:54:00Z</updated><content type="html">
&lt;p&gt;I posted this a while back in the SalesLogix Business Partner newsgroups, but it has recently just helped a few others who came across it there, so I thought it would be a worthwhile public post. Not everyone will get the error mentioned in this post, but if you are then this should help. This post also describes my troubleshooting process to locate this issue and determine the fix for it.&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;I have a customer who could not bring up the Insert New Opportunity Screen. After stepping through things with VS I determined that I was getting an error in the GetOppProductDefaults business rule on the Opportunity entity. The GetOppProductDefaults method looks like this (&lt;a href="http://customerfx.com/pages/crmdeveloper/2008/01/15/Documenting-SalesLogix-Web-with-Reflector.aspx"&gt;as seen through reflector&lt;/a&gt;): &lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; GetOppProductDefaults(IOpportunity opportunity)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:Blue;"&gt;string&lt;/span&gt; commonOption &lt;span style="color:Navy;"&gt;=&lt;/span&gt; ApplicationContext.Current.Services.Get&amp;lt;IUserOptionsService&amp;gt;().GetCommonOption(&lt;span&gt;&amp;quot;Products&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;OpportunityDefaults&amp;quot;&lt;/span&gt;);&lt;br /&gt;    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (commonOption !&lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        commonOption &lt;span style="color:Navy;"&gt;=&lt;/span&gt; commonOption.Substring(commonOption.IndexOf(&lt;span&gt;&amp;quot;&amp;lt;rs:data&amp;gt;&amp;quot;&lt;/span&gt;)).Replace(&lt;span&gt;&amp;quot;rs:data&amp;gt;&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;rsdata&amp;gt;&amp;quot;&lt;/span&gt;).Replace(&lt;span&gt;&amp;quot;z:row&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;zrow&amp;quot;&lt;/span&gt;).Replace(&lt;span&gt;&amp;quot;&amp;lt;/xml&amp;gt;&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;);&lt;br /&gt;        XmlDocument document &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; XmlDocument();&lt;br /&gt;        &lt;span style="color:Blue;"&gt;try&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            document.LoadXml(commonOption);&lt;br /&gt;            &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (XmlNode node &lt;span style="color:Blue;"&gt;in&lt;/span&gt; document.SelectSingleNode(&lt;span&gt;&amp;quot;rsdata&amp;quot;&lt;/span&gt;).ChildNodes)&lt;br /&gt;            {&lt;br /&gt;                &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (node.Attributes[&lt;span&gt;&amp;quot;PRODUCTID&amp;quot;&lt;/span&gt;].Value !&lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;null&lt;/span&gt;)&lt;br /&gt;                {&lt;br /&gt;                    IOpportunityProduct item &lt;span style="color:Navy;"&gt;=&lt;/span&gt; EntityFactory.Create&amp;lt;IOpportunityProduct&amp;gt;();&lt;br /&gt;                    item.Opportunity &lt;span style="color:Navy;"&gt;=&lt;/span&gt; opportunity;&lt;br /&gt;                    item.Product &lt;span style="color:Navy;"&gt;=&lt;/span&gt; EntityFactory.GetById&amp;lt;IProduct&amp;gt;(node.Attributes[&lt;span&gt;&amp;quot;PRODUCTID&amp;quot;&lt;/span&gt;].Value);&lt;br /&gt;                    item.Sort &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt;?(Convert.ToInt32(node.Attributes[&lt;span&gt;&amp;quot;SORT&amp;quot;&lt;/span&gt;].Value));&lt;br /&gt;                    item.Program &lt;span style="color:Navy;"&gt;=&lt;/span&gt; node.Attributes[&lt;span&gt;&amp;quot;PRICELEVEL&amp;quot;&lt;/span&gt;].Value;&lt;br /&gt;                    item.Price &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; decimal?(Convert.ToDecimal(node.Attributes[&lt;span&gt;&amp;quot;PRICE&amp;quot;&lt;/span&gt;].Value));&lt;br /&gt;                    item.Discount &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; double?(Convert.ToDouble(node.Attributes[&lt;span&gt;&amp;quot;DISCOUNT&amp;quot;&lt;/span&gt;].Value));&lt;br /&gt;                    item.Quantity &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; double?(Convert.ToDouble(node.Attributes[&lt;span&gt;&amp;quot;QUANTITY&amp;quot;&lt;/span&gt;].Value));&lt;br /&gt;                    item.ExtendedPrice &lt;span style="color:Navy;"&gt;=&lt;/span&gt; &lt;span style="color:Blue;"&gt;new&lt;/span&gt; decimal?(Convert.ToDecimal(node.Attributes[&lt;span&gt;&amp;quot;EXTENDED&amp;quot;&lt;/span&gt;].Value));&lt;br /&gt;                    opportunity.Products.Add(item);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;span style="color:Blue;"&gt;catch&lt;/span&gt; (Exception)&lt;br /&gt;        {&lt;br /&gt;            throw &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Exception(&lt;span&gt;&amp;quot;Invalid xml for default Opportunity Products&amp;quot;&lt;/span&gt;);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;The stack trace from the exception showed the following:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;   at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy)&lt;br /&gt;   at System.String.Substring(Int32 startIndex)&lt;br /&gt;   at Sage.SalesLogix.Opportunity.Rules.GetOppProductDefaults(IOpportunity opportunity)&lt;br /&gt;   at Sage.SalesLogix.Opportunity.Rules.CheckOppAccount(IOpportunity opportunity, Boolean&amp;amp; result)&lt;br /&gt;   at (Object )&lt;br /&gt;   at Sage.Platform.DynamicMethod.DynamicMethodLibrary.Execute(String methodName, Object[] args)&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;You&amp;#39;ll notice that the exception was thrown from the attempt to use Substring on a string within the GetOppProductDefaults method. The Substring is used to get only the XML between the &amp;lt;rs:data&amp;gt;&amp;lt;/rs:data&amp;gt; tags from the serialized XML from the Recordset stored there, ignoring the schema data from the beginning section of the XML. So, I looked and this is what this customer has stored there for *all* users for the Products in the OpportunityDefaults user option:&lt;/p&gt;

&lt;table style="table-layout:fixed;width:600px;" cellpadding="0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;&lt;pre&gt;&amp;lt;xml xmlns:z=&lt;span&gt;&amp;quot;#RowsetSchema&amp;quot;&lt;/span&gt; xmlns:rs=&lt;span&gt;&amp;quot;urn:schemas-microsoft-com:rowset&amp;quot;&lt;/span&gt; xmlns:dt=&lt;span&gt;&amp;quot;uuid:C2F41010-65B3-11d1-A29F-00AA00C14882&amp;quot;&lt;/span&gt; xmlns:s=&lt;span&gt;&amp;quot;uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;&amp;lt;s:Schema id=&lt;span&gt;&amp;quot;RowsetSchema&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt; &amp;lt;s:ElementType name=&lt;span&gt;&amp;quot;row&amp;quot;&lt;/span&gt; content=&lt;span&gt;&amp;quot;eltOnly&amp;quot;&lt;/span&gt; rs:updatable=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;SORT&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;1&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;int&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;4&amp;quot;&lt;/span&gt; rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:fixedlength=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;PRODUCTID&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;2&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;string&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;str&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;12&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;KEYFIELDID&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;3&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;string&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;str&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;16&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;PRODUCT&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;4&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;string&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;str&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;64&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;FAMILY&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;5&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;string&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;str&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;64&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;PRICELEVEL&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;6&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;string&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;str&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;32&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;PRICE&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;7&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;number&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;currency&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;8&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:fixedlength=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;DISCOUNT&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;8&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;float&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;8&amp;quot;&lt;/span&gt; rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:fixedlength=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;ADJPRICE&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;9&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;number&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;currency&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;8&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:fixedlength=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;PRICELOCAL&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;10&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;number&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;currency&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;8&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:fixedlength=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;QUANTITY&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;11&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;float&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;8&amp;quot;&lt;/span&gt; rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:fixedlength=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;EXTENDED&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;12&amp;quot;&lt;/span&gt; rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;number&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;currency&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;8&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:fixedlength=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:AttributeType name=&lt;span&gt;&amp;quot;EXTENDEDLOCAL&amp;quot;&lt;/span&gt; rs:number=&lt;span&gt;&amp;quot;13&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:write=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;   &amp;lt;s:datatype dt:type=&lt;span&gt;&amp;quot;number&amp;quot;&lt;/span&gt; rs:dbtype=&lt;span&gt;&amp;quot;currency&amp;quot;&lt;/span&gt; dt:maxLength=&lt;span&gt;&amp;quot;8&amp;quot;&lt;/span&gt;&lt;br /&gt;    rs:precision=&lt;span&gt;&amp;quot;0&amp;quot;&lt;/span&gt; rs:fixedlength=&lt;span&gt;&amp;quot;true&amp;quot;&lt;/span&gt; rs:maybenull=&lt;span&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/s:AttributeType&amp;gt;&lt;br /&gt;  &amp;lt;s:extends type=&lt;span&gt;&amp;quot;rs:rowbase&amp;quot;&lt;/span&gt;&lt;span style="color:Navy;"&gt;/&lt;/span&gt;&amp;gt;&lt;br /&gt; &amp;lt;/s:ElementType&amp;gt;&lt;br /&gt;&amp;lt;/s:Schema&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/xml&amp;gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;There is no &amp;lt;rs:data&amp;gt; section in this XML, so obviously, that is why the use of Substring is failing, because the IndexOf is returning an invalid integer for a start position. Normally, in any other system I&amp;#39;ve checked so far, this XML is completely blank for users that have never set any defaults. For a user that goes into the dialog to set the defaults and clicks OK without selecting any default products they will have the XML, but an empty &amp;lt;rs:data&amp;gt; section. Empty is OK, because at least it exists and the code above will not fail. &lt;/p&gt;

&lt;p&gt;So, I have no idea what caused the XML to get saved this way in the first place. I will continue to look for this in other systems, but I wanted to mention all this here in case others run into this. This is all fixed by having these users simply go into the Opportunity Defaults dialog (in the fat client) and just clicking OK. This will cause the empty &amp;lt;rs:data&amp;gt; section to be added to the XML for the serialized recordset and then all wil work fine.&lt;/p&gt;

&lt;p&gt;I was originally going to suggest that the code for the GetOppProductDefaults be changed to check the IndexOf the &amp;quot;&amp;lt;rd:data&amp;gt;&amp;quot; section frst before proceeding to get the Substring. This certainly would have saved me some headache since the code would not have completely crapped out for this customer - but I have no idea how this got stored this way for this customer in the first place, so no telling how common this scenario would be. The weird thing is that the XML is like this for *all* users for my customer. This was an upgrade BTW, but so was my own internal database and it doesn&amp;#39;t have this problem.&lt;/p&gt;

&lt;p&gt;&lt;font size="4"&gt;&lt;b&gt;The Solution&lt;/b&gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;For now, just have your users go to the Set Opportunity Defaults screen in the Windows client and just open and close (by clicking OK) the opportunity products default screen (they don&amp;#39;t actually have to select any product defaults). This will cause the proper XML string to be saved for that user. Optionally, you could programatically store the corrected XML for them. &lt;/p&gt;

&lt;p&gt;I&amp;#39;ve not checked yet to see if this business rule has been fixed for 7.5 or not. &lt;br /&gt;&lt;/p&gt;&lt;img src="http://customerfx.com/aggbug.aspx?PostID=39531" width="1" height="1"&gt;</content><author><name>Ryan Farley</name><uri>http://customerfx.com/members/Ryan-Farley.aspx</uri></author><category term="Issues and Bugs" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Issues+and+Bugs/default.aspx" /><category term="SalesLogix Web" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/SalesLogix+Web/default.aspx" /><category term="Troubleshooting" scheme="http://customerfx.com/pages/crmdeveloper/archive/tags/Troubleshooting/default.aspx" /></entry><entry><title>SalesLogix 7.5 Beta Testing Has Begun!</title><link rel="alternate" type="text/html" href="http://customerfx.com/pages/crmdeveloper/2008/07/11/saleslogix-7-5-beta-testing-has-begun.aspx" /><id>http://customerfx.com/pages/crmdeveloper/2008/07/11/saleslogix-7-5-beta-testing-has-begun.aspx</id><published>2008-07-11T20:55:00Z</published><updated>2008-07-11T20:55:00Z</updated><content type="html">&lt;p&gt;The beta tesing for SalesLogix 7.5 has begun! Completely exciting. This is &lt;b&gt;&lt;i&gt;THE&lt;/i&gt;&lt;/b&gt; release for SalesLogix web, and one that IMO puts SalesLogix in the front of all other web-based CRM applications.&amp;nbsp; If you&amp;#39;re using SalesLogix Web and not yet planning on moving to 7.5 it&amp;#39;s time to start planning that upgrade. &lt;/p&gt;
&lt;p&gt;There will be plenty of things coming to show all the new features of 7.5 (like the upcoming &lt;a href="http://customerfx.com/pages/events/2008/06/19/Jul-15_2C00_-2008-_2D00_-SalesLogix-v7.5-Sneak-Peek-Live-_2D00_-A-Customer-FX-Exclusive.aspx"&gt;Customer FX 7.5 Sneak Peek live workshop&lt;/a&gt;) , but I wanted to point out a few small and less talked about things that I&amp;#39;ve liked so far in this release.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New Look &amp;amp; Feel&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;The new &amp;quot;polished&amp;quot; look of the web client is completely impressive. I stuggled with the look of the original 7.2 client, had a hard time liking how it looked. Not the case any more. This looks awesome. Here&amp;#39;s a few examples:&lt;/p&gt;
&lt;p&gt;The new menus:&lt;br /&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/SalesLogix75/slx75-1.jpg" border="0" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;The new group viewer:&lt;br /&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/SalesLogix75/slx75-2.jpg" border="0" alt="" /&gt; &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;Collapsible navbar:&lt;br /&gt;&lt;img src="http://customerfx.com/blogs/crmdeveloper/SalesLogix75/slx75-3.jpg" border="0" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Awesome looking dialogs, especially lookups - wow those were really needed and I just can&amp;#39;t get over how great they look!&lt;br /&gt; &lt;img src="http://customerfx.com/blogs/crmdeveloper/SalesLogix75/slx75-4.jpg" border="0" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Session Timeout Indicator&lt;/b&gt; &lt;/p&gt;
&lt;p&gt;In the bottom-right corner. And you get bumped out to the login screen as soon as it expires. Small change, yes, but a nice one to have. Also, you get a count down to when you are going to get automatically logged off too - &amp;quot;auto logoff in 1 minute&am