I infrequently find myself on Joel Spolsky's site as the result of a search for something or other. It's not really a blog but a collection of articles on many different (it/web/developer) topics. The stuff he writes is ALWAYS interesting.
With that in mind, I finally added his Article Archive to the list of sites I visit regularly, just to see what's there.
I don't know how I missed this article previously, given it's relevance to me and my work, but The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) is my 'read of the week'.
Sunday, 16 May 2004
Saturday, 15 May 2004
More on... Client-Side Validation in Downlevel Browsers
This article ASP.NET.4GuysFromRolla.com: Client-Side Validation in Downlevel Browsers summarises the issues with validation in 'downlevel' browsers [although calling them 'downlevel' is Microsoft techmarketing at it's best]. Why not call them 'more standards compliant than IE' browsers instead?
More and more clients will be using non-IE browsers (Safari, Firefox, Mozilla) and non-PC-devices in future, so it makes sense to try and provide the same user-experience (ie. faster, client-side validation).
Go to the article to finds links to standards-DOM-based validation controls; or the longhorn beta documentation, which contains simplified versions of the validator controls that ship with the .NET Framework. Unlike the validator controls in the SDK, which work only with Internet Explorer, these controls comply with the World Wide Web Consortium Document Object Model Level 1 specification (W3C DOM Level 1) and support a number of browsers such as Internet Explorer 5, Netscape Navigator 6, and Opera 5.
More and more clients will be using non-IE browsers (Safari, Firefox, Mozilla) and non-PC-devices in future, so it makes sense to try and provide the same user-experience (ie. faster, client-side validation).
Go to the article to finds links to standards-DOM-based validation controls; or the longhorn beta documentation, which contains simplified versions of the validator controls that ship with the .NET Framework. Unlike the validator controls in the SDK, which work only with Internet Explorer, these controls comply with the World Wide Web Consortium Document Object Model Level 1 specification (W3C DOM Level 1) and support a number of browsers such as Internet Explorer 5, Netscape Navigator 6, and Opera 5.
Thursday, 13 May 2004
Automating Word with C#
The Microsoft Word MVP FAQ is a useful reference, however it's annoying that so much Office Automation code on the web is still in VB/VB.NET. It appears very few people are using C# for automation projects (so far).
Also, there is no more frustrating phrase in programming than finding this: Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article on MSDN in relation to a problem you are having, like automating OrgCharts in Excel. Argh!
Also, there is no more frustrating phrase in programming than finding this: Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article on MSDN in relation to a problem you are having, like automating OrgCharts in Excel. Argh!
Wednesday, 12 May 2004
HttpHandlers and HttpModules
Both these articles are very useful if you want to understand the handler/module concepts, and get some sample code.
You'll want to know about this if you are doing URL-rewriting, sophistication accept-language-detection or other early-in-the-pipeline processing.
You'll want to know about this if you are doing URL-rewriting, sophistication accept-language-detection or other early-in-the-pipeline processing.
Monday, 3 May 2004
Unicode to Html Entity and back again
WorldPay with C#/.NET [2] also discusses encoding "double byte" (unicode, really) values as Html Entities. The 'final' code is
But it's also fairly easy to get your 'original' string back... this code can go anywhere
as long as this method is available
UPDATE: list of HTML 4 entities which could be used to write a robust ResolveEntity() method using the 'pattern' abpve/
private string HtmlEntityEncode (string unicodeText) {
int unicodeVal;
string encoded="";
foreach (char c in unicodeText) {
unicodeVal = c;
if ((c >= 49) && (c <= 122)) {
// in 'ascii' range x30 to x7a which is 0-9A-Za-z plus some punctuation
encoded += c; // leave as-is
} else { // outside 'ascii' range - encode
encoded += string.Concat("",
unicodeVal.ToString(System.Globalization.NumberFormatInfo.InvariantInfo), ";");
}
}
return encoded;
}
But it's also fairly easy to get your 'original' string back... this code can go anywhere
System.Text.RegularExpressions.Regex entityResolver =
new System.Text.RegularExpressions.Regex (@"([&][#](?'unicode'\d+);)|([&](?'html'\w+);)");
string outputString = entityResolver.Replace(inputString,
new System.Text.RegularExpressions.MatchEvaluator (ResolveEntity) );
as long as this method is available
private string ResolveEntity (System.Text.RegularExpressions.Match matchToProcess) {
string x = "X"; // default 'char placeholder' if cannot be resolved
if (matchToProcess.Groups["unicode"].Success) {
x = Convert.ToChar(Convert.ToInt32(matchToProcess.Groups["unicode"].Value) ).ToString();
} else {
if (matchToProcess.Groups["html"].Success) {
switch (matchToProcess.Groups["html"].Value.ToLower()) {
// this could be expanded to as many as you like, or (maybe)
// System.Web.HttpUtility.HtmlDecode will work on
// the whole 'entity' string... ?
case "nbsp": x = " ";break;
case "copy": x = "(c)";break;
case "lt": x = "<";break;
case "gt":x = ">";break;
case "amp": x = "&";break;
}
}
}
return x;
}
UPDATE: list of HTML 4 entities which could be used to write a robust ResolveEntity() method using the 'pattern' abpve/
'Securing' data on client round-trips
When my website users go 'off-site' I want to set some information that I can check later, with some confidence that they have not altered it.
OK, I can put it in a Session variable, but I don't have Sessions enabled. What I want to do is encrypt a little chunk of data which can be added to the ViewState, hidden FORM field or Cookie (ie. it will be "client/transport implementation independent"), and check it again later on...
I think these two articles: String Encryption With Visual Basic .NET and Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication might be what I'm looking for... perhaps using Base64 if there's binary data being generated.
If I get it working I'll post it here (as always)
OK, I can put it in a Session variable, but I don't have Sessions enabled. What I want to do is encrypt a little chunk of data which can be added to the ViewState, hidden FORM field or Cookie (ie. it will be "client/transport implementation independent"), and check it again later on...
I think these two articles: String Encryption With Visual Basic .NET and Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication might be what I'm looking for... perhaps using Base64 if there's binary data being generated.
If I get it working I'll post it here (as always)
Tuesday, 27 April 2004
DHTML JavaScript Tooltips
I use ToolTips a lot in my web apps, not just for 'help' information but also hovering over rows in a table to present additional information rather than having super-wide tables/lots of columns.
This DHTML JavaScript for Cross Browser Tooltips is the coolest implementation I've come across...
This DHTML JavaScript for Cross Browser Tooltips is the coolest implementation I've come across...
Thursday, 22 April 2004
ASP.NET Browser Detection - uplevel FireFox?
I'm so impressed with the latest (0.8 last I checked) release of FireFox that I've started using it to test my ASP.NET apps.
Therefore I was pleasantly surprised to find someone(Rob)'s already figured out
Browser Testing and Detection Resources to encourage ASP.NET to play nicely with the latest IE-equivalent browsers...
Thanks to Mitch's blog on Web Controls and Browsercaps for pointing me there.
Therefore I was pleasantly surprised to find someone(Rob)'s already figured out
Browser Testing and Detection Resources to encourage ASP.NET to play nicely with the latest IE-equivalent browsers...
Thanks to Mitch's blog on Web Controls and Browsercaps for pointing me there.
Wednesday, 14 April 2004
C# and Excel Automation : Google Groups to the rescue
I don't post to newsgroups that often (although I try to contribute as much as I can to asp.net), but whenever I do I'm always amazed (and thankful) at the speed and quality of responses.
Overnight my problem with Excel automation was solved
Google Groups: Looping in Excel XP with C# -- Ranges and SpecialCells - reducing processing time from 90 minutes to 3 minutes!
Here is the 'working' code; loops through the Areas returned by the SpecialCells method so we only process non-empty cells...
Overnight my problem with Excel automation was solved
Google Groups: Looping in Excel XP with C# -- Ranges and SpecialCells - reducing processing time from 90 minutes to 3 minutes!
Here is the 'working' code; loops through the Areas returned by the SpecialCells method so we only process non-empty cells...
Excel.Range range = sheet.UsedRange;FYI, the SpecialCells (object)3 parameter is the sum of relevant 'constants' below:
Excel.Range newrange = range.SpecialCells(Microsoft.Office.Interop.Excel.XlCellType.xlCellTypeConstants, (object)3 );
for (int areaid = 1; areaid <= newrange.Areas.Count; areaid++){
Excel.Range arearange = newrange.Areas.get_Item(areaid);
for (int row = 1; row <= arearange.Rows.Count; row++){
for (int col = 1; col <= arearange.Columns.Count; col++){
cell = (Excel.Range)arearange.Cells[row, col];
// do stuff with cell.Value2
}
}
}
XlSpecialCellsValue
xlErrors 16
xlLogical 4
xlNumbers 1
xlTextValues 2
Tuesday, 6 April 2004
Automating Excel with C#
After much hair-pulling because I could not make Excel "work" as it should, I came across this article 328347 - PRB: "Member Not Found" Error Message When You Use a For Each Statement on an Excel Collection with Visual Basic .NET or Visual C# .NET
So that's why I couldn't loop through cells!
This seems to work better:
Incidentally, I still don't know why ".Value2" ...
So that's why I couldn't loop through cells!
This seems to work better:
if (m_Excel.Workbooks.Count >= 1) {
Excel.Sheets sheets = book.Worksheets;
Excel.Range range,cell;
// foreach (Excel.Range cell in range.Cells ) BROKE http://support.microsoft.com/?kbid=328347
foreach (Excel.Worksheet sheet in sheets) {
range = sheet.UsedRange;
for (int row = 1; row <= range.Rows.Count; row++){
for (int col = 1; col <= range.Columns.Count; col++){
cell = (Excel.Range)range.Cells[row, col];
if (null != cell) {
if (null != cell.Value2) {
cellContent = cell.Value2.ToString();
// do something with the text...
}
}
}
}
}
}
Incidentally, I still don't know why ".Value2" ...
Monday, 5 April 2004
File Extension filtering with .NET Regular Expressions
The 3 Leaf: .NET Regular Expression Repository provided a great starting point for writing a file extension filter to prevent certain file-types being uploaded in an ASP.NET HtmlInputFile control, using the RegularExpressionValidator.
Ultimately I came up with this
^([a-zA-Z]\:|\\)\\([^\\]+\\)*[^\/:*?<;>;|]+(\.txt|\.doc|\.xls|\.ppt|\.pdf|\.htm|\.html|\.zip)$
which seems to work OK, HOWEVER it's case-sensitive (so myFile.DoC won't upload).
If you want to only do validation on the server-side, a simple modification will enable 'case-insensitivity'
(?i)^([a-zA-Z]\:|\\)\\([^\\]+\\)*[^\/:*?<;>;|]+(\.txt|\.doc|\.xls|\.ppt|\.pdf|\.htm|\.html|\.zip)$
To really make it nice I wanted client-side validation as well, which meant building a custom validation control inheriting from BaseValidator. Most of the documentation I found was USELESS, but amazingly the 'beta' Longhorn documentation on Client-Side Functionality in a Server Control, Validator Control Samples and Client-Side Functionality in a Server Control
provided all the information I needed on the otherwise cryptic uses of RegisterValidatorCommonScript, RegisterValidatorDeclaration and the other bits and pieces required to implement a client- and server-side validator.
The result, InsensitiveRegularExpressionValidator is still in testing but will be posted soon.
Ultimately I came up with this
^([a-zA-Z]\:|\\)\\([^\\]+\\)*[^\/:*?<;>;|]+(\.txt|\.doc|\.xls|\.ppt|\.pdf|\.htm|\.html|\.zip)$
which seems to work OK, HOWEVER it's case-sensitive (so myFile.DoC won't upload).
If you want to only do validation on the server-side, a simple modification will enable 'case-insensitivity'
(?i)^([a-zA-Z]\:|\\)\\([^\\]+\\)*[^\/:*?<;>;|]+(\.txt|\.doc|\.xls|\.ppt|\.pdf|\.htm|\.html|\.zip)$
To really make it nice I wanted client-side validation as well, which meant building a custom validation control inheriting from BaseValidator. Most of the documentation I found was USELESS, but amazingly the 'beta' Longhorn documentation on Client-Side Functionality in a Server Control, Validator Control Samples and Client-Side Functionality in a Server Control
provided all the information I needed on the otherwise cryptic uses of RegisterValidatorCommonScript, RegisterValidatorDeclaration and the other bits and pieces required to implement a client- and server-side validator.
The result, InsensitiveRegularExpressionValidator is still in testing but will be posted soon.
Monday, 29 March 2004
Microsoft Word Automate WordCount frustration
It's amazing how difficult it can be to find information about MS Word when writing VBA (or automation using C#) - I needed to find the wordcount and charactercount programmatically, but the "document properties" m_Word.ActiveDocument.Words.Count and m_Word.ActiveDocument.Characters.Count don't seem to relate to ANYTHING!?!?!.
Thankfully this page myITforum.com : Document Word Counter gave me a push in the right direction:
object missing = System.Reflection.Missing.Value;
m_Word.ActiveDocument.ComputeStatistics(Microsoft.Office.Interop.Word.WdStatistic.wdStatisticWords, ref missing);
Why have Words and Characters properties if they don't DO anything???
P.S. Originally thought DSOFile would be able to do this job - but the Word and Char Count stored in the document properties in the filesystem isn't always up-to-date or meaningful either - it seems like ComputeStatistics is the only reliable way...
Thankfully this page myITforum.com : Document Word Counter gave me a push in the right direction:
object missing = System.Reflection.Missing.Value;
m_Word.ActiveDocument.ComputeStatistics(Microsoft.Office.Interop.Word.WdStatistic.wdStatisticWords, ref missing);
Why have Words and Characters properties if they don't DO anything???
P.S. Originally thought DSOFile would be able to do this job - but the Word and Char Count stored in the document properties in the filesystem isn't always up-to-date or meaningful either - it seems like ComputeStatistics is the only reliable way...
Wednesday, 24 March 2004
Parsing html markup text using MSHTML
Came across this article today; wondering whether this is a good solution for improving Searcharoo.net - both it's ability to "spider" the web by finding links in Html, and also parsing the Html into words for indexing (eg. pulling out the META tags, etc)... Parsing html markup text using MSHTML By Hendrik Swanepoel
I really want something lightweight that will help parse Html (a) links for spidering and (b) words for indexing... Other than some complex Regex, MSHTML is the only other option I've come across...
I really want something lightweight that will help parse Html (a) links for spidering and (b) words for indexing... Other than some complex Regex, MSHTML is the only other option I've come across...
Sunday, 21 March 2004
WorldPay with C#/.NET [2]
Maybe useful info for those using C# with WorldPay...
And if you're programming in Japanese... trying to get Japanese characters to display on the WorldPay pages was a real pain-- encoding issues (i'm using UTF-8 for my site - they use Shift_JIS). To set the job description, name and address info i'm currently using this hack
WorldPay.COMcallbackClass callback = new WorldPay.COMcallbackClass();
callback.processCallback();
if (callback.hadError() ) {
Trace.Write("WorldPay Error", callback.getRawAuthMessage() )
}
if (callback.didTransSuc() ) {
// #### WORLDPAY demo page ####
string traceInfo = "";
traceInfo +="culture:" + Thread.CurrentThread.CurrentCulture.EnglishName + "\n";
traceInfo +="uiculture:" + Thread.CurrentThread.CurrentUICulture.EnglishName + "\n";
traceInfo +="getTransId:" + callback.getTransId() + "\n";
traceInfo +="getRawAuthMessage:" + callback.getRawAuthMessage() + "\n";
traceInfo +="getRawAuthCode:" + callback.getRawAuthCode() + "\n";
traceInfo +="getTransTime:" + callback.getTransTime() + "\n";
traceInfo +="shopperId:" + callback.shopperId + "\n";
traceInfo +="getInstallationId:" + callback.getInstallationId() + "\n";
traceInfo +="getCompanyName:" + callback.getCompanyName() + "\n";
traceInfo +="getAuthMode:" + callback.getAuthMode() + "\n";
traceInfo +="getAmount:" + callback.getAmount() + "\n";
traceInfo +="getCurrencyISOCode:" + callback.getCurrencyISOCode() + "\n";
traceInfo +="getAmountString:" + callback.getAmountString() + "\n";
traceInfo +="getDescription:" + callback.getDescription() + "\n";
traceInfo +="Customer getName:" + callback.getName() + "\n";
traceInfo +="Customer getAddress:" + callback.getAddress() + "\n";
traceInfo +="Customer getPostalCode:" + callback.getPostalCode() + "\n";
traceInfo +="Customer getCountryISOCode:" + callback.getCountryISOCode() + "\n";
traceInfo +="Customer getTelephone:" + callback.getTelephone() + "\n";
traceInfo +="Customer getFax:" + callback.getFax() + "\n";
traceInfo +="Customer getEmail:" + callback.getEmail() + "\n";
traceInfo +="\nTRANS_ID:" + callback.getParameterString("MC_DataID") + "\n"; // CUSTOM PARAM prefix with MC_
traceInfo +="MEMBER_ID:" + callback.getParameterString("MC_MemberID") + "\n"; // CUSTOM PARAM
Trace.Write("WorldPay", traceInfo);And if you're programming in Japanese... trying to get Japanese characters to display on the WorldPay pages was a real pain-- encoding issues (i'm using UTF-8 for my site - they use Shift_JIS). To set the job description, name and address info i'm currently using this hack
// so manually converting to HTML Unicode Entities // as discussed here http://www.randyrants.com/archives/000348.asp int ch1; string snail2=""; foreach (char c in currentTransaction.Desc) { ch1 = c; if (!((ch1 >= 160) && (ch1 < 256))) {// if in 'ascii' range - *THINK* this works.... snail2 += c; // leave as-is } else { // convert to entity format Ӓ snail2 += string.Concat("", ch1.ToString(System.Globalization.NumberFormatInfo.InvariantInfo), ";"); } } purchase.setDescription (snail2); // HACK: HTML Entity Encoding[4-May-04] UPDATED CODE here
i18nguy.com
My job often involves multilingual programming (or at the very least content translation). This site i18nguy.com has an excellent collection of links on Internationalization (I18n), Localization (L10n), Standards etc. I've found it useful on a number of occasions, but sometimes I just go there to browse and learn.
Today's fav page is guidelines and resources.
Today's fav page is guidelines and resources.
Thursday, 18 March 2004
WayOffTopic: simple file exchange 'extranet'
Part of our everyday business is moving large files back and forth between offices (and countries). Usually FTP does the trick, but more and more clients are having firewall troubles with FTP (and to be honest, I'd rather not have the FTP service running at all).
What I wanted was a simple extranet application with an HTML File Upload and the ability to easily create client 'users' for one-off upload/downloads.
Google found Forms Authentication Using An XML Users File on MSDN, which has almost enough code to get me started.
First time in ages I've found an MS 'sample' useful (except the source projects on asp.net and winforms.net)!
What I wanted was a simple extranet application with an HTML File Upload and the ability to easily create client 'users' for one-off upload/downloads.
Google found Forms Authentication Using An XML Users File on MSDN, which has almost enough code to get me started.
First time in ages I've found an MS 'sample' useful (except the source projects on asp.net and winforms.net)!
Monday, 15 March 2004
SQL Server 2005 "Yukon" Full-Text Search
Interesting article about the 'internals' of the full-text-search in SQL Server, including discussion of ranking.
Data Access & Storage Home: SQL Server "Yukon" Full-Text Search: Internals and Enhancements (Microsoft SQL Server 9.0 Technical Articles)
First time I've seen "Yukon" officially named "SQLServer 2005"... maybe some useful ideas in there for Searcharoo
Data Access & Storage Home: SQL Server "Yukon" Full-Text Search: Internals and Enhancements (Microsoft SQL Server 9.0 Technical Articles)
First time I've seen "Yukon" officially named "SQLServer 2005"... maybe some useful ideas in there for Searcharoo
Sunday, 14 March 2004
Simple Site Search in .NET (1)
This article appeared on the MSDN Home Page recently: Part 4: Building a Better Binary Search Tree and it raised my curiousity about using the code provided to build a simple 'search engine' in C#.
I did a quick search to see what else was around (cheap/free products, or sample code) and found a few inspirational articles on WebMonkey, Perlfect and Apache.
A couple more articles on opening a file, removing white space and parsing HTML was all that was needed to get a basic search tool 'up and running' -- look for the code soon at Searcharoo.Net!
After being inspired by it, I didn't implement the Binary Search Tree straight away, that's another story...
I did a quick search to see what else was around (cheap/free products, or sample code) and found a few inspirational articles on WebMonkey, Perlfect and Apache.
A couple more articles on opening a file, removing white space and parsing HTML was all that was needed to get a basic search tool 'up and running' -- look for the code soon at Searcharoo.Net!
After being inspired by it, I didn't implement the Binary Search Tree straight away, that's another story...
WorldPay with C#/.NET
I'm in the process of converting an ecom site from ASP 'Classic' to .NET. The site uses the WorldPay gateway COM.
WorldPay supplies sample ASP files: purchase.asp and callback.asp. Purchase.asp "ported" just fine to C# (after using Reference -> Add Reference -> COM -> WorldPay Select COM to import the DLL).
BUT their callback.asp script failed with the following error
System.Runtime.InteropServices.COMException (0x80004005): aspcomp.AspComponentException: AspComponent: Retreiving MTx object context failed
at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
at WorldPay.COMcallbackClass.processCallback()
at ASP.callback_aspx.Page_Load(Object sender, EventArgs e) in C:\Inetpub\worldpay\callback.aspx:
on
WorldPay.COMcallbackClass callback = new WorldPay.COMcallbackClass();
callback.processCallback();
I couldn't figure out why one page would work and the other not. Surely it's the same DLL being imported/loaded? Changing the Identity in IIS, removing code, adding try/catch... nothing fixed the problem.
Just as I was about to give up and leave that one page in ASP 'Classic', I remembered long ago reading about a 'compability mode' in ASP.NET. A quick Google revealed this doco on aspcompat=true.
And it works! I could not find a single reference to this Googling for 'WorldPay' 'InterOp' 'Error' or any other likely terms -- surely I'm not the first!?!?
[hmm.. my first blog post...]
WorldPay supplies sample ASP files: purchase.asp and callback.asp. Purchase.asp "ported" just fine to C# (after using Reference -> Add Reference -> COM -> WorldPay Select COM to import the DLL).
BUT their callback.asp script failed with the following error
System.Runtime.InteropServices.COMException (0x80004005): aspcomp.AspComponentException: AspComponent: Retreiving MTx object context failed
at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
at WorldPay.COMcallbackClass.processCallback()
at ASP.callback_aspx.Page_Load(Object sender, EventArgs e) in C:\Inetpub\worldpay\callback.aspx:
on
WorldPay.COMcallbackClass callback = new WorldPay.COMcallbackClass();
callback.processCallback();
I couldn't figure out why one page would work and the other not. Surely it's the same DLL being imported/loaded? Changing the Identity in IIS, removing code, adding try/catch... nothing fixed the problem.
Just as I was about to give up and leave that one page in ASP 'Classic', I remembered long ago reading about a 'compability mode' in ASP.NET. A quick Google revealed this doco on aspcompat=true.
And it works! I could not find a single reference to this Googling for 'WorldPay' 'InterOp' 'Error' or any other likely terms -- surely I'm not the first!?!?
[hmm.. my first blog post...]
Subscribe to:
Posts (Atom)