<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Chivinou [ʃivinu]</title>
	<atom:link href="http://chivinou.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://chivinou.wordpress.com</link>
	<description>Adventures of a Belgian programmer exiled to Missouri</description>
	<lastBuildDate>Tue, 01 Sep 2009 18:44:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='chivinou.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Chivinou [ʃivinu]</title>
		<link>http://chivinou.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://chivinou.wordpress.com/osd.xml" title="Chivinou [ʃivinu]" />
	<atom:link rel='hub' href='http://chivinou.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Display user lookup as a dropdown (legacy-web style)</title>
		<link>http://chivinou.wordpress.com/2009/09/01/display-user-lookup-as-a-dropdown-legacy-web-style/</link>
		<comments>http://chivinou.wordpress.com/2009/09/01/display-user-lookup-as-a-dropdown-legacy-web-style/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 18:44:16 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/2009/09/01/display-user-lookup-as-a-dropdown-legacy-web-style/</guid>
		<description><![CDATA[Our users upgraded from 7.0 to 7.5 complained about the user lookup dialog – on 7.0 it used to be a dropdown, whereas on 7.5 it’s a popup similar to the LAN client. Sorry for the chopped image, I had to hide the name and was too lazy to re-run on the eval db. The [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=221&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Our users upgraded from 7.0 to 7.5 complained about the user lookup dialog – on 7.0 it used to be a dropdown, whereas on 7.5 it’s a popup similar to the LAN client. </p>
<p><a href="http://blog.chivinou.net/wp-content/uploads/2009/09/image2.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://blog.chivinou.net/wp-content/uploads/2009/09/image-thumb2.png" width="244" height="202" /></a> </p>
<p>Sorry for the chopped image, I had to hide the name and was too lazy to re-run on the eval db.</p>
<p> The problem is the popup takes a couple seconds to come up on IE7, sometimes more on slow machines or slow connections &#8211; it’s a bit irritating.&#160; After a brief phase of denial (how dare they refuse the New and Improved way, etc) I set to work.&#160; Had to struggle a bit with the combination of available properties but finally got it working.&#160; Configuring lookup is definitely a big pain on the web client!&#160; This is the winning combo:</p>
<ul>
<li>Display Mode = DropDownList</li>
<li>Display Property = UserInfo.UserName</li>
<li>Lookup Entity Name = User</li>
<li>Lookup Binding Mode = Object</li>
<li>In the Lookup Pre Filters, add a filter on “Enabled” (make sure the property is populated as System.Boolean) and filter value of “true”</li>
</ul>
<p>The DropDown style lookups are a bit more picky on the parameters than the regular lookup, because they actually use NHibernate parameters instead of inline HQL.&#160; In general I would say it is a good thing to use parameters, though in this case it makes it a bit harder for us to hack around the limitation of the control. </p>
<p>Data binding works fine, the only big problem I have found is that it sorts by first name instead of last name for some reason (which you can’t really see in the screen shot as I removed the last name but you can imagine).</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/221/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/221/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/221/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=221&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/09/01/display-user-lookup-as-a-dropdown-legacy-web-style/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>

		<media:content url="http://blog.chivinou.net/wp-content/uploads/2009/09/image-thumb2.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>Troubleshooting Reporting Server</title>
		<link>http://chivinou.wordpress.com/2009/09/01/troubleshooting-reporting-server/</link>
		<comments>http://chivinou.wordpress.com/2009/09/01/troubleshooting-reporting-server/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 16:19:34 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/2009/09/01/troubleshooting-reporting-server/</guid>
		<description><![CDATA[This post is an example of the tricks you can accomplish with Reflector as well as a reminder for me on how to do this. If you have tried to set up a report server on the web client and run into any kind of trouble you may have noticed that there was very little [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=217&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This post is an example of the tricks you can accomplish with Reflector as well as a reminder for me on how to do this.</p>
<p>If you have tried to set up a report server on the web client and run into any kind of trouble you may have noticed that there was very little diagnostic.&#160; Yesterday I upgraded one of our customers from 7.2.2 to 7.5.1.&#160; Most of it went smoothly (apart from some error in the downloaded installation files) but the reporting just would not work – Firefox just printed an obscure message “XML Parsing Error: no element found”, while Internet Explorer showed an empty page.&#160; </p>
<p><a href="http://blog.chivinou.net/wp-content/uploads/2009/09/image.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://blog.chivinou.net/wp-content/uploads/2009/09/image-thumb.png" width="450" height="127" /></a> </p>
<p>Well actually they were both right – in lieu of a diagnostic message the report server page (SLXWebReportingServer.ashx) just did not return anything at all.&#160; The first thing I did was make sure logging was enabled, and I edited log4net.config to make the name a bit more obvious (by default it just logs messages as “Service” – I changed it to “Saleslogix Web Reporting”).&#160; Yet it still showed no message.&#160; I had to get the report handler to print more diagnostic.&#160; As it is a compiled assembly this cannot be done directly – however we can extract it using Reflector:</p>
<p><a href="http://blog.chivinou.net/wp-content/uploads/2009/09/image1.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://blog.chivinou.net/wp-content/uploads/2009/09/image-thumb1.png" width="431" height="404" /></a> </p>
<p>Paste the code in a file called SLXWebReportingServer.ashx in the slxwebrpt folder and add the handler directive at the top:</p>
<pre class="csharpcode"><span class="asp">&lt;%</span> WebHandler language=<span class="str">&quot;C#&quot;</span> <span class="kwrd">class</span>=<span class="str">&quot;SLXWebReportingServer&quot;</span> <span class="asp">%&gt;</span></pre>
<p>Then comment out the httpHandler directive in web.config and re-run the report (or you can just F5 the reporting window).&#160; This will give a compilation error, of course, since we have not added any “using” directive.&#160; Turn off customErrors in web.config (add a &lt;customErrors mode=”off”/&gt; under &lt;system.web&gt;) and add the missing using statements until you get the page to compile with the same error as the original one (there might be a way to get Reflector to generate the using statements, if so, i have not found it).&#160; This is what I had to add for this one:</p>
<pre class="csharpcode"><span class="kwrd">using</span> System;
<span class="kwrd">using</span> System.Web;
<span class="kwrd">using</span> System.Web.SessionState;
<span class="kwrd">using</span> Interop.SLXWR;
<span class="kwrd">using</span> System.Runtime.InteropServices;
<span class="kwrd">using</span> log4net;
<span class="kwrd">using</span> Sage.SalesLogix.Reporting.Server;
<span class="kwrd">using</span> System.Data.OleDb;
<span class="kwrd">using</span> System.Data;
<span class="kwrd">using</span> System.Xml;
<span class="kwrd">using</span> System.IO;
<span class="kwrd">using</span> Sage.Platform;
<span class="kwrd">using</span> Sage.SalesLogix;</pre>
<p>Create a logger object </p>
</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> SLXWebReportingServer: IHttpHandler, IRequiresSessionState
{
    <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">readonly</span> ILog LOG =
        LogManager.GetLogger(<span class="kwrd">typeof</span>(SLXWebReportingServer));</pre>
<p>And verify that it works:</p>
<pre class="csharpcode">    <span class="kwrd">public</span> <span class="kwrd">void</span> ProcessRequest(HttpContext context)
    {
        <span class="kwrd">try</span>
        {
LOG.Warn(<span class="str">&quot;Boo&quot;</span>);</pre>
<p>OK, now we are ready to work.&#160; The first thing I <strong>should</strong> have done at this point was add a log statement in the top-level catch block, at the very end of the file:</p>
<pre class="csharpcode">        <span class="kwrd">catch</span> (Exception exception2)
        {
LOG.Warn(<span class="str">&quot;Error in top level try/catch&quot;</span>, exception2);
            context.Response.StatusCode = 500;
            context.Response.StatusDescription = exception2.Message;
        }</pre>
<p>It’s a good idea to first scan for trapped, unlogged exceptions and make sure they are reported.&#160; However, I smartly dove in and started peppering the code with LOG statements to get an idea of where it was hung:</p>
<pre class="csharpcode">    <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">bool</span> GetConnectionString(<span class="kwrd">string</span> userName, <span class="kwrd">string</span> password, <span class="kwrd">string</span> timeZoneKey, <span class="kwrd">out</span> <span class="kwrd">string</span> connectionString, <span class="kwrd">out</span> <span class="kwrd">string</span> dataSource, <span class="kwrd">out</span> <span class="kwrd">string</span> errorMsg)
    {
LOG.Info(<span class="str">&quot;GetConnectionString - 1&quot;</span>);
        <span class="kwrd">object</span> obj2;
        connectionString = <span class="kwrd">null</span>;
        dataSource = <span class="kwrd">null</span>;
        errorMsg = <span class="kwrd">null</span>;
        <span class="kwrd">string</span> physicalApplicationPath = HttpContext.Current.Request.PhysicalApplicationPath;
        <span class="kwrd">if</span> (<span class="kwrd">string</span>.IsNullOrEmpty(physicalApplicationPath))
        {
            errorMsg = <span class="str">&quot;ERR_APPLICATIONPATH&quot;</span>;
            <span class="kwrd">return</span> <span class="kwrd">false</span>;
        }
LOG.Info(<span class="str">&quot;GetConnectionString - 2&quot;</span>);
        <span class="kwrd">string</span> path = Path.Combine(physicalApplicationPath, <span class="str">&quot;connection.config&quot;</span>);
        <span class="kwrd">if</span> (!File.Exists(path))
        {
            errorMsg = <span class="str">&quot;ERR_CONNECTIONCONFIG_NOTFOUND&quot;</span>;
            <span class="kwrd">return</span> <span class="kwrd">false</span>;
        }
LOG.Info(<span class="str">&quot;GetConnectionString - 3&quot;</span>);
        XmlDocument document = <span class="kwrd">new</span> XmlDocument();
        <span class="kwrd">try</span>
        {
            document.Load(path);
        }
        <span class="kwrd">catch</span> (Exception exception)
        {
            errorMsg = <span class="kwrd">string</span>.Format(<span class="str">&quot;ERR_CONNECTIONCONFIG_LOAD&quot;</span>, exception.Message);
            <span class="kwrd">return</span> <span class="kwrd">false</span>;
        }
LOG.Info(<span class="str">&quot;GetConnectionString - 4&quot;</span>);</pre>
<p>You get the idea.&#160; Eventually I found the GetRWPassword call was not returning and that’s when I realized there was a blanket catch statement.&#160; From there the error was obvious (I had not installed the SQL native client on the report server) and of course the quick way to find out would have been to install the SalesLogix client on the box – but it was an interesting exercise nonetheless, and could prove useful in other cases.</p>
<p>To recap:</p>
<ol>
<li>First step should be to install the Sales client and make sure you can log in</li>
<li>Then, edit the logging options to make sure you are looking for the correct messages</li>
<li>If all fails, you can always replace the default handler to add some diagnostic</li>
<li>Don&#8217;t forget to put the default handler back when done! <img src='http://s2.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ol>
<p><a href="/media/SLXWebReportingServer.ashx">This</a> is the ashx file I used (for version 7.5.1 – on other versions you’d have to make sure you get the appropriate code using Reflector).</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/217/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/217/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/217/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/217/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/217/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/217/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/217/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/217/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/217/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/217/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/217/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/217/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/217/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/217/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=217&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/09/01/troubleshooting-reporting-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>

		<media:content url="http://blog.chivinou.net/wp-content/uploads/2009/09/image-thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://blog.chivinou.net/wp-content/uploads/2009/09/image-thumb1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>A bit of exploration with SalesLogix, Custom portals, and ASP.NET MVC</title>
		<link>http://chivinou.wordpress.com/2009/07/04/a-bit-of-exploration-with-saleslogix-custom-portals-and-aspnet-mvc/</link>
		<comments>http://chivinou.wordpress.com/2009/07/04/a-bit-of-exploration-with-saleslogix-custom-portals-and-aspnet-mvc/#comments</comments>
		<pubDate>Sat, 04 Jul 2009 17:23:25 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Saleslogix]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/2009/07/04/a-bit-of-exploration-with-saleslogix-custom-portals-and-aspnet-mvc/</guid>
		<description><![CDATA[Ever tried this menu? It basically lets you set up a new deployment – that is, a way to export your defined entities, dynamic methods, and interfaces.&#160; But you don’t get much when you try the “Portal Wizard” – the site it creates is almost empty, and because there will be no authentication set up, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=212&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Ever tried this menu?</p>
<p><img style="display:inline;border-width:0;" title="image" border="0" alt="image" src="http://blog.chivinou.net/wp-content/uploads/2009/07/image.png" width="244" height="70" /> </p>
<p>It basically lets you set up a new deployment – that is, a way to export your defined entities, dynamic methods, and interfaces.&#160; But you don’t get much when you try the “Portal Wizard” – the site it creates is almost empty, and because there will be no authentication set up, you can’t add pages to it right away either.&#160; On the plus side, it gives you a good building base and is very flexible.</p>
<p>I decided to give it a try and combine it with a quick shot at ASP.NET MVC (which, in case you did not know, is an alternative to regular ASP.NET published by Microsoft – if you like the simplicity of Rails or Django you will recognize some of those frameworks in there).&#160; I thought this might be a good option for some external sites that don’t need the full overhead of the regular Saleslogix web client.</p>
<p>As a little experimentation I decided to create a quick contact lookup site, it is actually slightly useful to me as the site is rudimentary enough to be used from a “dumb” phone (any phone that supports HTML) and as it does not have the long start up time of the regular web client it can be used to look up a contact basic info very quickly.</p>
<p>The only real trick was finding the right “modules” to configure in web.config.&#160; I also had to enable the integrated pipeline (from IIS7) from ASP.NET MVC (technically you can use it with the classic pipeline but the URLs don’t look as good), but fortunately this had no impact on Saleslogix (as long as you make it 32 bit).&#160; So here are the steps in (more or less) details.</p>
<p>The first step is obviously to download ASP.NET MVC from <a href="http://www.asp.net/mvc">http://www.asp.net/mvc</a>.&#160; </p>
<p>Next, I started up Visual Studio and created a new ASP.NET MVC site.&#160; This created a sample application with a few demo pages which I removed (remove everything under Views\Account and Views\Home, and remove the AccountController).&#160; I did test it before removing to make sure it worked!</p>
<p>At the same time (actually right before) I created a new portal in the Application Architect (using the “Service Host” template, but I don’t think it really makes a difference) and deployed it.&#160; I copied over my ASP.NET MVC site, keeping the following files from the Saleslogix portal:</p>
<ul>
<li>hibernate.xml </li>
<li>log4net.config </li>
<li>ServiceHosts.xml </li>
<li>dynamicmethods.xml </li>
<li>application.xml </li>
<li>connection.config </li>
</ul>
<p>Remember that those files will be re-generated every time we deploy the custom portal. The rest of the files come from the ASP.NET MVC template, we’ll eventually add those to the support files section of the portal so that we can re-deploy everything at once.</p>
<p>Next came the tricky part <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  I added the following modules to web.config (under system.webServer/modules – remember, we use the IIS7 section, not the IIS6 one):</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">=&quot;ProcessModule&quot;</span> <span class="attr">type</span><span class="kwrd">=&quot;Sage.Platform.Application.UI.Web.AppManagerModule, Sage.Platform.Application.UI.Web&quot;</span> <span class="kwrd">/&gt;</span>
<span class="rem">&lt;!-- NHibernate Session scope --&gt;</span>
<span class="kwrd">&lt;</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">=&quot;SessionScopeModule&quot;</span> <span class="attr">type</span><span class="kwrd">=&quot;Sage.Platform.Framework.SessionScopeWebModule, Sage.Platform&quot;</span> <span class="kwrd">/&gt;</span>

<span class="kwrd">&lt;</span><span class="html">add</span> <span class="attr">name</span><span class="kwrd">=&quot;SlxAuthenticationResetModule&quot;</span> <span class="attr">type</span><span class="kwrd">=&quot;MvcApplication1.Utility.SlxAuthenticationResetModule, MvcApplication1&quot;</span><span class="kwrd">/&gt;</span></pre>
<p>The ProcessModule is probably the most important – it initializes the good old ApplicationContext.Current object.&#160; SessionScopeModule works on maintaining an active NHibernate section for each web request, it is important for lazy-loading requests to work correctly (i.e. when you try to access myAccount.Contacts). The last one is not essential, it is a simple module I added to prevent drops when the session is lost (I am sure you have seen the “Authorization Token cannot be null” error a number of times – this module deals with it, does not work on the “regular” web client though because there are a few other things going on there).&#160; While I was in there I also set up the authentication, we use a basic Forms authentication here:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">authentication</span> <span class="attr">mode</span><span class="kwrd">=&quot;Forms&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">forms</span> <span class="attr">loginUrl</span><span class="kwrd">=&quot;~/Home/LogOn&quot;</span> <span class="attr">timeout</span><span class="kwrd">=&quot;2880&quot;</span> <span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">authentication</span><span class="kwrd">&gt;</span></pre>
<p>I went in global.asax and changed the default route to Home/Search as well (which does not exist yet):</p>
<pre class="csharpcode">routes.MapRoute(
  <span class="str">&quot;Default&quot;</span>,                                              <span class="rem">// Route name</span>
  <span class="str">&quot;{controller}/{action}/{id}&quot;</span>,                           <span class="rem">// URL with parameters</span>
  <span class="kwrd">new</span> { controller = <span class="str">&quot;Home&quot;</span>, action = <span class="str">&quot;Search&quot;</span>, id = <span class="str">&quot;&quot;</span> }  <span class="rem">// Parameter defaults</span>
);</pre>
<p>Now HomeController.cs is where most of the fun happens, starting with the LogOn function.&#160; Here we must make sure that we validate the user and also save his credentials into the “token” that is going to be used to build connection strings.&#160; Fortunately this is quite simple:</p>
<pre class="csharpcode"><span class="kwrd">public</span> ActionResult LogOn()
{
    <span class="kwrd">return</span> View();
}

[AcceptVerbs(HttpVerbs.Post)]
<span class="kwrd">public</span> ActionResult LogOn(String username, String password, <span class="kwrd">string</span> returnUrl)
{
    SLXWebAuthenticationProvider auth = (SLXWebAuthenticationProvider)ApplicationContext.Current.Services.Get&lt;IAuthenticationProvider&gt;();
    <span class="kwrd">if</span> (auth == <span class="kwrd">null</span>)
    {
        <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException(<span class="str">&quot;Can't access Authentication Provider&quot;</span>);
    }
    auth.AuthenticateWithContext(username, password);
    <span class="kwrd">try</span>
    {
        <span class="kwrd">using</span> (TransactionScope tx = <span class="kwrd">new</span> TransactionScope())
        {
            IUser user = EntityFactory.GetRepository&lt;IUser&gt;().FindByProperty(<span class="str">&quot;UserName&quot;</span>, username).First();
            <span class="rem">// now this will only succeed if the connection was successful</span>
            FormsAuthentication.SetAuthCookie(user.Id.ToString(), <span class="kwrd">true</span>);
        }
    }
    <span class="kwrd">catch</span> (Exception)
    {
        auth.Invalidate();
        ViewData.ModelState.AddModelError(<span class="str">&quot;message&quot;</span>, <span class="str">&quot;Authentication Failed&quot;</span>);
        <span class="kwrd">return</span> View();
    }
    <span class="kwrd">if</span> (!String.IsNullOrEmpty(returnUrl))
    {
        <span class="kwrd">return</span> Redirect(returnUrl);
    }
    <span class="kwrd">else</span>
    {
        <span class="kwrd">return</span> RedirectToAction(<span class="str">&quot;Search&quot;</span>, <span class="str">&quot;Home&quot;</span>);
    }
}</pre>
<p>The AcceptVerbs attribute on the second overload ensures that this is the function called when the form is posted, while the parameter-less overload is called on initial requests.&#160; The “return View()” means return the view with the same name.&#160; As for the view I just copied the one from Account/LogOn.aspx to the Home folder.&#160; Note that the “Remember Me” box actually keeps you logged in here, not like the Remember Me box of the Saleslogix client.&#160; It’s handy for a cell phone so you don’t have to retype your password every time.&#160; That part only works with the “SlxAuthenticationResetModule” I mentioned above though.</p>
<p>The “Search” action (in HomeController.cs) is extremely simple but it does illustrate the access to the EntityFactory… the “Authorize” attribute ensures that they get to log in first.&#160; We just get a (short) list of matching contact, stick it in the session, and send the control to the Contact/List action.&#160; If there is only one match we redirect to the detail screen.&#160; I only pass the Id, to make it simpler, but since it will be cached by NHibernate there is no performance hit.</p>
<pre class="csharpcode">[Authorize]
<span class="kwrd">public</span> ActionResult Search()
{
    <span class="kwrd">return</span> View();
}

[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
<span class="kwrd">public</span> ActionResult Search(String search)
{
    Session[<span class="str">&quot;List&quot;</span>] = <span class="kwrd">null</span>;
    IList&lt;IContact&gt; contacts = FindContact(search);
    <span class="kwrd">if</span> (contacts.Count == 1)
    {
        <span class="kwrd">return</span> RedirectToAction(<span class="str">&quot;Details&quot;</span>, <span class="str">&quot;Contact&quot;</span>, <span class="kwrd">new</span> { id = contacts.First().Id });
    }
    <span class="kwrd">else</span> <span class="kwrd">if</span> (contacts.Count &gt; 1)
    {
        Session[<span class="str">&quot;List&quot;</span>] = contacts;
        <span class="kwrd">return</span> RedirectToAction(<span class="str">&quot;List&quot;</span>, <span class="str">&quot;Contact&quot;</span>);
    }
    <span class="kwrd">else</span>
    {
        ViewData[<span class="str">&quot;Message&quot;</span>] = <span class="str">&quot;No match!&quot;</span>;
        <span class="kwrd">return</span> View();
    }
}

<span class="kwrd">private</span> IList&lt;IContact&gt; FindContact(<span class="kwrd">string</span> search)
{
    var repo = EntityFactory.GetRepository&lt;IContact&gt;();
    <span class="kwrd">using</span> (var session = <span class="kwrd">new</span> SessionScopeWrapper(<span class="kwrd">false</span>))
    {
        var query = session.CreateQuery(<span class="str">&quot;from Sage.SalesLogix.Entities.Contact where LastName like ?&quot;</span>)
            .SetString(0, search + <span class="str">&quot;%&quot;</span>)
            .SetMaxResults(15);

        <span class="kwrd">return</span> query.List&lt;IContact&gt;();
    }
}</pre>
<p>Add a view under Home/Search.aspx to make this complete.&#160; This is the code I used for it:</p>
<pre class="csharpcode">    <span class="asp">&lt;%</span> <span class="kwrd">using</span> (Html.BeginForm(<span class="str">&quot;Search&quot;</span>, <span class="str">&quot;Home&quot;</span>)){ <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        Search: <span class="asp">&lt;%</span>= Html.TextBox(<span class="str">&quot;search&quot;</span>) <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="asp">&lt;%</span> <span class="kwrd">if</span> (ViewData[<span class="str">&quot;Message&quot;</span>] != <span class="kwrd">null</span>){ <span class="asp">%&gt;</span>
       <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        <span class="asp">&lt;%</span>= ViewData[<span class="str">&quot;Message&quot;</span>] <span class="asp">%&gt;</span>
       <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="asp">&lt;%</span> } <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">input</span> <span class="attr">type</span><span class="kwrd">=&quot;submit&quot;</span> <span class="attr">value</span><span class="kwrd">=&quot;Search&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="asp">&lt;%</span> }  <span class="asp">%&gt;</span></pre>
<p>ContactController.cs is even simpler… for the List, we just pick it up from the session, and display it.&#160; For the Details, we retrieve the contact by id.&#160; For the sake of completeness here is the code:</p>
<pre class="csharpcode">[Authorize]
<span class="kwrd">public</span> ActionResult List()
{
    IList&lt;IContact&gt; list = Session[<span class="str">&quot;List&quot;</span>] <span class="kwrd">as</span> IList&lt;IContact&gt;;
    <span class="kwrd">if</span> (list == <span class="kwrd">null</span>)
        <span class="kwrd">return</span> RedirectToAction(<span class="str">&quot;Search&quot;</span>, <span class="str">&quot;Home&quot;</span>);
    <span class="kwrd">return</span> View(list);
}

[Authorize]
<span class="kwrd">public</span> ActionResult Details(String id)
{
    IContact contact = EntityFactory.GetById&lt;IContact&gt;(id);
    <span class="kwrd">if</span> (contact == <span class="kwrd">null</span>)
        <span class="kwrd">return</span> RedirectToAction(<span class="str">&quot;List&quot;</span>);
    <span class="kwrd">return</span> View(contact);
}</pre>
<p>Now one very neat thing is the way the data binding works.&#160; Try adding a view under contact and select “strongly typed view”.&#160; Under the View Data Class enter “Sage.Entity.Interfaces.IContact” (you have to type it in as the dropdown will not list interfaces).&#160; Then in the view you can use things like “Model.Mobile” – and the intellisense will show the auto-complete suggestion for you!&#160; This is my details view… very basic of course:</p>
<pre class="csharpcode"> <span class="kwrd">&lt;</span><span class="html">h2</span><span class="kwrd">&gt;</span><span class="asp">&lt;%</span>= Html.Encode(Model.FullName) <span class="asp">%&gt;</span><span class="kwrd">&lt;/</span><span class="html">h2</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">fieldset</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">legend</span><span class="kwrd">&gt;</span>Fields<span class="kwrd">&lt;/</span><span class="html">legend</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        Work Phone:
        <span class="asp">&lt;%</span>= Html.Encode(Model.WorkPhone) <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        Mobile:
        <span class="asp">&lt;%</span>= Html.Encode(Model.Mobile) <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        Company:
        <span class="asp">&lt;%</span>= Html.Encode(Model.AccountName) <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        Email:
        <span class="asp">&lt;%</span>= Html.Encode(Model.Email) <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">fieldset</span><span class="kwrd">&gt;</span>
<span class="asp">&lt;%</span> <span class="kwrd">if</span> (Session[<span class="str">&quot;List&quot;</span>] != <span class="kwrd">null</span>){ <span class="asp">%&gt;</span>
<span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="asp">&lt;%</span>=Html.ActionLink(<span class="str">&quot;Back to List&quot;</span>, <span class="str">&quot;List&quot;</span>)<span class="asp">%&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
<span class="asp">&lt;%</span> } <span class="asp">%&gt;</span>
<span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
    <span class="asp">&lt;%</span>=Html.ActionLink(<span class="str">&quot;Back to Search&quot;</span>, <span class="str">&quot;Search&quot;</span>, <span class="str">&quot;Home&quot;</span>) <span class="asp">%&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span></pre>
<p>And my list view (in List.aspx) – here for the type I entered “IEnumerable&lt;Sage.Entity.Interfaces.IContact&gt;”.&#160; This can be entered after the fact under the “Page” directive also.&#160; Here is the full listing:</p>
<pre class="csharpcode"><span class="asp">&lt;%@ Page Title=&quot;&quot; Language=&quot;C#&quot; MasterPageFile=&quot;~/Views/Shared/Site.Master&quot;
    Inherits=&quot;System.Web.Mvc.ViewPage&lt;IEnumerable&lt;Sage.Entity.Interfaces.IContact&gt;&gt;&quot;
    ContentType=&quot;text/html&quot; %&gt;</span>

<span class="kwrd">&lt;</span><span class="html">asp:Content</span> <span class="attr">ID</span><span class="kwrd">=&quot;Content1&quot;</span> <span class="attr">ContentPlaceHolderID</span><span class="kwrd">=&quot;TitleContent&quot;</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span><span class="kwrd">&gt;</span>
    List
<span class="kwrd">&lt;/</span><span class="html">asp:Content</span><span class="kwrd">&gt;</span>

<span class="kwrd">&lt;</span><span class="html">asp:Content</span> <span class="attr">ID</span><span class="kwrd">=&quot;Content2&quot;</span> <span class="attr">ContentPlaceHolderID</span><span class="kwrd">=&quot;MainContent&quot;</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;</span><span class="html">table</span> <span class="attr">border</span><span class="kwrd">=&quot;1&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">tr</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">th</span><span class="kwrd">&gt;</span>Name<span class="kwrd">&lt;/</span><span class="html">th</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">th</span><span class="kwrd">&gt;</span>Company<span class="kwrd">&lt;/</span><span class="html">th</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">tr</span><span class="kwrd">&gt;</span>
    <span class="asp">&lt;%</span> <span class="kwrd">foreach</span> (var contact <span class="kwrd">in</span> Model){ <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">tr</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;</span><span class="asp">&lt;%</span>= Html.ActionLink(contact.FullName, <span class="str">&quot;Details&quot;</span>, <span class="kwrd">new</span>{ id = contact.Id.ToString() }) <span class="asp">%&gt;</span><span class="kwrd">&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">td</span><span class="kwrd">&gt;</span><span class="asp">&lt;%</span>= contact.AccountName <span class="asp">%&gt;</span><span class="kwrd">&lt;/</span><span class="html">td</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">tr</span><span class="kwrd">&gt;</span>
    <span class="asp">&lt;%</span> } <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">table</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>
        <span class="asp">&lt;%</span>= Html.ActionLink(<span class="str">&quot;Back to Search&quot;</span>, <span class="str">&quot;Search&quot;</span>, <span class="str">&quot;Home&quot;</span>) <span class="asp">%&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">asp:Content</span><span class="kwrd">&gt;</span></pre>
<p>By the way, little detail here, don’t forget to add ContentType=&quot;text/html&quot; otherwise some phones will return an “File format unknown” error (my Nokia did).&#160; All done!&#160; This is what it looks like on the phone:</p>
<p><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://blog.chivinou.net/wp-content/uploads/2009/07/image1.png" width="280" height="395" /> </p>
<p>Hey, nobody said it was going to be a work of art! </p>
<p>All in all an interesting little experiment.&#160; I will probably come back and use that info in the near future as we have to do a small portal-type site outside of the web client.&#160; One neat thing by the way is that this can also be used even if the customer is still on the LAN client.&#160; If interested feel free to <a href="http://blog.nicocrm.com/wp-content/uploads/2009/07/2009-07-04%20SaleslogixMvcApplication.zip">download the code</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/212/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/212/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/212/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/212/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/212/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/212/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/212/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/212/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/212/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/212/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/212/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/212/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/212/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/212/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=212&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/07/04/a-bit-of-exploration-with-saleslogix-custom-portals-and-aspnet-mvc/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>

		<media:content url="http://blog.chivinou.net/wp-content/uploads/2009/07/image.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://blog.chivinou.net/wp-content/uploads/2009/07/image1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>Global Search / Replace (with Powershell)</title>
		<link>http://chivinou.wordpress.com/2009/06/17/global-search-replace-with-powershell/</link>
		<comments>http://chivinou.wordpress.com/2009/06/17/global-search-replace-with-powershell/#comments</comments>
		<pubDate>Wed, 17 Jun 2009 20:07:04 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/?p=203</guid>
		<description><![CDATA[Had to rename an assembly and was faced with the daunting task of updating a few dozen business rules&#8230; I knew I had to do it on the backend as having to click my way through that in App Architect would take a day or more. This is slow but does the trick: ls -recurse [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=203&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Had to rename an assembly and was faced with the daunting task of updating a few dozen business rules&#8230; I knew I had to do it on the backend as having to click my way through that in App Architect would take a day or more.  This is slow but does the trick:</p>
<pre>
ls -recurse -filter *.xml |% { $text = (get-content $_.FullName) -replace "SourceAssemblyName", "NewAssemblyName"; $text | out-file -encoding utf8 $_.FullName }
</pre>
<p>Kinda like it better than the old find / grep / sed combo.</p>
<p>There is an alternative that checks if the text was actually modified (otherwise it can append newline to files which sometimes messes things up):</p>
<pre>
ls -recurse -filter *.xml |% {
$oldtext = [string]::join([environment]::newline, (get-content $_.FullName));
$text = $oldtext -replace "SourceAssemblyName", "NewAssemblyName";
if($text -ne $oldtext) { $text | out-file -encoding utf8 $_.FullName }
}
</pre>
<p>Finally I stuck this in my powershell profile (do notepad $profile to bring it up).  This lets me use the &#8220;ReplText&#8221; command without having to retype the whole thing out.  It takes the list of files from the input pipeline to be flexible:</p>
<pre>
# Replace text in every file listed on the input.
# $input: list of file objects (from pipeline)
# $pattern: source pattern (regular expression)
# $replacement: replacement (can have backreferences)
#
# Usage: dir -recur -filter *.xml | ReplText SourcePattern DestPattern
function ReplText($pattern, $replacement) {
  process {
    $oldtext = [string]::join([environment]::newline, (get-content $_.FullName))
    $newtext = $oldtext -replace $pattern, $replacement
    if($newtext -ne $oldtext) { $newtext | out-file -encoding utf8 $_.FullName }
  }
}
</pre>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/203/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/203/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/203/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/203/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/203/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/203/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/203/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/203/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/203/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/203/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/203/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/203/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/203/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/203/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=203&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/06/17/global-search-replace-with-powershell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>
	</item>
		<item>
		<title>Things to try with Windows 7 / Win 2008 R2</title>
		<link>http://chivinou.wordpress.com/2009/06/05/things-to-try-with-windows-7-win-2008-r2/</link>
		<comments>http://chivinou.wordpress.com/2009/06/05/things-to-try-with-windows-7-win-2008-r2/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 16:26:26 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/?p=194</guid>
		<description><![CDATA[I installed Windows 7 RC1 last week-end and so far it has much exceeded my expectations. While Vista had a &#8220;oh shiny&#8230; but nothing works?&#8221; feel to it, Windows 7 seems to be finally fulfilling all those promises (or some of them, anyway!). Lots of neat stuff coming out from MS lately, hope they can [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=194&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I installed Windows 7 RC1 last week-end and so far it has much exceeded my expectations.  While Vista had a &#8220;oh shiny&#8230; but nothing works?&#8221; feel to it, Windows 7 seems to be finally fulfilling all those promises (or some of them, anyway!).  Lots of neat stuff coming out from MS lately, hope they can keep that up.  I am almost considering replacing my Linux box with a Windows server (gasp) to get the document libraries to work correctly (Samba is OK for basic use but lacks the more advanced search features).</p>
<p>Beside a much polished UI and a few very nice usability improvements, here are a few things that I find interesting or will need to try on the more technical side:</p>
<ul>
<li>Updated Virtual PC, now with USB support</li>
<li>Managed Services Account will allow password-less service accounts</li>
<li>VHD boot</li>
<li>Powershell 2.0</li>
<li>Search connectors</li>
<li>Multi touch?  Maybe.</li>
</ul>
<p>I still have not loaded it on my work machine, mind you &#8211; am not sure Saleslogix will like it too much.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/194/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/194/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/194/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/194/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/194/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/194/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/194/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/194/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/194/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/194/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/194/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/194/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/194/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/194/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=194&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/06/05/things-to-try-with-windows-7-win-2008-r2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>
	</item>
		<item>
		<title>Easy Business Rules with Extension Methods</title>
		<link>http://chivinou.wordpress.com/2009/06/01/easy-business-rules-with-extension-methods/</link>
		<comments>http://chivinou.wordpress.com/2009/06/01/easy-business-rules-with-extension-methods/#comments</comments>
		<pubDate>Mon, 01 Jun 2009 21:47:54 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/?p=185</guid>
		<description><![CDATA[I just realized that I could use C# extension methods to avoid the whole &#8220;open architect, expand the little tree to find my entity, add the business rule definition, select the assembly, select the method from the assembly, save, copy comment from the C# project, save again, build, deploy, pray that the deployment actually worked&#8221; [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=185&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I just realized that I could use <a href="http://msdn.microsoft.com/en-us/library/bb383977.aspx">C# extension methods</a> to avoid the whole &#8220;open architect, expand the little tree to find my entity, add the business rule definition, select the assembly, select the method from the assembly, save, copy comment from the C# project, save again, build, deploy, pray that the deployment actually worked&#8221; process.</p>
<p>I can declare my business rule like this:</p>
<pre class="csharpcode">
public static void CalculateProcessTask(this ITicketActivity ticketActivity)
</pre>
<p>save as TicketRules.dll, and add this to the code to use it:</p>
<pre class="csharpcode">
using TicketRules;
</pre>
<p>Another huge benefit is I can now use F12 to navigate to the definition.  One less reason to open the Application Architect for &#8211; YAY!  Sadly there is no way to do something like that for events, or for code snippet properties.  But if you add the namespace used for the extension rules to the web.config/system.web/pages/namespaces element (see <a href="http://www.west-wind.com/WebLog/posts/2287.aspx">http://www.west-wind.com/WebLog/posts/2287.aspx</a> for an example) you can use it in snippet actions.</p>
<p>It also opens the door to something that is a bit scary&#8230;  it looks like those rules could be defined in App_Code (the folder that contains dynamically compiled code for ASP.NET).  This would let us edit them without having to recompile&#8230; or restart the IIS app&#8230; mucho más rápido!  But this prevents the code from being unit-tested, and makes it harder to manage, so I am not very likely to use it (business rules typically don&#8217;t need to be adjusted very often anyway, once they are unit-tested)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/185/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/185/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/185/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=185&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/06/01/easy-business-rules-with-extension-methods/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>
	</item>
		<item>
		<title>SlxGridHelper &#8211; Make the SlxDataGrid more convenient in our custom smart parts</title>
		<link>http://chivinou.wordpress.com/2009/05/22/slxgridhelper-make-the-slxdatagrid-more-convenient-in-our-custom-smart-parts/</link>
		<comments>http://chivinou.wordpress.com/2009/05/22/slxgridhelper-make-the-slxdatagrid-more-convenient-in-our-custom-smart-parts/#comments</comments>
		<pubDate>Sat, 23 May 2009 04:13:31 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/2009/05/22/slxgridhelper-make-the-slxdatagrid-more-convenient-in-our-custom-smart-parts/</guid>
		<description><![CDATA[There are a few things that I like to set on all my datagrids (double-click edit, single-click select, delete/add button). In an earlier post I had described how to tweak the quickform template so that every quickform containing a grid would receive these changes.&#160; However there were a number of drawbacks to that approach, starting [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=180&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There are a few things that I like to set on all my datagrids (double-click edit, single-click select, delete/add button). In an <a href="http://blog.chivinou.net/2008/05/19/customize-the-quickform-datagrid-toolbar-buttons-and-double-click-to-edit/">earlier post</a> I had described how to tweak the quickform template so that every quickform containing a grid would receive these changes.&#160; However there were a number of drawbacks to that approach, starting with the fact that it was rather tedious to implement and affected “stock” grids negatively.&#160; I also found out that the limit of quickforms were very easy to hit and therefore ended up doing custom smartparts in most cases.&#160; Therefore I decided to group this functionality in an external control that would be included on the custom smart part and modify the grid’s behavior using its public API.</p>
<p>The general principle is the same as the one used in the previous approach, but with the increased flexibility I wanted to implement the following features:</p>
<ul>
<li>Ability to specify Add/Delete buttons, using control ids pointing to other objects in the form</li>
<li>Ability to have a grid’s title bar generated, optionally including Add/Delete buttons (useful when there are several grids on a form, or a grid and some other controls)</li>
<li>Optionally specify the databinding and parent/child relationship, so as to avoid having to put the datasource code on the smartpart itself (the code to bind a Saleslogix datagrid is rather noisy and not too pretty to look at)</li>
</ul>
<p>The code for a typical grid… with an automatically generated toolbar:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">SSS:SlxGridHelper</span> <span class="attr">ID</span><span class="kwrd">=&quot;grdSalesEntitiesHelper&quot;</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">GridId</span><span class="kwrd">=&quot;grdSalesEntities&quot;</span>
    <span class="attr">GridTitle</span><span class="kwrd">=&quot;Sales Entities&quot;</span> <span class="attr">ShowAddButton</span><span class="kwrd">=&quot;true&quot;</span> <span class="attr">ShowDeleteButton</span><span class="kwrd">=&quot;true&quot;</span> <span class="attr">AutoBind</span><span class="kwrd">=&quot;true&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">DialogSpecs</span> <span class="attr">ActiveSmartPartID</span><span class="kwrd">=&quot;SEOppSalesCreditForm&quot;</span> <span class="attr">CenterDialog</span><span class="kwrd">=&quot;true&quot;</span>
     <span class="attr">DialogHeight</span><span class="kwrd">=&quot;300&quot;</span> <span class="attr">DialogWidth</span><span class="kwrd">=&quot;600&quot;</span> <span class="attr">Title</span><span class="kwrd">=&quot;Edit Sales Entity&quot;</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">MyChildInsertInfo</span> <span class="attr">ChildEntityTypeName</span><span class="kwrd">=&quot;Sage.Entity.Interfaces.ISEOppSalesCredit, Sage.Entity.Interfaces&quot;</span>
             <span class="attr">ParentEntityTypeName</span><span class="kwrd">=&quot;Sage.Entity.Interfaces.IOpportunity, Sage.Entity.Interfaces&quot;</span>
             <span class="attr">ParentReferencePropertyName</span><span class="kwrd">=&quot;Opportunity&quot;</span>
             <span class="attr">ParentsCollectionPropertyName</span><span class="kwrd">=&quot;SEOppSalesCredits&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">DialogSpecs</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">SSS:SlxGridHelper</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">SalesLogix:SlxGridView</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">ID</span><span class="kwrd">=&quot;grdSalesEntities&quot;</span> <span class="attr">GridLines</span><span class="kwrd">=&quot;None&quot;</span>
<span class="attr">AutoGenerateColumns</span><span class="kwrd">=&quot;false&quot;</span> <span class="attr">CellPadding</span><span class="kwrd">=&quot;4&quot;</span> <span class="attr">CssClass</span><span class="kwrd">=&quot;datagrid&quot;</span> <span class="attr">PagerStyle-CssClass</span><span class="kwrd">=&quot;gridPager&quot;</span>
<span class="attr">AlternatingRowStyle-CssClass</span><span class="kwrd">=&quot;rowdk&quot;</span> <span class="attr">RowStyle-CssClass</span><span class="kwrd">=&quot;rowlt&quot;</span> <span class="attr">SelectedRowStyle-CssClass</span><span class="kwrd">=&quot;rowSelected&quot;</span> <span class="attr">ShowEmptyTable</span><span class="kwrd">=&quot;true&quot;</span> <span class="attr">EnableViewState</span><span class="kwrd">=&quot;false&quot;</span>
 <span class="attr">ExpandableRows</span><span class="kwrd">=&quot;True&quot;</span> <span class="attr">ResizableColumns</span><span class="kwrd">=&quot;True&quot;</span>  <span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">Columns</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">asp:ButtonField</span> <span class="attr">CommandName</span><span class="kwrd">=&quot;Edit&quot;</span> <span class="attr">DataTextField</span><span class="kwrd">=&quot;SalesmanName&quot;</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;Salesman Name&quot;</span> <span class="kwrd">/&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">asp:BoundField</span> <span class="attr">DataField</span><span class="kwrd">=&quot;Adder&quot;</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;Adder&quot;</span><span class="kwrd">/&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">asp:TemplateField</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;Percentage&quot;</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:Label</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">Text</span><span class="kwrd">='&lt;%# Bind(&quot;Percent&quot;, &quot;{0:##%}&quot;) %&gt;'</span> <span class="attr">ID</span><span class="kwrd">=&quot;lblPercent&quot;</span> <span class="kwrd">/&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">ItemTemplate</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;/</span><span class="html">asp:TemplateField</span><span class="kwrd">&gt;</span>
  <span class="kwrd">&lt;</span><span class="html">asp:BoundField</span> <span class="attr">DataField</span><span class="kwrd">=&quot;Title&quot;</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;Title&quot;</span> <span class="kwrd">/&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">Columns</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">SalesLogix:SlxGridView</span><span class="kwrd">&gt;</span></pre>
<p>And for a grid that is included on a tab (using the built-in toolbar – notice the “DeleteButtonId” and “AddButtonId”):</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">SSS:SlxGridHelper</span> <span class="attr">ID</span><span class="kwrd">=&quot;grdHelper&quot;</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">GridId</span><span class="kwrd">=&quot;grdLDC&quot;</span>
    <span class="attr">AddButtonId</span><span class="kwrd">=&quot;btnAdd&quot;</span> <span class="attr">DeleteButtonId</span><span class="kwrd">=&quot;btnDelete&quot;</span>
    <span class="attr">GridTitle</span><span class="kwrd">=&quot;&quot;</span> <span class="attr">ShowAddButton</span><span class="kwrd">=&quot;false&quot;</span> <span class="attr">ShowDeleteButton</span><span class="kwrd">=&quot;false&quot;</span> <span class="attr">AutoBind</span><span class="kwrd">=&quot;true&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">DialogSpecs</span> <span class="attr">ActiveSmartPartID</span><span class="kwrd">=&quot;SEOppLdcForm&quot;</span> <span class="attr">CenterDialog</span><span class="kwrd">=&quot;true&quot;</span>
     <span class="attr">DialogHeight</span><span class="kwrd">=&quot;300&quot;</span> <span class="attr">DialogWidth</span><span class="kwrd">=&quot;600&quot;</span> <span class="attr">Title</span><span class="kwrd">=&quot;Edit LDC Account&quot;</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">MyChildInsertInfo</span> <span class="attr">ChildEntityTypeName</span><span class="kwrd">=&quot;Sage.Entity.Interfaces.ISEOppLDCAccount, Sage.Entity.Interfaces&quot;</span>
             <span class="attr">ParentEntityTypeName</span><span class="kwrd">=&quot;Sage.Entity.Interfaces.IOpportunity, Sage.Entity.Interfaces&quot;</span>
             <span class="attr">ParentReferencePropertyName</span><span class="kwrd">=&quot;Opportunity&quot;</span>
             <span class="attr">ParentsCollectionPropertyName</span><span class="kwrd">=&quot;SEOppLDCAccounts&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">DialogSpecs</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">SSS:SlxGridHelper</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">SalesLogix:SlxGridView</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">ID</span><span class="kwrd">=&quot;grdLDC&quot;</span> <span class="attr">GridLines</span><span class="kwrd">=&quot;None&quot;</span> <span class="attr">AllowSorting</span><span class="kwrd">=&quot;true&quot;</span> <span class="attr">AllowPaging</span><span class="kwrd">=&quot;true&quot;</span>
<span class="attr">AutoGenerateColumns</span><span class="kwrd">=&quot;false&quot;</span> <span class="attr">CellPadding</span><span class="kwrd">=&quot;4&quot;</span> <span class="attr">CssClass</span><span class="kwrd">=&quot;datagrid&quot;</span> <span class="attr">PagerStyle-CssClass</span><span class="kwrd">=&quot;gridPager&quot;</span>
<span class="attr">AlternatingRowStyle-CssClass</span><span class="kwrd">=&quot;rowdk&quot;</span> <span class="attr">RowStyle-CssClass</span><span class="kwrd">=&quot;rowlt&quot;</span> <span class="attr">SelectedRowStyle-CssClass</span><span class="kwrd">=&quot;rowSelected&quot;</span> <span class="attr">ShowEmptyTable</span><span class="kwrd">=&quot;true&quot;</span> <span class="attr">EnableViewState</span><span class="kwrd">=&quot;false&quot;</span>
 <span class="attr">ExpandableRows</span><span class="kwrd">=&quot;True&quot;</span> <span class="attr">ResizableColumns</span><span class="kwrd">=&quot;True&quot;</span>  <span class="kwrd">&gt;</span>
 <span class="kwrd">&lt;</span><span class="html">Columns</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:ButtonField</span> <span class="attr">CommandName</span><span class="kwrd">=&quot;Edit&quot;</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;LDC Name&quot;</span> <span class="attr">DataTextField</span><span class="kwrd">=&quot;ProspectName&quot;</span> <span class="attr">ButtonType</span><span class="kwrd">=&quot;Link&quot;</span> <span class="attr">SortExpression</span><span class="kwrd">=&quot;ProspectName&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:BoundField</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;City&quot;</span> <span class="attr">DataField</span><span class="kwrd">=&quot;City&quot;</span> <span class="attr">SortExpression</span><span class="kwrd">=&quot;City&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:BoundField</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;State&quot;</span> <span class="attr">DataField</span><span class="kwrd">=&quot;State&quot;</span> <span class="attr">SortExpression</span><span class="kwrd">=&quot;State&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:BoundField</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;Zip&quot;</span> <span class="attr">DataField</span><span class="kwrd">=&quot;Postalcode&quot;</span> <span class="attr">SortExpression</span><span class="kwrd">=&quot;Postalcode&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:BoundField</span> <span class="attr">HeaderText</span><span class="kwrd">=&quot;Zone&quot;</span> <span class="attr">DataField</span><span class="kwrd">=&quot;Zone&quot;</span> <span class="attr">SortExpression</span><span class="kwrd">=&quot;Zone&quot;</span> <span class="kwrd">/&gt;</span>
 <span class="kwrd">&lt;/</span><span class="html">Columns</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">SalesLogix:SlxGridView</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">SalesLogix:SmartPartToolsContainer</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">ID</span><span class="kwrd">=&quot;toolbar&quot;</span> <span class="attr">ToolbarLocation</span><span class="kwrd">=&quot;right&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:ImageButton</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">ID</span><span class="kwrd">=&quot;btnAdd&quot;</span> <span class="attr">ImageUrl</span><span class="kwrd">=&quot;ImageResource.axd?scope=global&amp;type=Global_Images&amp;key=plus_16x16&quot;</span>
        <span class="attr">AlternateText</span><span class="kwrd">=&quot;Add LDC Account Number&quot;</span> <span class="attr">ToolTip</span><span class="kwrd">=&quot;Add LDC Account Number&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:ImageButton</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">ID</span><span class="kwrd">=&quot;btnImport&quot;</span> <span class="attr">ImageUrl</span><span class="kwrd">=&quot;ImageResource.axd?scope=global&amp;type=Global_Images&amp;key=Import_History_16x16&quot;</span>
        <span class="attr">AlternateText</span><span class="kwrd">=&quot;Import from Spreadsheet&quot;</span> <span class="attr">ToolTip</span><span class="kwrd">=&quot;Import from Spreadsheet&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">asp:ImageButton</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">ID</span><span class="kwrd">=&quot;btnDelete&quot;</span> <span class="attr">ImageUrl</span><span class="kwrd">=&quot;ImageResource.axd?scope=global&amp;type=Global_Images&amp;key=Delete_16x16&quot;</span>
        <span class="attr">AlternateText</span><span class="kwrd">=&quot;Remove LDC Account Number&quot;</span> <span class="attr">ToolTip</span><span class="kwrd">=&quot;Remove LDC Account Number&quot;</span>
        <span class="attr">OnClientClick</span><span class="kwrd">=&quot;return confirm('Are you sure you wish to delete this LDC account number?');&quot;</span> <span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">SalesLogix:SmartPartToolsContainer</span><span class="kwrd">&gt;</span></pre>
<p>&#160;</p>
<p>There is no associated code-behind in either case (of course, if I wanted to customize the databinding, I would need to do that in the code behind).</p>
<p>The result looks like this (this is a grid with a “generated” toolbar):</p>
<p><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="AddlDetails" border="0" alt="AddlDetails" src="http://blog.chivinou.net/wp-content/uploads/2009/05/addldetails1.png" width="479" height="113" /> </p>
<p>The code is simple – similar to what I used before in the quickform version.&#160; I saved a copy <a href="http://blog.chivinou.net/media/SlxGridHelper.cs">here</a> if interested feel free to rummage through it and keep what you want.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/180/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/180/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/180/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=180&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/05/22/slxgridhelper-make-the-slxdatagrid-more-convenient-in-our-custom-smart-parts/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>

		<media:content url="http://blog.chivinou.net/wp-content/uploads/2009/05/addldetails1.png" medium="image">
			<media:title type="html">AddlDetails</media:title>
		</media:content>
	</item>
		<item>
		<title>Tips &amp; Tricks of the Web Client</title>
		<link>http://chivinou.wordpress.com/2009/05/15/tips-tricks-of-the-web-client/</link>
		<comments>http://chivinou.wordpress.com/2009/05/15/tips-tricks-of-the-web-client/#comments</comments>
		<pubDate>Sat, 16 May 2009 05:24:35 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Saleslogix]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/2009/05/15/tips-tricks-of-the-web-client/</guid>
		<description><![CDATA[This is a collection of random tricks, pitfalls etc that I am encountering on the current web client project. I will update within the next few weeks with other tidbits I find out. General Tips Do not use quickforms.&#160; Ever.&#160; Seriously.&#160; For real.&#160; Well, there are exceptions: A form with really trivial layout, no dynamically [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=164&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This is a collection of random tricks, pitfalls etc that I am encountering on the current web client project.  I will update within the next few weeks with other tidbits I find out.</p>
<h4>General Tips</h4>
<ol>
<li>Do not use quickforms.&#160; Ever.&#160; Seriously.&#160; For real.&#160; Well, there are exceptions:
<ul>
<li>A form with really trivial layout, no dynamically set controls, and no validation logic </li>
<li>When trying to figure out the basic syntax to declare a Saleslogix control </li>
<li>When making a trivial change to an existing form</li>
<li><strike>If you have limited knowledge of HTML and really, really don’t want to learn</strike>: this it is NOT an exception because you will need to know HTML in order to troubleshoot the quickform! </li>
</ul>
</li>
<li>In case of an error, start with the event log.&#160; Especially for lookups. </li>
<li>Use CSS to your advantage when laying out the forms!&#160; The code in quickform smartparts can afford to be sloppy and repetitive because it’s automatically generated, but we can’t!&#160; </li>
<li>In order to add a linked entity, use code like:
<pre class="csharpcode">ISEOppUtility oppUtility = EntityFactory.Create&lt;ISEOppUtility&gt;();
<span class="rem">// link to the parent entity ...</span>
oppUtility.Opportunity = parentEntity;
<span class="rem">// ... and add to the parent's collection.  The link is bidirectional.</span>
parentEntity.SEOppUtilities.Add(oppUtility);
oppUtility.Save();
<span class="rem">// save the parent... in theory this should cascade and </span>
<span class="rem">// save the child entity... but that does not always work</span>
parentEntity.Save();
<span class="rem">// ensure that all views get refreshed - this is not always necessary</span>
PageWorkItem.Services.Get&lt;IPanelRefreshService&gt;().RefreshAll();</pre>
</li>
<li>Do not try to rename anything in the App Architect &#8211; it will mix stuff up.  It is quicker and safer to do it on the backend XML instead.</li>
<li>Run the web site on .NET 3.5 using the following steps: </li>
<ul>
<li>Global replace of 1.0.61025.0 to 3.5.0.0 in web.config (do NOT replace in the other files) </li>
<li>Add &quot;dependentAssembly&quot; tag under runtime/assemblyBinding:
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">dependentAssembly</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">assemblyIdentity</span> <span class="attr">name</span><span class="kwrd">=&quot;System.Web.Extensions&quot;</span> <span class="attr">culture</span><span class="kwrd">=&quot;neutral&quot;</span> <span class="attr">publicKeyToken</span><span class="kwrd">=&quot;31bf3856ad364e35&quot;</span><span class="kwrd">/&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">bindingRedirect</span> <span class="attr">oldVersion</span><span class="kwrd">=&quot;1.0.61025.0&quot;</span>
                         <span class="attr">newVersion</span><span class="kwrd">=&quot;3.5.0.0&quot;</span><span class="kwrd">/&gt;</span>
      <span class="kwrd">&lt;/</span><span class="html">dependentAssembly</span><span class="kwrd">&gt;</span></pre>
</li>
<li>Use this for compilation tag (under system.web): </li>
<pre class="csharpcode">    <span class="kwrd">&lt;</span><span class="html">compilation</span> <span class="attr">debug</span><span class="kwrd">=&quot;true&quot;</span> <span class="attr">defaultLanguage</span><span class="kwrd">=&quot;C#&quot;</span><span class="kwrd">&gt;</span>
      <span class="kwrd">&lt;</span><span class="html">assemblies</span><span class="kwrd">&gt;</span>
        <span class="rem">&lt;!--</span>
<span class="rem">        Cannot add System.Core - it conflicts with LinqBridge which is required by SLX</span>
<span class="rem">        &lt;add assembly=&quot;System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089&quot;/&gt;</span>
<span class="rem">        --&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">add</span> <span class="attr">assembly</span><span class="kwrd">=&quot;System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35&quot;</span><span class="kwrd">/&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">add</span> <span class="attr">assembly</span><span class="kwrd">=&quot;System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089&quot;</span><span class="kwrd">/&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">add</span> <span class="attr">assembly</span><span class="kwrd">=&quot;System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089&quot;</span><span class="kwrd">/&gt;</span>
      <span class="kwrd">&lt;/</span><span class="html">assemblies</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">compilation</span><span class="kwrd">&gt;</span></pre>
<li>As you cannot add System.Core not all features will be available. Most importantly System.Linq.Expressions. </li>
</ul>
<li>Do not use &lt;script&gt; tags for JavaScript on smart parts because they will get lost after a postback.  Use ScriptManager.RegisterClientScriptBlock instead.  Unfortunately this means a large performance hit if the script is big as the client will have to download and parse it every time.  Alternatively, disable the top-level UpdatePanel, and use smaller updatepanels to do the job (this will make the page a LOT more responsive on slow links but requires a bit of work to make sure everything is still getting refreshed as it should) </li>
</ol>
<h4>Data Access</h4>
<ol>
<li>Events on property changes have 2 serious drawbacks:
<ul>
<li>&#8220;BeforeUpdate&#8221; events do not fire at all</li>
<li>&#8220;AfterUpdate&#8221; events only fire when the entity itself is saved, thus they are not terribly useful as you might as well put that code in the OnUpdate event of the entity itself.  Also, because it is processed after the entity is actually saved, you cannot easily modify the entity at this point (you have to resave it, but because it is already inside of a Save call, it may cause NHibernate to crash)</li>
</ul>
</li>
<li>Events on an &#8220;extension&#8221; entity do not always trigger correctly on &#8220;cascading&#8221; save.  Basically if you have a rule on ContactExt.BeforeUpdate, and you make a change to the ContactExt field, then call Account.Save, the changes get saved, but the event rule does not necessarily get called.  It is a bit confusing, but you will recognize it when it happens.</li>
<li>Do not Delete and Save an entity within the same transaction (this includes Save / Delete that are made as part of a cascade operation)</li>
</ol>
<h4>Lookups</h4>
<ol>
<li>You can have a lookup exclude the entities that were already selected using code like:<br />
<blockquote>
<p>lueAddUtility.LookupExclusions = parentEntity.SEOppUtilities.ToArray();</p>
</blockquote>
</li>
<li>To invoke a lookup programmatically the following code works, sloppy as it may look:
<pre class="csharpcode">ScriptManager.RegisterClientScriptBlock(<span class="kwrd">this</span>, GetType(),
            <span class="str">&quot;ShowLookup&quot;</span>,
            <span class="rem">// we need a slight delay here to give the lookup a chance to initialize</span>
            <span class="str">&quot;$(document).ready(function() { setTimeout(function() { &quot;</span> + lueAddUtility.ClientID + <span class="str">&quot;_luobj.show() }, 500) })&quot;</span>,
            <span class="kwrd">true</span>);</pre>
<p>It is also possible to set up a lookup as &quot;Button only&quot; which creates the lookup button&#8230; good for &quot;associate a record&quot; buttons. </li>
<li>It is possible to use custom HQL in a lookup, by doing a PreFilter that points to a non-string property (this may well break in a later version).&#160; EG (taking advantage of the fact that TYPE is defined as an enum and not a string, this creates a condition to select remote, network and concurrent users only):
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">SalesLogix:LookupPreFilter</span> <span class="attr">PropertyName</span><span class="kwrd">=&quot;Type&quot;</span> <span class="attr">CondOperator</span><span class="kwrd">=&quot;Not Equal to&quot;</span> <span class="attr">FilterValue</span><span class="kwrd">=&quot;'' and User.Type in ('N', 'M', 'C')&quot;</span> <span class="kwrd">/&gt;</span></pre>
</li>
<li>If adding a LookupPreFilter on a field that is not a string (including enums), you have to add the single quotes explicitely.</li>
<li>I am not sure if you are supposed to use CondOperator or OperatorCode in the LookupPreFilters.  The documentation seems to mention CondOperator, but Saleslogix uses OperatorCode&#8230; the possible values for &#8220;CondOperator&#8221; are in the help file, but in addition to the ones mentioned there one can also use &#8220;Not Equal to&#8221;.</li>
<li>Lookups get cached the first time they are accessed&#8230; if the definition changes on the smart part, Log Off, and log back in. Closing IE or restarting IIS is not necessary. To some extent this may make it hard to modify lookups on the fly. Interesting tidbit: if LookupExclusion is not null then the cache won&#8217;t be used. So if you want to set up the LookupPreFilter dynamically you may have to make sure you set up a LookupExclusion (this may be an empty array). Will probably break in a later version. </li>
<li>Lookups with a displaymode of DropDownList behave completely differently and may as well be considered different controls. None of the above comments apply to them. </li>
</ol>
<h4>Databinding</h4>
<ol>
<li>Remember that the Saleslogix databinding works with events (i.e. when TextChanged fires is when the property will be populated on the entity). This has 2 important consequences:
<ul>
<li>You can&#8217;t bind to a property that does not have a corresponding change event (e.g. DropDownList.SelectedValue)</li>
<li>Within a Change handler, it is hard to know whether the properties have all been brought in yet or not.  Say you want to change the CurrentEntity.Price when the lookup returns &#8211; if txtPrice fires a TextChanged event after the LookupResultValueChanged event did, then the property will be overwritten.  To be safe it has to be written both to the entity and to the control.</li>
</ul>
</li>
<li>On the property itself there is a way to characterize the datatype (for some property types).  For example for a &#8220;Double&#8221; type property there is a way to indicate that the property refers to a percentage.  This is probably useful in some situation but other times it messes up with the rounding and the display.  So I turned it off (a few years ago I wrote a little piece of Javascript to format percentages in textboxes and it still works pretty well for me).</li>
<li>There is a client-side component for the databinding (responsible for undoing the changes when the user hits the close button, for example).  When messing with the DOM be careful not to get this one confused (do not move controls too far afar in the document &#8211; if they get under a different &#8220;workspace&#8221; some of the bindings won&#8217;t work).</li>
<li>It is possible for a smart part to interfere with the databinding of other smart parts.  For example calling Page.DataBind is a NO-NO.  If you notice that some values are getting cleared when they shouldn&#8217;t (often happens with the values that are loaded from ControlState, e.g. GridView.DataKeys), either check the other smartparts on the page or use a work around (e.g. instead of using grid.DataKeys we can use a CommandArgument).</li>
</ol>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/164/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=164&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/05/15/tips-tricks-of-the-web-client/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>
	</item>
		<item>
		<title>Using IChangedState to track before/after values of an entity</title>
		<link>http://chivinou.wordpress.com/2009/05/11/using-ichangedstate-to-track-beforeafter-values-of-an-entity/</link>
		<comments>http://chivinou.wordpress.com/2009/05/11/using-ichangedstate-to-track-beforeafter-values-of-an-entity/#comments</comments>
		<pubDate>Mon, 11 May 2009 23:01:20 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/2009/05/11/using-ichangedstate-to-track-beforeafter-values-of-an-entity/</guid>
		<description><![CDATA[This is a very nifty feature of the new Saleslogix platform that addresses the very common scenario of detecting when the user edited a field.&#160; In the legacy client we often had to either run a SQL or manually save the old value to a global on the form – this was a rather tedious [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=161&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This is a very nifty feature of the new Saleslogix platform that addresses the very common scenario of detecting when the user edited a field.&#160; In the legacy client we often had to either run a SQL or manually save the old value to a global on the form – this was a rather tedious and dirty if you had to check a lot of properties.&#160; In this new platform the change tracking is built-in – there are a few steps to it so it does not necessarily save in terms of line of code but it is less messy.</p>
<p>The basics are documented in the Saleslogix Web Client FAQ:</p>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">static</span> String GetOldMainPhoneValue(IAccount account)
{
    IChangedState accountState = account <span class="kwrd">as</span> IChangedState;
    <span class="kwrd">if</span> (accountState != <span class="kwrd">null</span>)
    {
        ChangeSet changes = accountState.GetChangedState();
        PropertyChange mainPhoneChange = changes.FindPropertyChange(<span class="str">&quot;MainPhone&quot;</span>);

        <span class="kwrd">if</span> (mainPhoneChange != <span class="kwrd">null</span>)
        {
            <span class="kwrd">return</span> (<span class="kwrd">string</span>) mainPhoneChange.OldValue;
        }
    }
    <span class="kwrd">return</span> <span class="kwrd">null</span>;
}</pre>
<p>However there are a few pitfalls.</p>
<p>First of all and not really related, but I found out your business rules would not execute if you specified it as a “Pre-Execute” or “Post-Execute” target but did not have a primary step on the rule.</p>
<p>Secondly, you have to know when this update information is available.&#160; As far as I can tell this is available on the form handlers, as well as on the “OnBeforeUpdate” entity events, but not once the entity has been saved (e.g. on the OnAfterUpdate event).</p>
<p>Another point is that there is a slightly different syntax depending on the type of change to be tracked.&#160; If it is a simple property change the above code (FindPropertyChange) works.&#160; However if the change is on a related entity… for example opportunity.AccountManager… you have to use this syntax:</p>
<pre class="csharpcode">ChangeSet changes = changeState.GetChangedState();
EntityPropertyChange change = changes.FindMemberChange&lt;EntityPropertyChange&gt;(<span class="str">&quot;AccountManager&quot;</span>);
<span class="kwrd">string</span> newUserId = (String) change.NewEntity.EntityId;
<span class="kwrd">string</span> oldUserId = (String)change.OldEntity.EntityId;</pre>
<p>Unfortunately this does not work with simple properties… so you have to know which property you are dealing with in order to know how to examine the changes.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/161/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/161/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/161/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=161&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/05/11/using-ichangedstate-to-track-beforeafter-values-of-an-entity/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>
	</item>
		<item>
		<title>AJAX Script Services on SlxWeb</title>
		<link>http://chivinou.wordpress.com/2009/03/12/ajax-script-services-on-slxweb/</link>
		<comments>http://chivinou.wordpress.com/2009/03/12/ajax-script-services-on-slxweb/#comments</comments>
		<pubDate>Thu, 12 Mar 2009 06:52:55 +0000</pubDate>
		<dc:creator>chivinou</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.chivinou.net/2009/03/12/ajax-script-services-on-slxweb/</guid>
		<description><![CDATA[From my user perspective one of the most dreadful aspect of the &#34;QuickForms&#34; is how slow they are.&#160; If you want to associate a piece of custom logic to a control, typically you will have to set it to auto-postback.&#160; At this point whenever the user changes it Saleslogix will have to post the entire [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=149&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>From my user perspective one of the most dreadful aspect of the &quot;QuickForms&quot; is how slow they are.&#160; If you want to associate a piece of custom logic to a control, typically you will have to set it to auto-postback.&#160; At this point whenever the user changes it Saleslogix will have to post the entire form and (since it does not know what may have changed) pull the entire form back over the network and render it in the browser.&#160; This is noticeable even on a local network connection but can easily take 1 to 3 seconds over a WAN, which really breaks the flow of the form.</p>
<p>In a custom smart part there are a couple ways to get around that.&#160; One of them and often the easiest is to put smaller updatepanels around the controls that you know are going to be updated.&#160; It is not the most efficient, and it requires a basic understanding of ASP.NET Ajax (because there are a few workarounds that need to be used to disable the default handling from the top-level SalesLogix container page), but it does not usually affect the page lifecycle so the code-behind does not need to be touched.&#160; This is not the subject here though.</p>
<p>As an alternative to the Microsoft ASP.NET Ajax controls it is perfectly possible to use 100% custom, client-side Javascript.&#160; For example it is easy to perform basic calculations in the page and display the results.&#160; If they are saved to a bound control they can be saved to the database when the form is actually posted.&#160; This is very fast because it is done entirely on the client but it does not let us access the database or any of the business rules defined in C# on the server side.</p>
<p>A middle-ground option is to have the client-side Javascript call a custom web service and display the results in the form controls.&#160; This can be quite a bit faster than using an UpdatePanel, especially if a lot of controls need to be updated, and it also offers greater control over the flow of the code.&#160; Sometimes the UpdatePanel&#8217;s behavior can become rather annoying and the custom Javascript actually be easier to use.&#160; This is the method that I want to write about here.</p>
<p>On the client side, traditionally this approach would have required coding of the Javascript XmlHttpRequest and possibly parsing of the resulting XML (unless JSON was used).&#160; However with ASP.NET it is a lot simpler, you can have a Javascript proxy generated automatically by using code like this:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">asp:ScriptManagerProxy</span> <span class="attr">runat</span><span class="kwrd">=&quot;server&quot;</span> <span class="attr">ID</span><span class="kwrd">=&quot;scriptManagerProxy&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">Services</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">asp:ServiceReference</span> <span class="attr">Path</span><span class="kwrd">=&quot;~/SmartParts/QuickTicket/InsertQuickTicketScriptService.asmx&quot;</span> <span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">Services</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">asp:ScriptManagerProxy</span><span class="kwrd">&gt;</span></pre>
<p>By the way the ScriptManagerProxy means that it will use the ScriptManager on the main page, which is created by the Saleslogix framework.&#160; You can&#8217;t just add a ScriptManager on your custom smart part as it will conflict with Saleslogix&#8217;.&#160; In the Javascript code the methods from the web service will appear as method under an &quot;InsertQuickTicketScriptService&quot; object:</p>
<pre class="csharpcode">InsertQuickTicketScriptService.GetAccountInfo(accId, <span class="kwrd">function</span>(accInfo){
  alert(accInfo.AccountName);
})</pre>
<p>Note they are called in an asynchronous fashion with a callback function.</p>
<p>Assuming the GetAccountInfo method returns an object containing a list of contacts the following code can be used to populate a list of contacts for the selected account:</p>
<pre class="csharpcode">InsertQuickTicketScriptService.GetAccountInfo(accId, <span class="kwrd">function</span>(accInfo){
        <span class="kwrd">var</span> cbo = $get(<span class="str">&quot;&lt;%= cboContacts.ClientID %&gt;&quot;</span>);
        cbo.options.length = 0;
        <span class="kwrd">for</span> (<span class="kwrd">var</span> i = 0; i &lt; accInfo.Contacts.length; i++) {
            cbo.options[cbo.options.length] =
                    <span class="kwrd">new</span> Option(accInfo.Contacts[i].ContactName,
                        accInfo.Contacts[i].Id);
        }
        <span class="kwrd">if</span> (cbo.options.length &gt; 0)
            cbo.options[0].selected = <span class="kwrd">true</span>;
})</pre>
<p>On the server side things are pretty easy thanks to the flexibility of the Saleslogix Entity service&#8230; In this case I used something similar to this:</p>
<pre class="csharpcode">[WebMethod(EnableSession = <span class="kwrd">true</span>)]
<span class="kwrd">public</span> AccountInfo GetAccountInfo(<span class="kwrd">string</span> accId)
{
    IAccount account = Sage.Platform.EntityFactory.GetById&lt;IAccount&gt;(accId);
    <span class="kwrd">if</span> (account == <span class="kwrd">null</span>)
        <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException(<span class="str">&quot;Account id not found &quot;</span> + accId);

    <span class="kwrd">return</span> <span class="kwrd">new</span> AccountInfo
    {
        Contacts = (from c <span class="kwrd">in</span> account.Contacts
                    select <span class="kwrd">new</span> ContactInfo
                    {
                        ContactId = (String)c.Id,
                        FullName = c.FullName
                    }).OrderBy(c =&gt; c.FullName).ToArray()
    };
}</pre>
<p>Don&#8217;t forget the EnableSession=true&#8230; Saleslogix uses sessions to store the current user&#8217;s connection data and by default won&#8217;t be able to access it from an asmx.&#160; By the way if you need to access it from an ashx you need to look for the similar option.&#160; AccountInfo and ContactInfo are just locally defined classes, with the minimum properties that need to be passed down to the client script.</p>
<p>If you are writing a custom smart part ASP.NET truly makes it easy to call the web service from your Javascript.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/chivinou.wordpress.com/149/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/chivinou.wordpress.com/149/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/chivinou.wordpress.com/149/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/chivinou.wordpress.com/149/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/chivinou.wordpress.com/149/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/chivinou.wordpress.com/149/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/chivinou.wordpress.com/149/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/chivinou.wordpress.com/149/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/chivinou.wordpress.com/149/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/chivinou.wordpress.com/149/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/chivinou.wordpress.com/149/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/chivinou.wordpress.com/149/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/chivinou.wordpress.com/149/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/chivinou.wordpress.com/149/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=chivinou.wordpress.com&amp;blog=2900595&amp;post=149&amp;subd=chivinou&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://chivinou.wordpress.com/2009/03/12/ajax-script-services-on-slxweb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/2a501d3f1493c8e8a4637521494eee62?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">chivinou</media:title>
		</media:content>
	</item>
	</channel>
</rss>
