Monday, June 7, 2010

Using Tasks to Redirect Output from Spawned Process

Here’s a small trick I found useful. I recently wrote a tool that performs an ‘xcopy’ backup of the source files in my visual studio projects directory. The tool is a command line application that spawns a few other command line applications (xcopy for one) and redirects their output to its own standard output. Since some spawned processes are long running, I want to show their output as they run, I created a static method that does it all using the Task class from the .Net 4 framework.

Code Snippet
  1. static int SpawnAndRedirect(string command, string args)
  2. {
  3.     Process process;
  4.     ProcessStartInfo processStartInfo;
  5.     processStartInfo = new ProcessStartInfo(command, args);
  6.     processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  7.     processStartInfo.RedirectStandardOutput = true;
  8.     processStartInfo.UseShellExecute = false;
  9.     process = Process.Start(processStartInfo);
  10.  
  11.     /* Start a background task that copies the spawned process
  12.      * standard output stream to our own standard output stream */
  13.     Task.Factory.StartNew(() =>
  14.     {
  15.         process.StandardOutput.BaseStream.CopyTo(Console.OpenStandardOutput());
  16.     });
  17.  
  18.     process.WaitForExit();
  19.     return process.ExitCode;
  20. }

Monday, May 31, 2010

Configuring Self-Hosted WCF Service with Transport Security (HTTPS)

I just finished what was a four-day nightmare trying to configure a self-hosted WCF service using wsHttpBinding with transport security (meaning it uses an https:// URL), with locally generated test certificates. This all happened on Windows 7 Professional, with Visual Studio 2010 Professional.

The following tools were used in this process:

  • makecert
  • netsh
  • mmc

Here are the steps:

  1. Create a self signed root certificate.
  2. Install the root certificate in the Trusted Root Certification Authorities store of the client and server machines (the same machine in my case).
  3. Create a signed service certificate.
  4. Install the service certificate in the Trusted People store of the client machine.
  5. Associate the service port with the service certificate.
  6. Configure the service.
  7. Configure the client.

Steps 1 through 4 were taken from the WCF Security Guidance codeplex site, from the How To – Create and Install Temporary Certificates in WCF for Transport Security During Development page.

Create a Self Signed Root Certificate

Run the following command:

makecert –n “CN=<<AnyName>>” –r –sv <<AnyName>>.pvk <<AnyName>>.cer

The <<AnyName>> may be different for the 3 occurrences but just for convenience, use the same one. I used RootCATest for mine, and I’ll use that for reference throughout the rest of the post.

image

Install the Root Certificate

Start the Microsoft Management Console by running the command mmc.

image

From the “File” menu select “Add/Remove Snap-in…”

image

On the left, select “Certificates”, and click the “Add >” button.

image

Then check the “Computer account” option (if you are not an administrator of your machine, you may have to settle for “My user account” – but I haven’t tested that).

image

Finish the wizard with the default selections and press “Ok” on the “Add or Remove Snap-ins” dialog.

Expand the “Certificates (Local Computer)” node, right click the “Trusted Root Certification Authorities” node and select “All Tasks –> Import…”. Use the wizard to browse for the certificate file you created in the previous step (RootCATest.cer in this example) and continue with all the default options.

Eventually you should see something like this on the left side:

image

And this on the right side:

image

Create a Signed Service Certificate

Run the following command:

makecert –sk <<KeyContainerName>> –iv RootCATest.pvk –n “CN=localhost” –ic RootCATest.cer –sr localmachine –ss my –sky exchange –pe localhost.cer

Use any name for <<KeyContainerName>> it has no significance. I chose “MyKeyName”:

image

This is taken as is from the howto page, but one thing needs to be stressed (this stumped me for hours because I missed it when reading the howto). The certificate’s subject name (specified with the –n switch) should be the same as the dns entry of the machine running the service. In the case of a single machine used for both the service and the client, using self-hosting, this must be “localhost” (Or rather “CN=localhost” for the command).

Install the Service Certificate

Installing the service certificate is done similarly to installing the root certificate, except it should be stored in the “Trusted People” store.

Associate Service Port with Certificate

Run the following command:

netsh http add sslcert ipport=0.0.0.0:<<port>> certhash=<<certificate thumbprint>> appid={00112233-4455-6677-8899-AABBCCDDEEFF}

Substitute <<port>> for the TCP/IP port number on which your service is configured to listen. To obtain the certificate thumbprint use the MMC tool again, double click on the service certificate in the “Trusted People” store to open its property pages, go to the “Details” tab, click the “Thumbprint” entry and copy the hex codes that appear at the bottom:

image

Use a text editor to remove all the spaces, and substitute that for the <<certificate thumbprint>> above. Here’s what it looks like in my example:

image

The “appid” argument is irrelevant for now, and may be any valid GUID value.

Configure the Service

Here is the “app.config” file I used in my example. It is nothing special, but note several things:

  • httpGetEnabled=”false” – Necessary for HTTPS metadata exchange (mex)
  • security mode=”Transport” and clientCredentialType=”None” – Since my example needs to run in partial trust, I didn’t use any message security or any client credentials. This may be changed if running in full trust.

<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceMetadata httpGetEnabled="false"/>
<serviceCredentials>
<serviceCertificate
findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="MyBinding">
<security mode="Transport">
<transport
clientCredentialType="None"
proxyCredentialType="None"
realm=""/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service
name="eftest.MyService"
behaviorConfiguration="MyBehavior">
<endpoint
address=""
binding="wsHttpBinding"
contract="eftest.IItemServices"
bindingConfiguration="MyBinding">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress=
"https://localhost:8733/MyService/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>

Configure the Client

Again, here is the “app.config” I used in my client configuration.

<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="MyBinding">
<security mode="Transport">
<transport
clientCredentialType="None"
proxyCredentialType="None"
realm="" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ServiceCert">
<clientCredentials>
<serviceCertificate>
<authentication
certificateValidationMode="PeerTrust"
revocationMode="NoCheck"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint
address="https://localhost:8733/MyService/"
binding="wsHttpBinding"
bindingConfiguration="MyBinding"
behaviorConfiguration="ServiceCert"
contract="MyService.IItemServices"
name="MyEndpoint">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
</client>
</system.serviceModel>

Monday, May 3, 2010

Non-Echoing Console Input

I recently stumbled upon the need to create a small console application that reads in a password from the user. Naturally, I didn't want the password to be echoed back into the console as it was typed, luckily there's a static method called ReadKey in the Console class, but in order to read a whole string, some acrobatics is required:

string ReadPassword()
{
    string passwordString;
    List<char> chList = new List<char>();
    ConsoleKeyInfo cki = Console.ReadKey(true);
    while (cki.Key != ConsoleKey.Enter)
    {
        if (cki.Key == ConsoleKey.Backspace)
        {
            if (chList.Count > 0)
                chList.RemoveAt(chList.Count - 1);
        }
        else
            chList.Add(cki.KeyChar);
        cki = Console.ReadKey(true);
    }
    passwordString = new string(chList.ToArray());
    return passwordString;
}

Monday, April 12, 2010

Regular Expressions in C#

Recently, while spending time in the .NET forums, I have come across an inordinate number of questions regarding regular expressions, which often sparked the usual religious argument between the proponents and opponents of regular expressions. One of the more widespread stances regarding regular expressions is that they are bad, and lead to unnecessarily unreadable and, in inexperienced hands, inefficient code. While there is some truth to this, regular expressions are no worse than the goto command, the if command, or any command for that matter; i.e. if used correctly, it can save time and enhance readability.

The thing to remember is that regular expressions are a field unto their own, and that it requires some expertise to use them right, as well as to properly judge when to use them at all. Two of the main misuses for regular expressions that I've encountered are:

  • Discovering their usefulness for a particular task, and then using them everywhere, just because you can.
  • Attempting to use regular expressions to parse structured text, such as a programming language, or XML.

To use regular expressions correctly, I follow these rules of thumb:

  • Keep the regular expressions short, don't let them span more than one line. But also remember not to compress them too much just so that they fit on one line. Keep them readable.
  • Use them only when necessary, if a concise, readable and efficient alternative exists to regular expressions, use that instead.
  • Use named capture groups where possible, to give semantics to the expressions.
  • Write comments regarding the expression, and include some examples of what it is expected to match and to reject.

Thursday, April 8, 2010

Introduction

For years I've been meaning to get me a blog, as sometimes I have ideas which are not good enough (or comprehesive enough) to warrant a CodeProject article, but which are also not small enough to deserve to disappear in page number >=2 in the forums which I visit.

This blog is for programmers, and mainly for .NET in general and the C# language. I personally have been writing code since the age of 9, when I got my first computer (Commodore VIC-20). That computer didn't come with any storage device, so at the end of the day I copied what I wrote using pencil and paper, and the next day I would type it all back in again, and continue coding... Things have changed slightly since then :-)

Anyway, I hope you find this blog interesting!

Aviad P.