Wednesday, November 25, 2009

Microsoft Web Development Server Command Line

If you ever need to host a web site on your machine (for testing or whatever), you can use the Microsoft Web Development Server (Visual Studio runs this from the IDE) manually via the command line.

I found this particularly useful to test deployment builds (eg: msdeploy) if you don’t have IIS!

There appears to be some confusion over where this EXE lives, but on my machine it is here:

C:\Program Files\Common Files\Microsoft Shared\DevServer\9.0\webdev.webserver.exe

All you need to do is give it a port, a file path, and the name of the virtual directory to use.

Example:

"C:\Program Files\Common Files\Microsoft Shared\DevServer\9.0\webdev.webserver.exe" /port:4955 /path:"C:\Build\Test\DotNet\Test.Project.Web" /vpath:/TestProj

Tuesday, July 14, 2009

WCF Security Issues With IIS

WCF Security shouldn't be that difficult, but I've recently run into some problems that just couldn't be forseen (at least for me).

I have a WCF Service hosted in IIS - I have set IIS to Require secure channel (SSL) traffic and set the virtual directory security to Integrated Windows authentication only.

In my WCF Service web.config, I use the following binding configuration:

<bindings>
<basichttpbinding>
<binding name="SecureTransport">
<security mode="Transport">
<transport clientcredentialtype="Windows">
</transport>
</security>
</binding>
</basichttpbinding>
The security mode of Transport is for communication over SSL. The client credential type of Windows is for Integrated Windows authentication.

This should work fine, right? Well, it did on one test box, but on another I had a number of problems, each outline below.

I would normally use a browser to test the connection first.


Error: Security settings for this service require Windows Authentication but it is not enabled for the IIS application that hosts this service.


Even if IIS is configured for Integrated Windows authentication only and your service configuration specifies Windows as the client configuration, you get the following error in your browser:

Security settings for this service require Windows Authentication but it is not enabled for the IIS application that hosts this service.

If this error is returned and Windows Authentication has been enabled in IIS, it means there is an issue with the supported network authentication schemes for the website that the web service is installed under. The most likely cause is that it is configured for NTLM only. We want to specify NTLM and Negotiate.

The following Microsoft KB article describes how to enable both schemes:
http://support.microsoft.com/kb/215383

After this has been done IIS will need to be restarted, or the web service application will need restarting (load the web.config file and save without changing anything).

It would appear that the Windows credential setting in WCF .NET maps directly to the Negotiate scheme in IIS.


Error: Could not establish trust relationship for the SSL/TLS secure channel with authority.

The certificate is not fully trusted. This is likely to be a temporary certficate or a locally issued certficate that the client machine does not trust.

The following client config change will ignore this particular certficate error:
<system.net>
<settings>
<servicePointManager checkCertificateName="false" checkCertificateRevocationList="false" />
</settings>
</system.net>

Error: The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate.


This appears to be an issue with .NET 3.5 SP1 (I say 'appears' as my only reference is a blog entry).

See this article: http://msmvps.com/blogs/alvin/archive/2008/11/14/net-3-5-sp1-breaking-change-to-wcf.aspx

The following client configuration change (for each endpoint) resolves this:
<system.serviceModel>
<client>
<endpoint address=... >
<identity>
<servicePrincipalName value="spn" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Note that the value of servicePrincipalName is not important.


Error: This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.

This error occurs when there are multiple entries for the Website Identification - it tries to create multiple service base addresses for each endpoint.

You can specify a filter in the server configuration to resolve this.

Here is an example:
<system.serviceModel>
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
<add prefix="http://tstmachine:80"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
</system.serviceModel>

Thursday, January 22, 2009

Access Violations, Interop and VS2008 SP1

After installing SP1 for VS2008 the other day, one of our programs stopped working. In fact, it came up with an AccessViolationException:

System.AccessViolationException: Attempted to read or write protected
memory. This is often an indication that other memory is corrupt.
at VariantClear(tagVARIANT* pvarg)
at
System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant.MoveNext()
at ...etc...

This was a surprise, because it ran fine before. Or, at least, that is what we thought.

An examination of the code revealed the exception was being thrown in a foreach() statement. Odd, but the foreach() statement was looping on a COM Interop collection. I've done a little Outlook Add-In development and one thing I've learnt about COM Interop is that it doesn't handle memory the way you would think .NET handles it.

Basically, there are two thing you need to do:
1) Do NOT use foreach() - these are bad, use for(;;)
2) Be very careful about releasing memory for references to COM objects behind Interop interfaces

There is a great article regarding this here:

OOM.NET: Part 2 - Outlook Item Leaks

If you do any Interop work, you really should read and understand it.

Back to the code that failed:

     private static bool ColIsForeignKey(Table t, Column col)
{
foreach (Key key in t.Keys)
{
if (key.Type != SQLDMO_KEY_TYPE.SQLDMOKey_Foreign) continue;
foreach (string keyCol in key.KeyColumns)
{
if (keyCol.ToLower() == col.Name.ToLower())
{
return true;
}
}
}
return false;
}

Now here is the code modified:
     private static bool ColIsForeignKey(Table t, Column col)
{
SQLDMO.Keys keys = t.Keys;
try
{
for (int i = 1; i <= keys.Count; i++)
{
Key key = keys.Item(i);
try
{
if (key.Type != SQLDMO_KEY_TYPE.SQLDMOKey_Foreign) continue;

Names columns = key.KeyColumns;
try
{
for (int j = 1; j <= columns.Count; j++)
{
string keyCol = columns.Item(j);
if (keyCol.ToLower() == col.Name.ToLower())
{
return true;
}
}
}
finally
{
Marshal.ReleaseComObject(columns);
columns = null;
}
}
finally
{
Marshal.ReleaseComObject(key);
key = null;
}
}
}
finally
{
Marshal.ReleaseComObject(keys);
keys = null;
}
return false;
}

It looks a lot uglier, but you can be sure you're not keeping any nasty
references around the place.

Friday, October 10, 2008

VSTO, Memory Leaks & Reference Management

Developing Add-ins for Office calls for some careful handling of references, particularly with references to objects that have an underlying COM reference. 

My previous blog entry Listening to Calendar Events with Outlook 2007 and VSTO talked about listening to Appointment events, but my code didn't handle references very well. This left some references to Outlook objects hanging and Outlook was showing values that were old.

I've since update this with some better handling of these references. In particular, the explicit releasing of COM objects via the Marshal.ReleaseComObject() method.

More Reading:

Friday, September 05, 2008

Visual Studio Using Huge Amounts of Memory

Lately I have been working on a solution with 33 projects on Visual Studio 2008.

Yeah, I know. That's a lot.

A lot of them were test projects and it is SCSF-based, so that is okay, but Visual Studio was chewing up loads of memory. I mean serious amounts, towards the 2GB limit. At this point, my hard disk would thrash at the smallest use of the IDE and be unusable for minutes on end.

Someone put me on to a tool from JetBrains, the guys that did ReSharper - it is supposed to change the way memory is allocated. One of the guys on our project who is using this tool is now using a lot less memory, but whilst mine is better than it was, it still aint that great.

So it may help.

Another option is to add /3GB /USERVA=3030 to the boot.ini file. Visual Studio is already large address aware (I think), so it should allow more VM use for the devenv.exe process.


Update:
One of the biggest causes of this was DevExpress Refactor! Pro. I'm normally a big fan of this add-in, but uninstalling it saved me enormous amounts of memory. 

Thursday, July 31, 2008

Including Setup Projects in Team Build

Setup (Deployment) projects are not supported by Team Build out of the box. You have to add
additional steps to the TFSBuild.proj file to build the setup project and copy the files to the output directory.

The following MSDN article describes this:

Walkthrough: Configuring Team Build to Build a Visual Studio Setup Project

Powered By Blogger