Category name:Visual Studio

BizTalk Software Factory v5 for BizTalk 2013R2

If you’re not familiar with the BizTalk Software Factory, please read the documentation on http://bsf.codeplex.com/releases.

Every new release of BizTalk requires some changes in the BizTalk Software Factory (BSF) and the 2013R2 edition is no exception. Most important change is in the Visual Studio version and the BSF relies on the Guidance Automation Toolkit (GAT) and Extensions (GAX) to be available.

Since Microsoft stopped development of the toolkit and extensions I’m happy to see the community continues it by means of the Open GAT/GAX (http://opengax.codeplex.com) project.

To be able to install the BSF (http://bsf.codeplex.com) you need to install the Visual Studio 2013 SDK and the Open GAT/GAX for Visual Studio 2013 upfront.

The functionality of the BSF hasn’t changed but it is important to know that at this moment there is no version of the BizTalk Deployment Framework (BTDF) that supports Visual Studio 2013. Since the BSF supports the BTDF, it currently is available but doesn’t work. Installing BTDF v5.5 on Visual Studio 2013 does work, but Visual Studio will not contain any of the BTDF functionality.

If you run into issues or you like to have some additional functionality in the BSF please let me know.

Didago IT Consultancy

Deploying WCF Services using Web Deploy

More than two years ago I wrote a blog post about deploying WCF services using a Web Setup project. Back then it wasn’t an easy task to get services deployed using it. Especially the UI customization of the installation wizard dialog gave me some headache, moreover because they were difficult to test and debug.

As also mentioned in the comments of that post, we now got Web Deploy! So I decided it was about time to rewrite the blog post using the same requirements but then with Web Deploy. Let’s see how much easier it became.

A small revisit of the requirements as formulated in the other blog post:

  1. support deployment of the WCF artifacts
  2. be able to be deployed to whatever web site 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

Web Deploy is available for Visual Studio 2005/2008, but I’ll be focusing on Visual Studio 2010. The approaches of the Web Deploy and Web Setup are different. In Web Setup the output was an MSI which could be run by a system administrator. The Web Deploy approach is focused on IIS as the host of the web application or service. This means the output is no longer an MSI but a (ZIP) package that can be imported in IIS or IIS Express or installed using the MSDeploy command line tool.

What are the typical steps to take to deploy a web application or WCF service using Web Deploy from Visual Studio?

First, select the ‘Publish’ option on the project context menu.

A profile page will show up in which you can specify which publish method to use. The options are:

  • Web Deploy
  • FTP (File Transfer Protocol)
  • File system
  • FPSE (FrontPage Server Extensions)

Also define a profile name, the server to deploy to and the name of the web application or WCF service. Next click ‘Publish’ and the artifacts are deployed to the target IIS server and site/application.

This covers requirement 1: support deployment of the WCF artifacts

As a side step: if you want to deploy to a remote server, you might run into a few challenges. The Web Deploy is a client/server installation so you need to correctly setup your (IIS) server in order for it to receive the deployment request. If you want to know more, take a look at these posts:

Requirement 2 is: be able to be deployed to whatever web site is available on the server

In the previous step the target web site was defined in Visual Studio, but that should be dynamically changeable when a system administrator runs the package on for example a production environment.

First the package must become portable so it can be installed on a different server, and the next step is enabling the system administrator to pick the website to deploy the service to.

To create a package there are 2 options you can use:

  • Visual Studio
  • IIS (use the Export Application functionality, which is a topic by itself and not covered here)

In Visual Studio take from the project context menu the option ‘Package/Publish Settings’ to define how the package looks like and then ‘Build Deployment Package’ to actually build the package.

Important settings here are the location of the package, which is a ZIP file, and the target location of the WCF service on the IIS server. Next select ‘Build Deployment Package’ to create it.

Now the package has been build, it is interesting to see what’s in it. Browse to the folder specified in the ‘Package/Publish Settings’ folder to find the files below.

The package consists of:

  • CMD file
    • This batch file can be used to deploy the package to a server without having to access IIS via the administration console. It uses the command line tool MSDeploy to deploy the package using Web Deploy. Suitable for unattended and/or bulk installations
  • Readme file
    • Interesting file describing all options for the CMD file. One very interesting one is the /T option, which calls msdeploy.exe with the “-whatif” flag, which simulates deployment. This does not deploy the package. Instead, it creates a report of what will happen when you actually deploy the package. Very useful for testing purposes!
  • Parameter file
    • This file contains the parameters that are defined for this service and are extracted from the project file (DeployIisAppPath element) during packaging. This file contains by default only one item, see below. Here we immediately notice that this is the value we need to cover requirement 2.
  • Manifest file
    • This file is not used during deployment, but during generating the package. It contains provider settings and like you can see below some security related entries for the IisApp and setAcl provider.
  • ZIP package
    • Contains the service to deploy, including configuration, binaries and other artifacts. If you open the ZIP you’ll see all kinds of configuration files that are used during import of the application

For now let’s see how to install the package onto a different server based on the package. First open IIS and select the web site you want to import the web application or WCF service to.

It is out of scope to describe all wizard dialogs but at a certain time you’re asked to specify the application:

In here you can define the destination application and if it doesn’t exist, it will be created for you. This is out-of-the box functionality, but nothing different from the Web Setup approach. Anyhow, this is what we need to fulfill requirement 2.

Requirement 3 is: be able to set ASP.NET security to NTLM

By default the security is set to anonymous access, so we need to change that to windows authentication.

At first this didn’t seem like a big deal, because I expected it to be some parameter or manifest setting, but the more I read on the internet the more I got worried. There is a lot to find about Web Deploy and Windows Authentication, but that mostly relates to using Windows Authentication to connect to the Web Deploy server (up to adding keys to the registry), and not about changing the authentication of a deployed WCF service or web application.

So far I haven’t found an easy way to change the authentication of a deployed WCF service or web application. What I did find was a thread in the IIS Forums about specifying the authentication in the web.config, but in order for that to work the applicationHost.config must be changed to allow overrides. That config file is maintained by the system administrator and I can understand why the system administrator should know about deployment scripts that change the authentication. On the other hand, having a WCF service with Windows Authentication is not that uncommon.

Another option that was mentioned in this thread refers to running a command file which can be added to the manifest file. This command file will probably contain some VBScript to change the authentication after the package has been installed. The difficult thing here is knowing in which web site the WCF Service has been deployed…..

I really hope I overlooked something, so if somebody knows how to do this please leave a comment! Thanks in advance!

Requirement 4 and 5 will be discussed combined: “be able to gather service settings during setup” and “be able to change custom AppSettings in the web.config according to the settings”

Like we’ve seen before, there is a parameters file. This file can be customized from within Visual Studio to make it possible to change the UI the system administrator will see. For this example I’ll demonstrate what it takes to change the value of a custom AppSetting in the web.config. This will be changed from within the UI of IIS. The value to change is a key named ‘Test’ in the AppSettings section of the web.config.

First, add an XML file to your project called “Parameters.xml”, this will contain the parameters the UI will show. This is a different file from the ‘SetParameters.xml’ file we saw earlier; that one is used with the command line option and this one with the IIS import.

Next add this piece of XML. By the way, this is a good resource to learn more about parameters in Web Deploy.

This piece describes two things:

  • It defines a parameter with a description to show up in the UI and a default value which will be filled in.
  • It defines where the value, read from the UI, should be applied. In this case it is targeted at the web.config file and the XPath points to the AppSettings key ‘Test’.

Building a package from this and importing it in IIS results in the following UI:

As you’ll notice the name and description are displayed nicely, together with the default value. When the value is changed, it will be changed in the web.config when the wizard is finished.

You can imagine the possibilities of this approach. It is very easy to change the UI and set values for example in the web.config without having to code it.

So, did it actually became easier to deploy WCF services? Yes and no. Obviously it is much easier to customize the UI and perform all kinds of actions while deploying, but on the other hand it seems very difficult to perform some common task like changing the authentication of a web site. Like mentioned before, I hope someone will leave a comment with a clarification on the authentication issue.

Anyhow, there is much more you can do with Web Deploy then is covered in this blog post. Please find below useful spending of your spare time.

Didago IT Consultancy

BizTalk in the Cloud, One Step Closer

We all know Microsoft is putting an enormous amount of effort in their cloud initiative called Azure. It started with compute and storage but in the mean time it has grown and more and more products are released in a cloud version before the on-premise version is released. An example is Microsoft Dynamics CRM Online.

Since the September 2011 release of Azure the Service Bus is part of it. In the service bus we find things we know from BizTalk. The most well-known ones are Queues, Topics and Subscriptions. This so called ‘Brokered Messaging’ introduces message queuing and durable publish/subscribe messaging, which is the basis of BizTalk messaging.

Of course BizTalk is capable of a lot more, but Microsoft released today the CTP of Windows Azure Service Bus EAI and EDI. If we take a look at this release we immediately recognize the BizTalk influences in there. It is a CTP but it is showing the direction Microsoft is going.

Let’s focus on EAI for now. To install the SDK you just need a regular development machine with Windows 7/2008, .NET4 and VS2010. Download the SDK here. Installing the SDK will install some new VS templates under the section ‘ServiceBus’.

When the EAI project is created, the Solution Explorer looks like this:

And also new toolbox items are present, in which you’ll recognize the ServiceBus features Queues and Topics:

So the first step in BizTalk development would typically be to add a schema. This can be done by the regular ‘Add Item’ option in the Solution Explorer. There the first real BizTalk items show up! We all know the Maps and Schemas!

One thing that caught my eye was the extension of the mapping file, not BTM but TRFM. I can only speculate what the extension stands for.

Adding the schema is nothing new since adding XSD’s has been part of Visual Studio 2010 from the beginning.

 

Next step is creating a map, after adding the item another familiar screen shows up!

As well as selecting the source and destination schema. Unfortunately it isn’t possible to drag the schemas onto the mapping canvas.

And of course the toolbox is also familiar, although some items are missing, new or named differently from BizTalk.

This is definitely a preview of the new mapper as it will show up in the next version of BizTalk. Although the mapper has improved in BizTalk 2010, this one is even more advanced (and worth a blog post by itself!). For example I put the ‘If-Then-Else’ expression on the canvas:

This is really awesome!

Testing the map works quite the same way as in BizTalk, however it isn’t possible yet to generate a sample message from the schema so you need to create one yourself.

Typically you would also create artifacts like orchestrations, pipelines, etc, but they are missing in this CTP. However it won’t be a surprise that at least orchestrations will show up with WF4 in the near future.

So now we have a schema and a mapping, now what to do with it? Keep in mind that this is all Azure stuff so we need to deploy it into the cloud.

I’ll discuss these steps in my next blog post, but we’re definitely moving towards BizTalk in the cloud! Exciting stuff!

Didago IT Consultancy

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!

Setting the icon in a guidance recipe

Yesterday I co-presented at the Dutch BizTalk User Group. It was a talk about the BizTalk Software Factory and I did the demo. Afterwards I got the question on how to set the icon on a guidance recipe, like in the picture below.

hostdataicon[1]

I had to look it up in the code but I found it. By blogging it now it is also a note to self.

In the recipe you specify the arguments, actions and also the icon for the recipe. Below is a piece from the recipe for adding a map unit test from the BizTalk Software Factory. The HostData section specifies the icon and where the recipe should show up.

hostdata[1]

Next issue is what icon to take and what does the 133 mean? There is not much documentation about that on, for example, how to add your own icon. So I decided to use an existing one. Which one to take? To find out the ID of the icons, I used this tool: FaceID browser

It is a tool to get the ID’s of the Office icons and since Excel is installed on basically every BizTalk installation it does work well.

My fight with T4 Templates for BSF

At the moment I’m working on integrating the great Pipeline Component Wizard by Martijn Hoogendoorn into the BizTalk Software Factory. I decided to use a T4 template to get the job done. T4 templates are very powerful and easy to write (but hard to debug, as I found out). This post is dedicated to what I ran into while developing the templates.

The issues I had to deal with were:

  • Changing the wizard into a custom wizard
  • Getting the data out of the wizard into the T4 template
  • Processing the data in the T4 template to get the right code generated
  • Debugging T4 templates
  • Figuring out why I ran into the error “The given key was not present in the dictionary”

     

First of all, the current implementation of the PLCW wasn’t functioning on systems with GAT installed. That was the basic reason to change the wizard. The PLCW is based on the Microsoft.BizTalk.Wizard framework. The custom wizard pages in the guidance inherit from the Microsoft.Practices.WizardFramework.CustomWizardPage class and the wizard of the PCLW couldn’t be used 1-on-1. One of the reasons for that is that it is important for the CustomWizard page to have the following constructor:

public MyCustomWizardPage(WizardForm parent) : base(parent)
{
   // This call is required by the Windows Form Designer.
   InitializeComponent();
}

Among other things like the way the wizard saves state between pages, I decided to reuse the pages but inherit them from the CustomWizardPage.

The wizard collects some data to use in the pipeline component creation process and everybody who is familiar with the PLCW knows you can define custom design properties at the end of the wizard. I thought it was a good idea to create a small class for that to contain the type/name values and put that into a generic list for ease of use.

For every variable you want the wizard save between pages and have available at the end, you should define an argument in your recipe. So I defined like this:

<Argument Name="ClassName" Type="System.String" />
<Argument Name="DesignPropertyList" Type="System.Collections.Generic.List<MyDesignProperty>" />
 

Everybody with a bit of XML knowledge understands that this isn’t going to work, so I looked at some samples and changed it into this:

<Argument Name="DesignPropertyList" Type="System.Collections.Generic.List&lt;MyDesignProperty&gt;" />
 

In the code of the custom wizard pages, you can write and read the arguments like this. Make sure the name used in ‘SetValue’ is exactly the same as the argument.

IDictionaryService dictionaryService = GetService(typeof(IDictionaryService)) as IDictionaryService;
dictionaryService.SetValue("ClassName", txtClassName.Text);
 

  • Make sure every argument has a value otherwise you will end up with error messages saying the specific argument is empty.

So now I have defined the necessary arguments and created the custom wizard pages and now I want to use the arguments in a T4 template action. For that I need in fact 2 actions:

  • Generate the content with Microsoft.Practices.RecipeFramework.VisualStudio.Library.Templates.TextTemplateAction
  • Write the content to file with Microsoft.Practices.RecipeFramework.Library.Actions.AddItemFromStringAction

I defined the arguments as properties in the T4 template, but it didn’t work. I didn’t receive the generic list with design property values as I saved into the arguments in the wizard. After a long search I found that a generic class isn’t supported by this action. How to solve this? I downloaded the Smart Client Software Factory and the Web Services Software Factory to peek at their solution (they are quite good at this, I can tell you that). There appeared to be a simple solution for this like defining an empty new ‘collection’ class like this:

public class MyDesignPropertyCollection : List<MyDesignProperty>
{
}

So I had to change the argument again into:

 <Argument Name="DesignPropertyList" Type="BizTalkSoftwareFactory.BusinessEntities.MyDesignPropertyCollection, BizTalkSoftwareFactory" />

In the T4 template the value should be specified as this:

<#@ Assembly Name="BizTalkSoftwareFactory.dll" #>
<#@ Import Namespace="BizTalkSoftwareFactory.BusinessEntities" #>
<#@ property processor="PropertyProcessor" name="DesignPropertyList" #>
 

One of the other issues is that I was uncertain what I received in the T4 template. Debugging T4 templates can be hard although there seems to be tools available. I used a custom debug class to be able to view the available values in the template. I defined a method which I call in the beginning of the template:

<#  TemplateHelper.DebugThis(this); #>

Of course you need to import the namespace where the method can be found:

 <#@ Import Namespace="BizTalkSoftwareFactory.BusinessComponents" #>

So I now have generated content which I need to write to file, that is what the second action is for. It takes the output of the previous action, location to add the file to and name of the file. That doesn’t look too difficult as I used it already in the Unit test part. So I copied that part of the recipe and then I ran into the error “The given key was not present in the dictionary” and I really didn’t understand where it came from. I compared the code and it looked the same. At these times it can be very frustrating not to be able to debug, as I found out I didn’t even get into the second action. I grabbed the code using reflector and created my custom action with that code, but the error showed up even before entering the action.

Now what?

Literally hours later I found what caused the action and of course afterwards it is always easy.

I defined the action like this:

 <Action Name="AddPipelineComponent" Type="Microsoft.Practices.RecipeFramework.Library.Actions.AddItemFromStringAction, Microsoft.Practices.RecipeFramework.Library" Open="true" >
  <Input Name="Content" ActionOutput="GeneratePipelineComponent.Content" />
  <Input Name="TargetFileName" RecipeArgument="PipelineComponentFileName" />
  <Input Name="Project" ActionOutput="PipelineComponentProject" />
</Action>

The problem is in the “ActionOutput” for input “Project”. Logically “ActionOutput” means……..output of an action and that wasn’t the case. It was a regular “RecipeArgument”. Very easy to fix, but hard to find.

So if you run into the error “The given key was not present in the dictionary”, think about this it will save you hours. J

If you need guidance with generic lists and wizards/actions I would advise you to look at the Smart client software factory and the Web service Software Factory.

BizTalk Server 2006 R3 announced

In an earlier post I wrote about Microsoft researching possibilities for BizTalk Server 2006 supporting the latest Windows, SQL Server and Visual Studio releases.

Today I read a blogpost by Richard Seroter who writes about a new release of BizTalk Server 2006 marked as R3 is scheduled for the first half of 2009, this was announced by Steve Martin (Microsoft CDS).

So R3 will support:

  • Window Server 2008
  • SQL Server 2008
  • Visual Studio 2008

Besides that there will be some enhancements and additions

“We are also taking the opportunity as part of this BizTalk Server release to deliver additional customer-requested capabilities for our core SOA infrastructure.  We will give more updates on specific features in the coming months, but at a high level we are planning some new investments in the release that includes: “

  • New web service registry capabilities with support for UDDI (Universal Description Discovery and Integration) version 3.0
  • Enhanced service enablement of applications (through new and enhanced adapters for LOB applications, databases, and legacy/host systems
  • Enhanced service enablement of “edge” devices through BizTalk RFID Mobile
  • Enhanced interoperability and connectivity support for B2B protocols (like SWIFT, EDI, etc
  • SOA patterns and best practices guidance to assist our customer’s implementations

However, this release does not correspond to the Oslo project.

Delete a locked file in TFS

This is more or less a note to self because I probably will run into this again.


Today I was cleaning up the code tree in TFS and found a project that could be deleted. Unfortunately the developer left the company leaving a file checked out. With the Source Control Explorer it wasn’t possible to remove the project as long as there were locked files. The file status is stored in the workspace, so deleting it would solve the problem


Using the TF.exe commandline tool it was possible to lookup ad delete that workspace.


Getting the workspace name:



tf workspaces /owner:<developers_logonname> /computer:* /server:<your TFS server>


Deleting the workspace:



tf workspace /delete /server:<your TFS server> workspace_name;developers_logonname


Remember that you need AdminWorkspaces global permissions to be able to delete the workspace.


 

[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.

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?