Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

11 April 2011

IIS6 to IIS7 - Catching Ajax errors

The way Ajax errors are sent to the browser has changed between IIS6 and IIS7. Errors used to be sent automatically and you could parse the XML on the client. Now, the developer is required to do a little more work because IIS traps the error and stops code execution before reaching the end of the method.
For example, the Ext JS Ajax call takes an object with 5 parameters: method, url, params, success and failure. The last parameter is a callback function that is executed if the server sends back a failure.
The good news is that you have to make a small change to the server-side code (only). Another piece of good news is that the code is generic - the snippet will work with most web methods.
To make it work, create a try... block around the code that may throw an error. (This example is written in C#.) Next, add the following catch block:

catch (Exception e) {
HttpResponse Response = HttpContext.Current.Response;
Response.StatusCode = 500;
Response.Write(e.Message);
HttpContext.Current.ApplicationInstance.CompleteRequest();
Response.End();
}

The code above intercepts the error and returns it to the client. If you already had Ajax code listening for failure, you will not have to change the client side at all.

Note: Special thanks to this blog post by Rick Strahl.

12 February 2010

C#: Add history to an ACT! Group (and contacts)

My current project requires interaction with ACT!, both retrieving and setting data. 
Working with the ACT! framework is an interesting experience.  The code is very verbose and requires some expertise to understand.  And it took me a while to realize that the best way to retrieve data is through the database, while using the framework to perform the updates.
The following method writes an email history to the database.  It is useful for when you need to record automated processes to groups in the database. 
The method takes a GUID as an argument, primarily because there are no unique naming constraints in the group list.

using Act.Framework;
using Act.Framework.Contacts;
using Act.Framework.Groups;
using Act.Framework.Histories;
using Act.Framework.Lookups;
using Act.Shared.Collections;
 
// simplified connection for multiple methods
privateActFramework actFramework() {
    string cn = ConfigurationManager.ConnectionStrings["actDb"].ConnectionString;
    string login = ConfigurationManager.AppSettings["actLogin"].ToString();
    string pwd = ConfigurationManager.AppSettings["actPwd"].ToString();
ActFramework f = newActFramework();
f.LogOn(cn, login, pwd);
 
    return f;
}
// adds email history to the database
public void AddEmailGroupHistory(string GUID, string subject, string body) {
 
    // create a disposable connection to the database

    using(ActFramework f = actFramework()) {
 
    // create a new group GUID array with one element
Guid[] gGuid = new Guid[] { new Guid(GUID) };
    // get a group list - the list will contain one group
GroupList gList = f.Groups.GetGroupsByID(null, gGuid);
    // get a contact list from the first group in the list
ContactList cList = gList[0].GetContacts(null);
    // creates an all-zero GUID
Guid activityClearedId = Guid.Empty;
    // creates a system type of Email sent
HistoryType hType = new HistoryType(SystemHistoryType.EmailSent);
    // the history is public
    bool isPrivate = false;
    // start and emd (duration) are equal
DateTime startEnd = DateTime.Now;
    // Create a new history object
History h = f.Histories.CreateHistory(cList, gList, activityClearedId,
hType, isPrivate, startEnd, startEnd, subject, body);
    // commit the history to the database
h.Update();
}
}

02 October 2009

Implementing PGP File Encryption in ASP.Net/C# Using GnuPG

I was recently asked to implement PGP encryption for a file before sending it to a vendor.  In performing my research, I found GnuPG to be the easiest solution to understand as well as posing the least amount of risk for implementation.  The great thing about GnuPG is that you can download it and the instructions are easy to follow for encrypting files.

Unfortunately, I also found are some challenges during the implementation.  The existing documentation on the web is also confusing and is old.  This post is an attempt to update the existing documentation to 2009, provide a working coded example, and give a quick and easy roadmap for implementing PGP in an ASP.Net project.
Step 1 – Download and install GnuPG (GPG)
The main GnuPG page is http://www.gnupg.org.  The Windows download can be found here.  The version I refer to in this post is GnuPG 1.4.10b.

Installing the GnuPG software is easy as it uses a standard installer. 

Note: Be careful when installing the application on the server.  Choose a Windows account that is generic to installations.  There is a mistake in the installation process where important application data is installed in the Application Data directory of the account performing the installation. 

You can find the files by installing GnuPG on your local machine and then looking in C:\Documents and Settings\[%Windows User Name%]\Application Data\GnuPG.  Several key files are installed there and you will need to reference this directory from the ASP.Net code.  This is the biggest ‘gotcha’ for the entire process.


Update (2011-01-12): For 64-bit servers, the directory is C:\Users\[user name]\AppData\Roaming\gnupg
Step 2 – Learn GPG
An excellent introduction to GPG has been written by Brendan Kidwell and can be found here.
You will find excellent instructions for installation and use in Windows and Linux.  Pay special attention to the GPG Cheat Sheet and make sure you successfully encrypt and decrypt files from the command line before proceeding with coding.
You will need to install any public keys needed for encryption before running the code, as well as understanding how to retrieve the name of the name of the key (using –list-keys) before running the C# below.
Step 3 – Implement the PGP Object
Following is the code that I use to encrypt files.  It is heavily indebted to an article at the Code Project on decrypting files by Kurt Mang.

using System;
using System.Diagnostics;
using System.IO;
using System.Security;

/// <summary>
/// File encryption wrapper.  Executes GNU PGP as described here:
/// http://www.glump.net/howto/gpg_intro
/// And downloaded from here:
/// http://www.gnupg.org/download/index.en.html#auto-ref-2
/// </summary>
public class PGP
{
/// <summary>
/// Path to the PGP software
/// </summary>
string _pgpPath = @"C:\Program Files\GNU\GnuPG\gpg.exe";

/// <summary>
/// The path to the PGP file can be changed (if needed) 
/// or executed
/// </summary>
public string PgpPath {
get { return _pgpPath; }
set { _pgpPath = value; }
}
/// <summary>
/// The home directory argument in GnuPG
/// </summary>
string _homeDir;
/// <summary>
/// The location of the PubRing and SecRing files
/// </summary>
public string HomeDirectory {
get { return _homeDir; }
set { _homeDir = value; }
}
/// <summary>
/// Public constructor stores the home directory argument
/// </summary>
public PGP(string homeDirectory) {
HomeDirectory = homeDirectory;
}

/// <summary>
/// Encrypts the file
/// </summary>
/// <param name="keyName">Name of the encryption file</param>
/// <param name="fileFrom">Source file to be encrypted</param>
/// <param name="fileTo">Destination file (after encryption)</param>
public bool Encrypt(string keyName, string fileFrom, string fileTo) {

/// File info
FileInfo fi = new FileInfo(fileFrom);
if(!fi.Exists) {
throw new Exception("Missing file.  Cannot find the file to encrypt.");
}

/// Cannot encrypt a file if it already exists
if(File.Exists(fileTo)) {
throw new Exception("Cannot encrypt file.  File already exists");
}

/// Confirm the existence of the PGP software
if(!File.Exists(PgpPath)) {
throw new Exception("Cannot find PGP software.");
}

/// Turn off all windows for the process
ProcessStartInfo s = new ProcessStartInfo("cmd.exe");
s.CreateNoWindow = true;
s.UseShellExecute = false;
s.RedirectStandardInput = true;
s.RedirectStandardOutput = true;
s.RedirectStandardError = true;
s.WorkingDirectory = fi.DirectoryName;

/// Execute the process and wait for it to exit.  
/// NOTE: IF THE PROCESS CRASHES, it will freeze
bool processExited = false;

using(Process p = Process.Start(s)) {
/// Build the encryption arguments
string recipient = " -r \"" + keyName + "\"";
string output = " -o \"" + fileTo + "\"";
string encrypt = " -e \"" + fileFrom + "\"";
string homedir = " --homedir \"" + HomeDirectory + "\"";
string cmd = "\"" + PgpPath + "\"" + homedir + recipient + output + encrypt;

p.StandardInput.WriteLine(cmd);
p.StandardInput.Flush();
p.StandardInput.Close();
processExited = p.WaitForExit(3500);
p.Close();
}
return processExited;
}

}


A couple of things should be noted about this object:
  • The constructor takes a HomeDirectory argument.  This is the Application Settings directory where the GPG application files have been installed. 
  • Obviously the Windows account that runs the ASP.Net code needs to have access to the executable as well as the ability to run executables and create files.
  • The code checks for the existence of the GPG executable, the source file and the destination file.  The reason is that the application can hang without throwing an exception if anything goes wrong.

26 October 2007

Things I learned about ASP.Net web services today

I have been writing a Web Service in C#/ASP.Net that manipulates PDFs, requires a long timeout period, and needs to perform some IO (moving files and cleaning up after itself). None of these things in themselves is difficult, but combined make for some hours of research.

Here are a few lessons I learned today, listed here for later use:

Lesson #1: File IO is not difficult to implement on a local XP machine, but can be tricky to get working. The application I am using uses the System.IO namespace, File.Move method, to rename files. When I first tried to get the application running, ASP kept returning the error 'Access denied to path.' A quick search around the net displays all kinds of answers, from editing the registry to granting IIS permission to the folder to adding the directory in question as a virtual directory.

For me, the answer turned out to be much more simple. My machine already had full access to the directories, so what was the source of the error. What I needed to do was add the identity tag to the Web.config file. The actual code is as follows (from an old MSDN article):

<configuration>
<system.web>
<identity impersonate='true'/>
</system.web>
</configuration>

I added this setting and then removed the permissions I had added before, and the File IO still worked on my machine. The implication is that the web service will impersonate the caller and have the same rights on the box as the rights of the calling application. Or anyway, that is what I imagine since the Web.Config documentation and my understanding of Windows security is lacking.

A long Microsoft explanation of impersonation can be found here.

Lesson #2: What happens if the service takes a long time to process?
If a service takes too long to process, the client will time out and you will either recieve an 'html/utf' error or a timeout error. The way to resolve this is as follows:
  1. In the client, add the System.Threading namespace to your calling class. When declaring your service variable, set the Timeout property of the Service to Timeout.Infinite, or the outer edge of what you expect the timeout to be in milliseconds. I usually use a calculation for millisecond settings, so I can quickly make the change. For instance, to set the Timeout property to 3 minutes, I would use myService.Timeout = 1000 * 60 * 3; 1000 milliseconds = 1 second, 60 seconds = 1 minute, for 3 minutes.

  2. The Web.config file will also need to be edited on the server. Use the httpRuntime tag and set the executionTimeout attribute to get the desired number of seconds in the timeout. No calculation is allowed as above. This tag also goes inside the system.web tag. Full Microsoft documentation of this tag can be found here.
I should mention that this application is an intranet application, so by definition all users have to be on a Windows network for these settings to be relevant to another environment.

23 October 2007

Some Useful Regular Expressions

I've been sifting through a lot of strings lately and experimenting with the C#/.Net RegularExpressions name space. I have been extracting the string values from PDF files and then using the strings to make database calls.

The challenge has been to clean up the strings as the PDF software I am using doesn't do any cleanup for me when transporting the string back to C#.

The expressions I have been using are as follows*:

Regular Expression: @"^[!""#$%&'()*+,-./:;?@[\\\]_`{|}~0-9]+"
Purpose: Remove non-alpha characters from the start of a string.

Regular Expression: @"[!""#$%&'()*+,-./:;?@[\\\]_`{|}~0-9]+$"
Purpose: Remove non-alpha characters from the end of a string.

Regular Expression: @"[^ -~’]"
Purpose: Remove unprintable characters from string.

Regular Expressions: "[^0-9]"
Purpose: Remove non-numerical characters from a string. (via AnimaOnline)


For a useful Regular Expression tool, check out the RegExLib.com site that has a convenient .Net tester.

* @ in front of string to mark it as a literal

18 October 2007

C#: Using foreach with an generic list (List<t>)

The List is a fantastic class for working with lists and arrays in C#, but it does not directly expose an iEnumerator to allow the foreach command to iterate through the collection. Until today, I would use the for...next structure to cycle through the collection to access each item.

The List also exposes a ForEach method which delegates the ForEach to another method. This is good for some applications that need to share the functionality - and while I understand the use from an OO perspective - can decrease the readability of the code.

There is a better way that can make the code readable and exposes the iEnumerable method.

The List method also exposes the ToArray() method. Use this method to access the items in the collection. For instance, if you have a List<t> called strings, you can write the code as follows:

foreach(string s in strings.ToArray()) { ...looping code here... }

24 September 2007

Enumerating the Enumerator

One of the joys of switching from Visual Basic to C# is the finding out about the power of the enumerator class. VB has fair enumerator support, but C# takes it to a whole new level with the enumerator class and all of it's methods.

Like VB, you can declare an enumerator and each value can have a custom numeric value. Like VB, you can declare and pass enumerator's as method arguments, which makes code very clear and easy to write.

But C# takes the enumerator many steps farther. First, the toString() method of the enumerator class prints out the actual string of the enumerator. This means that you can use it in string and numeric representations of the value.

One of the most valuable operations an enumerator class implements is the ability to inspect the class for membership. This helps make code more flexible because additions or changes to the enumerator class can flow through to other parts of the program.

For example, let's say you have a database enumerator that indicates what the database is doing at this time. This enumerator will be used for monitoring asynchronous calls to a database. The enumerator declaration would look like the following example.

Example 1: Sample Enumerator Declaration

public enum AsyncDBAction : int {
    insert,
    update,
    delete
}


Inspecting the enumerator object is very simple. In the example below, I use a foreach loop to iterate through the object and print individual member values to the console. The console will display the string representation and the numeric value for each enumerated member.

Example 2: Iterating through the Enumerator
foreach(AsyncDBAction val in Enum.GetValues(typeof(AsyncDBAction))) {
    Console.WriteLine("String value: " + val + "/numeric value " + (int)val);
}


How is this useful? If you are using the string value and the numeric value (or enumerated value), adding a new enumerated value such as 'select' or 'other' will not break your code. Simply add the new value to the enumerator and then examine it where needed to continue processing.