CopyAsHtml Add-in for VS – level 100

This is a very useful tool.  Properly formatting code for a blog post has been a hassle up until now!  This is great.  A must-have tool.  Great job Colin.


Here is an example of code copied directly from VS using this add-in.



        private void WebForm1_Init(object sender, EventArgs e)


        {


            Trace.Write(“WebForm1_Init”);


        }


 


        private void WebForm1_Load(object sender, EventArgs e)


        {


            Trace.Write(“WebForm1_Load”);


        }


 


        private void WebForm1_PreRender(object sender, EventArgs e)


        {


            Trace.Write(“WebForm1_PreRender”);


        }


 


        private void WebForm1_Unload(object sender, EventArgs e)


        {


            Trace.Write(“WebForm1_Unload”);


        }

How to use app-relative paths in ASP.NET – level 100

I’ve been using this feature since the beginning, but I’ve come to realize
that a lot of people aren’t aware of this.  The application path shortcut:
“~/”

When including any resource in your page whether it be a user control,
image, css or whatever, it has to be located.  The simplest thing to do is
to type the entire path, http://localhost/myApp/myStyle.css, but that isn’t
very maintainable because when you deploy, you have to change this
reference.  So the next step is making the path relative to the page (buried
2 levels deep):  ../../myStyle.css, but what if the site structure changes?
What do you do?  You could make it domain-relative:  /myApp/myStyle.css, but
what if your application needs to be deployed to it’s own domain:
http://myAppDomain.com/ ?  Now this reference is broken.  Some people get
around this by setting the path with Request.ApplicationPath +
“/myStyle.css”, but this doesn’t work in all cases.  If you have a virtual
path, you get /myApp, but if you are at the root, you get “/”, so in the
case of /myApp, you have to add a “/” to the end.

To get around all this, use “~/” as a shortcut to you application path.
With that shortcut at the beginning of your path, any server control will
resolve the url for you.  If you use this in a non-server control or just
print it out, you will need to resolve it yourself using the ResolveUrl(…)
method of the Control class.  This method is inherited by all controls, so
you can use it directly in Page, UserControl and all web controls.  I use
nothing but app-relative paths now.

In .Net 2.0, we’ll get more App-relative shortcut properties like
Request.AppRelativePath.  It’s really a much cleaner way to represent a
resource relative to the application no matter what the path to the
application is.

Impersonating a web user – level 200

One of these days, it will become necessary to impersonate a user at a
website.  Or, a more common use would be to use a legacy ASP app as a
make-shift web service.  Say an ASP page does an important function?  From
your application(whether windows, console, or web), you can write code to
contact this page and interact with it over HTTP.  Here is a sample:

String uriString = http://localhost/WebApplication1/AcceptFile.aspx;
// Create a new WebClient instance.
WebClient myWebClient = new WebClient();
string fileName = @”c:upload.txt”;
byte[] responseArray = myWebClient.UploadFile(uriString, “POST”, fileName);


Using the WebClient class in the System.Net namespace, it’s very easy to
create a custom web request and execute it.  Then you can capture the
response and analyze it. . . parse any important data contained in it.

If you have used Application Center Test or the Web Application Stress Tool,
you record a web session, and then that session is repeated many times.
Code is being written to repeat the web requests.

EASY, EASY custom web.config section – level 200

Some people my shy away from this, but see how easy it is.  You need a block of custom xml as configuration, so you create your own .xml file and read it in.  Instead, use the web.config file.  It’s already there, and it’s good to keep all configuration in one place.  This is all it takes to make your own Configuration Handler class:


public class Config : IConfigurationSectionHandler {


//stores authorization xml from .config file


protected static XmlNode m_oXmlSection;


public static XmlNode XmlSection{


get { return m_oXmlSection; }


}


public object Create(object parent, object configContext, XmlNode section) {


m_oXmlSection = section.FirstChild;


return section.InnerXml;


}


}


Then, you just access Config.XmlSection, and you have the complete Xml, so why wouldn’t you do it this way?

Tabbed browsing revisited

I’m reposting my previous post in binary for those geeks for whom English is a second language.  Go to http://nickciske.com/tools/binary.php to translate.


010101000110100001101001011100110010000001100100011011110110010101110011011011100010011101110100001000000110001101
101111011011100110001101100101011100100110111000100000001011100100111001100101011101000010000001100101011110000110
001101100101011100000111010000100000011101000110100001100001011101000010000001110100011010000110010100100000011000
100111001001101111011101110111001101100101011100100010000001101001011100110010000001110100011010000110010100100000
011000110110110001101001011001010110111001110100001000000110011001101111011100100010000001000001010100110101000000
101110010011100100010101010100001011100010000000100000010100110110111101101101011001010010000001110000011100100110
000101101001011100110110010100100000010001100110100101110010011001010110011001101111011110000010000001100001011011
100110010000100000011011110111010001101000011001010111001000100000011000100111001001101111011101110111001101100101
011100100111001100100000011001100110111101110010001000000111010001100001011000100110001001100101011001000010000001
100010011100100110111101110111011100110110100101101110011001110010110000100000011000010110111001100100001000000100
100100100000011101000110100001101001011011100110101100100000011101000110100001100001011101000010000001110100011010
000110100101110011001000000110100101110011001000000110000100100000011001100110010101100001011101000111010101110010
011001010010000001110100011010000110000101110100001000000111001101101000011011110111010101101100011001000110111000
100111011101000010000001100010011001010010000001101100011000010110001101101011011010010110111001100111001000000110
011001110010011011110110110100100000010010010100010100101110001000000010000000001101000010100000110100001010010010
010010011101110110011001010010000001100010011001010110010101101110001000000111010101110011011010010110111001100111
001000000100110101100001011110000111010001101000011011110110111000100000001010000111010101110011011001010110010000
100000011101000110111100100000011000100110010100100000010011010111100101001001010001010011001000101001001011000010
000001100001011011100110010000100000010010010010000001100001011011010010000001110110011001010111001001111001001000
000111001101100001011101000110100101110011011001100110100101100101011001000010111000100000001000000100100101110100
001000000110100101110011001000000110000100100000011101110111001001100001011100000111000001100101011100100010000001
100110011011110111001000100000010010010100010100101100001000000110000101101110011001000010000001101001011101000010
000001101011011001010110010101110000011100110010000001101001011011100111001101110100011000010110111001100011011001
010111001100100000011011110110011000100000010010010100010100100000011010010110111000100000011000010010000001110100
011000010110001001100010011001010110010000100000011000010111000001110000011011000110100101100011011000010111010001
101001011011110110111000101110001000000010000001001001001000000110010001100101011101100110010101101100011011110111
000000100000010000010101001101010000001011100100111001000101010101000010000001100001011100000111000001101100011010
010110001101100001011101000110100101101111011011100111001100100000011101110110100101110100011010000010000001001101
011000010111100001110100011010000110111101101110001011000010000001100001011011100110010000100000011101000110100001
100101011100100110010100100000011010010111001100100000011011100110111100100000011001000110100101100110011001100110
010101110010011001010110111001100011011001010010000001100010011001010110001101100001011101010111001101100101001000
000110100101110100001000000111010101110011011001010111001100100000011101000110100001100101001000000100100101000101
001000000110010101101110011001110110100101101110011001010010111000100000001000000000110100001010000011010000101001
000001011011000110111101101110011001110010000001110100011010000110010100100000011000100111001001101111011101110111
001101100101011100100010000001101100011010010110111001100101011100110010110000100000011010010110011000100000011101
110110010100100000001010000100000101010011010100000010111001001110010001010101010000100000011001000110010101110110
011001010110110001101111011100000110010101110010011100110010100100100000011001000110010101110110011001010110110001
101111011100000110010101100100001000000111000001100001011001110110010101110011001000000111010101110011011010010110
111001100111001000000111010001101000011001010010000001011000010010000101010001001101010011000010000001110011011101
000110000101101110011001000110000101110010011001000010000001110111011010010111010001101000001000000100001101010011
010100110010110000100000011101000110100001100101011011100010000001110111011001010010000001110111011011110110111000
100111011101000010000001101000011000010111011001100101001000000111001101101111001000000110110101100001011011100111
100100100000011000110111001001101111011100110111001100101101011000100111001001101111011101110111001101100101011100
100010000001101001011100110111001101110101011001010111001100101110001000000010000001010011011101000110000101101110
011001000110000101110010011001000111001100100000011001100110111101110010001000000111010001101000011001010010000001
110111011001010110001000100000011000010111001001100101001000000111011101100101011011000110110000101101011001010111
001101110100011000010110001001101100011010010111001101101000011001010110010000100000011011100110111101110111001011
000010000001110011011011110010000001110111011001010010000001101110011001010110010101100100001000000111010001101111
001000000110000101100100011010000110010101110010011001010010000001110100011011110010000001110100011010000110010101
101101001000000111001101101111001000000111010001101000011000010111010000100000011000100111001001101111011101110111
001101100101011100100010000001100011011010000110111101101001011000110110010100100000011001000110111101100101011100
110110111000100111011101000010000001101101011000010111010001110100011001010111001000101110001000000010000000001101
000010100000110100001010010010000110111101110111001000000110110101100001011011100111100100100000011100000110010101
101111011100000110110001100101001000000111001101110100011010010110110001101100001000000110010001101111011011100010
011101110100001000000111010101110011011010010110111001100111001000000110000100100000010001000100111101000011010101
000101100101010000010001010010000001101001011011100010000001110100011010000110010101101001011100100010000001110000
01100001011001110110010101110011001111110000110100001010


I’ve been using tabbed browsing in IE with Maxthon for a while now – level 000

This doesn’t concern .Net except that the browser is the client for ASP.NET.  Some praise Firefox and other browsers for tabbed browsing, and I think that this is a feature that shouldn’t be lacking from IE. 


I’ve been using Maxthon (used to be MyIE2), and I am very satisfied.  It is a wrapper for IE, and it keeps instances of IE in a tabbed application.  I develop ASP.NET applications with Maxthon, and there is no difference because it uses the IE engine. 


Along the browser lines, if we (ASP.NET developers) developed pages using the XHTML standard with CSS, then we won’t have so many cross-browser issues.  Standards for the web are well-established now, so we need to adhere to them so that browser choice doesn’t matter. 


How many people still don’t using a DOCTYPE in their pages?

DO NOT implement web security with your UI – level 100

I mark this post as 100 because this basic knowledge that every developer should know.  I’m maintaining a semi-legacy ASP web application, and so many page implement security through the UI.  For instance if a user isn’t allow to update data, then a “disabled” attribute is added to the <input type=”submit”>.  That’s it!  That’s all they do to protect their data.  So, how do you get around this?  You change the html and repost, or you run some script to remove the disabled attribute, or just create your own HTTP request.  The page that actually does the update does NO validation, NO checks.  It just assumes that the request is coming from the previous page unchanged, and it blindly updates data.


There is no easy fix for a site that is developed like this.  You really have to recode all the areas that modify data.  Some people might suggest checking the HTTP_REFERER Server Variables, but I whipped up a sample to show how easy it is to spoof that variable, and it’s not even a required variable in the HTML specification, so that’s out the window as a “real” solution.  The only solution is to code it correctly.  Check credentials before allowing the update.


I wonder how many applications out there have this security hole.


It’s common knowledge that .Text has this “feature”.   The comments feature is UI only.  If it’s not on, then the UI won’t be displayed, but if you just post a comment, the web interface will accept it but not display it.  But that comment will be downloaded with the RSS feed.  I’ve already informed Scott W. about this, so he knows I’m not knocking him.


I think this is very common of web applications, and we need to do a better job of writing secure code.

Abstracting from ASP.NET pages – level 300

Some of the common things we do in ASP.NET v1.1 is set configuration information explicitly to our aspx’s.  We set the title, the template we are using, the theme (maybe css), the navigation (links), the roles that are allowed access to our page, maybe some custom information for that page, and then think of some other information you “hard-code” in your page.  To abstract this away and make my pages more configurable without changing code, I’ve developed an interface that my base page class implements.  The definition of the interface is as follows:


 public interface IPageConfig
 {
  string this[string sKey]{get;set;}
  string Title{get;set;}
  string VirtualPath{get;set;}
  string Template{get;set;}
  string Theme{get;set;}
  string[] Roles{get;set;}


  bool IsRoot{get;}
  IPageConfig Parent{get;}
  IPageConfig[] Siblings{get;}
  IPageConfig[] Children{get;}
  string[] ChildrenNames{get;set;}


  NameValueCollection Attributes{get;}
  NavigationUrlCollection Navigation{get;}
 }


 


Then I implemented a custom object to read information from my web.config file.  In my properties that implement this interface, I can access this helper object to retrieve the configuration items from my web.config: title, template, theme, etc.  It is really powerful and allows me more control over my site through my configuration file instead of a lot of repetitive code changes.


You don’t have to use the web.config right off to implement this interface, just implement this interface in your base page and make the properties return the value you want to use for that page.  This allows for abstraction later on when you find you need it.  If you find you don’t need it, you have some standardized locations to set setting for that page.


I’ve learned something the hard way with .Net:  “Always code to interfaces.”

Philosophies for developing, using, and trusting software – level 200

I worked the election in my county yesterday, and something that came to my mind was the computerized voting machines.  These voting machines run software, and this software is in charge of keeping track of votes.  This job is very important, and if the code has bugs, it could lose track of votes.  My precinct uses bubble-in ballots, so there is NO doubt what the vote is.  We see on the paper the selections.  Some of these voting machines take in data and then report on it.  We just have to TRUST that the report is accurate.  Because of that, we have to TRUST that the software has no major bugs, and that is TRUSTING the developer who wrote the software.  These machines perform such an important job, that I believe we shouldn’t just TRUST the software. 


This situation resonates with me in normal software development.  Sometimes when a user has a problem, my response includes something like “just do this, and the software with do this and that and then show you the result.”.  I just EXPECT that the user will trust the software, but some users aren’t comfortable with that, and I know that if I don’t know how some software works internally, I’m skeptical about it.  Going forward, I’m going to make an effort to provide more detail about what the software is doing to the user. 


Logging is another issue.  If I have code that does a series of things and then spits out a result, but it doesn’t log intermediate data, how do I find where I went wrong if the result is wrong?  Same with voting machines.  If they spit out a completed paper ballot after every voter, this paper trail would ensure than no malfunction ever lost votes.

You mean my web app has to support characters other than English?!? – level 300

The time will come when some text or some data will need to contain foreign characters.  For me, this means Japanese Kanji text for a global application under development.  I need to use the following text: ??????????????. You are seeing question marks because .Text doesn’t support these characters in all places.


ASP.NET is unicode-based, so a lot of the work is done for me, but in order to work with this text, I have to make some changes to my development workstation and database (potentially).  First, I looked at the database, and the database was developed with a forward-thinking method, and all character fields are nchar or nvarchar, so SQL Server 2000 will be able to store all unicode characters without anything special.  I also had to check to make sure my stored procedures all used nvarchar and that no strings were ever converted to another codepage.  I was please to find the database in order, and I could store and retrieve this text.  With .Net, I was able to whip up a web app, and it just worked, but when looking at our existing application written with ASP & VB6 COM+, I found that it didn’t “just work”.  I separated the parts and discovered that I could call the COM+ pieces to store and retrieve this data, so the large part was taken care of.  Thank God VB6 supports unicode.  Of course, all that is happening is the transport of character codes.


The problem came with ASP making the call to COM+, getting information, but it was written to the page garbled.  After a lot of research, the fix was to set the CodePage that ASP uses to stream the response to the client.  This can be done in the header line with CodePage=”65001” – which is the unicode codepage, or I can use Response.CodePage = 65001 at the top of the ASP.  But header information also needed to be in the HTML page to display properly on the client, so I use Response.CharSet = “utf-8” to tell the browser to use this character set.  Doing this is every page did the trick, but I have a LOT of pages, so I set about looking for a global setting for the CodePage.  After a lot of searching, I found the AspCodePage IIS Metabase setting.  This is an obscure setting because we don’t normally have to change the IIS Metabase.  It’s kind of like a registry for IIS.  IIS Manager have GUI for some common settings, but this isn’t one of them.  I downloaded the IIS Metabase Explorer with the IIS 6.0 kit from Microsoft, and I was able to set this setting to 65001 for my application, and this affected all the pages in my app.


For good measure, I went ahead and added


<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>


to all my pages. 


It took me quite a while to educate myself on character sets because up to this point, I’d only had to deal with English.  It’s good education though.  I think all developers should know that text doesn’t always translate to normal ASCII codes.