:::: MENU ::::

Wednesday, April 29, 2009

Just thought of sharing a some useful IIS App pool functions I wrote long back in C#.  Requirement was to play around with IIS v5.0/6.0 and do all settings dynamically -

Note : You must have administrator priveledge to perform all IIS actions.

Namespace Required

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.IO;
using System.Diagnostics;
using IISOle; // IISOle requires a reference to the Active Directory Services.
using System.Reflection;
using System.Configuration;
using System.Text.RegularExpressions;

Functions

public static bool RecycleAppPool(string serverName, string adminUsername, string adminPassword, string appPoolName)
        {
            DirectoryEntry appPools = new DirectoryEntry("IIS://" + serverName + "/w3svc/apppools", adminUsername, adminPassword);
            bool status = false;
            foreach (DirectoryEntry AppPool in appPools.Children)
            {
                if (appPoolName.Equals(AppPool.Name, StringComparison.OrdinalIgnoreCase))
                {
                    AppPool.Invoke("Recycle", null);
                    status = true;
                    break;
                }
            }
            appPools = null;
            return status;
        }

 

/// <summary>
        /// Creates AppPool
        /// </summary>
        /// <param name="metabasePath"></param>
        /// <param name="appPoolName"></param>
        public static bool CreateAppPool(string metabasePath, string appPoolName)
        {
            //  metabasePath is of the form "IIS://<servername>/W3SVC/AppPools"
            //    for example "IIS://localhost/W3SVC/AppPools"
            //  appPoolName is of the form "<name>", for example, "MyAppPool"
            DirectoryEntry newpool, apppools;
            try
            {
                if (metabasePath.EndsWith("/W3SVC/AppPools"))
                {
                    apppools = new DirectoryEntry(metabasePath);
                    newpool = apppools.Children.Add(appPoolName, "IIsApplicationPool");
                    newpool.CommitChanges();
                    newpool = null;
                    apppools = null;
                    return true;
                }
                else
                    throw new Exception(" Failed in CreateAppPool; application pools can only be created in the */W3SVC/AppPools node.");               
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Failed in CreateAppPool with the following exception: \n{0}", ex.Message));
            }
            finally
            {
                newpool = null;
                apppools = null;
            }
        }

        /// <summary>
        /// Assigns AppPool to Virtual Directory
        /// </summary>
        /// <param name="metabasePath"></param>
        /// <param name="appPoolName"></param>
        public static bool AssignVDirToAppPool(string metabasePath, string appPoolName)
        {
            //  metabasePath is of the form "IIS://<servername>/W3SVC/<siteID>/Root[/<vDir>]"
            //    for example "IIS://localhost/W3SVC/1/Root/MyVDir"
            //  appPoolName is of the form "<name>", for example, "MyAppPool"
            //Console.WriteLine("\nAssigning application {0} to the application pool named {1}:", metabasePath, appPoolName);

            DirectoryEntry vDir = new DirectoryEntry(metabasePath);
            string className = vDir.SchemaClassName.ToString();
            if (className.EndsWith("VirtualDir"))
            {
                object[] param = { 0, appPoolName, true };
                vDir.Invoke("AppCreate3", param);
                vDir.Properties["AppIsolated"][0] = "2";
                vDir = null;
                return true;
            }
            else
                throw new Exception(" Failed in AssignVDirToAppPool; only virtual directories can be assigned to application pools");
        }

 

  /// <summary>
        /// Delete AppPool
        /// </summary>
        /// <param name="metabasePath"></param>
        /// <param name="appPoolName"></param>
        public static bool DeleteAppPool(string serverName, string adminUsername, string adminPassword, string appPoolName)
        {
            //  metabasePath is of the form "IIS://<servername>/W3SVC/AppPools"
            //  for example "IIS://localhost/W3SVC/AppPools"
            //  appPoolName is of the form "<name>", for example, "MyAppPool"

            DirectoryEntry appPools = new DirectoryEntry("IIS://" + serverName + "/w3svc/apppools", adminUsername, adminPassword);
            bool status = false;
            foreach (DirectoryEntry AppPool in appPools.Children)
            {
                if (appPoolName.Equals(AppPool.Name, StringComparison.OrdinalIgnoreCase))
                {
                    AppPool.DeleteTree();
                    status = true;
                    break;
                }
            }
            appPools = null;
            return status;
        }

Hope you folks find it useful. If you need any other help related to IIS, just post me your requirement.

        public static void AddHostHeader(string serverName, string adminUsername, string adminPassword, string websiteName, string hostHeader)

        {

            string siteID = GetSiteID(serverName, adminUsername, adminPassword, websiteName);

            DirectoryEntry root = new DirectoryEntry("IIS://" + serverName + "/W3SVC/" + siteID, adminUsername, adminPassword);

            PropertyValueCollection serverBindings = root.Properties["ServerBindings"];

            //Add the new binding        

            serverBindings.Add(hostHeader);

            //Create an object array and copy the content to this array     

            Object[] newList = new Object[serverBindings.Count];

            serverBindings.CopyTo(newList, 0);

            //Write to metabase

            root.Properties["ServerBindings"].Value = newList;

            root.CommitChanges();

            root.Close();

            root.Dispose();

        }

 

        public static string GetSiteID(string serverName, string adminUsername, string adminPassword, string websiteName)

        {

            DirectoryEntry root = new DirectoryEntry("IIS://" + serverName + "/W3SVC", adminUsername, adminPassword);

            string siteID = "0";

            foreach (DirectoryEntry e in root.Children)

            {

                if ((e.SchemaClassName == "IIsWebServer") && (e.Properties["ServerComment"][0].ToString() == websiteName))

                {

                    siteID = e.Name;

                }

            }

            root.Close();

            root.Dispose();

            return siteID;

        }

When deploying ASP.NET applications to a production environment, you will most likely want to set the compilation debug attribute in web.config to false, as having debug set to true has some downsides:

  • Compilation takes longer as batch optimizations are disabled
  • Scripts and images from WebResources.axd will not be cached on the client
  • Larger memory footprint
  • Code will execute slower because of enabled debug paths

To force debug = false in all ASP.NET applications on the server, you can change the retail switch in machine.config:

<configuration>

    <system.web>

        <deployment retail="true"/>

    </system.web>

</configuration>

 

Tuesday, April 21, 2009

The ExpressionBuilder is still unknown to a lot of developers that haven’t experienced the sadistic pleasure of localizing a web application. It was introduce in ASP .NET 2.0 and allows you to bind values to control properties using declarative expressions.

I learnt about the ExpressionBuilder when I was doing some research on localization best practices in .NET. The recommendation is to use the specialized ResourceExpressionBuilder that creates code to retrieve resource values when the page is executed.

The ResourceExpressionBuilder is great for localization but what if we want to bind a control’s property to something else? Maybe a value in the Web.config’s AppSetting section. You may have tried something like this: 

<asp:TextBox
id="foo"
runat="server"
text="<%=ConfigurationManager.AppSettings["FooText"] %>"/>

Don’t be embarrassed. We’ve all done it at least once, and we’ve all been greeted with:

Parser Error Message: Server tags cannot contain <% ... %> constructs.

Thankfully there is an ExpressionBuilder that can help. the AppSettingsExpressionBuilder provides access to values in the AppSettings section of the Web.config and we use it as follows:

<asp:TextBox
id="foo"
runat="server"
text="<%$ AppSettings: FooText %>"/>

The ResourceExpressionBuilder and the AppSettingsExpressionBuilder are both derived from the ExpressionBuilder base class. That means we can create our own but I'll leave that topic for another day.

Keep in mind that the ExpressionBuilder only works when it is assigned to the property of a control. So you won’t be able to use it, for example, to pass values to a JavaScript constructor.

 

Monday, April 6, 2009

Why I used streams?

First, the resizing method is thought for web applications. Second, using streams is more general solution that using file paths (you don’t want to save files to hard disc if you get them from file upload and save to database). Web application may get image files from following sources:

  • files located on web server hard disc,
  • file uploads,
  • web services,
  • BLOB field of database table.

For first two sources we can ask stream directly. For the other two we can create memory stream and write byte array with image bytes to it.

Streams are useful also for output. Output stream may be file, response output stream or memory stream by example. And you can use also other streams that you need. In the case of file stream the resized image is written to file. In the case of response output stream the resized image is written back to browser. If you use memory stream then you may convert it to byte array so you can send image to database or post to web service.

Example

Let’s see now simple example that resizes images and uses streams. We have Resize.aspx page that accepts file uploads. If image is uploaded then it resizes it to 50% and shows it to user. If error occurs then error message is printed out.


protected void Page_Load(object sender, EventArgs e)

{

    if (Request.Files.Count > 0)

    {

        ShowPreview();

        return;

    }

}

protected void ErrorMessage(string error)

{

    var outputBuilder = new StringBuilder();

    outputBuilder.Append("<html><head></head><body>");

    outputBuilder.Append("<span>");

    outputBuilder.Append(error);

    outputBuilder.Append("</span>");

    outputBuilder.Append("</body></html>");

 

    try

    {

        Response.Clear();

        Response.ContentType = "text/html";

        Response.Write(outputBuilder);

        Response.End();

    }

    catch { }

}

 

protected void ShowPreview()

{

    var file = Request.Files[0];           

    try

    {

        Response.Clear();

        Response.ContentType = file.ContentType;

        ResizeImage(0.5,file.InputStream, Response.OutputStream);

        Response.End();               

    }

    catch (ArgumentException)

    {

        ErrorMessage("Unknown image file!");

    }

    catch(ThreadAbortException)

    {

 

    }

    catch (Exception ex)

    {

        ErrorMessage("Unknown error: " + ex);

    }

}

 

private void ResizeImage(double scaleFactor, Stream fromStream, Stream toStream)

{

    var image = Image.FromStream(fromStream);

    var newWidth = (int)(image.Width * scaleFactor);

    var newHeight = (int)(image.Height * scaleFactor);

    var thumbnailBitmap = new Bitmap(newWidth, newHeight);

 

    var thumbnailGraph = Graphics.FromImage(thumbnailBitmap);

    thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;

    thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;

    thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;

 

    var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);

    thumbnailGraph.DrawImage(image, imageRectangle);

 

    thumbnailBitmap.Save(toStream, image.RawFormat);

 

    thumbnailGraph.Dispose();

    thumbnailBitmap.Dispose();

    image.Dispose();

}

 

More