Thursday, June 3, 2010

The Most Helpful Web Page For Custom Website ISV Deployment for CRM 4.0

I have been extending CRM 4.0 for quite a while now, and it wasn't until recently that I had to do a custom ASPX page that would run in the context of the current user using IFD authentication. I knew I had to use the CrmAuthenticationToken.ExtractCrmAuthenticationToken(Context, orgName) method, but I didn't understand how the site needs to be set up in IIS.


Here's the key: If you want to do this, you DON'T make a new website or virtual directory. You just put the aspx files and the bin folder in the ISV folder of the root of the CRM website.


I figured this out by finding an amazing web page from Microsoft that answered all my questions. Here it is:


http://msdn.microsoft.com/en-us/library/dd548493.aspx


Important things to note:

  • You can put dll's in the bin folder in the application's folder in the ISV folder of the root of the website if you have installed Rollup Update 2
  • You must do all of your configuration in other ways from the web.config
  • If you are using a web application project, you must explicitly reference the dll in the @Assembly page directive in your aspx pages.

I hope this saves you some pain and time.

Wednesday, February 10, 2010

C# Flags Enumeration Helper

Working in the confines of .NET 2.0 (no extension methods), I was in dire need of a helper that would assist in the checking and manipulating of flags enumerations. Over the years that I have used them, I've been bitten enough times using the wrong operators and having to deal with other people maintaining my code that used these enumerations that I finally wrote an enum helper.

This helper covers the setting, checking, and evaluating the flags that have been set on the enum. I wanted to share it with y'all to save you a little of the grief that I have borne. Here it is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace TestFlags
{
class Program
{
[Flags]
public enum Flags
{
None = 0,
First = 1,
Second = 2,
Third = 4
}
static void Main(string[] args)
{
var flag = Flags.None;

Debug.Assert(Enum.EnumHasFlag(flag, Flags.Second));
Debug.Assert(Enum.EnumHasFlag(flag, Flags.Third));

List allFlags = Enum.GetFlagEnumList(flag);
foreach (var allFlag in allFlags)
{
Console.WriteLine(allFlag);
}

Console.ReadKey();
}
}

///
/// Assists with enum operations
///
/// The type of the enum.
public static class Enum where TEnum : struct
{
///
/// Adds the specified flag to an enum.
///
/// The append to.
/// To append.
public static void AddFlagToEnum(ref TEnum appendTo, TEnum toAppend)
{
int appendToInt = Convert.ToInt32(appendTo);
int toAppendInt = Convert.ToInt32(toAppend);

appendTo = (TEnum)(object)(toAppendInt | appendToInt);
}

///
/// Determines whether the enum has a certain flag
///
/// The flags enum value to check to see if it contains the checkAgainst value.
/// The flags enum value to check against.
/// whether the enum contains a certain flag
public static bool EnumHasFlag(TEnum toCheck, TEnum checkAgainst)
{
int checkAgainstInt = Convert.ToInt32(checkAgainst);
int toCheckInt = Convert.ToInt32(toCheck);
return (checkAgainstInt & toCheckInt) == checkAgainstInt;
}

///
/// Gets the flag enum list.
///
/// The flags.
/// The list of enum values contained in the flag
public static List GetFlagEnumList(TEnum flags)
{
List result = new List();
var enumValues = (TEnum[])Enum.GetValues(typeof(TEnum));
foreach (var enumValue in enumValues)
{
if (Convert.ToInt32(enumValue) != 0 && EnumHasFlag(flags, enumValue))
{
result.Add(enumValue);
}
}
return result;
}
}
}

Friday, July 17, 2009

.NET Runtime version 2.0.50727.3053 - Fatal Execution Engine Error – VS 2008 Crashing with Web Site Project

Visual Studio 2008 Development Team Edition kept crashing when opening a certain solution.  I looked in the event viewer and saw this:

temp

I tried unloading and reloading each project in the solution individually to see which project was causing the problem.

After a while of Googling, I found others who had unistalled ReSharper and had success.  That didn’t work for me.  After a little bit more searching, I found someone who had success unistalling PowerCommands for Visual Studio.

That worked for me.  Hope that helps someone reduce brain damage from bashing their head against the wall.

Happy Coding!

Thursday, July 16, 2009

Triple DES Encryption implementation compatible between Java and .NET!

One problem that I have had to solve in the past was making encryption between Java and .NET possible.  Specifically, I was charged to read an encrypted query string parameter from a Java system in my ASP.NET application.  After a few iterations of incompatible implementations, I created an implementation in both .NET (c#) and Java to ensure compatibility.

Since this caused me so much pain, I thought I would share my implementation with you in hopes that it will work for you as well.

Let me know if you have any questions or want to provide a decrypt implementation for the java class.

DOWNLOAD C# CLASS FILE

DOWNLOAD JAVA CLASS FILE

 

.NET (C#) Implementation

/// <summary>
/// Encryption utility class that implements Triple DES algorithm
/// </summary>
public class TripleDESImplementation
{
    //Encryption Key
    private byte[] EncryptionKey { get; set; }
    // The Initialization Vector for the DES encryption routine
    private byte[] IV { get; set; }

    /// <summary>
    /// Constructor for TripleDESImplementation class
    /// </summary>
    /// <param name="encryptionKey">The 24-byte encryption key (24 character ASCII)</param>
    /// <param name="IV">The 8-byte DES encryption initialization vector (8 characters ASCII)</param>
    public TripleDESImplementation(string encryptionKey, string IV)
    {
        if (string.IsNullOrEmpty(encryptionKey))
        {
            throw new ArgumentNullException("'encryptionKey' parameter cannot be null.", "encryptionKey");
        }
        if (string.IsNullOrEmpty(IV))
        {
            throw new ArgumentException("'IV' parameter cannot be null or empty.", "IV");
        }

        EncryptionKey = Encoding.ASCII.GetBytes(encryptionKey);
        // Ensures length of 24 for encryption key
        Trace.Assert(EncryptionKey.Length == 24, "Encryption key must be exactly 24 characters of ASCII text (24 bytes)");

        this.IV = Encoding.ASCII.GetBytes(IV);
        // Ensures length of 8 for init. vector
        Trace.Assert(IV.Length == 8, "Init. vector must be exactly 8 characters of ASCII text (8 bytes)");
    }

    /// <summary>
    /// Encrypts a text block
    /// </summary>
    public string Encrypt(string textToEncrypt)
    {
        TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
        tdes.Key = EncryptionKey;
        tdes.IV = IV;

        byte[] buffer = Encoding.ASCII.GetBytes(textToEncrypt);
        return Convert.ToBase64String(tdes.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length));
    }

    /// <summary>
    /// Decrypts an encrypted text block
    /// </summary>
    public string Decrypt(string textToDecrypt)
    {
        byte[] buffer = Convert.FromBase64String(textToDecrypt);

        TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
        des.Key = EncryptionKey;
        des.IV = IV;

        return Encoding.ASCII.GetString(des.CreateDecryptor().TransformFinalBlock(buffer, 0, buffer.Length));
    }
}

Java Implementation

public class TripleDesImplementation {
    private String key;
    private String initializationVector;
    public TripleDesImplementation(String key, String initializationVector)
    {
        this.key = key;
        this.initializationVector = initializationVector;
    }

    public String encryptText(String plainText) throws Exception{
    //----  Use specified 3DES key and IV from other source --------------
      byte[] plaintext = plainText.getBytes();
      byte[] tdesKeyData = key.getBytes();

      byte[] myIV = initializationVector.getBytes();

      Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
      SecretKeySpec    myKey = new SecretKeySpec(tdesKeyData, "DESede");
      IvParameterSpec ivspec = new IvParameterSpec(myIV);

      c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
      byte[] cipherText = c3des.doFinal(plaintext);

      return Base64Coder.encodeString(new String(cipherText));
    }
}

Wednesday, July 8, 2009

Managing Session State – Using A Strongly Typed Session Store

Download the example VS 2008 solution here.

As an ASP.NET developer, I’ve found myself in situations where I’ve needed to manage state for the current use by using Session.  I know that there are other ways to keep track of a user’s state aside from Session, and that the use of Session should be very used with discretion. The point of this post is not to say that any time you need to keep track of state in your web application that you should use Session, but rather to present one way of effectively managing this if you ever find that Session is something that you want or need to use.

In my experience, I’ve seen many issues with developers using Session ineffectively and dangerously.  Here are some common follies of using (or misusing) Session:  assuming that something is in Session when it may or may not be, mistyping of the string literal when placing something in or retrieving it from Session (e.g. Session[“UserId”] and Session[“UserID”] are not referencing the same thing), and accidentally having the same Session variable mean two different things.

I created a pattern in the form of a SessionRepository class that will hopefully alleviate some of these issues that are commonly found throughout ASP.NET projects.

This is an example SessionRepository property:

image

This is an example snippet of code that you write while using the SessionRepository:

 image

This gives us a uniform way of setting and getting things from the session without as much work that has to be done with casting and null checking.  It also gives uniform way of removing from the session.  We also are able to easily find all references to a given session variable without having to search our entire solution for strings.  We can just right click on the property and click ‘Find All References,’ and we’re done.

I’ve included a link to an example VS 2008 Web Application project that uses this pattern.  Refer to the SessionState folder within the project.  Hopefully this will prevent some of the head banging that I’ve experienced while working with Session.  Happy Coding!

image

Download it here.

Tuesday, July 29, 2008

Managing Your Different Environments Using External Configuration Files

Download Example Solution: Click Here

One thing that I have found as I have worked for my current employer and worked on a large-scale web application is that configuration files can get hairy.  This has proven to be especially true as we have managed the different configurations for our different environments (development, integration, staging and production).

Our web.config files have grown to about 1000 lines, which becomes a bear when you have to make sure that 4 of those files are in sync.

 

External Config Files To The Rescue

Recently I stumbled upon the beauty of external configuration files, which has made me realize that I can isolate the configuration settings that change and only worry about managing those changes in each of the configuration files and not the entire set of configuration settings.

You may put all of your external configuration files in the root folder along with your web.config, but I'm warning you that this can get ugly in a hurry the more environments you have and as the sections of the configuration file you are breaking out.  I recommend making a sub-folder that will hold all of your external config files and reference them by prefixing the configSource with your sub-folder (e.g. configSource="Config\ConnectionStrings.config").  You may then use folders to organize the different types of configuration settings as well.

 

image

 

Keep in mind as you use external config files that you have to have a separate configuration file for each section of the configuration file that you break out.  You also can only specify an external config file at certain levels of the configuration file.  For example, you can't specify an external configuration file for the entire System.ServiceModel section of your config file.  However, you can specify an external config file at the client level under the System.ServiceModel section.

image

Download

Download the example project to see how you might us these external configuration files:

Click Here

Monday, July 28, 2008

When In Doubt, Regen The Proxies

As I've worked with web services, mainly WCF services, I've run into some really funky problems as I've consumed services that have made me want to rip my hair out.  Hopefully this little bit of advice will help many developers keep more of their hair intact.

Update your service reference before getting too far into trying to diagnose the problem:

image

This is often required when a namespace changes in the service code even if none of the method signatures have changed.  This has usually been the case when the service is mysteriously returning null when you know it shouldn't.

Cheers!

Tuesday, July 8, 2008

A Count Down Asp.NET User Control

Download Example Here:

Count Down Test Web Application

Recently at work, I did some work on our website that would alert our users that the website would be going down soon.  The customer wanted "count down" functionality that would give users an idea of how long they have until the site goes down as the time to take the website down approaches.

image

I figured there would be someone who had already done this sort of thing, so I went to Google.  I found an article by Robert Hashemian at http://www.hashemian.com/tools/javascript-countdown.htm that explains how you would create a count down timer with JavaScript.  His example was pretty slick, but I wanted to create a user control in .NET that I could just set the time of when the timer should expire and forget about all the JavaScript under the covers.  So I did just that.

At first I tried to use Mr. Hashemian's way of setting the ending time in the JavaScript and figuring out how much time was left there, but the problem I found was that the time was dependant on the browser's time, so I decided to change the way the initial number of seconds is determined.  Instead of setting the time in JavaScript, I decided to count how many seconds were left until the target time and just set the number of seconds in JavaScript, so the functionality wouldn't be disrupted by time zone differences.

Anyway, after some work, all I had to do was put the user control tag in my page and set the time in the code behind like so:


            this.countDown1.TimeToEnd = DateTime.Now.AddHours(1.02);

            this.countDown2.TimeToEnd = new DateTime(2050, 1, 1);

I've created a sample web app that uses this control shown in the examples above.

Download Here:

Count Down Test Web Application

Wednesday, June 25, 2008

Running Batch Jobs In An ASP.NET Web Application Using Application State

Download Example Files:

Sample Run Job Web Application

 

Recently while doing work for a client, I came across the need to run a job (batch) within the application while giving the user that ability to monitor the progress of the job and also being able to track how much time was remaining until the completion of the job.

Along with the aforementioned specs, the requirements were as follows:  they needed a web page that they could go to in order to start the job, they needed the website to be able to alert them if another job was being run, they needed to be able to cancel the job at any time.

I assume that this is a common need for businesses and would like to share a simple example that illustrates how one might go about solving such a problem.

image

How I Did It

Since I didn't want to create a database or something similar to handle such a task due to the overhead that it takes to create a database, I decided to store information about my 'job' in the Application State object (which is essentially a HashTable) due to the fact that Application State object could be accessed and modified across the entire application.  This way, anyone, regardless of who started a job, would be able to access the information regarding the job.

The meat of my solution lies in two things: The BatchRun class that I created (Figure 1), and the use of a special property that accesses the Applicaiton State object within my page (Figure 2).

 


 

    [Serializable]

    public class BatchRun

    {

        #region Constructors

 

        public BatchRun()

        {

        }

 

        public BatchRun(int totalNumberOfItems)

        {

            TotalNumberOfItems = totalNumberOfItems;

        }

 

        #endregion

 

        #region Properties

 

        public DateTime? LastUpdatedTime { get; set; }

        public DateTime? StartTime { get; set; }

        public int TotalNumberOfItems { get; set; }

        public int ItemsCompleted { get; private set; }

        public bool ShouldStop { get; set; }

 

        public bool HasNotBegun

        {

            get

            {

                return StartTime == null;

            }

        }

 

        public bool IsCompletedOrExpired

        {

            get

            {

                return PercentDone == 100 || ShouldStop || (LastUpdatedTime != null && LastUpdatedTime.Value < DateTime.Now.AddMinutes(-Settings.Default.StalledMinuteWait));

            }

        }

 

        public int PercentDone

        {

            get

            {

                if (TotalNumberOfItems == 0)

                    return 0;

                return (int)(100 * ((double)ItemsCompleted / (double)TotalNumberOfItems));

            }

        }

 

        private TimeSpan? TotalTime

        {

            get

            {

                if (StartTime == null)

                    return null;

                return DateTime.Now - StartTime.Value;

            }

        }

 

        public TimeSpan EstimatedTimeRemaining

        {

            get

            {

                if (ItemsCompleted == 0 || TotalTime == null)

                    return default(TimeSpan);

                return TimeSpan.FromSeconds(

                (int)((TotalTime.Value.TotalSeconds / ItemsCompleted) * (TotalNumberOfItems - ItemsCompleted)));

            }

        }

        #endregion

 

        #region Public Methods

        public void Start()

        {

            if (TotalNumberOfItems == 0)

            {

                throw new ArgumentException("Total Number of Items not set!", "TotalNumberOfItems");

            }

            StartTime = DateTime.Now;

            LastUpdatedTime = DateTime.Now;

        }

 

        public bool IncrementItemsCompleted()

        {

            if (ItemsCompleted < TotalNumberOfItems)

            {

                LastUpdatedTime = DateTime.Now;

                return (++ItemsCompleted == TotalNumberOfItems);

            }

            return true;

        }

        #endregion

    }

Figure 1

 

 


        protected BatchRun CurrentBatchRun

        {

            get { return (BatchRun)this.Application["CurrentBatchRun"]; }

            set { this.Application["CurrentBatchRun"] = value; }

        }

Figure 2

 

The BatchRun class keeps all of the information that you need to derive what percent of the job is complete as well as how much time is left.  As you can see, I've included some intelligent properties within the BatchRun class to make these calculations easier and uniform.

The special application state property allows you to just access and modify the information about the job without having to be thinking about where you are storing this data.

The rest of the solution is just hooking into this information to let the user know what the status of the job is.

Here's the entire code behind file for the batch run example web page (please note that not everything I've done here is optimal, but is merely to give an example of how one would accomplish such a task):

 


using System;

using System.Threading;

 

namespace RunJobWebsite

{

    public partial class _Default : System.Web.UI.Page

    {

        protected BatchRun CurrentBatchRun

        {

            get { return (BatchRun)this.Application["CurrentBatchRun"]; }

            set { this.Application["CurrentBatchRun"] = value; }

        }

 

        protected void Page_Load(object sender, EventArgs e)

        {

            if (!IsPostBack)

            {

                this.txtStartDate.Text = DateTime.Today.AddMonths(-1).ToShortDateString();

                this.txtEndDate.Text = DateTime.Today.ToShortDateString();

            }

        }

 

        protected void btnRunBatch_Click(object sender, EventArgs e)

        {

            SetBatchParameterTableVisibility(false);

 

            if (!CurrentBatchInProgress())

            {

                this.lblPercentage.Text = "0";

                this.lblTimeRemaining.Text = "Unknown";

                CurrentBatchRun = new BatchRun();

                var ts = new ThreadStart(RunBatch);

                var thread = new Thread(ts);

                thread.Start();

            }

            else

            {

                ShowAlert("Statement Batch Already In Progress");

            }

            timerBatchRun.Enabled = true;

        }

 

        private void RunBatch()

        {

            DateTime startDate = DateTime.Parse(this.txtStartDate.Text);

            DateTime endDate = DateTime.Parse(this.txtEndDate.Text);

 

            var tempDate = startDate;

            int i = 0;

            while (tempDate < endDate)

            {

                i++;

                tempDate = tempDate.AddHours(1);

            }

 

            CurrentBatchRun.TotalNumberOfItems = i;

            CurrentBatchRun.Start();

 

            tempDate = startDate;

            while (tempDate < endDate)

            {

                DoSomething(new Random().Next(1, 5));

                tempDate = tempDate.AddHours(1);

                if (CurrentBatchRun == null || CurrentBatchRun.ShouldStop)

                {

                    break;

                }

                CurrentBatchRun.IncrementItemsCompleted();

            }

        }

 

        private void DoSomething(int seconds)

        {

            Thread.Sleep(seconds * 1000);

        }

 

        private void SetBatchParameterTableVisibility(bool visible)

        {

            this.tblBatchParameters.Visible = visible;

            this.tblBatchProgress.Visible = !visible;

        }

 

        private bool CurrentBatchInProgress()

        {

            var batchRun = CurrentBatchRun;

            if (batchRun == null || batchRun.HasNotBegun)

            {

                return false;

            }

            return !batchRun.IsCompletedOrExpired;

        }

 

        protected void timerBatchRun_Tick(object sender, EventArgs e)

        {

            BatchRun currentBatch = CurrentBatchRun;

            if (currentBatch != null && currentBatch.HasNotBegun)

            {

                return;

            }

            if (currentBatch == null)

            {

                SetBatchParameterTableVisibility(true);

                return;

            }

            if (currentBatch.IsCompletedOrExpired)

            {

                if (currentBatch.ShouldStop)

                {

                    ShowAlert(String.Format("Statement Run Completed at {0}, but was cancelled.", currentBatch.LastUpdatedTime));

                }

                else

                {

                    ShowAlert(String.Format("Statement Run Completed at {0}.", currentBatch.LastUpdatedTime));

                }

                timerBatchRun.Enabled = false;

                SetBatchParameterTableVisibility(true);

            }

            else

            {

                this.lblPercentage.Text = currentBatch.PercentDone.ToString();

                this.lblTimeRemaining.Text = String.Format("{0:f2}", currentBatch.EstimatedTimeRemaining.TotalMinutes);

            }

        }

 

        private void ShowAlert(string alert)

        {

            Response.Write("<script>alert('" + alert + "')</script>");

        }

        protected void btnStop_Click(object sender, EventArgs e)

        {

            ShowAlert("Batch Run Stopped");

            if (CurrentBatchRun != null)

            {

                CurrentBatchRun.ShouldStop = true;

                this.timerBatchRun.Enabled = false;

                SetBatchParameterTableVisibility(true);

            }

        }

 

 

    }

}

 

Download Example Files:

Sample Run Job Web Application

Thursday, June 19, 2008

Hacking The Zune Podcast Feature To Give You Bookmarks For Your Audio Books

I got a Zune (www.zune.net) about a year and a half ago and have been quite happy with it. One of the major features that was lacking was the ability to save your place if you were listening to an audio book. I spend a lot of my time listening to self-help audio books and religious audio books. In order to keep track of my place in the audio book I realized I had two choices: just listen to one audio book and nothing else since the Zune remembers your last listening location, or have my audio books have many small tracks and try to remember the track that I was on.

As you can imagine, both of these methods have serious follies. I looked online to see if there was some sort of hack that could provide some sort of bookmark functionality, but didn't find anything of value. I did, however, stumble upon a forum post where someone suggested that you put your audio files into the Podcast section of your Zune. I realized that the Zune keeps track of your last listening location in each of your Podcast episodes. I immediately tried to drag files into the Podcast section of the Zune software, but it didn't take.

After a lot of investigation and trial and error, I found that marking the mp3 as an "ITUNESPODCAST" (iTunes podcast), if you drag it into your Zune software under music, it would immediately recognize it as a Podcast.

Here's how I did it:

First, download Mp3Tag (http://www.mp3tag.de/en/download.html), which is software you are going to want regardless. Mp3Tag makes it SOOO much easier to tag your mp3s with proper information about the album, artist, song, etc.


Second, you're going to want to change a couple settings to make Mp3Tag a little easier to use.

Set Mp3Tag so it doesn't annoy you every time you save mp3 tag information:

Under Tools-> Options-> Messages

image

Now make it so Mp3Tag will auto-save everything you change so you don't have to manually save every time you make a change:

Under Tools-> Options-> Tags

image


Third, open the mp3 you will want to add by either dragging it into Mp3Tag or using the open dialog.


Fourth, add the ITUNESPODCAST=1 extended tag to the mp3 by right-clicking on the mp3 in Mp3Tag and click on "Extended Tags..."

image

image

You can also set up your other tag info (you will mainly be concerned about the Title and Album information) for your Podcast file.


Fifth, just go to the 'Music' section of your Zune software and drag your quasi Podcast file into your Zune software, or put it where Zune will pick it up, and you now have a Podcast file that will save your place when you listen to it!