Statistics
Visits: 105080
Page Visits: 139140
Active visitors (monthly): 5364
Feed Count: 45
Most visited page: Adding value as a technical analyst
Category : ASP.NET

Service throttling issues in WCF hosted in Windows 7

My development environment is WCF 4 / IIS 7.5 / Windows 7 Professional. I have a WCF service with a single operation that sleeps for 2 seconds. My goal is to run 100 concurrent requests and ensure that all the requests complete within 2.1 seconds.

I started tinkering with service throttling. A service can have a service behavior which has throttling properties defined. So, I set the following parameters:


<serviceThrottling maxConcurrentInstances="100"
maxConcurrentCalls="100" maxConcurrentSessions="100" />

I went into perfmon and check the ServiceModelService => TimeOutService => Instances counter. It was showing as 10.

I assumed that there was some problem with the processModel. So, in machine.config, I changed the processModel to:


<processModel autoConfig="false"
minIOThreads="100" minWorkerThreads="100"
maxIOThreads="100" maxWorkerThreads="100" />

In perfmon, the instances counter was showing as 10. So, I went and checked the .NET CLR LocksAndThreads => w3wp => Total logical threads. This counter was showing somewhere between 30 and 40.  Again, very confusing.

After searching for more information, I found this forum post which suggests that Windows 7 has some limitations on performance tuning: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/449c17ca-1518-49f7-a58e-c043f0751bce/ . I wish I had checked this post earlier!

Permalink | No Comments | Leave your comment
 

Good articles in DNK

Here are some good articles in DNK for this month:
http://blogs.dotnetkicks.com/best-of-dnk/2011/11/02/best-net-articles-of-october-2011-fresh-off-the-presses/

I have been working on an interesting assignment involving Exchange web services (EWS). If you want to get started using EWS Managed API SDK, here is how you can:
http://blogs.dotnetkicks.com/vijayst/2011/11/getting-started-with-ews-managed-api-sdk/

I have been working on Silverlight and MVVM for the past few weeks. PRISM is an implementation of MVVM pattern. Here is the project in Codeplex:
http://compositewpf.codeplex.com/

Permalink | No Comments | Leave your comment
 

Localization of Webform applications in multiple languages

Usually, web applications should be available in multiple languages other than English. In this blogpost, I am going to walk over creating a sample application that will be localized in French and Dutch. Usually, the preferred language is picked from the user's browser settings. To make it a little tougher, we will allow the user to switch languages at runtime. To enable runtime switching of languages, we will add three link buttons in the master page.


<div style="background-color: #cccccc;float:right;">
    <asp:LinkButton ID="btnEn" runat="server" Text="en" CommandArgument="en" OnCommand="SetCulture"></asp:LinkButton> | 
    <asp:LinkButton ID="btnFr" runat="server" Text="fr" CommandArgument="fr" OnCommand="SetCulture"></asp:LinkButton> | 
    <asp:LinkButton ID="btnNl" runat="server" Text="nl" CommandArgument="nl" OnCommand="SetCulture"></asp:LinkButton> 
</div>

Localization is providing a placeholder for text in multiple languages. The text comes from a resource file. Asp.Net provides multiple ways of doing localization: implicit and explicit. In Default.aspx, we enable implicit localization. We allow the text within a label with ID lblImplicit to come from resource files. The code for the label has a meta:resourcekey="" attribute attached to it:


<h2>
    Culture Demo - Implicit Localization
</h2>
<p>
    <asp:Label ID="lblImplicit" runat="server" meta:resourcekey="lblImplicit" Text="Implicit Localization"></asp:Label>
</p>

In implicit localization, the text comes from a resource file defined under App_LocalResources folder. The resource file has the convention of .aspx..resx. The default resource file for default.aspx is default.aspx.resx. The resource file for french is default.aspx.fr.resx. Create resource files for each supported language. Within the resource file, use the .Text to define the text for the label. The french resource file looks like:

We can set explicit localization for About.aspx (just to try it out). Explicit localization looks for resource files under App_GlobalResources. In this folder, resource files are not organized by aspx page names. You can create a default resource file of Messages.resx. In the About.aspx, we can create a label to use Message1 from Messages.resx as follows:


<h2>
    Culture Demo - Explicit Localization
</h2>
<p>
    <asp:Label ID="lblExplicit" Text="<%$ Resources: Messages, Message1 %>" runat="server"></asp:Label>
</p>

In the above label, the text is available within a tag. It has a Resources: keyword. Both the Resource file name as well as the Key name is provided (delimited with a comma). The french resource file for Messages will look like Messages.fr.resx. The dutch resource file, Messages.nl.resx looks like:

 

Now, we are ready to write some code to make all of this work. When we are clicking the link button in the master page, the SetCulture event handler is called. All we do in the below code is set the Session["Culture"] variable to the selected language. Also, the page is redirected to. This will ensure that the selected culture will set in the reload.


protected void SetCulture(object sender, CommandEventArgs e)
{
    Session["Culture"] = e.CommandArgument.ToString();
    Response.Redirect(Request.RawUrl);
}

Every page has a method - InitializeCulture(). This method is triggered in the Page lifecycle ahead of all events including Page_PreInit(). This is one reason that the page is reloaded again. In InitializeCulture(), we pick the language setting from the Session variable. Then, we set the UICulture for the current thread. This will ensure that the right resource files are picked for the current request.


protected override void InitializeCulture()
{
    // When the user comes to the page for the first time
    if (Session["Culture"] == null)
    {
        Session["Culture"] = "en";
        Session["OldCulture"] = "en";
    }

    // Set the UI Culture here

    System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo((string)Session["Culture"]);
    UICulture = (string)Session["Culture"];
    base.InitializeCulture();

}

Finally, there is some code to enable / disable the link buttons in the Page_load of the master page:


protected void Page_Load(object sender, EventArgs e)
{
          
    string culture = (string)Session["Culture"];
    string oldCulture = (string)Session["OldCulture"];

    // Disable the button in current culture
    // This is required if user goes to some other page
    // Page is populated with controls.
    LinkButton newBtn = FindControl("btn" + culture) as LinkButton;
    if (newBtn != null)
        newBtn.Enabled = false;

    // if old culture is different
    // This happens when the user clicks on any of the link buttons
    if (culture != oldCulture)
    {
        // disable the button for the current culture
              

        // enable the old button and reset oldculture  
        LinkButton oldBtn = FindControl("btn" + oldCulture) as LinkButton;
        if (oldBtn != null)
            oldBtn.Enabled = true;
        Session["OldCulture"] = culture;
    }
}

One last thing to note, I have used a baseclass for Page - CultureDemo.MainPage. This class overrides the InitializeCulture method. All pages in the CultureDemo application derive from CultureDemo.MainPage instead of System.Web.UI.Page. This ensures that all page and all requests have the right language setting. The complete application is available in the zip file: CultureDemo

Permalink | No Comments | Leave your comment
 

Little things about the Page Lifecycle

PreInit: If you want to change the masterpage programatically, this is the event handler where it should be done: http://msdn.microsoft.com/en-us/library/c8y19k6h.aspx. Trying to change the MasterPage in any other event will cause an InvalidOperationException. This is because the masterpage rearranges the hierarchy of controls.

This is also the event handler where themes should be set programatically. If you try to change themes elsewhere, this is what you get: Invalid operation exception -
The 'Theme' property can only be set in or before the 'Page_PreInit' event.  http://msdn.microsoft.com/en-us/library/tx35bd89.aspx

Dynamic controls have to be recreated each time in PreInit. If dynamic controls are not recreated (on each postback), they do not appear in the page. If dynamic controls are created after PreInit method, the themes are not properly set.

Init: You can init control properties here. This is generally not used at all. This is because of the next event - LoadViewState

LoadViewState: LoadViewState loads control properties from the ViewState. This usually works in the case of postbacks.

Load: Do databinding of controls here manually. Initialize controls (for first time). Most initialization is done for the first time (IsPostback=false)

UserControl Load: Each UserControls Load is called. Here user controls are initialized.

LoadComplete: If you want to make some initializations based on UserControl's state, this is where to do it. Very rarely used. This is because UserControls initialize from ViewState. This is usually used when EnableViewState=false

Validation: If any validator controls are there in the page, this event is fired. After this event, Page.IsValid property is set. This is fired for postbacks

RaisePostBackEvent: This is the postback event handler where you write your code. Before writing any code, check if the page is valid. (IsValid=true)

PreRender: Used to emit custom scripts.

Automatic DataBinding: If you are using SqlDataSource, XmlDataSource etc, this is where automatic data binding happens. Automatic DataBinding happens only when IsPostBack=false (for the first time). In Postbacks, the ViewState loads the data.

SaveViewState: Saves the control properties into ViewState (which goes into the Response)

Render: Renders the control into the Response stream as HTML + Javascript.

Unload: Page and all its objects are released from memory.

 

Permalink | No Comments | Leave your comment
 

LINQ to XML versus XMLDOM

I have been trying out LINQ to XML and I am impressed with the improvements made over XML DOM. In this post, I will illustrate a few nice features where LINQ scores over DOM.

Creation of elements

To create a new element in DOM, the following code should be written:


XmlElement elem = XmlDocument.CreateElement("Employee");
XmlAttribute attr = XmlDocument.CreateAttribute("EmpID");
attr.Value = "100";
elem.Attributes.Add(attr);


The code is simpler in the case of LINQ:


XElement elem = new XElement("Employee",
               new XAttribute("EmpID", 100)); 

Adding elements as first node

In DOM, this takes quite a few steps. In LINQ, it is simpler with the AddFirst method: parent.AddFirst(child);

Removing elements is elegant

Removing elements in DOM is something like this: parent.Remove(child); In LINQ, removing a child element is done on the child element itself: child.Remove();

Setting optional attributes

In DOM, this is quite complex:


XmlAttribute attr = elem.Attributes("EmpID");
if(attr!=null)
{
    attr = XmlDocument.CreateAttribute("EmpID");    
}
attr.Value = "100";

In LINQ, this is a one liner: elem.SetAttributeValue("EmpID", 100);

Querying and XPath

In XML DOM, XPath was very useful to select elements:


XmlNode emp = XmlDocument.SelectSingleNode("/Employees/Employee[@id=100]");

Using LINQ is slightly longer. But the code is readable and it does not require a new skillset (XPath).


var qry = from elem in root.Elements("Employee")
                where elem.Attribute("EmpID").Value == 100
                select elem;

XElement emp = qry.First<xelement>();</xelement>

Overall, LINQ 2 XML supersedes DOM in capability and readability. The only disadvantage is that LINQ 2 XML does not support entities.

Permalink | No Comments | Leave your comment
 

HttpContext.Current.Profile is null

I ran into a problem where HttpContext.Current.Profile is returning null. This was after turning anonymous identification on. After investigation, I found the reason for this was Url rewriting. Using HttpContext.RewritePath caused the Profile module to terminate (or failed to start)


The following change in web.config will ensure that all modules will run irrespective of such events.

<system.webServer><modules runAllManagedModulesForAllRequests="true"><add name="UrlRewrite" type="VijayT.UrlRewrite,VijayT" /></modules></system.webServer>

The attribute runAllManagedModulesForAllRequests should be set to true. This also solved the session problem that I encountered earlier. See previous post.

Permalink | No Comments | Leave your comment
 

Interesting observation on Sessions

A web application loses its SessionModule in the following case:
  • Web application runs on IIS 7 in integrated pipeline mode
  • Web application has few folders that are authorized by forms authentication
  • The remaining Web application has access to unauthenticated users
  • The user moves from the free-for-all zone to authenticated zone and moves back to the free-for-all zone.
  • In this case, the web application does not have access to Session module. Any run-time access to Session object will throw a HttpException. The code if (Session != null) will create exception.
To illustrate the above, consider the web application having a web.config like the below:
<authentication mode="Forms"><forms loginUrl="~/Admin/Login.aspx" defaultUrl="~/Admin/Login.aspx" timeout="30" slidingExpiration="true"><credentials passwordFormat="Clear"></credentials></forms></authentication><authorization><allow users="?" /></authorization>

In the sub-folder - Admin, the web application has a web.config like the below:
<authorization><deny users="?" verbs="*" /></authorization>

When the user moves to Admin folder, and comes back to the main application, access to Session object in the runtime throws HttpException!
Permalink | 1 Comment | Leave your comment
 
Commented by Vijay at 30-Oct-2010 03:12 PM

This issue is resolved by making an adjustment in the web.config. Check the next post for resolution!

Auto-detect feeds programatically

The feed of any blog or site can be detected by the link tag:
<link href="rss.xml" rel="alternate" type="application/rss+xml" />
This can be found using WebRequest / WebResponse objects like this:
            Uri uri = new Uri(url, UriKind.Absolute);
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);

            HttpWebResponse res;
            try
            {
                res = (HttpWebResponse)req.GetResponse();
            }
            catch (WebException)
            {
                return bi;
            }

            string response = "";

            switch (res.StatusCode)
            {
                case HttpStatusCode.OK:
                    byte[] buffer = new byte[4096];
                    res.GetResponseStream().Read(buffer, 0, 4096);
                    response = System.Text.Encoding.UTF8.GetString(buffer);
                    break;
            }
Once the feed URL is found programmatically, it is easy to strip the entire XML and deserialize it as System.ServiceModel.Syndication.SyndicationFeed object. SyndicationFeed has a list of SyndicationItems which is nothing but the blogpost or news item
           XmlReader reader;
            try
            {
                reader = XmlReader.Create(feed);
            }
            catch
            {
               
                return;
            }

            SyndicationFeed synFeed = null;

            string type = blog.Attributes["Type"].Value;
            if (type == "ATOM")
            {
                Atom10FeedFormatter atom = new Atom10FeedFormatter();
                if (atom.CanRead(reader))
                {
                    atom.ReadFrom(reader);
                    synFeed = atom.Feed;
                }
            }
            else
            {
                Rss20FeedFormatter rss = new Rss20FeedFormatter();
                if (rss.CanRead(reader))
                {
                    rss.ReadFrom(reader);
                    synFeed = rss.Feed;
                }
            }
Permalink | No Comments | Leave your comment
 

A Simple XmlProfileProvider

A simple XmlProfileProvider can be created without any membership provider. This MSDN article provides the basics of creating a Custom Profile Provider. The most important methods to override are: Initialize, GetPropertyValues, SetPropertyValues, GetProfilesByUserName, GetProfiles. The rest of the method can be implemented for the sake of completeness (of implementing the ProfileProvider base class). The following zip file contains a sample implementation of the simplest XmlProfileProvider. This provider supports only the basic primitive types, String, DateTime. Complex objects are serialized using .ToString()

Sample XmlProfileProvider
Permalink | No Comments | Leave your comment
 

Path of TreeNode

How do I get the full path of TreeNode, all the way from the Root node?

Each TreeNode has a property ValuePath which gives the full path of TreeNode from the Root node. All node values, from the Root node, are appended with a separator. Each node value is separated by the PathSeparator attribute of TreeView control. Here is an example:


<asp:TreeView ID="tvw" runat="server" PathSeparator="\">
    <Nodes>
        <asp:TreeNode Text="C:" Value="C:">
            <asp:TreeNode Text="Abc" Value="Abc"></asp:TreeNode>
        </asp:TreeNode>
    </Nodes>
</asp:TreeView>


void tvw_SelectedNodeChanged(object sender, EventArgs e)
{
    Response.Write(tvw.SelectedNode.ValuePath);
}

Permalink | 3 Comments | Leave your comment
 
Commented by Vijay at 31-Jul-2011 10:11 PM

Please try the jQuery plugin for TreeView: http://docs.jquery.com/Plugins/Treeview

Commented by ejazhasan at 22-Jul-2011 10:55 PM

I want to get the same functionality with php and jquery, any tip, thanks, phycomp01@gmail.com

Commented by Gk at 04-Jun-2010 09:51 PM
This is too simple for a blogpost ..

Cropping Images to similar size

I want to show images of different sizes in a ListView. The image is displayed in a standard size. However, I do not want the images to be skewed or expanded while displaying.How can I do this?

The most common approach is to use Image.GetThumbnailImage(). This will work if all images have the same width / height ratio. But if width / height ratio is different, then the images will appear skewed.

A more suitable approach is to crop the image so that width / height ratio of all images is same as desired width / height ratio of desired display. Here is some sample code:


public void ProcessRequest(HttpContext context)
{
    // This is the dimensions you want to display in the web page
    int displayWidth = 400;
    int displayHeight = 300;
    float displayAspect = (float)displayWidth / displayHeight;

    // Get the filename and initialize the image to draw
    string file = context.Request.QueryString["name"];
    Image image = Image.FromFile(context.Server.MapPath("~/" + file + ".jpg"));

    // Get the aspect of image in the file
    // Crop the image to the same ratio as the display desired
    float aspect = (float)image.Width / image.Height;
    
    int newWidth = image.Width;
    int newHeight = image.Height;

    if (aspect > displayAspect)
    {
        newWidth = (int)(image.Height * displayAspect);
    }
    if (aspect < displayAspect)
    {
        newHeight = (int)(image.Width / displayAspect);
    }

    // SrcRect = Cropped rectangle from the file
    Rectangle srcRect = new Rectangle((image.Width - newWidth) / 2, (image.Height - newHeight) / 2, newWidth, newHeight);
    
    // Bitmap to copy to
    Bitmap bmp = new Bitmap(newWidth, newHeight);
    Rectangle destRect = new Rectangle(0, 0, newWidth, newHeight);
    Graphics graphics = Graphics.FromImage(bmp);

    // Copy to new image using Graphics object
    graphics.DrawImage(image, destRect, srcRect, GraphicsUnit.Pixel);
    
    // Get the bytestream of the cropped bitmap
    MemoryStream ms = new MemoryStream();
    bmp.Save(ms, ImageFormat.Jpeg);
    context.Response.BinaryWrite(ms.GetBuffer());
}

Here is a sample markup using the above handler.

<form id="form1" runat="server"><div><img src="Viewer.ashx?name=Kp1" width="400" height="300" /><img src="Viewer.ashx?name=Kp2" width="400" height="300" /><img src="Viewer.ashx?name=Kp3" width="400" height="300" /></div></form>

Permalink | No Comments | Leave your comment
 

Restrictions of FileUpload control

The FileUpload control from ASP.Net has several limitations. The most common limitation is regarding the filesize. By default, files of upto 4MB can be uploaded without any problems. Beyond that, ASP.Net will reject the request. To allow files of upto 2GB to be uploaded, you can change the httpRunTime in web.config as follows:

<system.web><httpRunTime maxRequestLength="2000000" executionTimeOut="999999" /></system.web>
The maxRequestLength is specified in KB. A size of 2,000,000 will allow almost a 2GB file to be uploaded. Also, the timeout to complete the request should be set high so that upload can happen. If maxRequestLength is exceeded in a request, then the request is abruptly declined and control is returned back to the browser. This error cannot be trapped within the AsP.Net framework because - the page is not loaded, no exception is raised, no HttpModule is called, the request abruptly terminates and browser receives no status code.

The other limitation is that it is not possible for the upload control to determine the size of the file before the upload. This means that it is not possible to restrict the upload of files based on file size. I cannot set a javascript rule that files beyond 100KB cannot be uploaded

Apart from large files upload, the upload control has other problems. It is not possible to set a filter-type of which files to upload. For eg, if you want to upload only image files, it is not possible to set a filter - .jpg | .gif | .bmp to the upload control so that only files of these types are shown.

The FileUpload control does not have a progress bar to indicate the progress of the upload. If your website allows users to upload files regularly, then it is better to go for a custom FileUpload control based on JQuery or Silverlight

Permalink | No Comments | Leave your comment
 

Image Handler

I have images stored in a network drive in another server. How can I show the image in a web page?

If for some reason, it is not possible to create a virtual directory within IIS, then creating a handler for streaming images is the best solution. A handler is a class derived from IHttpHandler. It has a method called ProcessRequest which contains the Request and Response objects. The code for showing streaming images in a webpage using handler is as follows:


public class ImageViewer : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        string id = context.Request.QueryString["Id"];
        if (!String.IsNullOrEmpty(id))
        {
            // Retrieve the image filename based on id
            // For our example, the image filename is C:\red.jpg
            string filePath = "C:\\red.jpg";
            // The above path could be any network drive

            
            FileStream fs = new FileStream(filePath, FileMode.Open);
            byte [] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, (int)fs.Length);
            context.Response.BinaryWrite(bytes);
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

In the above code, a filestream object is used to access the file in a network drive. The image is read into a binary buffer (byte []) and is written into the Response object.

In the ASPX page, you will write code like below to access the image using Handler (.ashx):

<img src="ImageViewer.ashx?id=1" />

Permalink | 3 Comments | Leave your comment
 
Commented by EStein at 26-Oct-2009 05:20 AM

I am facing error in line Dim fs As New FileStream(sFilePath, FileMode.Open) The error is : Logon failure: unknown user name or bad password


Dim sId As String = "" 
Dim sFilePath As String = "" 
sId = context.Request.QueryString("id") 
If Not String.IsNullOrEmpty("id") Then 
   sFilePath = "\\it-dt-04\AAA\aaa.png" 
   Dim fs As New FileStream(sFilePath, FileMode.Open) 
   Dim bytes As Byte() = New Byte(fs.Length - 1) {} 
   fs.Read(bytes, 0, CInt(fs.Length)) context.Response.BinaryWrite(bytes) 
End If

Commented by Vijay at 26-Oct-2009 08:26 PM

Are you using out-of-process app pooling. Check this KB article: http://support.microsoft.com/kb/255770

Commented by Qvcool at 26-Apr-2010 05:07 PM
It isn't working when I run the page. It just shows a messed up picture of a document.

Referer in Request Header

I have a page which I do not want to the user to access directly by typing the hyperlink. If the user directly accesses the page, I want to display a 500 Internal Server Error

The Request header has a key called Referer. This key contains the URL from which the user has come to the page. If the user clicked on a link in Page1 and came to Page2, the Referer header in Page2 will contain the URL of Page 1. Here is some code:


string referer = Request.Headers["Referer"];

if (String.IsNullOrEmpty(referer))
{
    Response.Clear();
    Response.Status = "500 Internal Server Error";
    Response.StatusCode = 500;
    Response.End();
}

Permalink | 1 Comment | Leave your comment
 
Commented by rtpHarry at 15-Oct-2009 09:47 AM
Just so you know - certain firewalls and security software clears the referrer field - http://en.wikipedia.org/wiki/HTTP_referrer#Referrer_hiding

Application_End() and Server.MapPath()

I wrote the following code in Application_End. It appeared as if Application_End was not firing


XmlDocument statDoc = new XmlDocument();
string path = Server.MapPath("~/App_data/Stat.xml");
statDoc.Load(path);
statDoc.SelectSingleNode("/Stats/Stat[@id=\"Visits\"]").Attributes["Count"].Value = Application["Visits"].ToString();
statDoc.SelectSingleNode("/Stats/Stat[@id=\"Hits\"]").Attributes["Count"].Value = Application["Hits"].ToString();
statDoc.Save(path);

With the help of this forum post, I was able to solve the mystery. Server.MapPath() does not work within Application_End() or Session.End()

Permalink | No Comments | Leave your comment