A 64-bit 32-bit Dilemma

I recently ran into an interesting situation that I was able to solve through code. The project was to create a document migration tool, something I’ve done many times, so it seemed pretty straightforward. I was moving documents and metadata from a 3rd party content management system to SharePoint 2007. I was developing on a 32-bit OS on a machine provided by my client. The source system had an API, albeit 32-bit COM. There was some example code in their SDK for VB6, so at least there was something. It was easy enough to create a .Net wrapper to that COM DLL and figure out the API. The SharePoint code was not too difficult either, something I’ve done before. In this case I had to use the API, not the web services because I wanted to keep the original file created/modified dates from the source system. You can’t set those using the web services. Therefore, the tool is forced to run on the SharePoint server (this is important factor for the upcoming dilemma). Luckily the source system was accessible remotely.

Works on My Machine

Of course, in my dev environment everything works great. So I copy my app to a SharePoint server to test in an environment more like production. It crashes immediately with a COM exception:

 Retrieving the COM class factory for component with CLSID {FDD9199A-1BB4-4433-B9E1-D550D3118676} failed due to the following error: 80040154.

What?? After a little research I determine the problem: the SharePoint server is 64-bit. My .Net code was compiled for any CPU, so it ran as 64-bit on the server, while it was 32-bit on my dev box. When compiled for 64-bit, it can’t access the 32-bit COM DLL (there might be a solution for this, I didn’t find it). I went back, and forced the code to compile for 32-bit. The app soared right past the error for the COM DLL, but came to a screeching halt when trying to access the SharePoint API. If SharePoint is installed on a 64-bit server, the code has to run compiled for 64-bit in order to access the API. Now you see the dilemma. I have to use a 32-bit only COM DLL and a 64-bit app for accessing SharePoint. I can’t skirt the issue using the SharePoint web services because I need functionality only available in the API.

My Solution

I decided on using two applications, one compiled for 32-bit which accesses the source system and fetches the data, and a second one compiled for 64-bit to access the SharePoint API. Five years ago I probably would have done the same thing, and write the data to an XML file from the first app, and then launch the second app and read the data from the file. There were hundreds of thousands of documents to migrate, all that disk access would be a performance killer. But now that I have WCF, I could do this much more elegantly.

32-64solution[1]

The 32-bit app contained the UI, and was able to use the 32-bit COM DLL to fetch documents and metadata. Once it had a logical set of data in memory, it used WCF with named pipes as the transport protocol to pass the data structure to the second app. The second app was 64-bit, and launched by the first app as a process using the System.Diagnostics namespace. It communicated just fine with the SharePoint API. The second app had no GUI, but I kept the console window for writing messages and to provide a way to manually exit the app in case things went awry. The first app kept a handle on the process that launched the second app, so that when a user closed the first app, it could close the second app for  the user.

WCF was a good fit for this dilemma. The only issue I encountered was managing the message size, because WCF expects you to configure a maximum size for that. Of course configuring WCF is not that easy, but you only have to do it once. I was pleased that I could make a mex endpoint in the 64-bit app, and then use Visual Studio to make a Service reference to it from the 32-bit app, and the configuration comes out for named pipes even though the mex endpoint was http. Another feature I didn’t know but managed to discover. In the end, the process is seamless to the user, and does what I need without much disk access to slow it down.

Posted: Tuesday, July 13, 2010 10:12:05 AM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | SharePoint | WCF

Using Linq Against a Custom ConfigurationElementCollection

By default, ConfigurationElementCollections don’t implement IEnumerable<T>, so if you are using custom configuration sections you can’t query them with linq. I found a casting solution, but I figured I could do better because the custom configuration classes are under my control, so it would be cleaner to implement the required functionality instead of using the clunky cast in the code consuming the collection. I implemented IEnumerable<T> against the ConfigurationElementCollection. It’s pretty straightforward, just calling the base class BaseGet function and casting the result properly using the As keyword. Now I can execute linq queries against my collection.

using System;

using System.Collections.Generic;

using System.Configuration;

 

namespace Config.Demo

{

    public class MapConfig : ConfigurationSection

    {

        [ConfigurationProperty("fields")]

        public MapConfigCollection Fields { get { return this["fields"] as MapConfigCollection; } }

    }

    public class MapConfigElement : ConfigurationElement

    {

        [ConfigurationProperty("server")]

        public string Server { get { return this["server"] as string; } }

 

        [ConfigurationProperty("name")]

        public string Name { get { return this["name"] as string; } }

 

        [ConfigurationProperty("id")]

        public int Id { get { return (int)this["id"]; } }

    }

    public class MapConfigCollection : ConfigurationElementCollection, IEnumerable<MapConfigElement>

    {

        public MapConfigElement this[int index]

        {

            get { return base.BaseGet(index) as MapConfigElement; }

            set

            {

                if (base.BaseGet(index) != null)

                {

                    base.BaseRemoveAt(index);

                    this.BaseAdd(index, value);

                }

            }

        }

 

        protected override ConfigurationElement CreateNewElement()

        {

            return new MapConfigElement();

        }

 

        protected override object GetElementKey(ConfigurationElement element)

        {

            return ((MapConfigElement)element).Id;

        }

 

        #region IEnumerable<MapConfigElement> Members

 

        public new IEnumerator<MapConfigElement> GetEnumerator()

        {

            int count = base.Count;

            for (int i = 0; i < count; i++)

            {

                yield return base.BaseGet(i) as MapConfigElement;

            }

        }

 

        #endregion

    }

}

Posted: Wednesday, June 02, 2010 4:58:09 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | Linq

Creating an Extraction Rule for VSTS 2008 Web Tests

Extraction rules are essentially for finding data in the HTTP response and placing it in the output context of the web test. There are a few built-in tests, but they mostly focus on the HTML tags themselves and the attributes. In my case I really needed the data between span tags. I think this could probably be done with the existing rules and some regular expressions, but I couldn’t resist the chance to write some code and learn something new.

All you need to do is place the class file in the Test Project and compile it. The rule automatically becomes available to the tests in the project.  Here is my class that finds a span for a given ClientId. It overrides the Execute method of the ExtractionRule base class and attempts to find a span for the given ID. If the span is found, it parses the HTML string to find the content of the span tag.

namespace WebTestDemo

{

    [System.ComponentModel.DisplayName("Span Extractor")]

    public class ExtractSpan : ExtractionRule

    {

        // The name of the desired input field

        private string nameValue;

        public string ClientId

        {

            get { return nameValue; }

            set { nameValue = value; }

        }

 

        public override void Extract(object sender, ExtractionEventArgs e)

        {

            string[] tagTypeFilter = new string[] { "span" };

 

            //Fail the test if nothing is found (this may need to be modified)

            e.Success = false;

 

            if (e.Response.HtmlDocument != null && e.Response.IsHtml)

            {

                try

                {

                    //Find the span tag based on ID. Exception if none found

                    HtmlTag result = e.Response.HtmlDocument.GetFilteredHtmlTags(tagTypeFilter).First(t => string.Equals(t.GetAttributeValueAsString("ID"), this.nameValue, StringComparison.OrdinalIgnoreCase));

 

                    //The span was found (no exception), now find the data

 

                    //Get the location of the ID in the span tag

                    int startPosition = e.Response.BodyString.IndexOf(this.nameValue);

 

                    //Find the position of the data immediately following the closing angle bracket of the span,

                    //  accounting for the > character as well

                    startPosition = e.Response.BodyString.IndexOf(">", startPosition) + 1;

 

                    //Get the position of the closing tag for the span

                    int endPosition = e.Response.BodyString.IndexOf("</span>", startPosition);

 

                    //Fetch the content

                    string content = e.Response.BodyString.Substring(startPosition, endPosition - startPosition);

 

                    //Add the value to the context output. This could just as easily go to a file or a DB

                    // this step is not necessary for the extraction to succeed

                    e.WebTest.Context.Add(this.ContextParameterName, content);

 

                    //Mark the extraction as successful

                    e.Success = true;

                }

                catch (Exception)

                {

                    e.Success = false;

                    e.WebTest.Context.Add(this.ContextParameterName, string.Format("span tag id={0} not found", this.nameValue));

                }

            }

        }

    }

}

Now that I have the class, I need to wire it up to a URL in a web test. Right-click the URL and choose Add Extraction Rule…

AddRuleToTest[1]

I need to set two properties:

  1. Context Parameter Name. This comes from the base ExtractionRule class, and is the name for the data that ends up in the output.
  2. ClientId. This is a custom property from my class. It is the ClientId of the rendered control in the HTML output. The class finds the span with this name and returns the data.

Now when I run the test, if the ClientId I specified was found, it shows up in the Context output after running the test. The Context Parameter Name was “SpanData” in this case:

ExtractionRuleResults[1]

This could be made more robust by not coding specifically for spans. Certainly there could be issues if the tag ID is used more than once or if there is significant nesting of spans within the tag you are trying to find. This code is intended to prove out the concept, it could certainly be made stronger.

One thing I want to mention is that all the code samples I have run across (MSDN included) show the RuleName property as the way to display the extraction rule name in the Visual Studio UI. But under compilation this property comes up as obsolete. I found the answer on Ed Glas’s blog. The obsolete message mentioned using attributes, but this info was not discoverable, so I was quite grateful for that posting to get the syntax correct.

Helpful Links

Must Read VSTS - Testing Related Blogs and Introductory Articles

How to: Create a Custom Extraction Rule

Custom Extraction Rule and Generating a Code Test from VSTS

Posted: Wednesday, August 26, 2009 8:29:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | Performance | Visual Studio | VSTS

Another “Why didn’t someone tell me this earlier” Post

90% of the projects I work on need to send emails, and most clients don’t allow developer SMTP servers floating around their network (for good reason). So a big headache ensues trying to get access to an Exchange or SMTP server somewhere. I have been doing this same dance for years. But today I find a blog post about sending emails without an SMTP server. The .Net calls to SMTP just write the emails out on the file system. It’s just configuration even. So much to know, so little time.

Posted: Wednesday, July 29, 2009 7:12:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 2.0 | .Net 3.5 | ASP.NET

Casting a Null

Found an interesting tidbit today. There is an ASP.NET page that is using session variables. The user has visited the page, and populated the session. But then the user lingers, and the session times out on a page that is not protected. The user then clicks a button, and the following line of C# code executes:

User foo = (User)Session[“bar”];

So what should happen here? An Exception? That’s what I would have thought. But not true. Since the session has expired, the session variable is now null, and you can cast a null into another data type having a value of null. Just as long as that type is nullable. So the line above is the same as:

User foo = (User)null;

which is perfectly valid.

I got the null reference exception down the line when trying to access a property of foo. So once again, defensive programming is the rule. Check your session variables for null!

Posted: Thursday, July 16, 2009 9:14:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 2.0 | .Net 3.5 | Strange Problems

LINQ: Selecting in Nested Collections

This took me longer than it should have to figure it out, so I am documenting it for later reuse. The case here is described as such:

I have a collection of person objects, which themselves contain a collection of address objects. I want to find all the addresses in a given city:

public class Address

{

     public string Street { get; set; }

     public string City { get; set; }

     public string Region { get; set; }

     public string Postal { get; set; }

     public AddressType Location { get; set; }

}

 

public class Person

{

     public string Name { get; set; }

     public string ID { get; set; }

     public string Title { get; set; }

     public List<Address> Addresses { get; set; }

}

....

IEnumerable<Address> results = from guy in allPersons

                               from addressResult in guy.Addresses

                               where addressResult City == "London"

                               select addressResult;

I understand this is similar to a join in a SQL statement, but in my case the data does not come from a database but a service where I can't control data selection in that way.

Posted: Tuesday, June 23, 2009 3:07:00 AM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | Linq

Invalid postback or callback argument - AJAX Control Toolkit

I was working to add some Ajax interactivity to a page that needed some asynchronous workings. Unfortunately, after displaying a ModalPopupExtender and the user clicking the Close button on the “popup”, the page would throw the following exception:

System.ArgumentException occurred
  Message="Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation=\"true\"/> in configuration or <%@ Page EnableEventValidation=\"true\" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation."
  Source="System.Web"
  StackTrace:
       at System.Web.UI.ClientScriptManager.ValidateEvent(String uniqueId, String argument)
  InnerException:

There are lots of explanations out there for this kind of problem, but none of the common answers really fit. The most common answer was to disable event validation. That wasn’t a good answer for me, I don’t think disabling an important security feature because you have complex code is a good solution. The other common answer was to override the render event to register the control posting back with the ScriptManager. This did not work at all for me.

After finding an reading through this post and the comments, I realized the problem was indeed in the code. After the call to ModalPopupExtender.Show(), the original code was re-binding a grid on the page. This order of events was causing the problem. I changed the binding to occur before the call to the ModalPopupExtender by changing which event containing the rebinding call, and the error went away.

Posted: Monday, March 23, 2009 8:46:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.0 | .Net 3.5 | ASP.NET | JavaScript/AJAX

Linq Foray

I’m working on a website with lots of user controls interacting with one another using ASP.NET Ajax using events. So I end up needing to find other controls often, especially within repeaters. Nested controls all over the place. I found this wonderful post about using an extension method to the Controls Collection that flattens the tree and allows for much simpler Linq queries. The extension method adds and All() function which is seriously useful.

Posted: Sunday, March 22, 2009 9:27:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | ASP.NET | JavaScript/AJAX | Linq

Don’t Do This

In ASP.NET, the DataList control renders as a table. Opening a new table in the header and trying to get rows to render just won’t end well. Lots of strange browser behavior should be the tip off that this isn't right.

Posted: Sunday, March 22, 2009 7:48:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 2.0 | .Net 3.5 | ASP.NET

eBooks on CodePlex

Wriju has a gread roundup of eBooks/guidance available on CodePlex.

Posted: Friday, January 09, 2009 4:01:49 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 2.0 | .Net 3.0 | .Net 3.5 | Programming | TFS | WCF

Getting Started with WCF and REST

Now that WCF has support for REST in .Net 3.5, it's time to get learning....

WCF REST Starter Kit

A Guide to Designing and Building RESTful Web Services with WCF 3.5

A bunch of screencasts by Aaron Skonnard

WCF and REST from the PDC

Dan Rigsby - REST support in WCF

Posted: Tuesday, November 04, 2008 12:58:09 AM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 3.5 | WCF