Run a single-threaded apartment method with parameters that returns a value within a web service

by Heathesh 21. July 2010 20:22

The need arose for me to run a method that used the WebBrowser object within a web service. The problem that I had is that you cannot run a WebBrowser object unless it's run in a single-threaded apartment. Within a windows forms or console application it's easy enough to set the apartment state by decorating your method with the [STAThread] attribute or using:

//set the current thread's apartment state

That does not work within a web service. My method also needed to accept parameters and to return a value. The method I needed to run looked like this:

public static byte[] GenerateScreenshot(string url, CustomImageFormat imageFormat, int width, int height)

This method was contained within a manager class I had created called GraphicsManager. As you can see it returns a byte[] and needs to accept four parameters. To call this method from the web service I first created a static private variable (make sure you create static variables) in my web service class for each of the parameters as well as the byte array like so:

        /// <summary>
        /// The returned image
        /// </summary>
        private static byte[] _returnedImage = null;
        /// <summary>
        /// The url
        /// </summary>
        private static string _url = string.Empty;
        /// <summary>
        /// The custom image format
        /// </summary>
        private static CustomImageFormat _imageFormat = CustomImageFormat.Gif;
        /// <summary>
        /// The width
        /// </summary>
        private static int _width = -1;
        /// <summary>
        /// The height
        /// </summary>
        private static int _height = -1;

I set default values for the variables simply out of habit. Next I created a single-threaded apartment method to execute my manager method like so. Notice that I decorated the method with the [STAThread] attribute and that the method is also a static method:

        /// <summary>
        /// Static method to run under Apartment State
        /// </summary>
        private static void generateScreenShot()
            _returnedImage = GraphicsManager.GenerateScreenshot(_url, _imageFormat, _width, _height);

As you can see I'm using the private variables I setup above in call to GraphicsManager.GenerateScreenshot. The last thing I needed to do was to create the WebMethod on my web service itself. I did this like so:

        /// <summary>
        /// Generates a portion of a screen shot image of the URL specified with with width and height specified and returns the byte stream of it in the specified format
        /// </summary>
        /// <param name="url">String of the URL to thumb nail</param>
        /// <param name="imageFormat">CustomImageFormat enum of the image format to return</param>
        /// <param name="width">Int of the width of the image to be returned</param>
        /// <param name="height">Int of the height of the image to be returned</param>
        /// <returns>Byte array of the thumb nail in the CustomImageFormat specified</returns>
        [WebMethod(Description = @"Generates a portion of a screen shot image of the URL specified with with width and height specified and returns the byte stream of it in the specified format.")]
        public byte[] GenerateWebsiteScreenshot(string url, CustomImageFormat imageFormat, int width, int height)
            //set the private property values to the values passed in
            _url = url;
            _imageFormat = imageFormat;
            _width = width;
            _height = height;

            Thread apartmentThread = new Thread(new ThreadStart(generateScreenShot));

            //set the apartment state to single-threaded apartment

            //block the calling thread so as to wait for the method to complete processing

            //return the private property value that was generated in the apartment state thread
            return _returnedImage;

That was it. My web service method could now run and utilize the web browser object with no problems...

Happy threading!

Tags: , , ,

.Net | Web Services

Powered by BlogEngine.NET (with enhancements by Heathesh)
Theme by Mads Kristensen (with tweeks by Heathesh)


Microsoft Certified Professional

Microsoft Certified Technology Specialist

Answer Questions


Tag cloud


<<  May 2017  >>

View posts in large calendar