Nik's Technology Blog

Travels through programming, networks, and computers

IE6 – Why Web Developers Should Support the Browser

There seems to be so much fuss surrounding support for aging Microsoft browser Internet Explorer 6 lately, both from the web developer community and big corporations such as Google and Facebook. There are many websites dedicated to eradicating the browser, a Twitter petition, a joke campaign to save IE6 and a whole lot more…

While I don’t particularly enjoy spending a considerable amount of time per project making sure websites I build are IE6 compatible, I do see the benefit of supporting the browser.

I was in Google Analytics recently and looked at my browser statistics for this site.  Visitors to my site are fairly IT literate but Internet Explorer 6 still has a larger user base than Safari, Chrome and Opera with almost 9% share. Looking on the W3C Schools browser statistics, 12.1% of their users browsed the web with IE6 in September 2009.

NikMakris.com Web browser market share Sept 2009

Web browser market share

NikMakris.com Internet Explorer browser share Sept 2009

Internet Explorer browser versions

I could make the decision not to support IE6 for my personal site and about 9% of my visitors would be affected, but if I made that decision on a commercial website, I could end up losing out on business, especially since many of the people still actively using IE6 are businesses or public sector organisations who can’t easily upgrade or install an alternative web browser.
Many organisations also have legacy applications that do not work with new versions of Internet Explorer and during a recession many organisations will avoid spending money on upgrades and new software if they can afford not to.

Whilst it might be okay for Google and Facebook to block support for the browser when you visit their own web properties, would a client of yours be happy if you did the same with a website you built, potentially losing them business?

Internet Explorer 6 may be a dog of a browser in 2009, if you’re a web developer it probably causes you hours of pain creating dedicated style sheets and conditional statements.  You may even have had to make major template changes to deal with the many quirks of the browser rendering engine, but hopefully in the not too distant future it will become such a small percentage of the web browser market that we can all forget about it and start concentrating on new technologies such as HTML 5!

Learning jQuery 1.3 - Book Review

My first exposure to jQuery was using other developer's plugins to create animation effects such as sliders, and accordion menus.
The highly refactored and compressed production code isn't the easiest to read and understand, especially if you want to alter the code to any great extent.
After reading a few tutorials, I thought I'd buy a book and get more involved with the jQuery library.

As an ASP.NET developer used to coding with intellisense, I was pleased that jQuery has been incorporated into Visual Studio to allow ease of developing.
I browsed through the jQuery books on Amazon and opted to buy "Learning JQuery 1.3" by Jonathon Chaffer and Karl Swedberg after reading the user reviews.

I've now read most of the book and can highly recommend it.  The book assumes the reader has good HTML, CSS knowledge as well as a familiarity with JavaScript and the DOM, but this enables the book to quickly move onto doing useful, everyday tasks with jQuery.

The first six chapters of the book explore the jQuery library in a series of tutorials and examples focusing on core jQuery components.  Chapters 7 to 9 look at real-world problems and show how jQuery can provide solutions to them, and the final two chapters cover using and developing jQuery plugins.

Web developers should be aware of web accessibility and SEO issues with using client-side scripting and it is good to see the book highlighting the concepts of progressive enhancement and graceful degradation where appropriate.

"the inherent danger in making certain functionality, visual appeal, or textual information available only to those with web browsers capable of (and enabled for) using JavaScript.  Important information should be accessible to all, not just people who happen to be using the right software." - Learning jQuery 1.3,  page 94

After a brief introduction into the world of jQuery, what it does and how it came about the book moves quickly on to selectors, which are a fundamental part of how jQuery selects element(s) from the DOM.  It also covers jQuery's chaining capability, which coming from other programming languages looks odd at the outset, but quickly proves to be a very powerful technique.

The authors then move on to talk about events.  What I particularly like about the way jQuery handles events is that the behavioural code can be cleanly separated away from the HTML mark-up without having to litter tags with onclick and onload attributes.

The examples show how to add functionality on top of your HTML by binding events to elements on the page, which when triggered cause jQuery to modify the HTML to bring the page to life.  Techniques are introduced by example, then slowly refactored and improved while introducing new jQuery methods along the way, which is a breeze to follow and learn.

The fourth chapter covers effects such as fading in and out and custom animations, and jumps straight in to cover a useful example of how text size can be increased on-the-fly for ease of reading.  The intro also mentions an important usability example of effects.

jQuery effects "can also provide important usability enhancements that help orient the user when there is some change on a page (especially common in AJAX applications)."- Learning jQuery 1.3,  page 67

Chapter 5 is all about DOM manipulation and covers jQuery's many insertion methods such as copying and cloning parts of the page, which it demonstrates with another useful example in the form of dynamically creating CSS styled pull quotes from a page of text used to attract a readers attention.

AJAX is the next topic, which interested me enough to create a little tool to load in an XML RSS feed and create a blog category list from the data.
The chapter covers the various options of loading partial data from the server including appending a snippet of HTML into the page, JSON, XML and how to choose which method is the most appropriate.

Table manipulation is next on the agenda and the book discusses how to sort table data preventing page refreshing using AJAX as well as client-side sorting, filtering and pagination.

Chapter 8 delves into forms, using progressive enhancement to improve their appearance and behaviour.  It also covers AJAX auto-completion as well as an in-depth look at shopping carts.

Shufflers and Rotators are next and the book starts out by building a headline news feed rotator which gets it's headlines from an RSS feed, typically used by blogs.  It also covers carousels, image shufflers and image enlargement.

Chapter 10 and 11 examine the plugin architecture of jQuery and demonstrate how to use plugins and build your own.  I successfully produced my first jQuery plugin from reading this book.  You can check out my tag cloud plugin and read about how I originally built it before turning it into a plugin that other developers can use.

No defining declaration found for implementing OnValidate(System.Data.Linq.ChangeAction)

If you happen to be getting an error message like the one below, then read on.

Error    1    No defining declaration found for implementing declaration of partial method 'mvcCMS.Models.WebPage.OnValidate(System.Data.Linq.ChangeAction)'    C:\mvcCMS\Models\WebPage.cs    28    22    mvcCMS


I'm using LINQ to SQL designer in Visual Studio to create a database schema and I'm using a partial class to extend the code generated by the designer.

In the example below I am using the pattern used by NerdDinner.com to add business rules/validation to the model classes LINQ to SQL built based on my database schema.

namespace mvcCMS.Models
{
    public partial class WebPage
    {
        public bool IsValid
        {
            get { return (GetRuleViolations().Count() == 0); }
        }
        public IEnumerable<RuleViolation> GetRuleViolations()
        {
            if (String.IsNullOrEmpty(Title))
                yield return new RuleViolation("Title is required", "Title");
            if (String.IsNullOrEmpty(Text))
                yield return new RuleViolation("Web copy is required", "Text");

            yield break;
        }
        partial void OnValidate(ChangeAction action)
        {
            if (!IsValid)
                throw new ApplicationException("Rule violations prevent saving");
        }
    }
}

Where OnValidate() is a partial method LINQ to SQL provides which enables us to be notified when the object is about to be persisted to the database, so we can check all our business rules have been met before the object is flushed to the database.

An empty OnValidate() method is part of the designer generated code for your data class located in the #region Extensibility Method Definitions and it seems that these Extensibility Method Definitions only get added to the designer code when your tables have primary keys.

When a table is dragged onto the Object Relational Designer in Visual Studio the classes that are generated will only implement INotifyPropertyChanging and INotifyPropertyChanged if your tables have primary keys.  If the classes don't implement these interfaces the code won't implement the OnValidate() method, and if the OnValidate() method doesn't exist your partial class won't compile.

The Solution

The solution is simple.  Add a primary key to your database table, delete the associated data class from the Object Relational Designer and then drag the database table from Server Explorer back onto the Object Relational Designer surface.

You should then find the designer generated code now implements INotifyPropertyChanging and INotifyPropertyChanged and the class contains a definition for OnValidate() in the #region Extensibility Method Definitions.  Your code should now compile.

Create a jQuery Tag Cloud from RSS XML Feed

I previously created a jQuery Blogger Template Category List Widget to retrieve blog categories from a Blogger.com RSS feed and create a list of links which click through to Blogger label pages.

I've now taken this code a step further and modified it to calculate the number of times each category/tag occurs enabling me to create a tag cloud from the data, like the one below.

 

Before I explain the code I wrote to make the tag cloud I'll go through the solution to a bug I found with the original categories code.

You may recall this snippet of code where I iterate through each post and then each category of each post, finally, when all the categories have been added to the array I sort them prior to de-duping them.

$.get('/blog/rss.xml', function(data) {
//Find each post
        $(data).find('item').each(function() {
//Get all the associated categories/tags for the post
            $($(this)).find('category').each(function() {
                categories[categories.length] = $(this).text();
            });
        });
        categories.sort();

I later refactored the code removing the $(data).find('item').each iteration which wasn't required since find('category') will find them all anyway.

I then discovered that the JavaScript .sort() function was case-sensitive which resulted in lower case categories being placed at the end of the list, causing problems when I de-dup them.

So the rewritten snippet of code became:

$.get('blog/rss.xml', function(data) {
     //Find each tag and add to an array
     $(data).find('category').each(function() {
         categories[categories.length] = $(this).text();
     });
     categories.sort(caseInsensitiveCompare);

where caseInsensitiveCompare refers to a JavaScript compare function:

function caseInsensitiveCompare(a, b) {
    var anew = a.toLowerCase();
    var bnew = b.toLowerCase();
    if (anew < bnew) return -1;
    if (anew > bnew) return 1;
    return 0;
}

Creating the Tag Cloud jQuery Code

I start off as before fetching the XML, adding all the categories/tags from the RSS feed to a JavaScript array, then sorting them.

But I needed a way to store, not only the tag name, but the number of times that tag is used on the blog (the number of times the category appears in the feed).  For this I decided to use a multi-dimensional array which would essentially store the data in a grid fashion e.g.

Tag Name Count
ASP.NET 5
Accessibility 2
Blogging 15
jQuery 2

 

The de-dup loop from my previous categories script now performs two jobs, it removes the tag duplicates and creates a count of each tag occurrence.

Once the multi-dimensional array has been populated, all that's left to do is iterate through the array creating the HTML necessary to build the tag cloud, followed by appending it to a DIV tag with an ID="bloggerCloud" on the page.

Note the calculation I perform to get the tags appearing a reasonable pixel size ((tagCount * 3) + 12).

$(document).ready(function() {
    var categories = new Array();
    var dedupedCategories = [];
    $.get('blog/rss.xml', function(data) {
        //Find each tag and add to an array
        $(data).find('category').each(function() {
            categories[categories.length] = $(this).text();
        });
        categories.sort(caseInsensitiveCompare);
        //Dedup tag list and create a multi-dimensional array to store 'tag' and 'tag count'
        var oldCategory = '';
        var x = 0;
        $(categories).each(function() {
            if (this.toString() != oldCategory) {
                //Create a new array to put inside the array row 
                dedupedCategories[x] = [];
                //Store the tag name first 
                dedupedCategories[x][0] = this.toString();
                //Start the tag count 
                dedupedCategories[x][1] = 1;
                x++;
            } else {
                //Increment tag count
                dedupedCategories[x - 1][1] = dedupedCategories[x - 1][1] + 1;
            }
            oldCategory = this.toString();
        });
        // Loop through all unique tags and write the cloud
        var cloudHtml = "";
        $(dedupedCategories).each(function(i) {
            cloudHtml += "<a href=\"/blog/labels/";
            cloudHtml += dedupedCategories[i][0] + ".html\"><span style=\"font-size:" + ((dedupedCategories[i][1] * 3) + 12) + "px;\">";
            cloudHtml += dedupedCategories[i][0] + "</span></a> \n";
        });
        $('#bloggerCloud').append(cloudHtml);
    });
    return false;
});

Since building this script I've now gone one step further and created a jQuery plug-in based on this code.  For more details and the source code see my jQuery Blogger.com Tag Cloud Plugin page.

Setting Up ASP.NET MVC with NUnit for Visual Studio 2008 Standard Edition &amp; Visual Web Developer Express 2008

I've just spent my lunch hour downloading and installing ASP.NET MVC.  I also downloaded the sample chapter from Professional ASP.NET MVC 1.0 (large PDF) which walks through the development of NerdDinner.com.  I began to create a test ASP.NET MVC project on Visual Studio 2008 Standard.

One of the main positives of ASP.NET MVC is that Test Driven Development is so much easier than with ASP.NET Webforms.

I soon realised when I created my first ASP.NET MVC project however that unless you have Visual Studio Professional or higher you don't get Visual Studio test Unit Framework, which means that to create a test project, you first need to install another testing framework such as NUnit, and configure Visual Studio or Visual Web Developer 2008 to use it.

This is an extract from the book Professional ASP.NET MVC 1.0:

Note: The Visual Studio Unit Test Framework is only available with Visual Studio 2008 Professional and
higher versions). If you are using VS 2008 Standard Edition or Visual Web Developer 2008 Express you
will need to download and install the NUnit, MBUnit or XUnit extensions for ASP.NET MVC in order for
this dialog to be shown. The dialog will not display if there aren't any test frameworks installed.

I already had NUnit installed, so I began my search for an NUnit extension for ASP.NET MVC, which I found here. Updated NUnit Templates for ASP.Net MVC 1.0 RTM

After running installNUnit.cmd which created the registry entries required by Visual Studio, you need to make sure the registry entries created point to the compressed templates.

Note: If you are using Visual Web Developer 2008, this might be all you need to do.  Click on File > New Project and check to see if "Test" appears under "Project types" on the left-hand menu in the dialogue box.  If not carry on reading.

Copy the NUnit test templates from the downloaded directory (in your chosen .NET language) MvcApplication.NUnit.Tests.zip to the following folder on your machine:

%Program Files%\Microsoft Visual Studio 9.0\Common7\IDE\ProjectTemplates\CSharp\Test

or here for VWD 2008:

%Program Files%\Microsoft Visual Studio 9.0\Common7\IDE\VWDExpress\ProjectTemplates\CSharp\Test

Then make sure the registry entry here:

HKEY_LOCAL_MACHINE\SOFTWARE\VisualStudio\9.0\MVC\TestProjectTemplates\NUnit\C#

or here for VWD 2008:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VWDExpress\9.0\MVC\TestProjectTemplates\NUnit\C#

Correctly points to the location of MvcApplication.NUnit.Tests.zip. e.g.

Path: CSharp\Test\

Template: MvcApplication.NUnit.Tests.zip

Then close all instances of Visual Studio and open up the command prompt and move to the following location:

C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE>

and run the following command:

> devenv /setup

Once this has completed, you should find that when you create an ASP.NET MVC project, you will now get another pop-up menu asking you if you wish to create a unit test project for your application using NUnit.

jQuery Blogger Template Category List Widget

Blogger is a hosted blogging service which allows you to publish your blog to your own URL and create your own custom HTML templates to match your website design. 
I have been using Blogger for this blog for several years, and have been trying to find a good way of displaying a list of categories on each blog page.

As yet I haven't found an official way of creating a category list using the Blogger mark-up code, so I decided to write my own widget to do the job for me.

When I say category list I mean a list of all the blog tags/labels in your blog, each linking to a page with posts categorised using that particular tag, just like the examples below.

Blog Categories

Because Blogger is a hosted blogging service you can't use a server-side language to create the category list for your HTML template, instead you must rely on client-side JavaScript.

Thankfully the Blogger service publishes XML files to your website along with the post, archive and category HTML pages.  These are in ATOM and RSS formats and are there primarily for syndication, but XML files are also fairly straight-forward to parse using most programming languages and contain all the category data we need to build a categories list.

I chose to use the jQuery library because it makes the process even easier.

The Blogger XML Format

From the Blogger ATOM XML snippet below you can see that each blog item can have multiple category nodes.  This means that the code must loop through each blog post, then loop through each category of each post to create our category list, but it also means that we will have duplicate categories, because more than one post can have the same category.

<item>
  <guid isPermaLink='false'></guid>
  <pubDate>Thu, 14 May 2009 18:30:00 +0000</pubDate>
  <atom:updated>2009-05-15T11:35:03.262+01:00</atom:updated>
  <category domain='http://www.blogger.com/atom/ns#'>C Sharp</category>
  <category domain='
http://www.blogger.com/atom/ns#'>ASP.NET</category>
  <category domain='
http://www.blogger.com/atom/ns#'>Visual Studio</category>
  <title>Language Interoperability in the .NET Framework</title>
  <atom:summary type='text'>.NET is a powerful framework which was built to allow cross-language support...</atom:summary>
  <link>http://www.nikmakris.com/blog/2009/05/language-interoperability-in-net.html</link>
  <author>Nik</author>
  <thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total>
</item>

The jQuery Code

The jQuery code is fairly easy to follow, but here is a quick explanation.  After the DOM is available for use, I create two JavaScript arrays, one to hold the categories and one to hold our de-duped category list.  Then I load in the Blogger RSS feed and iterate through each blog post adding each category to the categories array.
Once it reaches the end of the RSS feed, I need to sort the array into alphabetical order so that I can de-duplicate the categories list I just populated, which is what the next jQuery .each() function does.
All I have left to do is loop through the de-duped categories list, create the HTML link for each category and the append the HTML unordered list to the page.

$(document).ready(function() {
    var categories = new Array();
    var dedupedCategories = new Array();
    $.get('/blog/rss.xml', function(data) {
        //Find each post
        $(data).find('item').each(function() {
            //Get all the associated categories/tags for the post
            $($(this)).find('category').each(function() {
                categories[categories.length] = $(this).text();
            });
        });
        categories.sort();
        //Dedup category/tag list
        var oldCategory = '';
        $(categories).each(function() {
            if (this.toString() != oldCategory) {
                //Add new category/tag
                dedupedCategories[dedupedCategories.length] = this.toString();
            }
            oldCategory = this.toString();
        });
        // Loop through all unique categories/tags and write a link for each
        var html = "<h3>Categories</h3>";
        html += "<ul class=\"niceList\">";
        $(dedupedCategories).each(function() {
            html += "<li><a href=\"/blog/labels/";
            html += this.toString() + ".html\">";
            html += this.toString() + "</a></li>\n";

        });
        html += "</ul>";
        $('#bloggerCategories').append(html);
    });
    return false;
});

 

Update your Blogger Template HTML to Show Categories

The only HTML you need to add to your Blogger template is a call to jQuery, and this script in the head of your page, plus an empty HTML DIV tag, in the place where you want your categories list to appear.

<script type="text/javascript" src="/scripts/jquery.js"></script>
<script type="text/javascript" src="/scripts/blogcategories.js"></script>

<div id="bloggerCategories"></div>

You can see the script in action on my blog, or see this code rewritten to create a tag cloud.

An Introduction to Web Development and Design for Work Experience Students

We have a school student coming into our agency for work experience shortly, so I'm putting together a programme which will introduce him to the various areas of web development, such as HTML, CSS, client-side and server-side code, databases and XML.

It is going to be difficult to cover the various different skills involved in web development in a week, and without knowing what sort of web development knowledge the student already possesses it is hard to determine what can be achieved in such a short time.

However the main goal of work experience is to give the student a flavour of what is involved in the profession, to allow them to make an informed decision on whether such a career is for them.

I've structured the programme as follows:

Day 1 - Introduction to Web Design
Day 2 - Introduction to HTML and CSS
Day 3 - Understanding web servers, web browsers and HTTP and FTP
Day 4 - Introduction to server-side and client-side programming
Day 5 - Overview of databases and XML

Within each topic I have posed questions and tasks, which will require research and learning.  For each subject I have provided links to tutorials and online information.

I'm also aware that web development is very much a practical and creative skill, so I've also set a project which will run for the whole week and will allow him to put what he has learned into practice by building a simple personal portfolio website.

I have no idea whether I'm being too ambitious, but surely that will depend on the student's current knowledge and interest in the subject.  I think that it can easily be tailored to each student depending on their interests. 

I have uploaded a PDF of my programme entitled An Introduction to Web Development and Design for Work Experience Students and would appreciate any feedback.

TargetInvocationException - Exception has been thrown by the target of an invocation

This exception isn't very useful because it's a general exception thrown when a method invoked through reflection throws an exception, took me a while to figure out what the issue was.  Even though I knew the page causing the error.

This exception was thrown by a ASP.NET web form which contained a GridView connected to an ObjectDataSource.

The ObjectDataSource references methods in a data access layer class.  These methods then call stored procedures in the MS SQL database. 

The code worked perfectly in my development environment.

I have the SQL database set up so that the database user ASP.NET uses only has rights to execute the stored procedures it needs to.  The database user cannot run commands against the tables directly, this way I limit the surface area of attack should my application have a weakness that could be exploited.

I double checked the stored procedures were all up-to-date, then double checked all the permissions on the stored procedures, and everything seemed in order, but I still kept getting the stack trace below in Event Viewer:


    Stack trace:    at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Web.UI.WebControls.ObjectDataSourceView.InvokeMethod(ObjectDataSourceMethod method, Boolean disposeInstance, Object& instance)
   at System.Web.UI.WebControls.ObjectDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments)
   at System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback)
   at System.Web.UI.WebControls.DataBoundControl.PerformSelect()
   at System.Web.UI.WebControls.BaseDataBoundControl.DataBind()
   at System.Web.UI.WebControls.GridView.DataBind()
   at System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound()
   at System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls()
   at System.Web.UI.Control.EnsureChildControls()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Custom event details:

I then decided to check the stored procedures.  Then it dawned on me that one of the stored procedures used EXEC sp_executesql, which requires the database user to have, in my case, SELECT permissions on the actual table itself.

Once I granted these permissions to the database user, the web form loaded correctly.

ASP.NET Content Disposition Problem in IE7

I've just spent quite a while debugging a problem with content disposition I was having with Internet Explorer 7, the code works fine in Firefox but causes this error message to occur in IE7.

"Internet Explorer cannot download xxx from xxx."

"Internet Explorer was not able to open this Internet site.  The requested site is either unavailable or cannot be found.  Please try again later."

content-disposition-error

This was my original snippet of C# code:

Response.Buffer = true;
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = docToDisplay.Type.ContentType.ToString();
Response.AddHeader("Content-Disposition", "attachment;filename=" + Server.UrlEncode(docToDisplay.FileName));
Response.Cache.SetCacheability(HttpCacheability.NoCache);

Response.BinaryWrite(docToDisplay.FileContent);
Response.End();
Response.Flush();
Response.Close();

Response.Cache.SetCacheability

I eventually figured out that the following line on code was causing the issue.

Response.Cache.SetCacheability(HttpCacheability.NoCache);

I then did a quick search for "Response.Cache.SetCacheability(HttpCacheability.NoCache);" and discovered another developer who have had the same Content-Disposition issue.  Unfortunately for me that page didn't get returned when I was searching for the Internet Explorer error message.

This was the response to the post by Microsoft Online Support:

"Yes, the exporting code you provided is standard one and after some further
testing, I think the problem is just caused by the httpheader set by
Response.Cache.SetCacheability(HttpCacheability.No Cache)
I just captured the http messages when setting and not setting the above
"NOCache" option and found that when the http response returned the
Cache-Control: no-cache
header. So we can also reproduce the problem when using the following code:
page_load...
{
Response.CacheControl = "no-cache";
ExportDataGrid(dgSheet,"test.xls");
}
IMO, this should be the clientside browser's behavior against "no-cache"
response with stream content other than the original text/html content. So
would you try avoid setting the CacheAbility or the "Cache-Control" header
to "no-cache" when you'd like to output custom binary file stream?
Thanks,
Steven Cheng
Microsoft Online Support"

After removing the Response.Cache.SetCacheability line the file downloads correctly in Internet Explorer.

Authenticate with MailEnable SMTP using ASP.NET 2.0

I've recently been trying to send emails using ASP.NET 2.0 on a web server which uses MailEnable. MailEnable had relaying locked down to avoid opening the server up to spammers, but I wasn't able to authenticate with MailEnable to relay emails to external domains.

I tested my code was working by temporarily checking the "Allow relay for local sender addresses" checkbox in the SMTP properties on MailEnable and my email was relayed successfully. However as soon as I uncheck this option I get this error message in the SMTP W3C logs:

503+This+mail+server+requires+authentication+when+attempting+to+send+to+a+non-local+e-mail+address.+Please+check+your+mail+client+settings+or+contact+your+administrator+to+verify+that+the+domain+or+address+is+defined+for+this+server.

I eventually got it working. I changed the authentication type from "MailEnable integrated authentication" to "Authenticate against the following username/password." then I supplied a username and password to MailEnable.
After restarting the SMTP service in MailEnable. I was able to relay emails using the following C# ASP.NET 2.0 code snippet...


using System.Net.Mail;

MailAddress source = new MailAddress("admin@localdomain.com", "Server");
MailAddress recipient = new MailAddress("external@mail.com", "External");

MailMessage enquiryMail = new MailMessage(source, recipient);
enquiryMail.Subject = "Test";
enquiryMail.Body = "Test content";
enquiryMail.IsBodyHtml = true;

SmtpClient smtpServer = new SmtpClient("mail.localdomain.com");
smtpServer.Credentials = new NetworkCredential("username", "password", "localdomain.com");
smtpServer.Send(enquiryMail);