Tuesday, May 25, 2010

How to add a default value to column in T-SQL (SQL Server)

If you have a Not Null column in SQL Server and you want have a default value you can add that at any time. The most difficult situation I have seen is doing it when you want the default to be the current date.

In the example below I have a table called Person and a column CreatedDateTimeUtc that I want to default to the current utc date if the value is null. This will occur on both update and insert.

ALTER TABLE [dbo].[Person] ADD  DEFAULT (GetUtcDate()) FOR [CreatedDateTimeUtc]

Monday, May 17, 2010

Unit Testing Asynchronous calls in Visual Studio 2010

I am simply amazed how much effort I had to go through to figure out how to test asynchronous calls in Visual Studio 2010 (VS2010). In the end, I was able to figure it out with the help of some blogs that I read.

VS2010 ships with integrated Unit Testing which I would like to take advantage of. I am writing a Silverlight application that calls a Windows Workflow Foundation service that I implemented using the WCF Workflow Service Application. I really like it, but I want to be able to unit test the workflow service.

The only way I found to test a WCF Workflow Service Application that I could find was to add a Service Reference to my Unit Test project. This is good for me because that is how Silverlight will call it. The problem is that the WCF Workflow Service Application can’t be called synchronously. So, we have to call it Asynchronously. The problem is that the Unit Test framework used in VS2010 does not support Asynchronous calls in  a Unit Test. Well, it runs, but doesn’t wait for the response to the Async call, so the test is pretty worthless.

Now that you know what I am trying to do, here is what I found as solutions.

Option 1: Simulate Synchronous call using an Asynchronous call

Here is a class I created to simplify the process of make an asynchronous call appear to be synchronous.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MyApp.Tests
{
public class AsyncTest
{

// max number of milliseconds to wait for an asynchronous call
int timeout = -1;

public AsyncTest()
{
// if debugging, make it a much larger like infinity
if (System.Diagnostics.Debugger.IsAttached)
{
timeout = -1; // infinity (wait for ever)
}
else
{
timeout = 20 * 1000; // 10 seconds
}
}

public AsyncTest(int timeout)
{
this.timeout = timeout;
}

// we'll use this to make the current thread wait until our asynchrous call finishes
ManualResetEvent block = new ManualResetEvent(false);

// we'll use this to flag if/when our async call finishes
bool isAsyncDone = false;

public void Done()
{
isAsyncDone = true; // flag that we are done (do NOT do this after calling block.Set() this will cause race conditions!!!!)
block.Set(); // tell the calling / this thread that it can continue now.
}

public void Wait()
{
block.WaitOne(timeout, false); // wait until block.Set() is called or the timeout expires (which ever comes).
Assert.IsTrue(isAsyncDone, "Test took too long"); // if it took too long then report it to the test framework.
block.Reset(); // set the event to non-signaled before making the next asynchronous call.
}
}
}

Here is an example of how you would use it to create a method that acts like a synchronous method, but calls an asynchronous WCF Service.

public GetWorkflowStatusCompletedEventArgs GetWorkflowStatus(long requestID)
{
AsyncTest at = new AsyncTest();

GetWorkflowStatusCompletedEventArgs returnedArgs = null;

// setup our service reference and callback for when it is done
ServiceClient wf = new ServiceClient();
wf.GetWorkflowStatusCompleted += delegate(object sender, GetWorkflowStatusCompletedEventArgs e)
{
returnedArgs = e;
at.Done();
};


wf.GetWorkflowStatusAsync(requestID);
at.Wait();

return returnedArgs;
}

I created one of these methods for each of the asynchronous methods I wanted to test. In fact I created a helper class to hold them. Now, in my class that has all my tests in it, I just call the methods on this helper class which are synchronous. Now the test run properly.

For completeness, here is what the unit test (testmethod) would look like.

[TestMethod]
public void TestCanGetWorkflowStatusTwiceInARow()
{
var status = Helper.GetWorkflowStatus(1234);
Assert.AreEqual<long>(status.RequestID, requestData.RequestID, "The wrong request id was returned.");
Assert.IsTrue(status.RequestID > 0);
}
Now I can write a unit test just as easily as I do any other unit test. The synchronous / asynchronous issue is encapsulated in a helper class. I like it. Not much extra work either. Especially since each helper method I write is almost identical. It could be generated if desired (using CodeSmith, etc).
I wish I could take credit for all this, but I can’t. The solution / implementation is completely mine, but the underlying technique is borrowed. For more info on those links, see here:

Option 2: Use the Silverlight Unit Test Application

I think this method is a reasonable approach, but for testing a WCF Service, it seems a bit unnatural to me. I like Option 1 better because I want my test results to be managed in VS2010. If nothing else other than no browser opens and also that you can block check-in of code if tests fail. The integrated Unit testing just seems a bit more integrated with VS2010.
I do think the Silverlight Unit Test Application is a great testing technology. However, I think it is best and most natural for testing Silverlight applications, not the web services they call.
There are lots of good blogs on the subject, so I won’t repeat it here. Here are some of the blogs that I found particularly useful when I went down this road.

Tuesday, May 4, 2010

Getting Current User when using WCF and Silverlight

First off, when you start to create a WCF Service in Visual Studio 2010 or 2008 for that matter, you can choose WCF Service, but if you are using Silverlight as the client, you do NOT want to select this. You want to select, Silverlight-enabled WCF Service. If you don’t or didn’t you can follow the instructions here to make sure a few things are in place and then you will be in the same position as if you had selected the Silverlight-enabled WCF Service.

All I want to do is get the username of the user that is using my Silverlight application. Note, this also opens the door to ASP.NET roles.

Alot of what I read said that if I mess with my app.config and turn on transport or message security then I can get the user if I go to System.ServiceModel.ServiceSecurityContext.Current. Well, maybe that was for a Self-Hosted WCF service or some other scenario, but I could not get it to work in my tests with Silverlight with IIS hosted WCF Service. I think my biggest difficulty with these docs were that all the configuration tags that I expected to see in the web.config (they had an app.config) were not there, but yet I had a working (without security) WCF Service.

I had to assume it uses some defaults. I figured out that I was right. If you read A Developer's Introduction to Windows Communication Foundation 4 you will understand much better. It is a fairly lengthy read, but well worth it. There is actually a section on Workflow Foundation 4, but the first part of the article is most excellent in describing the defaults and how they work. For instance search it for ProtocolMapping to see that the defaults include basicHttpBinding, netTcpBinding, netNamedPipeBinding, and netMsmqBinding. They are defined in the Machine.config. WCF 4 also support inheritance / merging of configuration items. Very cool.

I am using an IIS hosted WCF service. I want to use Windows Authentication for authentication. Nothing fancy. What I found works well and quite easily is ensure the following things are in specified and in synch with each other. They must all agree!

Web Server
  • IIS has anonymous access disabled (not enabled).
  • IIS has Integrated Windows authentication enabled.
  • If you are using Visual Studio 2010 and using the built-in dev server, the default settings are fine. I did NOT have to check the NTLM Authentication checkbox.
Web.config
  • This is needed to have ASP.NET be able to get security info as well.
<system.web>
<authentication mode="Windows"/>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
  • Make sure you have aspnet compatability enabled as follows:
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"  aspNetCompatibilityEnabled="true"/>
Your Service Class
  • Make sure to add the following above your class for your WCF Service. You can also use Required, instead of of Allowed
    [AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]

And now the moment of glory. You can now get the user just like you would in ASP.NET.

System.Web.HttpContext.Current.User.Identity.Name

References: A Developer's Introduction to Windows Communication Foundation 4

Tuesday, April 27, 2010

Creating a LogError Activity

Surprisingly, in Visual Studio 2010 there is not an Activity in Windows Workflow Foundation (WF) 4.0 that writes an error to the Windows Event Log / Viewer. The good news is that it is very easy to write. Below are the instructions for creating one.

Step 1: Add new Code Activity

Add a new Code Activity called LogError to your Workflow project (This could be any of them, but I recommend putting your Activities in an Activity Library project.).

Step 2: Modify Code Activity to look similar to the following example

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

namespace MyApp.MyActivities
{

public sealed class LogError : CodeActivity
{
// Define an activity input argument of type string
public InArgument<string> PreMessageText { get; set; }
public InArgument<Exception> Exception { get; set; }

protected override void Execute(CodeActivityContext context)
{
Log(PreMessageText.Get(context), Exception.Get(context));
}

public void Log(string preMessageText, Exception ex)
{
string sourceName = "My App";
string logName = "Application"; // i.e. System, Application , or other custom name

if (!EventLog.SourceExists(sourceName))
{
EventLog.CreateEventSource(sourceName, logName);
}

string message = string.Empty;
message += ex.Message + "\r\n";
message += ex.StackTrace;

EventLog.WriteEntry(sourceName, preMessageText + "\r\n" + message, EventLogEntryType.Error);

}
}
}

To use the Activity just compile your project. It will then show up in your Toolbox. You will probably want to drag a TryCatch Activity onto your workflow. Then drag the LogError Activity we created to the Exception section of the TryCatch Activity. Set the Exception property to the argument name in the Exception section.

Misleading error message in Windows Workflow Foundation 4.0

If you are running a Windows Workflow Foundation 4.0 (in Visual Studio 2010) and you are testing it with the WCF Test Client and you get a message similar to the following:

Failed to invoke the service. Possible causes: The service is offline or inaccessible; the client-side configuration does not match the proxy; the existing proxy is invalid. Refer to the stack trace for more detail. You can try to recover by starting a new proxy, restoring to default configuration, or refreshing the service.

The operation could not be performed because WorkflowInstance 'cb123a26-34bd-4ab8-876f-63dee2080b42' has completed.

Server stack trace:

   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)

   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)

   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)

   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:

   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)

   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

   at IService.GetData(String inParameter1)

   at ServiceClient.GetData(String inParameter1)

The good news is that if you have not messed with bindings, etc, and you made a simple change to the workflow and your service started throwing this exception, it is likely the message is just misleading. I have concluded that you will get this message anytime an exception is thrown during the execution of the workflow. This could be something as simple as a null pointer or much more complex.

The question is how do we figure out what the real exception is. A more important question is how do we catch and log these exception. Without the logging, we won’t know if our users are having issues and how have a clue what the cause is.

One way to address this issue is to Use the TryCatch Activity in Windows Workflow Foundation (WF) Designer in Visual Studio 2010. This works just like a try-catch-finally would work in C#. You can create a custom Code Activity called something like LogError. Click here for details on creating this custom Activity. You can then use it in the catch portion of the TryCatch activity.

You can put the TryCatch Activity at the highest level in your workflow to server as a catch all or you can use it particular points in your workflow. Just like when coding, it is often appropriate to do both.

Now when you try to run test your Workflow you will see your error in the Windows Event Log / Viewer. Since the workflow didn’t return the expected response, you still get this generic / useless error, but at least you know the cause now.

If after all this, there is no exception being thrown then it is likely you are trying to send an message to your workflow that is not valid. By not valid, I mean it could be that the Message you are sending is not to the Current Message. Consider the case where you have 2 ReceiveRequest Activities and they are in a Sequence. If you try to send a Message to the second one before the first one this is not valid. Why? Because they are in a sequence. The first Activity must complete before the second one can be executed. That is the vary nature of a workflow. If you need them to be able to be called regardless of the sequence, then you should probably use the Parallel Activity.

Lastly, if you are executing the Activities in order and still getting the error, make sure you are referencing the same CorrelationHandle and that you have specified a key for it to use as the correlation object. This is essentially a primary key for an instance of the workflow. IN WF3 this was the workflow id. In WF4, you can use a key in your data or you can use a GUID like WF3 did, but in any case, you need to tell all your Receive Activities what you want to use to make the correlation. If you don’t have a correlation handle and key defined then WF4 will have now way of telling what instance of the workflow you are trying to access.

Wednesday, April 14, 2010

SharePoint stsadm.exe export / import issues

I am exporting a web from WSS 3.0 64-bit with https and importing to MOSS 2007 32-bit with just http on another server. I ran into some errors issues along the way. Here is what I ran into and how I got around it.

Keep in mind, the export/import commands work on the specified site AND ALL SUB-SITES, not just the one you specify.

Exporting the Site

I wanted to export the security, all versions, etc so that I have EVERYTHING that was on the SharePoint web (site). Here is the commend I used:

c:
cd "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\"
stsadm -o export -url https://yoursite/level1/level2/yourSiteHere -filename c:\yourSiteHere -includeusersecurity -haltonwarning -haltonfatalerror -versions 4 –nofilecompression

This will create a directory: c:\yourSiteHere. There are lots of files, etc so you may want to zip the directory if you are moving it to another server because copying one file is much faster than many small ones.

You can remove the –nofilecompression switch, but you may need to edit some of the files in the directory later, and I couldn’t get it to work with the import. I suspect because I had multiple files created when it exported.

Import the Site

Once you copy and unzip the directory to your new server (or same on if you want to).

Tip: When you unzip it be sure that the contents are just as they were on the other server, and not in a parent folder as Windows unzip typically does. Move the folders around to correct this or adjust the path below when you execute the command.

Best case is the following command will work and there is nothing more to do.

c:
cd "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\"
stsadm -o import -url http://yourNewServer/newLevel1/yourSiteHere -filename C:\yourSiteHere -includeusersecurity –haltonwarning -haltonfatalerror -updateversions 1 –nofilecompression

NOTE: I used updateversion 1 instead of updateversions 2. I couldn’t get updateversion 2 to work because it coudn’t delete one of the files. Using 1 instead will only add to the files, not delete and replace the files that are there. Since this site has never been on this server, I think updateversions 1 works well.

You an use any path on the new server you want. It doesn’t have to be the same as the one on the previous server.

Import Issues?

You may run into some issues importing.

You may get some of these errors (you’ll only see the others after you correct each error in succession).

The 'AllowAutomaticASPXPageIndexing' attribute is not declared.
The 'ASPXPageIndexMode' attribute is not declared.
The 'NoCrawl' attribute is not declared.
The 'CrawlAllSchema' attribute is not declared.

To correct the issues, just open up the C:\yourSiteHere directory and find the Manifest.xml file. Open the file in Notepad or your favorite text editor.

Delete the following attributes (search is easiest).

AllowAutomaticASPXPageIndexing="true" ASPXPageIndexMode="Automatic"
NoCrawl="false"
CacheAllSchema="false"

Save your changes to he Manifest.xml file and run the import command again. It will hopefully work now.

Tuesday, April 13, 2010

Using RIA Services / WCF with multiple host headers

If you are using RIA Services or just plain old WCF you and you have more than one url that you use to access your website and use IIS 6 you will need to modify your web.config file.

In my example, I access the same IIS web site using two different host headers because I have a small web farm and I want to be able to check each server in the farm after a deployment, not just use the load balanced url.

This means that I have two urls, one for load balancing that everyone uses, and the one I use for testing to make sure a particular server in the farm is working.

In my case, I have http://myapp:8888 which everyone uses, and http://myapp:18888 I use to hit server one, http://myapp:28888 to hit server two, etc.

Here is the change I had to make to my web.config on the first server.

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" >
<baseAddressPrefixFilters>
<add prefix="http://myapp:8888" />
<add prefix="http://myapp:18888" />
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
</system.serviceModel>

If you don’t do this, you may get errors about anonymous, security, bindings, communication, etc. This tends to fix a lot of these issues.

This is one of the better references I have found for getting RIA Services and WCF running under .Net 3.x, IIS 6, etc.