Setting the Connection String Programmatically on a Crystal Reports ReportDocument

Programmatically setting the connection string for a Crystal Reports ReportDocument will allow you to have the report automatically use the active connection string for the rest of the application (as in previous posts). In this case, the report is created using a method that is triggered by clicking a button on a form. The log on information must be applied to each table in the ReportDocument.

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim crReportDocument As ReportDocument
            crReportDocument = New ReportDocument
            crReportDocument.Load(<<name of reportdocument>>)

            Dim sConn As SqlConnectionStringBuilder = New SqlConnectionStringBuilder(<<connection string>>)

            Dim tables As CrystalDecisions.CrystalReports.Engine.Tables = crReportDocument.Database.Tables

            For Each table As CrystalDecisions.CrystalReports.Engine.Table In tables
                Dim tableLogOnInfo As CrystalDecisions.Shared.TableLogOnInfo = table.LogOnInfo
                tableLogOnInfo.ConnectionInfo.ServerName = sConn.DataSource
                tableLogOnInfo.ConnectionInfo.DatabaseName = sConn.InitialCatalog
                tableLogOnInfo.ConnectionInfo.IntegratedSecurity = True
                table.ApplyLogOnInfo(tableLogOnInfo)
            Next

            ' ...

       End Sub

Classics of Software Engineering

Even though I have been writing programs for most of my life, that does not mean that my programs have always been written well. Only following the standard prohibitions on spaghetti code and documenting well does not a good program make.

The best advice I ever got about writing programs was to read two books:

1. The Pragmatic Programmer, by Andy Hunt and Dave Thomas
2. Code Complete, 2nd Edition, by Steve McConnell

After applying the techniques from these books, your programs will be much easier to maintain, and much more efficient.

A third book that is also quite helpful is Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides (aka the Gang of Four).

These books are all available at Amazon.com in paper or Kindle format.

Free Spell Checker for TextBoxes

One of the hardest things for me to find coherent information on has been how to set up spell checking for multi-line TextBoxes on ASP.NET forms.  In my search, I came across Hunspell, an open source spell checker that is widely used in applications such as OpenOffice.

To set up Hunspell for use in your ASP.NET Web site, you will need to complete these steps.  Download the most recent version (currently 1.3.2) from the Hunspell download page and extract the archive file.

  1. Place the hunspellx64.dll and/or hunspellx86.dll (depending on 32- or 64-bit IIS process), NHunspell.dll, and language-appropriate dictionary files (for English – en_US.aff, en_US.dic, and hyph_en_US.dic) into the “bin” folder of your Web site.
  2. Create the SpellCheckerService Web Service.

Create a folder under the root named WebServices and add SpellCheckerService.asmx:

&lt;%@ WebService Language=&quot;VB&quot; CodeBehind=&quot;~/App_Code/SpellCheckerService.vb&quot; %&gt;

In the App_Code folder, add SpellCheckerService.vb:

Imports NHunspell
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Web
Imports System.Web.Script.Services
Imports System.Web.Services
Imports System.Web.Services.Protocols

' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
&lt;System.Web.Script.Services.ScriptService()&gt; _
&lt;WebService(Namespace:=&quot;http://tempuri.org/&quot;)&gt; _
&lt;WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)&gt; _
&lt;Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()&gt; _
Public Class SpellCheckerService
Inherits System.Web.Services.WebService

&lt;WebMethod()&gt; _
&lt;ScriptMethod(ResponseFormat:=ResponseFormat.Json)&gt; _
Public Function CheckSpelling(words As List(Of String)) As Dictionary(Of String, List(Of String))

Dim results As Dictionary(Of String, List(Of String)) = New Dictionary(Of String, List(Of String))
Dim spellEngine As SpellEngine = CType(Application(&quot;SpellEngine&quot;), SpellEngine)
'Check spelling of each word that has been passed to the method
For Each word As String In words
Dim correct As Boolean = spellEngine(&quot;en&quot;).Spell(word)
'If the word is spelled incorrectly, add it to the list of words to be
'returned along with suggestions
If Not correct Then
Dim suggestions As List(Of String) = spellEngine(&quot;en&quot;).Suggest(word)
suggestions.Sort()
results.Add(word, suggestions)
End If
Next
Return results
End Function

End Class
  1. Put the spellchecker.css file into a folder called css directly under the root and put this line into the head section of the markup file (for the page where the TextBox to be spell-checked is):

&lt;link href=&quot;~/css/SpellChecker.css&quot; type=&quot;text/css&quot; rel=&quot;stylesheet&quot;/&gt;

  1. Place the jQuery files from the Hunspell download into a folder called js under the root and insert this JavaScript into the head section of your markup. For my folder names to work, minor changes were necessary for the jquery.spellcheker.js and jquery.spelldialog.js files, so the text of those files (as modified by me) will be included at the bottom of this post.
&lt;script type=&quot;text/javascript&quot; src=&quot;../js/jquery-1.4.2.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;../js/jquery.spellchecker.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;../js/jquery.spelldialog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
var SpellCheckOptions = { learn: false, serverScriptURL: '../WebServices/SpellCheckerService.asmx' };

function spellCheckTextArea(targetId) {
var $textarea = $(targetId);

//this callback will be called when the spellcheck is
//complete. In this case we set the value of the target
//textarea to the corrected text.
var callback = function (textInfos) {
$textarea.val(textInfos[0].text);
}

var spellcheck = JQSpellCheckDialog.create({ text: $textarea.val() }, callback, SpellCheckOptions);
spellcheck.open();
}
&lt;/script&gt;
  1. Next to the TextBox (I’ll call it TextBox1 here) that you want to have associated with the spell checker, place a Button (called Button1 here). In your code-behind, enter this into the Page.Load event:
Button1.Attributes.Add(&quot;OnClick&quot;, &quot;spellCheckTextArea('#&quot; &amp; TextBox1.ClientID &amp; &quot;');return false;&quot;)

And that’s it.

Code for the jQuery files is below!

jquery.spellchecker.js:

////////////////////////////////////////////////////
// spellcheck.js
//
// SpellCheck object
//
// This file is sourced on web pages that have a textarea object to evaluate
// for spelling. It includes the implementation for the SpellCheck object.
// 
// Author: Lenny Marks
// Date: 10.08.2008
//
// Modified by David Young on 05.31.2012
//
////////////////////////////////////////////////////


/**
 * A SpellCheck object is created with one or more &lt;i&gt;textObjects&lt;/i&gt;
 * and a callback which is invoked once the checking has been completed.
 * 
 * Each textObject must minimally include a text property which will reflect
 * the corrected text when the callback is invoked.
 * 
 * eg.
 * textObjects = [{text: $textarea.val()}, ...]
 * 
 * Each textObject can additionally include other properties such as contentType 
 * for use by the spellchecking program and identifying info to be picked up
 * when the spellcheck is complete.
 * 
 * See demo for examples.
 *  
 * SpellCheck must be &lt;i&gt;configure&lt;/i&gt;d with a view and a remote
 * spellcheck handler. 
 * 
 * ExampleView = function() {
 *   //called when the SpellCheck is opened
 *   this.open = function() {}; 
 *   
 *   //called each time a remote spellcheck is about to start
 *   //can be used to display loading message
 *   this.checkingStarted = function(textObject) {}  
 *   
 *   //invoked each time the position context has changed with
 *   //the current position &lt;i&gt;SpellCheck.Context&lt;/i&gt; object.                                       
 *   this.update = function(context, enableUndo, skipEnabled) {} 
 *                                                         
 * }
 * 
 * The remote check handler is expected to be a function that accepts a textObject
 * and a callback. The callback should be invoked with a hash of misspelled words
 * once the remote check has returned. The misspelled words hash should be made
 * up of 'misspelledword' =&gt; ['list', 'of', 'suggestions'] pairs.
 * 
 * ex. from the JQuery implementation 
 * 
 * var remoteCheckHandler = function(textObject, callback) {
 *      jQuery.post(options.serverScriptURL, { 'text' : textObject.text }, function(result) {            
 *            callback(result);
 *      }, 'json');
 * };
 */
function SpellCheck(textObjects, spellCheckCompletedCallback) {
    SpellCheck.prototype.configure = function(view, server) {
        var self = this;
        
        self.view = view;
        self.server = server;
        
        var checkStartingCallback = function(textObjectIndex) {
            self.view.checkingStarted(self._textObjects[textObjectIndex]);
        };
        
        self._misspelledWords = new SpellCheck.internal.MisspelledWords(server, checkStartingCallback);
        
        self._contextManager = new SpellCheck.internal.ContextManager(self._textObjects, self._misspelledWords, function() { 
            var context = self._contextManager.getContext();
            
            if(context.word &amp;&amp; self.isIgnored(context.word)) {
               self._contextManager.step();
            } else {
                self._updateView();
            }
        });
        
    }
    
    SpellCheck.prototype.open = function() {
        this.view.open(); 
            
        this._contextManager.step();
       
    }
    
    SpellCheck.prototype.close = function() {
        this.view.close(); 
            
        spellCheckCompletedCallback(this._textObjects);
       
    }
     
    SpellCheck.prototype._updateView = function() {
        var context = this._contextManager.getContext();
        
        var textObjects = this._textObjects;
        
        var canUndo = this._lastAction != null;
        var canSkip = context.textObjectIndex &lt; textObjects.length - 1;
        
        this.view.update(textObjects[context.textObjectIndex], context, canUndo, canSkip);
    }
    
    SpellCheck.prototype.ignore = function() {
        this._lastAction = new SpellCheck.internal.IgnoreAction(this._contextManager.getContext());
        this._contextManager.step();
    }
    
    SpellCheck.prototype.learn = function() {
       
        var self = this;
        
        var context = self._contextManager.getContext();
        
        self.server.learn(context.word, function() {
            self._contextManager.step();
        });
        
      
    }
    
    SpellCheck.prototype.ignoreAll = function() {
        this._lastAction = new SpellCheck.internal.IgnoreAllAction(this._ignoredWords, this._contextManager.getContext());
        this._contextManager.step();
    }
    
    SpellCheck.prototype.undo = function() {
        if(this._lastAction) {
            this._contextManager.setContext(this._lastAction.undo());
            this._updateView();
        }
        
    }
    
    SpellCheck.prototype.replace = function(replacement) {
      this._lastAction = new SpellCheck.internal.ReplaceAction(this._textObjects, this._contextManager.getContext(), replacement);
      this._contextManager.step();
    }
    
    SpellCheck.prototype.replaceAll = function(replacement) {
      this._lastAction = new SpellCheck.internal.ReplaceAllAction(this._textObjects, this._contextManager.getContext(), replacement);
      this._contextManager.step();
    }
    
    SpellCheck.prototype.skip = function() {
       this._contextManager.skip();
    }
    
    SpellCheck.prototype.isIgnored = function(word) {
        return this._ignoredWords[word];
    }
    
    SpellCheck.prototype.textObject = function() {
        var context = this._contextManager.getContext();
        return this._textObjects[context.textObjectIndex];
    }
    
    SpellCheck.prototype.getSuggestions = function(word) {
        var context = this._contextManager.getContext();
        return this._misspelledWords.getSuggestions(this.textObject(), word);
    }
    
    SpellCheck.prototype.isMisspelled = function(word) {
        var context = this._contextManager.getContext();
        return this._misspelledWords.isMisspelled(this.textObject(), word);
    }
    
    SpellCheck.prototype.replaceMisspelled = function(startIndex, replaceWithBlock) {
        
        var replacedText = '';
        
        var textObject = this.textObject();
        
        var text = textObject.text;
        
        var self = this;
        
        SpellCheck.eachWord(textObject, startIndex, function(word, wordIndex) {
            replacedText += text.substring(startIndex, wordIndex);
            
            if(self.isMisspelled(word)) {
                replacedText += replaceWithBlock(word);
            } else {
                replacedText += word;
            }
            
            startIndex = wordIndex + word.length;
            
            return true;
        });
        
        if(startIndex &lt; text.length) replacedText += text.substring(startIndex);
        
        return replacedText;
        
        
    }
   
    var self = this;
    
    self._ignoredWords = {}
    self._textObjects = textObjects instanceof Array ? textObjects : [textObjects];
    self._lastAction = null;
      
    //collaborators setup by configure   
    self._misspelledWords = null;   
    self._contextManager = null;    
    self.view = null;
    self.server = null;
   
}   

SpellCheck.internal = {}

SpellCheck.internal.IgnoreAction = function(context) {
  SpellCheck.internal.IgnoreAction.prototype.undo = function() {
      return context;
  }
  
}

SpellCheck.internal.IgnoreAllAction = function(ignoredWords, context) {
  SpellCheck.internal.IgnoreAllAction.prototype.undo = function() {
      
      ignoredWords[context.word] = false;
  
      return context;
      
  }
 
  SpellCheck.internal.IgnoreAllAction.prototype._init = function() {
      if(!context) return;
      
      ignoredWords[context.word] = true;
  };
  
  this._init();
}

SpellCheck.internal.ReplaceAction = function(textObjects, context, replacement) {
  SpellCheck.internal.ReplaceAction.prototype.undo = function() {
      
      var textObject = textObjects[context.textObjectIndex];
       
      var text = textObject.text;
      
      text = text.substring(0, context.wordIndex) + 
          context.word +
          text.substring(context.wordIndex + replacement.length);
      
      
      textObject.text = text;
      
      return context;
  }
  
  SpellCheck.internal.ReplaceAction.prototype._init = function() {
    
      if(!context) return;
      
      var textObject = textObjects[context.textObjectIndex];
      
      var text = textObject.text;
      
      text = text.substring(0, context.wordIndex) + 
          replacement +
          text.substring(context.wordIndex + context.word.length);
      
      textObject.text = text;
  }
  
  this._init();
}

SpellCheck.internal.ReplaceAllAction = function(textObjects, context, replacement) {
    SpellCheck.internal.ReplaceAllAction.prototype.undo = function() {
        for(var i = context.textObjectIndex; i &lt; textObjects.length; i++) {
           textObjects[i].text = this._originalTexts.shift();  
        }
        
        return context;
    }
    
    SpellCheck.internal.ReplaceAllAction.prototype._init = function() {
        
        if(!context) return;
        
        var regexp = new RegExp('b' + context.word + 'b', 'g');
        
        var textObject = textObjects[context.textObjectIndex];
        
        var text = textObject.text;
        
        this._originalTexts.push(text);
        
        textObject.text = text.substring(0, context.wordIndex) + 
            textObject.text.substring(context.wordIndex).replace(regexp, replacement);
        
        for(var i = context.textObjectIndex + 1; i &lt; textObjects.length; i++) {
            textObject = textObjects[i];
            this._originalTexts.push(textObject.text);
            textObject.text = textObject.text.replace(regexp, replacement);
        }
    }
    
   
    this._originalTexts = []
    
    this._init();
}

/**
 * This class manages the list of misspellings for each textObject. It delegates
 * to &lt;i&gt;server.check&lt;/i&gt; to connect to spell checking program(on server).
 * 
 */
SpellCheck.internal.MisspelledWords = function(server, beforeCheckCallback) {
    var idSequence = 1;
    
    /*
     * Get misspelled words for textObject at textObjectIndex and invoke afterCheckCallback
     * when we have results. 
     * 
     */
    SpellCheck.internal.MisspelledWords.prototype.check = function(textObject, afterCheckCallback) {
        var self = this;
        
        textObject._identifier = idSequence++;
        
        if(!textObject.text.match(/w+/)) {
            self._misspelledWords[textObject._identifier] = {};
            afterCheckCallback();
            return;
        }
        
        beforeCheckCallback();
        
        var seen = {};
        var uniqueWords = [];
        
        SpellCheck.eachWord(textObject, 0, function(word, wordIndex) {
            if(seen[word] != true) { //specifically check for true to avoid false positives object props like 'constructor'
                uniqueWords.push(word);
                seen[word] = true;
            }
            return true;
        });
        
        server.check(uniqueWords, function(result) {
            self._misspelledWords[textObject._identifier] = result;            
            afterCheckCallback();            
        });
        
    }
    
    SpellCheck.internal.MisspelledWords.prototype.isMisspelled = function(textObject, word) {
        return typeof(this._misspelledWords[textObject._identifier]['d'][word]) != 'undefined';
    }
    
    SpellCheck.internal.MisspelledWords.prototype.getSuggestions = function(textObject, word) {
        return this._misspelledWords[textObject._identifier]['d'][word];
    }
    
    SpellCheck.internal.MisspelledWords.prototype.haveWords = function(textObject) {
        return typeof(this._misspelledWords[textObject._identifier]) != 'undefined';
    }
    
    this._misspelledWords = {}
}

/**
 * This class manages the position of the current misspelled word(Context) as
 * we step/skip through the textObjects. It uses a MisspelledWords instance
 * to handle actual spell checking.  
 * 
 */
SpellCheck.internal.ContextManager = function(textObjects, misspelledWords, contextChangedCallback) {
    SpellCheck.internal.ContextManager.prototype.getContext = function() {
        return this._context;
    }
    
    SpellCheck.internal.ContextManager.prototype.setContext = function(context) {
      this._context = context;
    }
    
    SpellCheck.internal.ContextManager.prototype.step = function() {
        var self = this;
        
        var textObject = textObjects[this._context.textObjectIndex];
        
        if(!misspelledWords.haveWords(textObject)) { 
          return misspelledWords.check(textObject, function() { self.step() });
        }
        
        this._nextLocalContext();
        
        var noMoreTextObjects = this._context.textObjectIndex == textObjects.length - 1;
        
        if(this._context.wordIndex &gt;= 0 || noMoreTextObjects) {
            if(contextChangedCallback) contextChangedCallback(this._context);
        } else {
            
          this._context = new SpellCheck.Context(this._context.textObjectIndex + 1, 0);
          this.step();
        }
       
    }
    
    SpellCheck.internal.ContextManager.prototype.skip = function() {
        if(this._context.textObjectIndex &lt; textObjects.length - 1) {
          this._context = new SpellCheck.Context(this._context.textObjectIndex + 1, 0);
          this.step();
        }
    }
    
    SpellCheck.internal.ContextManager.prototype._nextLocalContext = function() {
        if(this._context.word) {
          this._context = 
              new SpellCheck.Context(this._context.textObjectIndex, this._context.wordIndex + this._context.word.length);
        } 
         
        var context = this._context;
        
        var textObject = textObjects[context.textObjectIndex];
        
        SpellCheck.eachWord(textObject, context.startIndex, function(word, wordIndex) {
            if(misspelledWords.isMisspelled(textObject, word)) {
                
                context.word = word;
                context.wordIndex = wordIndex;
                
                return false;
            }
            
            return true;
        });
        
    }
    
   
   this._context = new SpellCheck.Context(0, 0);
   
}

/**
 *  The position context represents the context
 *  around the current misspelled word and basically breaks it up 
 *  into the text before misspelling, misspelled word, and text after
 *  
 *  Each time the position changes due to a user action(e.g. replace, ignore..),
 *  the view will be notified. When there are no more misspellings, the context.word
 *  will be null and the wordIndex will be -1.
 *  
 */
SpellCheck.Context = function(textObjectIndex, startIndex) {
  
    this.textObjectIndex = textObjectIndex;
    this.startIndex = startIndex;
    this.word = null;
    this.wordIndex = -1;
    
}

SpellCheck.lastNLines = function(text, maxLines) {
     
    var re = /[rn]/g;
    
    var result = null;
    
    var startLineIndexes = [];
    
    while((result = re.exec(text))) {    
      startLineIndexes.push(result.index);
    }
      
    if(startLineIndexes.length &lt; maxLines) return text;
    
    var lineCnt = 0;
    var cutIndex = 0;
    
    for(var i = startLineIndexes.length - 1; i &gt;= 0; i--) {
      
      cutIndex = startLineIndexes[i];
      
      if(++lineCnt == maxLines) break;
    }
    
    var lastNLines = text.substring(cutIndex).replace(/^[rn]/, '');
    
    return lastNLines;
}


    
/**
 * Call block(word, wordIndex) for each word. Stop if block returns false. 
 *
*/
SpellCheck.eachWord = function(textObject, startIndex, block) {
    var nonSpaceSeqPattern =  /S+/g;
    var wordPattern = /[a-zA-Z]+('[a-zA-Z]+)?/g;
    
    var nonSpacesMatchData, wordMatchData;
    
    var text = textObject.text.substring(startIndex);
    
    while((nonSpacesMatchData = nonSpaceSeqPattern.exec(text))) {
        var word = nonSpacesMatchData[0];       
        var wordIndex = startIndex + nonSpacesMatchData.index;
        
        if(word.match(/^/)) continue;        //TeX
        if(word.match(/w+@w+.w+(.w+)?/)) continue; //email   
        if(word.match(/^https?/)) continue; //url
       
        while((wordMatchData = wordPattern.exec(word))) {
           
            var subWord = wordMatchData[0];
            var subWordIndex = wordIndex + wordMatchData.index;
           
            if(subWord.length &lt; 2) continue;
            if(subWord.match(/'$/)) {
              subWord = subWord.substring(0, subWord.length - 1);
            }
            
            if(!block(subWord, subWordIndex)) {
                nonSpaceSeqPattern.lastIndex = 0;
                wordPattern.lastIndex = 0;
                return;
            }
        }                    
    }            
}

jquery.spelldialog.js:

/**
 * JQuery Dialog wiring for SpellCheck. 
 * 
 * ex.
 * 
 * //See default options below. SpellCheck options are:
 * loadingImgSrc - 
 * serverScriptURL - 
 * 
 * All other options are passed directly to JQuery Dialog. 
 * 
 * var spellcheck = JQSpellCheckDialog.create({text : $textarea.val()}, callback, SpellCheckOptions);
 *
 * spellcheck.open();
 * 
 *
 * Modified by David Young on 05.31.2012
 *
 */

var JQSpellCheckDialog = {};

JQSpellCheckDialog.defaults = {
    loadingImgSrc : '../images/loading.gif',
    serverScriptURL : '../WebServices/SpellCheckerService.asmx',
    modal:true, 
    autoOpen:true,
    width : 700,
    height : 550,
    title : 'Spell Check',
    learn : false
}

JQSpellCheckDialog.create = function(textObjects, completedCallback, options) {
    options = jQuery.extend(JQSpellCheckDialog.defaults, options);
    
    var spellcheck = new SpellCheck(textObjects, completedCallback);
    
    var view = new JQSpellCheckDialog.View(spellcheck, options);
   
    spellcheck.configure(view, new JQSpellCheckDialog.Server(options));
    
    return spellcheck;
    
}

JQSpellCheckDialog.Server = function(options) {
    JQSpellCheckDialog.Server.prototype.serverError = function() {
       alert('A server error occurred during the spellcheck.');
    }
    
    JQSpellCheckDialog.Server.prototype.check = function(words, callback) {
        var self = this;
        
        var p = { words: words };

        jQuery.jsonService({
             url:  options.serverScriptURL,
             method: '/CheckSpelling',
             params: p,
             error : self.serverError,
             success : function(result) { callback(result); }
         });                      
    };
    
    JQSpellCheckDialog.Server.prototype.learn = function(word, callback) {
        var self = this;
        
        jQuery.ajax({
            type : 'POST',
            dataType : 'json',
            url : options.serverScriptURL,
            data : { learn : word },
            error : self.serverError,
            success : function() { callback(); }
        });
    }
}


JQSpellCheckDialog.View = function(spellcheck, options) {
    JQSpellCheckDialog.View.Template = 
	'&lt;div class=&quot;controlWindowBody&quot;&gt;' +
	'' +
	'&lt;table&gt;' +
	'&lt;tr&gt;' +
	'   &lt;td colspan=&quot;3&quot; class=&quot;normalLabel&quot;&gt;Not in dictionary:&lt;/td&gt;' +
	'&lt;/tr&gt;' +
	'&lt;tr&gt;' +
	'	&lt;td colspan=&quot;3&quot;&gt;&lt;/td&gt;' +
	'&lt;/tr&gt;' +
	'&lt;tr&gt;' +
	'	&lt;td class=&quot;normalLabel&quot;&gt;Change to:&lt;/td&gt;' +
	'&lt;/tr&gt;' +
	'&lt;tr valign=&quot;top&quot;&gt;' +
	'	&lt;td&gt;' +
	'		&lt;table&gt;' +
	'		&lt;tr&gt;' +
	'			&lt;td class=&quot;normalLabel&quot;&gt;' +
	'        		' +
	'			&lt;/td&gt;' +
	'       &lt;/tr&gt;' +
	'       &lt;tr&gt;' +
	'			&lt;td&gt; ' +
	'			' +
	'				' +
	'			' +
	'			&lt;/td&gt;' +
	'		&lt;/tr&gt;' +
	'		&lt;/table&gt;' +
	'	&lt;/td&gt;' +
	'	&lt;td&gt;&amp;nbsp;&amp;nbsp;&lt;/td&gt;' +
	'	&lt;td&gt;' +
	'		&lt;table&gt;' +
	'		&lt;tr&gt;' +
	'			&lt;td style=&quot;padding-right:10px;&quot;&gt;' +
	'			Ignore' +
	'			&lt;/td&gt;' +
	'			&lt;td&gt;' +
	'			Ignore All' +
	'			&lt;/td&gt;' +
	'		&lt;/tr&gt;' +
	'		&lt;tr&gt;' +
	'			&lt;td&gt;' +
	'			Replace' +
	'			&lt;/td&gt;' +
	'			&lt;td&gt;' +
	'			Replace All' +
	'			&lt;/td&gt;' +
	'		&lt;/tr&gt;' +
        '               &lt;tr&gt;' +
	'			&lt;td&gt;' +
	'			Undo' +
	'			&lt;/td&gt;' +
	'			&lt;td&gt;' +
	'			Learn' +
	'			&lt;/td&gt;' +
	'		&lt;/tr&gt;' +
	'		&lt;tr&gt;' +
	'			&lt;td style=&quot;padding-top:13px;&quot;&gt;' +
	'			Next Block' +
	'			&lt;/td&gt;' +
	'			&lt;td style=&quot;padding-top:13px;&quot;&gt;' +
	'			Done' +
	'			&lt;/td&gt;' +
	'		&lt;/tr&gt;' +
	'		&lt;/table&gt;' +
	'	&lt;/td&gt;' +
	'&lt;/tr&gt;' +
	'&lt;/table&gt;&lt;/div&gt;';
    
    JQSpellCheckDialog.View.prototype._createUI = function() {
        var $loading = $('&lt;div class=&quot;loadingMessage&quot;&gt;&lt;img src=&quot;' + options.loadingImgSrc + 
            '&quot; /&gt;&amp;nbsp;Checking....&lt;/div&gt;').hide();

        var $wordText = $('&lt;div class=&quot;wordWindowText&quot;&gt;&lt;/div&gt;');
        
        var $wordWindow = $('&lt;div class=&quot;wordWindow&quot;&gt;&lt;/div&gt;').append($loading).append($wordText);
        
        var $window = $('&lt;div id=&quot;spellCheckDialog&quot;&gt;&lt;/div&gt;').
            append($wordWindow).
            append(JQSpellCheckDialog.View.Template);
        
        var thisView = this;
        
        $('button[name=close]', $window).click(function() {
            spellcheck.close();
            return false;
        });
        
        $('button[name=replace]', $window).click(function() {
            spellcheck.replace(thisView.getChangeTo());
            return false;
        });
        
        $('button[name=replaceAll]', $window).click(function() {
            spellcheck.replaceAll(thisView.getChangeTo());
            return false;
        });
        
        $('button[name=undo]', $window).click(function() {
            spellcheck.undo();
            return false;
        });
        
        $('button[name=ignore]', $window).click(function() {
            spellcheck.ignore();
            return false;
        });
        
        $('button[name=ignoreAll]', $window).click(function() {
            spellcheck.ignoreAll();
            return false;
        });
        
        $('button[name=skip]', $window).click(function() {
            spellcheck.skip();
            return false;
        });
        
        if(options.learn) {
            $('button[name=learn]', $window).click(function() {
                spellcheck.learn();
                return false;
            });
        } else {
            $('button[name=learn]', $window).attr('disabled', 'disabled');
        }
        
        $('select', $window).change(function() {
            $('input[name=txtsugg]', $window).val($(this).val());
        });
        
        return $window;
    }
    
    JQSpellCheckDialog.View.prototype.open = function() {        
        this._$dialog = this._createUI().dialog(options);
    }
    
    JQSpellCheckDialog.View.prototype.close = function() {
        this._$dialog.dialog('close');
    }
    
    JQSpellCheckDialog.View.prototype.getChangeTo = function() {
      return $('input[name=txtsugg]', this._$dialog).val();
    }
    
    JQSpellCheckDialog.View.prototype.checkingStarted = function(textObject) {
      $('.loadingMessage', this._$dialog).show();
      $('.wordWindowText', this._$dialog).hide();
      
    }
    
    JQSpellCheckDialog.View.prototype.update = function(textObject, context, canUndo, canSkip) {
        var self = this;
        
        $('.loadingMessage', this._$dialog).hide();
        $('.wordWindowText', this._$dialog).show();
        
        if(context.word == null) {
            var $closeLink = $('&lt;a href=&quot;void(0);&quot;&gt;Close&lt;/a&gt;').click(function() {
                spellcheck.close();
                return false;
            });
            
            var $container = $('&lt;div class=&quot;spellCheckCompleted&quot;&gt;&lt;/div&gt;');
            
            $container.append('Spell Check Completed. ').
                append($closeLink);
            
            
            $('.controlWindowBody', this._$dialog).empty().append($container);
        } 
        this._updateWordWin(textObject, context);
        this._updateControlWindow(context);
        
        if(!canUndo) {
            $('button[name=undo]', this._$dialog).attr('disabled', 'disabled');
        } else {
            $('button[name=undo]', this._$dialog).removeAttr('disabled');
        }
        
        if(!canSkip) {
            $('button[name=skip]', this._$dialog).attr('disabled', 'disabled');
        } else {
            $('button[name=skip]', this._$dialog).removeAttr('disabled');
        }
        
    }
    

    JQSpellCheckDialog.View.prototype._updateControlWindow = function(context) {
        var word = context.word;
        
        $('input[name=misword]', this._$dialog).val(word);
        
        var $select = $('select', this._$dialog).empty();
        
        var suggestions = spellcheck.getSuggestions(word);
        
        if(suggestions) {
            for(var i in suggestions) {
                $select.append('' + suggestions[i] + '');
            }
            
            if(suggestions.length &gt; 0) {
                $select.val(suggestions[0]);
                $select.change();
            }    
        } else {
            $('input[name=txtsugg]', this._$dialog).val('');
        }
    }
    
    JQSpellCheckDialog.View.prototype._updateWordWin = function(textObject, context) {
        var text = textObject.text;
        
        var markup = '';
        
        if(context.word != null) {
            markup = text.substring(0, context.wordIndex);
            
            markup = SpellCheck.lastNLines(markup, 10);
            
            markup += '&lt;span class=&quot;currentWord&quot;&gt;' + context.word + '&lt;/span&gt;';
             
            var startIndex = context.wordIndex + context.word.length;
            
            var theRest = spellcheck.replaceMisspelled(startIndex, function(word) {
                
                if(! spellcheck.isIgnored(word)) {
                    return '&lt;span class=&quot;misspelled&quot;&gt;' + word + '&lt;/span&gt;';
                }
                
                return word;
            });
            
            markup += theRest;
        } else {
            markup = text;
        }       
                
        $('.wordWindowText', this._$dialog).html(markup);
    }
    
    this.spellcheck = spellcheck;
    this._$dialog = null;
    
}

Dynamically Setting the Connection String for Session State on SQL Server

In ASP.NET, there are four ways to store Session State.  The way I prefer to store it is using SQL Server.  However, instead of storing it in the ASPstate database, which is the default way to store it on SQL Server, I choose to store it in the application database, which is a “custom SQL database” implementation.

When storing Session State in the application database, the web.config will have an entry that points at the database server and the name of the database:

<sessionState mode="SQLServer" timeout="20" allowcustomsqldatabase="true"
   sqlconnectionstring="Data Source=Server;Initial Catalog=databasename; User ID=UserID;
   Password=Password;" cookieless="false" />

Because this is set in web.config, it suffers from the same problem that I wrote about in this post — namely, that the connection string must be changed when moving between different environments (such as development, test / staging , and production).

To remedy this, a function that returns the dynamic connection string for the application should already be in place.  Something like this will work:


using System.Configuration;

public class ConnectionStrings
{
   public static string _AppDB_ConnectionString = ConfigurationManager.ConnectionStrings["AppDB_ConnectionString_" + ConfigurationManager.AppSettings.Get("Environment").ToUpper()].ConnectionString;
}

(This is assuming that you have an “Environment” key set in the appSettings section of either web.config or machine.config, and that your connection strings are named accordingly in your web.config connectionStrings section.)

Next, a PartitionResolver class must be created that can get the correct connection string by using the function declared above:

public class MyPartitionResolver : System.Web.IPartitionResolver
{
   public void Initialize()
   {
   //Empty Initializer
   }

   public string ResolvePartition(object key)
   {
     return ConnectionStrings._AppDB_ConnectionString;
   }
}

Lastly, the sessionState entry in web.config must be modified to look like this:

<sessionState mode="SQLServer" allowCustomSqlDatabase="true" partitionResolverType="MyPartitionResolver"
regenerateExpiredSessionId="true" compressionEnabled="true" useHostingIdentity="true" timeout="480"/>

Note: The options after “partitionResolverType” can be set according to your needs.