Category name:.NET

Deploying a WCF Service using a Web Setup Project

With this blog post I hope I can save others some time and besides that it is also nicely stored for me in case I need it again.

For my current project I’m building some WCF services. One of the requirements is to have a MSI to hand-over to the system engineers for deployment.

The setup should:

  1. support deployment of the WCF artifacts
  2. be able to be deployed to whatever website is available on the server
  3. be able to set ASP.NET security to NTLM
  4. be able to gather service settings during setup
  5. be able to change custom AppSettings in the web.config according to the settings

While I’m familiar with Visual Studio Setup projects, I came across some interesting challenges.

Requirement 1 and 2 are easy. The regular Web Setup project is capable of doing that out of the box. If you add a Web Setup project to your solution and specify the “File System on Target Machine”. Put the svc and web.config in the “Web Application Folder” and the output of the WCF project to the “bin” folder. This will deploy your WCF service to the website you specify in the setup wizard.

filesystem[1]

One caveat however is to set the value of the Virtual Directory as it is shown by default when you run the setup. This is by default the name of your WebSetup project. In my case this was <company>.<division>.<Project>.<Subproject>.<Setup>

This is definitely not the virtual directory name you want to see in IIS. This cannot be changed in Visual Studio because it is not shown as a property, you need a text editor like Notepad. So open the project file of the WebSetup project: the ‘vdproj’ file. Search for “VirtualDirectory” and change the value to something suitable.

The 3rd requirement is a bit more difficult. By default the web services are installed with anonymous authentication so to change that, a step in the setup should be appended. After some searching I found out I had to add a so called custom installer. That is a class that inherits the System.Configuration.Install.Installer class. You can override the ‘Install’ and/or ‘Uninstall’ methods to add custom code to the installer.

So I added a CustomInstaller Class Library project to host the CustomInstaller class. Next step was how to modify the authentication of the just installed web service? This can be done using WMI or ADSI and I decided to go for WMI. I already did some things with WMI but now I needed to do more. Unfortunately the documentation is not very ‘user friendly’ and after some trying I decided to look for a ‘WMI query analyzer’ or something like that to get at least an overview of the possible queries. I was very happy to find the WMI Explorer by KS-Soft. It is a free download that exactly does what I needed: give an overview of what is out there regarding classes, instances and properties. A very valuable tool.

I needed a query to access the properties of the WCF service. Therefore I needed to query the “IIsWebVirtualDirSetting” class, based on the virtual directory of my WCF service. But how to get the virtual directory name? The system engineer can change that value so we need to ask the runtime to get it.

By default the runtime keeps some variables that you can retrieve in your code. For WebSetup projects that are:

  • TARGETVDIR – virtual directory to be created
  • TARGETSITE – website where the virtual directory is to be created (site must exist), example: "/LM/W3SVC/1
  • TARGETAPPPOOL – application pool to use (must exist, it won’t be created)

If you supply the parameters (to which I will come back later), you can access the runtime context to get the variables using Context.Parameters. The code below does that and more.

wmicode[1]

I create a ManagementScope for “\localhostrootMicrosoftIISv2” to connect to the local IIS instance. Next I query for the IISWebVirtualDirSettings of my WCF service to get access to the properties. This query is based on the website name and the virtual directory. If there are multiple websites in IIS, we have to get the correct one.

With the following code we can iterate over the result (which should only contain one record) and set the property.

wmicode2[1]

So now the code is in place to set the authentication, but how do these parameters get into the Context object? You have to specify a custom action to your project and the custom installer is the action you need to add.

setupcustomaction[1]

Then you can specify properties on the custom installer and they will end up in the Context object.

setupcustomaction2[1]

As you can see the parameter starts with ‘/’ and the value is in double quotes and square brackets if it is a variable which is gathered during the setup process in the wizard. You can also add plain text like I did with ‘localhost’ in this case. Warning: do think about the double quotes, if forgotten nothing works and there are no messages to tell you why!

Requirement 4 is simply extending the user interface. You can find a very good blog post here so I won’t cover that in detail.

Finally the 5th requirement: set some AppSettings values in the web.config

The blog post I just mentioned also describes how to modify web.config settings from a setup project. There is one difference to my situation and that is that I have to change the configuration file for a process I haven’t loaded the host of. So I cannot use the OpenExeConfiguration method of the ConfigurationManager class. Also the web.config specific method OpenWebConfiguration of the WebConfigurationManager class cannot be used.

Via WMI I was able to find the physical path of the web.config and I was almost thinking about using some XmlDocument class to read and process the settings when I found this forum topic.

It describes exactly what I need. I have to use the OpenMappedWebConfiguration method of the WebconfigurationManager class. Then I can still use the capabilities of this class to modify the settings without having to foul around with XML tags myself. With this in place it’s a piece of cake to change the settings.

modifywebconfig[1]

Looking back everything is very easy, as always, but I had a hard time finding the right information. Also I have my doubts about WMI over ADSI. It seems like the ADSI queries are more intuitively but I’m not sure about that.

If you have a better, easier, quicker or fancier solution, please let me know!

[WCF] Great tools in SDK

While browsing the WCF SDK I found two great tools:



  • Microsoft Service Configuration Editor

  • Microsoft Service Trace Viewer

The configuration editor helps you with the confguration files that you need with WCF. It simplyfies editing those files significantly. By using a tool you also avoid typing errors and it is very easy for example to switch diagnostic information on or off.


With the tracing switched on, you can use the trace viewer to browse the actual log files produced. This tool shows all messages flowing and additional information about the messages like what the body of the message was and the duration of the message. With this tool it is easier to find out what is going wrong if you run into an error or unexpected behavoir.


Both tools can be found in the following SDK folder C:Program FilesMicrosoft SDKsWindowsv6.0Bin or you can download it here.

WCF: HTTP 404 when hosted in IIS

While playing with WCF I ran into someting when I wanted to host the service in IIS.


I created a ‘service.svc’ in a folder, added a web.config, created a bin folder to put the assembly in, and added a website to that folder in IIS. According to the MSDN documentation and several blogposts, that was enough to host the WCF service in IIS.


But when I tried to browse the service, I received an HTTP 404 error.


In the release notes of the .NET 3.0 framework I found the following, which I thought should solve the problem because it exactly describes my problem.


2.7.4 May not be able to web host WCF services if a pre-RC1 version of WCF was previously installed


If you installed a previous version of the .NET Framework 3.0 while IIS was installed, when you upgrade to the RTM version of the .NET Framework 3.0 you may have difficulty accessing WCF services that are IIS hosted using .svc files. On computers running Windows Server 2003, accessing an .svc extension from the browser may return a “404: Page Not Found” error. On computers running Windows XP, the .svc content may be displayed as plain text.

This is due to an issue with WCF script map registrations in a previous release.   


To resolve this issue


There are three ways to work around this issue:



  1. Download the unsupported tool, CleanIISScriptMaps.exe from http://wcf.netfx3.com/files/folders/product_team/entry5648.aspx. Run the tool from a command console without any arguments.
  2. Uninstall and reinstall IIS or re-create your Web sites:

    1. Uninstall IIS and reinstall it so that the IIS Metabase is refreshed. Then run the WCF install tool manually to re-register the WCF scriptmaps:
      “%windir%Microsoft.NETFrameworkv3.0Windows Communication FoundationServiceModelReg.exe” /r /y

    2. If you are running Windows 2003 Server, you may be able to resolve the problem by deleting the “Default Web Site” and re-creating it.

  3. Install .svc manually as a temporary workaround:
    You can run the following command to install .svc mapping manually. However, this refreshes the IIS Metabase for existing sites. “%windir%Microsoft.NETFrameworkv3.0Windows Communication FoundationServiceModelReg.exe” /s:W3SVC

After trying all this, still a 404. 🙁
What actually caused the problem was the fact that I forgot to mark the website as a .NET 2.0 website instead of a 1.1 site which is the default.


 

Winforms: web browser control trouble

The last couple of days I had a big fight with the web browser control that ships with Visual Studio 2005 and the .NET framework 2.0.


I was using the ‘DocumentText’ property to display some HTML in the control, but for some dark reason it refused to do that. Instead it just contained <HTML></HTML> after assigning some HTML text to it. The strange thing was that everything worked fine after assigning HTML text to it the second time, but doing that the first time failed for some reason.


At the end I was very happy to find a blogpost with the solution: C# 2.0 WebBrowser control – bug in DocumentText?

Be careful with String.IsNullOrEmpty

While I ran FxCop over someone else’s code it pointed me to a String method I didn’t know about: IsNullOrEmpty.


This method is new in .NET 2.0 and FxCop supplies the following description with it:


“To test for empty strings, check if String.Length is
equal to zero. Constructs such as “”.Equals(someString)
and String.Empty.Equals(someString) are less efficient
than testing the string length. Replace these with
checks for someString.Length == 0.”


Sounds like a nice addition, but then I ran into this blog which tells me to be very careful with it:


http://msmvps.com/blogs/bill/archive/2006/04/04/89234.aspx

Don’t depend on intellisense

Recently I was working with a FormView control which contains several textboxes and a dropdownlist.

I wanted to use databinding to be able to easily insert new entries in a database, but I couldn’ figure out how to databind the dropdownlist.

In an example I read about the "selectedValue" property but intellisense didn’t show that one.

<asp:DropDownList selectedValue=’<%# Bind("CategoryId") %> ID="ddNewsCategory" runat="server" DataSourceID="odsCategory" DataTextField="Title" DataValueField="CategoryId" />

I tried it anyway and it worked! 🙂

When I tried to submit the bug in Visual Studio 2005 professional I found out that someone else already submitted the bug in november 2004 (that was in an express edition) !

ASP.NET 2.0 and SQL Server 2005 Express hosting

While looking around for possible hosting options for ASP.NET 2.0 and SQL Server 2005 I ran into the following:

https://www.hosting.com/hosting/microsoft/microsoft-hosting.asp

They offer a kind of experimental (beta plan) hosting for only $1 and no monthly fee. In their detailed beta plan report they say that they can stop the service any time so I (like them) wouldn’t recommend to run there a live website. However for testing purposes this could be an option.