Programming, technology, and CRM – from a Belgian programmer exiled to Missouri
  • rss
  • Home
  • Soft Gallery
    • autosvnbackup.sh
    • VBScript Snippets
  • Contact Me
  • Welcome

Unit Testing SLX – 7.2.2 Update

Nicolas Galler | March 11, 2008

A follow up to my post, Unit Testing SLX. The post was written on Saleslogix 7.2.1 and there have been several very, very good improvements in the last service pack. So much in fact that unit testing and external access might actually be viable. Most importantly, transactions are now well supported, and inserts actually work. I have not tried on a production application yet but it should actually now be possible to use the SLX 7.2 libraries for external database access from our own components (eg integration services, external web services, etc).

The setup is the same as before, so please read the original posts for details on that. Here is an example test using a transaction:

using (IDBConnectionWrapper con = new DBConnectionWrapper())
{
    String histId = (String)con.GetField("top 1 historyid", "history", "1=1 order by newid()");
    IHistory history;
    using (TransactionScope tx = new TransactionScope())
    {
        history = EntityFactory.GetById<IHistory>(histId);
        history.UserDef1 = new Random().Next().ToString();
        history.Save();

        using (ISession sess = new SessionScopeWrapper(false))
        {
            IDbCommand cmd = sess.Connection.CreateCommand();
            cmd.CommandText = "SELECT USERDEF1 FROM HISTORY WHERE HISTORYID='" + histId + "'";
            sess.Transaction.Enlist(cmd);
            Assert.AreEqual(history.UserDef1, (String)cmd.ExecuteScalar());
            cmd.Dispose();
        }
        tx.VoteRollBack();
    }
    // make sure the transaction rolled back
    Assert.AreNotEqual(history.UserDef1,
        (String)con.GetField("USERDEF1", "HISTORY", "HISTORYID=?", histId));
}

In order to setup the test harness I have created a NUnit SetupFixture class. It has a Setup method which runs before every test of the project (actually before each test within the same namespace as the setup fixture, which works well for this case):

/// <summary>
/// A setup fixture helper.
/// </summary>
[SetUpFixture]
public class TestSetupBase
{

    /// <summary>
    /// Setup helper (this does the setup with the default files)
    /// </summary>        
    [SetUp]
    public virtual void Setup()
    {
        // setup using the default file
        this.Setup("dynamicMethods.xml");
    }

    public virtual void Setup(String methodsFile)
    {
        // ...
    }

    /// <summary>
    /// Teardown helper.
    /// </summary>
    [TearDown]
    public virtual void TearDown()
    {
       // ...
    }
}

If anyone is interested feel free to download it. You’ll have to adjust the references to point to the various Saleslogix assemblies, log4net, NUnit, and NHibernate. To reuse the library in a separate project I can create a TestSetup class in the same namespace as my tests, inheriting from the one in TestSupport (and optionally passing a different path to the dynamicMethods.xml file, since this should be the one from the site deployed by AA) and making sure to link to the Sage.Entity.Interface and Sage.SalesLogix.Entities from the deployed web site (so that they contain the custom entities). Also make sure that the app.config file defines a connection string named “ConnectionString”.

Next step – test the group builder side. This should be pretty interesting.

Comments
1 Comment »
Categories
Saleslogix
Tags
Favorites
Comments rss Comments rss
Trackback Trackback

Enabling log4net logging in SLX 72

Nicolas Galler | January 20, 2008

The Saleslogix web client comes packaged with a wonderful logging system called log4net. This enables us to receive very detailed information about what is going on in every request, how the data is being read from the database, what business rules or events are being executed, etc. Unfortunately it is all disabled in the default installation. While I hope this changes in the near future to a configuration option, here is how you can turn it on for now. Warning: there is a significant performance impact to logging the debugging information – make sure you tweak this before deploying on production (you can restrict it to log only warning or errors).

  • Edit the web.config file, you need to add a line in the top (after the <configSections> tag) that reads:

    <section name="log4net"
      type="log4net.Config.Log4NetConfigurationSectionHandler,log4net,
        Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821" />
  • At the end of your web.config file (right before the closing </configuration> tag) you will need to paste the log4net configuration proper. I won’t lie, this is a pretty decent chunk of XML and I usually just carry the same one around. But in truth it is pretty simple: we are defining Appenders which is where you want to send the log output (eg to files, or to the event viewers), Loggers which are settings for where the log comes from (for example you can specify that you only want log messages of a certain severity for a given logger, or decide to send messages from some loggers to emails and not others), and finally a root setting which is simply the default settings for all loggers. These are the settings that I use for development – they configure the logger to show only warnings from NHibernate (you can change that to DEBUG but be warned that there is a lot of info and it does have a significant effect on performance at that level), and all messages from any other part of the system. Everything is sent to a text file under the Log subdirectory:
    <!-- This section contains the log4net configuration settings -->
    <log4net debug="false">
      <appender name="rollingFile" type="log4net.Appender.RollingFileAppender" >
    
        <param name="File" value="Log/log.txt" />
        <param name="AppendToFile" value="false" />
        <param name="RollingStyle" value="Date" />
        <param name="DatePattern" value="yyyy.MM.dd" />
        <param name="StaticLogFileName" value="true" />
    
        <layout type="log4net.Layout.PatternLayout">
          <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
        </layout>
      </appender>
    
      <!-- Setup the root category, add the appenders and set the
         default priority -->
    
      <root>
        <priority value="DEBUG" />
        <appender-ref ref="rollingFile"/>
      </root>
    
      <logger name="NHibernate">
        <level value="WARN" />
      </logger>
    
      <logger name="NHibernate.SQL">
        <level value="ALL" />
      </logger>
    </log4net>
  • Create a Log directory under the folder and set the permission to be modifiable by Everyone – this is where log4net will send the output.
  • You are almost done, the last thing is you need to create a file called Global.asax in the root of the web client with the following code to initialize the logging system:

    <%@ Application Language="C#" %>
    
    <script runat="server">
    
        private static log4net.ILog _log;
    
        /// <summary>
        /// Initialize web leads library.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>   
        void Application_Start(object sender, EventArgs e)
        {
            log4net.Config.XmlConfigurator.Configure();
            _log = log4net.LogManager.GetLogger(typeof(global_asax));
            _log.Info("Application Started");
        }
    
        void Application_End(object sender, EventArgs e)
        {
            //  Code that runs on application shutdown
            _log.Info("Application Ended");
            log4net.LogManager.Shutdown();
        }
    
        /// <summary>
        /// Redirect to generic error page.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>    
        void Application_Error(object sender, EventArgs e)
        {
        }
    
        void Session_Start(object sender, EventArgs e)
        {
            // Code that runs when a new session is started
    
        }
    
        void Session_End(object sender, EventArgs e)
        {
            // Code that runs when a session ends. 
            // Note: The Session_End event is raised only when the sessionstate mode
            // is set to InProc in the Web.config file. If session mode is set to StateServer 
            // or SQLServer, the event is not raised.
    
        }
    
    </script>

That’s it! Browse to the client and make sure the “log.txt” file gets created.

There is one more thing I like to do, add this code in the Page_Load of SmartParts/General/GeneralException.ascx, it will give you a traceback in the log whenever you hit an exception (the ones that are reported with the “Saleslogix has encountered an error” screen, not the ones that give you a Yellow Page Of Death):

if (Page.Request.QueryString["exceptionid"] != null)
{
  Exception ex = Sage.Platform.Application.ApplicationContext.Current.State[
     Page.Request.QueryString["exceptionid"]] as Exception;
  if (ex != null)
  {
    ExceptionID.Text = ex.Message;
    log4net.LogManager.GetLogger(typeof(GeneralException)).Warn("Exception Reported", ex);
  }
}

Now in your code, if you want to output some log messages, put code similar to this at the top of your class to declare a logger:

private static readonly log4net.ILog LOG =
  log4net.LogManager.GetLogger(typeof(myclass));

and in your code add calls to LOG.Info, LOG.Debug, etc.

See the log4net home page for more information about this excellent tool.

Comments
3 Comments »
Categories
Programming, Saleslogix
Tags
ASP.NET, Favorites, Saleslogix, Slx Web
Comments rss Comments rss
Trackback Trackback

SLX EntityBoundSmartPart lifecycle

Nicolas Galler | December 6, 2007

I added some logging statements to figure out what the lifecycle of user controls implementing SLX smart parts was and how it meshed with the standard ASP.NET events. This is what I came up with. SLX-specific events are in italic – the rest are standard ASP.NET (I skipped a few of the ASP.NET ones).

When the smart part is not displayed (eg an undisplayed dialog), none of the SLX stuff fires, but the standard ASP.NET still does:

  • OnInit
  • OnLoad
  • OnUnload

EntityContext.GetEntity() is available at all time but is of the type that is bound to the main form – not necessarily the same as the smartpart’s.

The first time it is displayed and bound:

  • OnInit
  • OnLoad
  • OnAddEntityBindings
  • OnLoadCurrentEntity starts
  • OnCurrentEntitySet
  • OnLoadCurrentEntity returns
  • MyDialogOpening
  • OnPreRender
  • OnFormBound (which is actually called from OnPreRender)
  • OnUnload

Again, EntityContext.GetEntity() is available but is of the type of the main form until OnCurrentEntitySet.

On postbacks:

  • OnAddEntityBindings
  • OnInit
  • OnLoad Starts
  • OnLoadCurrentEntity starts
  • OnCurrentEntitySet
  • OnLoadCurrentEntity returns
  • OnLoad Returns
  • Control postback events
  • OnPreRender
  • OnFormBound (which is actually called from OnPreRender)
  • OnUnload

EntityContext.GetEntity() is available and of the correct type.

OnFormBound is not a bad place to hook data binding stuff but it only fires from the PreRender which is a bit late sometimes. OnCurrentEntitySet executes before the bound data is saved to the entity (therefore before any SLX property change handler fires) so it is usually not great either.

Comments
1 Comment »
Categories
Saleslogix
Tags
Favorites
Comments rss Comments rss
Trackback Trackback

Categories

  • Experiments (4)
  • Interesting (1)
  • MSCRM (1)
  • Programming (60)
  • Rant (3)
  • Saleslogix (34)
  • Tricks (8)
  • Uncategorized (30)

Post History

  • 2010
    • January (3)
    • March (3)
    • April (2)
    • August (2)
  • 2009
    • March (2)
    • April (1)
    • May (3)
    • June (3)
    • July (1)
    • September (3)
    • October (2)
    • December (5)
  • 2008
    • January (9)
    • February (4)
    • March (9)
    • April (1)
    • May (5)
    • June (8)
    • July (1)
    • August (2)
    • September (1)
    • November (1)
    • December (3)
  • 2007
    • January (3)
    • February (7)
    • March (1)
    • April (3)
    • May (6)
    • June (2)
    • July (1)
    • August (2)
    • September (5)
    • October (3)
    • November (5)
    • December (4)
  • 2006
    • January (2)
    • September (1)
    • November (3)
    • December (4)
  • 2005
    • April (1)

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox