TypeConverter, Arrays and ASP.NET

Link. July 24, 2008. Comments [0]. Posted in:

I've been spending a bunch of time today doing some customization of some ASP.NET custom controls (yes, I know!). One of the things I needed to get working was decent design time support for a property of the control that returned an array of a simple custom structure.

[Browsable(true)]
public MyStruct[] StructData {
   get { return _structData; }
   set { _structData = value; }
}

This should've been simple, but it took me a far longer time than I expected to get working correctly. Getting the basic design time work done wasn't too much of a problem; since the property type was an array and not a custom collection, the default editors did the right thing and offered a good design time experience out of the box.

However, you still need to provide the designers and ASP.NET a way to store the property contents as an string, so that you can use markup to specify the value of the property.

Time to write a TypeConverter! I went ahead and wrote a simple TypeConverter that would take a string and return an array of structs based on its contents, or take an array and return a string based on the values in it. Nothing fancy.

I then enabled the type converter by using the TypeConverterAttribute on the property declaration:

[Browsable(true),
TypeConverter(typeof(MyStructArrayConverter))]
public MyStruct[] StructData {
   get { return _structData; }
   set { _structData = value; }
}

Once I added this, the designer worked right away. I could change the array contents in the designer, and it would get serialized into the aspx page markup correctly. Loading the page worked as well and all values would be correctly deserialized.

I thought I was home free until I tried to actually build the ASP.NET site (this was on a VS WebSite, not a Web Application Project). As soon as the ASP.NET compiler tried to compile the ASPX page hosting the control, it would error out with the dreaded error message:

Page.aspx (web): Object reference not set to an instance of an object.

That's it. No stack trace, no more details at all. I knew it was related to the TypeConverter, but that one was working correctly (already tested and verified). Checking further, I came to the conclusion that the error would appear every time that my TypeConverter.ConvertFrom() implementation would return an array with a non-zero size (useful, huh?).

So the array conversion was working perfectly, but ASP.NET was choking on the values contained in the array. At this point I realized the problem wasn't with the TypeConverter itself, but with how the ASP.NET was manipulating the values returned to generate the code from the ASPX page.

After much head-scratching and finding little explicit documentation about the issue I ran into this documentation piece on MSDN. The last section in the article talks about how "To implement a type converter that produces constructor-based property initialization code".

Based on that, I wrote my yet another custom TypeConverter that, following the guidelines on the article, implemented ConvertTo to convert from a MyStruct value to a corresponding InstanceDescriptor object. I applied this second TypeConverter to the struct declaration itself:"

[Serializable,
TypeConverter(typeof(MyStructConverter))]
public struct MyStruct {
   //...
}

And lo and behold, this time it worked perfectly: No complication errors anymore! Hopefully, next time I run against this and have forgotten again all about TypeConverters and its brethren, I'll remember to look here for hints :-).

Windows SDK Features

Link. July 24, 2008. Comments [0]. Posted in: .NET | Development

The Windows SDK Team blog has posted an open question about some potential features of future SDK releases and is gathering our opinions about it. I'd like to comment a bit on them and provide some feedback.

There are 9 areas the team is looking for feedback on. Let's consider each one:

1. A new, small download of “Core SDK” components is made available to customers, with only the basics.  What components should be included in this product in addition to the Windows headers and libraries?

I think the idea of offering smaller download options is a good one overall, and one that a lot of people (myself included) have asked for a number of times in the past. It's true that the special web downloader/installer we had in the past allowed you to download just parts of the SDK, but it just didn't work sometimes at all, and it was too rigorous in enforcing dependencies that might, or might have not, applied to your specific needs.

However, I disagree on what the contents of the "Core SDK" should be. To me, the most important part of the SDK nowadays is not the Windows headers/libraries, but the SDK tools. Hence, I want the minimum download option to be just the tools. The headers/libraries package should be built on top of the tools package, not the other way around (which is what has happened some times in the past).

My justification for this is that the SDK tools package today is very relevant to all SDK users; both .NET and Win32/64 developers. The headers/libraries package, however, is only relevant most of the time to the second camp.

2. PowerShell Build environment. The Windows SDK would include a script similar to SetEnv that users could run, which will set up an SDK build environment under PowerShell.

I've already said in the past I think this is an excellent idea, which I fully support. For now, I make do with my own custom version tailored to some particular needs of my dev environment.

3. Quick method to install “only .NET” or “only Win32” components.  For example, Win32 developers could quickly choose to receive only Win32 resources in the documents, tools, samples, etc.  Developers focused on managed code could choose to receive only .NET Framework resources in the documents, tools, samples, etc.

I guess this might be a good choice for many people, but to be honest, it's not one I'd particularly use much.

4. Improvements to documentation: better Table of Contents, better filters, search, etc.

Improved documentation is always welcome. The table of contents is the main entry point into it for a lot of people, so organizing it better would definitely be beneficial.

As for the rest, search and filtering really depends a lot on the underlying medium that hosts the documentation itself (the offline help viewer or the online MSDN site), so not sure what the SDK team can actually do to address those issues.

On the face of this, I'd say just focus on improving the content itself.

This does remind me of something: The current local help viewer MSDN uses (and many of the dev-side tools) is not something I'm particularly fan of. I was around when the original HtmlHelp engine was introduced and replaced the old Infoviewer that MSDN/Technet used, and was one of those that complained a lot about it.

I now long for the good old days of HtmlHelp. For example, I've seen the BizTalk SDK docs (which usually ship in the current help technology) in the old HtmlHelp format, and damn, it was way better/faster than what we have now. That sucks.

5. Improvements to documentation: integrate the SDK docs with MSDN docs.

We've had integration between the SDK docs into the MSDN docs in the past. In fact, I'm somewhat surprised it isn't now (I haven't installed either MSDN or the SDK docs in years!).

I used to think this was a good idea; I'm not so sure anymore. Two things come to mind:

  • MSDN is already huge, and somewhat bloated. Adding the SDK docs on top isn't going to improve the situation. In fact, considering point 4 above, integrating them is going to make search and filtering them even harder/worse.
  • The MSDN/SDK docs integration we had in the past had one significant flaw, in my humble opinion: It tried to integrate the SDK table of contents into separate sections in the MSDN TOC. So if you opened the standalone SDK help, you'd see all the SDK content grouped together, but if you launched the MSDN docs, there wasn't a single place in the TOC where the entire SDK content was hanged of. Annoying as hell.

The second point, in particular, brings up one question: Do we really want them integrated, or merely accessible from a single place?

6. Ship a newTools Explorer” to group the tools and provide a more friendly and efficient way for users to search and use the SDK tools.

Not interested. Keep the SDK lean and mean and get it back into shape.

7. Ship a newSamples Explorer” to group the samples and provide a more friendly and efficient way for users to search and use the SDK samples.

Not interested on an offline tool for this. I think there might be some use for this as an online tool where I could look for a sample and quickly get the code just for that specific sample, instead of having to download the entire SDK samples package (which is huge) to find it.

8. Windows SDK in non-Visual studio IDEs. Provide additional support for other IDEs, such as Windows SDK integration with non-Microsoft development environments, links to Windows SDK documentation from within other IDEs (Eclipse, IBM VisualAge for C++, Borland’s C++ Builder), among other possible integration scenarios.

Haven't been using them at all, so I'm not qualified to really talk about it. I do believe that, for the most part, the SDK should be completely independent of VS and should be usable in a standalone fashion.

9. Create a new Download portal with SDK ‘nuggets’ so that you can download small packages – perhaps a popular tool or file that shipped broken or was missing from a released SDK.

Might be a good idea, but if you're going to do it; do it right and stick with it. The SDK has seen as many changes in installer/downloaders as name changes, and it's a drag.

Don't get me wrong, it's OK to change installers if they bring a significant improvement to the SDK user, but I've never really found that obvious during the several last installer changes. I'm sure each one might have improved something for the SDK team, but from where I'm sitting, it's just been an annoyance to me without bringing any benefits.

It does bring up the question of just what exactly the SDK needs an installer for, besides just registering environment variables and creating the start menu entries...

Vim 7.2 Beta

Link. July 16, 2008. Comments [2]. Posted in: Vim

A few days ago the second beta release of Vim 7.2 came out and I decided to give it a try. Seems to be working great so far, and I'm pretty excited about this release for a couple of reasons:

  1. Performance Improvements: Under Windows, Vim 7.1 had some  performance problems, particularly related to redrawing the screen. This was particularly noticeable when scrolling large windows with syntax highlighted code with the mouse wheel, and when redrawing the [omni-] completion menu.
    The former feels much snappier, even with long lines, while the second appears to be fixed altogether!
  2. Floating Point support: I don't create much Vim scripts myself, but I'm excited by some of the possibilities this opens up for scripts I may use. One example of this is Yukihiro Nakadaira's HueRotation script.

CreateXmlInstance() with Multi-Root Schemas

Link. July 16, 2008. Comments [1]. Posted in: BizTalk

The DocumentSpec class in the Microsoft.BizTalk.Component.Interop namespace of the Microsoft.BizTalk.Pipelines assembly is commonly used in custom pipeline components (particularly assemblers in disassemblers) to represent a compiled BizTalk schema (a document specification).

This class has one interesting method: CreateXmlInstance(), which can generate an sample instance XML based on the associated schema [1]. Recently I saw a question in the BizTalkGurus forum about how to use this functionality if you had a schema definition with multiple potential root elements.

Turns out its pretty easy, once you understand how DocumentSpec works and how Schemas are compiled into BizTalk assemblies.

The constructor for the DocumentSpec class takes two arguments: The docSpecName (schema name) and the name of the assembly it is defined in.

The clue to support multi-root schemas is that the docSpecName is, in reality, the namespace + type name of the class generated by the compiler when you compile the Schema into the BizTalk assembly. Each schema becomes one class in the generated code.

If the schema has a single root, that's the end of it; All you need to know is that docSpecName == Namespace.ClassName. If the schema has multiple roots, however, each root becomes a nested class within the schema class.

The way to select which root element to use for the sample instance generation, then, is to provide the type name of the root element nested class as to the DocumentSpec constructor instead of the name of the schema class. In other words, in this case docSpecName == Namespace.SchemaClass+RootClass.

[1] One annoyance of this method is that it takes a TextWriter argument but doesn't actually write the generated XML into it; instead it returns a Stream you need to read!

PipelineTesting code now on GitHub

Link. July 13, 2008. Comments [0]. Posted in: BizTalk

I just pushed all the source code for my BizTalk 2006 PipelineTesting library to GitHub. I'll keep this public repository updated whenever I make any changes to the library, so if you're interested in keeping track of the code or forking it, this should make it a lot easier.

You can find the clone URL for the new repository is: git://github.com/tomasr/pipelinetesting.git

Enjoy!

NTFS Junction Points

Link. July 7, 2008. Comments [0]. Posted in: Tools | Vista

I spent some time this weekend organizing a few files and source code repositories. As part of this process, I wanted to take advantage of NTFS hard-links and junction points, both of which are supported on Windows Server 2003/8 and Vista.

I had no problems with hard-links at all. I'm using the ln.exe tool from http://www.flexhex.com/docs/articles/hard-links.phtml to create them, and it worked great right from the start (I could also use the "fsutil hardlink create" command).

Junction points, however, gave me quite a bit more trouble. I've used Junction points in the past very successfully. I work with some code bases that for many reasons expect to have certain directories in the C:\ drive, but I keep all my code in the E:\ drive.

For this I've used cross-drive junction points to have the folder in C:\ point to the real folder in E:\ and it's worked great for a couple of years. One other tool I've used for this sometimes is Junction Link Magic.

Yesterday, however, I discovered that on Windows Server 2003, if the junction folder was on the same drive as the target folder, it just wouldn't work correctly. I could create the junction just fine, and I could even see the contents of the directory through the junction using explorer, cmd.exe or PowerShell.

Actually trying to access any of the children through the junction would result in the error:

The filename, directory name, or volume label syntax is incorrect.

I tried both of the tools I mentioned before, and it just wouldn't work. I tried creating the junctions from WinServer2K8 (where they worked perfectly) and then using the drive from 2003, and it still wouldn't work. This was easy to test, by the way, since this is a VHD image I share between several virtual machines.

Eventually, fellow MVP Juan T. Libre insisted I tried the linkd.exe tool in the Windows Server 2003 Resource Kit. I was reluctant to it since the other tools could create working cross-drive junctions and I was starting to suspect an OS limitation, but I gave it a go.

Much to my surprised, linkd.exe was able to create working same-drive junction points on Windows Server 2003. My guess is that there's some (probably undocumented) detail about how the APIs need to be called that can affect whether this works correctly or not.

Looking at the junctions using the "fsutil reparsepoint query" command clearly shows that the Reparse Data is slightly different between cross and same drive junctions, but not sure what it means from the API point of view. Just something to watch out for.

The lesson: Use linkd.exe on Windows Server 2003 to create same-drive junctions.

GMail + Vim

Link. June 30, 2008. Comments [5]. Posted in: Vim

I've been a big GMail user ever since I got my first account and I've gotten very used to it. About a year ago I switched the email for my website and our corporate email over to Google Apps and eventually was able to drop Outlook completely [1].

I've been extremely satisfied with this setup and don't regret it at all. However, as much as I like GMail and all, it's sometimes a drag when actually editing new emails or responses to existing ones. It's not really GMail's fault; it's just that a TEXTAREA isn't really a good editor for email (I try to stick to plain text email only as much as possible).

IAT Fortunately, I discovered a while ago the It's All Text! extension for Firefox. This little extension gives you a small button next to textareas; when you click it, it will open your favorite text editor to edit the text, and then replace it with whatever you saved before closing it.

Now, I can just use this to edit complex/longer emails in gVim, and get all the text-editing goodness I'm used to!

Firefox did have one nice feature I missed at first: Spell checking. This wasn't always useful, though, as it only really supports a single language at a time, and I regularly use both Spanish and English, but it was better than nothing.

Vim, however, also supports spell checking! I just had never bothered setting it up correctly. I've now configured my .vimrc file so that I can enable/disable spell checking for English or Spanish with a few key-presses. Here's how I configured mine:

map <Leader>se :setlocal spell spelllang=en_us<CR>
map <Leader>ss :setlocal spell spelllang=es_es<CR>
map <Leader>sn :setlocal nospell<CR>

Now I can just press \se in normal mode to start the spell checker in English or \ss for Spanish, and then \sn to disable it later on, if I want to. Otherwise I just keep spell checking disabled so that it doesn't get in the way of my coding sessions.

VimSpell

The combination of It's all Text!, Vim and its spell checker makes for a much nicer GMail experience for me.

[1] I still need to migrate some old personal email over to my GMail account, which I haven't done because I'm lazy, but I should definitely get around to that some day.

Controlling BizTalk Orchestrations with PowerShell

Link. June 26, 2008. Comments [1]. Posted in: BizTalk | PowerShell

Here's a sample PowerShell script/functions to start/stop BizTalk orchestrations. This is an extended version of the Stop-Orchestration VBScript included in the BizTalk 2006 SDK, which I hope someone finds useful :-).

The script can be used to start or stop either a specific orchestration or a group of orchestrations defined in a BizTalk assembly. For example, to stop and unenlist all orchestrations in a given assembly, you could use this:

stop-orch -assembly 'MyProject.BizTalk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=50b7b2906e3f8aa5' -unenlist

Here's the code for the script:

$script:bound = 2
$script:started = 4
$script:controlRecvLoc = 2
$script:controlInst = 2

function script:get-assemblyfilter([string]$assembly) {
   # The BizTalk WMI provider uses separate properties for each
   # part of the assembly name, so break it up to make it easier to handle
   $parts = $assembly.Split((',', '='))
   $filter = "AssemblyName='$($parts[0])'"
   if ( $parts.Count -gt 1 ) {
      for ( $i=1; $i -lt $parts.Count; $i += 2 ) {
         $filter = "$filter and Assembly$($parts[$i].trim())='$($parts[$i+1])'"
      }
   }
   return $filter
}
function script:find-orch([string]$name, [string]$assembly) {
   # We want to be able to find orchestrations by
   # name and/or assembly. That way we can control
   # all orchestrations in a single assembly in one call
   $filter = ""
   if ( ![String]::IsNullOrEmpty($name) ) {
      $filter = "Name='$name'"
      if ( ![String]::IsNullOrEmpty($assembly) ) {
         $filter = "$filter and $(get-assemblyfilter $assembly)"
      }
   } else {
      $filter = $(get-assemblyfilter $assembly)
   }
   get-wmiobject MSBTS_Orchestration `
      -namespace 'root\MicrosoftBizTalkServer' `
      -filter $filter
}

function start-orch([string]$name, [string]$assembly) {
   $orch = (find-orch $name $assembly)
   $orch | ?{ $_.OrchestrationStatus -eq $bound } | %{
      write-host "Enlisting $($_.Name)..."
      [void]$_.Enlist()
   }
   $orch | ?{ $_.OrchestrationStatus -ne $started } | %{
      write-host "Starting $($_.Name)..."
      [void]$_.Start($controlRecvLoc, $controlInst)
   }
}

function stop-orch([string]$name, [string]$assembly, [switch]$unenlist = $false) {
   $orch = (find-orch $name $assembly)
   $orch | ?{ $_.OrchestrationStatus -eq $started } | %{
      write-host "Stopping $($_.Name)..."
      [void]$_.Stop($controlRecvLoc, $controlInst)
      if ( $unenlist ) {
         [void]$_.Unenlist()
      }
   }
}

BizTalk Filters not Getting Imported

Link. June 21, 2008. Comments [1]. Posted in: BizTalk

... or how automatic formatting of XML files can make you miserable.

During the last few days I've been helping out a client get ready for deploying a BizTalk solution. One of those things this involved was taking the existing BizTalk Binding XML files and making minor edits to them so they would match the new environment.

I did the changes, and the BizTalk Administrator used the updated Binding Files to import them into the new BizTalk Servers. They imported without any errors at all. A couple hours later he noticed some test messages were getting incorrectly routed to the wrong send ports (there's a lot of messaging only stuff in this solution)., so he checked the send port configuration.

There were no filters defined at all! We checked the Binding files again, and yes they were clearly defined there. Why were they not getting imported?

The culprit turned out to be Visual Studio. I had edited the binding files in VS and, for several reasons, this involved doing copy-and-pasting the entire XML content of the binding files between machines. Normally this isn't a problem, but this time it was.

VS will reformat XML content when you paste it into VS. This is usually a welcomed feature, but not now. Turns out that VS reformatted the <Filter> elements of the Send port configurations like this:

<Filter>
   &lt;?xml version="1.0" encoding="utf-16"?&gt;
   &lt;Filter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
...

See anything weird? I didn't see it either at first. The problem is the line break and extra white space caused by the indentation between the opening <Filter> element and the actual string-encoded XML of the filter expression.

Apparently, BizTalk can't deal with this at all and simply treats it as if the <Filter> element had been empty when it imports the binding file. No warnings, no errors, it simply ignores it silently.

I removed the space leaving it like this:

<Filter>&lt;?xml version="1.0" encoding="utf-16"?&gt;
   &lt;Filter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
...

And now it was imported correctly and all the Filters were recreated successfully. This was maddening to say the least, and it's one of those pesky bugs that can make deploying BizTalk solutions an even more miserable experience than it already is. Definitely a very annoying bug in the Binding importer code.

403 Forbidden in Reporting Services

Link. June 11, 2008. Comments [1]. Posted in:

I just spent a good chunk of time fighting a problem with my SQL Server 2005 Reporting Services installation. I had not previously used it on this machine so it should've been exactly as the SQL Server (and SP2) installation program configured it.

I started by deploying a new set of reports from Visual Studio over to the server, which worked straight away. I then went to the Web-based Report manager and could see my reports deployed, but as soon as I tried actually rendering one of the reports, I'd get an error like this one:

Remote server returned an error: (403) Forbidden

Long story short, the problem was in how the /Reports application references the services in the /ReportServer application, and I fixed it by going to IIS and modifying the /ReportServer application configuration to add "ReportService2005.asmx" as a possible default content page under the "Documents" tab of the application's property page.

About

Tomas Restrepo is co-founder of devdeo. His interests include .NET, Connected Systems, PowerShell and, lately, dynamic programming languages. More...

email: tomas@winterdom.com
msn: tomasr@passport.com
twitter: tomas_restrepo

Technorati Profile

devdeo logo

View my profile on LinkedIn

MVP logo

Syndicate

Ads


Links

Categories

Statistics

Total Posts: 1006
This Year: 76
This Month: 7
This Week: 0
Comments: 771

Blogroll

Post Archive

Other

Copyright © 2002-2008, Tomas Restrepo.

Powered by: newtelligence dasBlog 1.9.7174.0

Sign In