Showing posts with label aspnet. Show all posts
Showing posts with label aspnet. Show all posts

Thursday, January 28, 2010

Four tool approaches to automated web UI tests

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/four_tool_approaches_to_automated_web_ui_tests.htm]

 We all know that in the ideal world, our web apps would have "sufficient" automated tests. But how? I'm not an expert here, but I've come across four general strategies:
DescriptionExamplePROCON
Send web requests, and then parse the corresponding response.MSTest WebTests
  • Handles simple postbacks very well
  • Independent of server technology (you don't care if it's ASPX, JSP, or PHP providing the responses back)
  • Lots of Visual Studio support
  • Dies on Ajax because it can't parse JavaScript
  • Requires a ton of parsing logic. Granted, there are free Html parsers to help with this.
  • Requires the expensive version of Visual Studio for Testers, so not everyone can run on their machines unless management pays $$$ for the licenses.
Directly tap into the ASPX pipeline (I'm no expert here, but to my limited knowledge, it seemed different than merely the request-response model).NUnitAsp (but this was officially ended)
  • Minimizes the parsing
  • Free
  • Still trouble with JavaScript (if memory serves me right).
Recording and playing back the mouse and keyboard movementsDon't know offhand, but I've heard of them with COM+
  • Tests actual UI layout (is the textbox 10 pixels below the button).
  • Very brittle with browsers, especially because browsers can resize
Run the browser in an automated script.WatiN
  • Because it runs the browser itself, it can handle whatever the browser handles, like JavaScript. This is huge in today's Ajax world.
  • Free! This is great when you want the entire team to run it on their local machines.
  • Active community supporting it
  • (I believe, but may be wrong) that because it runs the browser, it's limited to just IE.

 

Personally, I've seen the best luck with WatiN. Especially in the Ajax age, automated tests need to run JavaScript. I also find that to get a team to adopt a new tool, it's invaluable to let them run it themselves (i.e. anyone can download the open-source tool and run it with management paying $$$ for a license), and to provide tutorials (i.e. WatiN has an active community).

 

Tuesday, June 9, 2009

An easy way to hack unvalidated web input

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/an_easy_way_to_hack_unvalidated_web_input.htm]

Many security bugs get overlooked because hackers use "special" tools that give them options that the original developers anticipate. For example, most web developers only test their application through a browser. While this is sometimes sufficient to check different querystring inputs, it gives one an enormous false sense of security. Consider two cases:

  • A button is disabled, therefore the developer assumes you can't click it (Example: A Save button is disabled because some data isn't valid)

  • Data is stored in a hidden field, therefore the developer assumes that you can't change it. (Example: A record's ID is stored in a hidden field)

To some people, this appears safe because IE doesn't let you click disabled buttons or change the value of hidden fields. However, IE is only used to collect the data from the page and aggregate it into a post that it sends to the webserver. What if the hacker is using a different tool besides IE that gives them more control on how to assemble and send this post (or an extension to IE that lets them modify fields)?

 

How to hack it

 

You could crack both the above cases using Visual Studio Team Test (or I bet Firebug, or the IE8 dev tools). Here's how:

  1. Open up VS Team Test

  2. Create a Test Project, and add a new web test. This opens up a recorder in IE.

  3. Navigate to the page you want to crack, such as something that stores data in a hidden field.

  4. Perform a normal save action, such as saving the page (which uses data from the hidden field)

  5. Stop the recording. Play back the test just to make sure it works in the normal case. Note how for each request, VS provides you a new row and lets you see the exact request and response, as well as what visually appears in the Web Browser.

    1.  

  6. Now start the hacking. Go to the request where you saved the page (that collected data from the hidden field), and unbind that field and change its value to whatever you want. In this case, I simply had a field called "Hidden1", and I changed it's value to "abc". Note that just like IE, the webtest sends a post to the server. But unlike IE, you can easily change the contents of that post.

    1.  

  7. Rerun the webtest. The new, hacked, value is sent to the server.

  8. Note that you can also script VS WebTests with C#. So, you could have a for-loop that re-submits a 1000 requests, varying the post values each time.

So, what can we do?

 

As a developer, we always need to validate and do security checks on the server - merely JS side validation is not enough. For example, knowing that that hidden field could be hacked, always validate that data as if it were a free-form textbox.

 

The problem is that this degree of extra validation (1) costs much more time, and (2) could be a big performance hit - which is especially ironic because it's for something that 99% of users won't even know about.

 

Allotting time requires managerial approval. However, most managers see security as one of those "nice-to-have" buzzwords, that they'll have implemented later "if time permits".

I think a good solution to this is to give management a live demo of your site being hacked (perhaps try it on the QA machine, not necessarily production). To really make a point, see if you can hack into their profile. Hopefully that will convince management that it's worth the time.

 

About the performance hit - I don't see a silver bullet. Most application performance can be improved by adding more resources somehow - more hardware, better design (caching, batching), coding optimizations, etc... Because applications vary so much, there's not a one-size-fits-all solution.

Sunday, May 17, 2009

Tips to refactor Asp.Net codebehinds to a common base page.

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/tips_to_refactor_aspnet_codebehinds_to_a_common_base_page.htm]

In Asp.Net, it is common to have the aspx page inherit from a custom page as opposed to directly from System.Web.UI.Page. Usually the application architecture has at least one common "base page" that handles core architectural components. However, you may find that for larger apps, you want to extend your base-page hierarchy such that an entire sub system gets its own base page (which in turn inherits from the global base page). While inheritance with normal C# classes (like in a ClassLibrary project) works great, there are some common hurdles when trying to refactor to a base page in ASP.Net codeBehinds.

Perhaps the biggest issue is the dependencies, namely:

  1. Your base page cannot directly reference any user controls. Assuming you put the page page in the AppCode folder, this gets compiled to its own separate DLL, and that DLL has no reference to the UC dll (however, the UC has a reference to AppCode).
  2. Your base page cannot directly reference the html controls instantiated in the derived-page's aspx file. For example, if your derived aspx page contains a hidden field or textbox, your base page cannot reference that.

There are ways to break these dependencies.

For problem #1 with the User Control references, you can make an interface, have that user control implement the interface, and then let the base page have a member variable of the interface type. The derived page could populate that variable. In other words:

  • Say you have UserControl "Address".
  • Your base page needs to call the "LookupZipCode" method
  • Create an interface IAddress with member "LookupZipCode". Have the UC implement this interface.
  • Have your base page contain an instance field of type IAddress. Your base page can then call this.
  • Have the derived page pass the UC reference to the base page (perhaps in the OnInit method), for example set base.IAddress = MyUserControl.

Another approach, say if you're casting, is to pass in a generic. For example, create this kind of method in your base page: Note that "T' would be a user control, but your base page cannot reference user controls.

public T HeaderControl<T>() where T : class
{
    return this.Master.FindControl("Header") as T;
}

For problem #2, with html control references, you could solve this in several ways. Keep in mind that unlike user controls, Html (or WebControls) are predefined in an external assembly - System.Web - and can hence be referenced in the base page. So the question becomes how to pass the reference from the derived to the base class?

  • Pass in references via method signature - for example the method that sets a hidden control expects an HtmlInputHidden parameter, as opposed to referencing "this.MyHiddenControl".
  • Make the base class have its own separate protected instance, and have the derived class set this (such as in the derived class's OnInit). For example, the derived class OnInit method may contain a line like "base.BaseHiddenField = thisMyHiddenField". This is useful if that control is referenced in many base-class methods, and you don't want to update all the signatures.
  • FindControl - You can always use the "Page.FindControl(string)" method to get a control given the string ID, but this is brittle and slower. Because you pass in a string, you don't get compile-time type checking. It also must search the entire control collection instead of just having a direct reference to the control.

While there's a lot more ways to refactor an ASP.net codeBehind, these two tricks are useful.

Monday, May 11, 2009

Avoiding unnecessary server work in ASP.Net

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/avoiding_unnecessary_server_work_in_aspnet.htm]

One of the best ways to increase performance in ASP.Net pages is to not do any unnecessary server-side work. For example, every postback and callback will re-trigger the entire Page's server life cycle - rerunning OnInit, OnLoad, OnPreRender, etc... However, a server-side action only require a fraction of the original code to run - for example clicking a button may not require you to repopulate all dropdowns.

ConceptExampleDetails
Is PostbackClicking an ASP.Net button postbacks the pagethis.IsPostBack
Is CallbackA JavaScript triggers an ASP.Net 2.0 callbackthis.IsCallback
Is RedirectingA method has called Response.Redirect, but there is still heavy processing (that is now unnecessary) that will still be called.Response.IsRequestBeingRedirected
Is Ajax update panel postbackA button within an Ajax update panel has been clicked, but don't redo server work outside of that update panelpublic static bool IsPartialPostback(System.Web.UI.Page p)
{
return ((System.Web.UI.ScriptManager.GetCurrent(p) != null)
&& (System.Web.UI.ScriptManager.GetCurrent(p).IsInAsyncPostBack))
}
Is Button clickUser clicks exit button - no need to repopulate dropdownsRequest["__EVENTTARGET"] //indicates which event (like a button) triggered the postback.

 

Wednesday, November 12, 2008

MVC troubleshooting: If the controller doesn't have a controller factory...

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/mvc_troubleshooting_if_the_controller_doesnt_have_a_contro.htm]

I was toying around with the MVC pattern, and I kept getting this error while doing a tutorial:

 

'TaskList.Controllers.HomeController'. If the controller doesn't have a controller factory, ensure that it has a parameterless public constructor.
 

I'm no MVC expert, so I had to poke around a little. Ultimately, what seemed to fix it was making the database connection key in web.config match the key in the auto-generated dbml code.

 

The dbml code was failing on this line (in a file like "*.designer.cs"):

public TaskListDataContext() :
base(global::System.Configuration.ConfigurationManager.ConnectionStrings["TaskListDBConnectionString"].ConnectionString,

mappingSource)
{
    OnCreated();
}

I had modiefied my web.config, so there was no ConnectionString setting for "TaskListDBConnectionString", so that returned null, hence it failed. I needed to update web.config to something like so:

 


   

    name="TaskListDBConnectionString"

    connectionString="your_connection_here"

    providerName="System.Data.SqlClient"/>

 

To troubleshoot, I started stubbing out things one at a time - making an empty solution, downloading the final code, comparing the differences, etc...

 

Sunday, December 17, 2006

ASP.NET AJAX Control Toolkit - making it simple

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/aspnet_ajax_control_toolkit__making_it_simple.htm]

Looking at the newly available ASP.NET AJAX Control Toolkit, there are several things I really like about it.

  • It has a quickstart with a sample page for each control.
  • It takes less than 5 minutes to download and get running.
  • The controls are mostly cross-browser compatible.
  • It's free.
  • It's open-source.
  • It's practical - i.e. the controls are based on useful needs, not just flashy toys.

I especially like the ModalPopup and PopupControl. The first presents just that - a modal popup (which nicely fades out the screen). The second provides a dropdown-type control which is great for X-Pickers (Date-Pickers, Employee-Pickers, Color-Pickers, etc...)

Even if you're in an older shop that already developed a lot of your own controls, it's still worth investigating because these are (1) standardized, (2) likely to continually improve with the support of an entire community, and (3) potentially better and more robust than a control that a single dev whipped up a year ago under schedule pressure.

What I notice is that these controls abstract a lot of complicated DHTML features, like drag & drop, multi-layering, and DOM-modification, all while being cross-browser compliant. In a way, it's reduced advanced DHTML to mere copying and pasting.

Sunday, November 19, 2006

Adding an Event to a User Control (Code Sample)

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/adding_an_event_to_a_user_control.htm]

I had talked about how to trigger an event from a UserControl.

This ability has many benefits, such as with refactoring. For example, suppose a UserControl is hosted on many different pages, and each page requires that the control have slightly different validation that incorporates values from the host page. One way to do this is to have the UserControl call a validation method on the host page.

Here's a code snippet you can download that shows how to have a UC call a method on its parent. The idea is to add an event member to the control, and hook it up with a delegate. (I had initially seen this technique from an article on MSDN several years ago).

This specific example has four files:

  • A UserControl - RecordNav.ascx and RecordNav.ascx.cs
  • A host page - HostRecordNav.aspx and HostRecordNav.aspx.cs

The UserControl contains an event "UpdateDate" and the host page adds a method to handle the event: RecordNav1_UpdateData.

    RecordNav1.UpdateData += new AspxDemo_Events_RecorNav.UpdateDataEventHandler(RecordNav1_UpdateData);

Sunday, October 15, 2006

'__pendingCallbacks[...].async' is null or not an object

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/__pendingcallbacksasync_is_null_or_not_an_object.htm]

I was doing so ASP.Net 2.0 callbacks (see an overview here: http://dotnet.sys-con.com/read/192509.htm), and kept getting this error when I did a document.location redirect on the ReceiveCallback JavaScript function.

Microsoft JScript runtime error: '__pendingCallbacks[...].async' is null or not an object

Looks like a flagrant Microsoft bug: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101974

People have different suggestions

What worked for me is the setTimeout. However, I needed to pass a parameter to the variable, so I used a technique like so:

var _gRValue;
function ReceiveCallback(rValue)
{
  _gRValue = rValue;
  window.setTimeout('__ReceiveCallback(_gRValue)',0);
}

function __ReceiveCallback(rValue)
{
  //Do stuff here
} //end of method
 

To handle the nature of setTimeout, I stored the returned data in a member variable.

Sunday, March 26, 2006

ASP.Net 2.0 Callbacks: Using callbacks to create a rich Web UI

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/aspnet_20_callbacks_using_callbacks_to_create_a_rich_web_ui.htm]

I just had an article on ASP.Net 2.0 Callbacks published in .Net DJ. It provides a basic intro, and some more advanced uses like handling multiple callbacks and passing multiple data values.