Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

20/02/2010

JavaScript / C# Hack to For Latency Simulation In ASP.Net Web Applications

When developing AJAX functionality sometimes a latency simulation can be quite revealing. The following four lines of code serve as an interception point injecting a user specified network delay in serving network resources for UI testing purposes.

If you use your imagination a bit, and leverage the power of jQuery selectors, one can quickly build a network latency injector for help in developing those tough to test RIA interfaces. I hope you enjoy:

1) Create a new WebForm Called ImageLatencySimulator.aspx in the root of your web application.

2) Within the .aspx file delete all the html markup so only the @Page level declaration is visible (optional).

3) In the Page Load event of the .aspx.cs(.vb) file add the following code (C#, message me for VB):

int delay = Convert.ToInt32( Request.QueryString["delay"] );
string redirectTo = Request.QueryString["redirect"];
System.Threading.Thread.Sleep(delay);
Response.Redirect(Page.ResolveUrl(redirectTo));
// quite simple really isn't it? ya ya ya parse the int properly and perform appropriate null checks ... play your little violin for me before commenting ...

4) Add an image to the images directory within the root of your web application named .gif;

5) Add another WebForm or Html File to your project in the same level in the hierarchy as ImageLatencySimulator.aspx called LatencyTest.aspx|html.

5) Within the body tag in the LatencyTest.html file add an image tag with the src attribute pointing to ImageLatencySimulator.aspx with the appropriate get params as such:

.gif" alt="latency example redirect" />

6) Run the project.

You should notice all requests for your image resource are now being redirected through the ImageLatencySimulator.aspx and therefore are subject to your user defined delay parameter of 5000 miliseconds. Your waterfall diagram is now visibly apparent as the page loads.

OK - so why is this cool at all you may ask? We'll, imagine I add a #if declaration to my .Net assembly which registers a piece of JavaScript on my page when running in debug mode that does the following (using jQuery):

$(document).ready(function() {
$("img").each(function() {
$(this).attr("src") = "ImageLatencySimulator.aspx?delay=500&redirectTo=" + $(this).attr("src");
});
});
// coded the above in WYSIWYG editor so message me if it doesn't work.

If you can read jQuery code then it should be obvious - the previous code injects a network delay against every image on your entire web page simulating network latency in any and every web browser!! Now go add an eTag (PageOutput Cache in ASP.Net) to your ImageLatencySimulatory.aspx file and test out your cache layer. Just add a random parameter at the end of the GET string to invalidate the cache and you have an extremely simple network latency simulator for use in development.

I'd encourage you to get creative with the jQuery part of this algorithm, add the appropriate type checks to the C# component - see what else you can simulate latency for - use templates for urls - I personally find this technique invaluably simple - simple to implement, simple to expalin, simple to advocate for - and in the spirit of KISS, that makes me warm and fuzzy.

Over and Out

18/02/2010

AOP: Aspect Oriented Programming

AOP goes like this: If it's not part of your core logic it's an aspect and should in some way be separated from your core algorithm.

In a more literal sense, Aspects are application infrastructure components, as a foundation is to a house, Aspects are to a software application. Now how does this differ from OOP?

The intention of Aspect Oriented Programming is two fold:
  1. Separation of Concern: the separation and centralization of application logic in a non redundant fashion.

  2. Cross Cutting: entanglement of application logic within a program resulting in scattering tangling or both.
"For instance, if writing an application for handling medical records, the bookkeeping and indexing of such records is a core concern, while logging a history of changes to the record database or user database, or an authentication system, would be cross-cutting concerns since they touch more parts of the program." - Wikipedia

Some of you may argue AOP is no more than another level of abstraction in OOP, and you'd be correct in saying that. I personally find the theory interesting, but the practice a bit defeatist. As a .Net developer, I'm sure I'd prefer using the built in .Net Roles & Members over AOP, but, heck, if I can make my code more readable I'm up for giving it a shot.

Here are some interesting articles which talk to AOP, and a simple AspectF implementation (which isn't real AOP) by the creator of pageflakes.com:

Aspect Oriented Programming Wikipedia

AspectF Fluent Way to Add Aspects for Cleaner Maintainable Code

AspectF Simple way to cache objects and collections for greater performance and scalability

What do you think about AOP?

Over and Out

18/09/2009

Reassign bugs to gays.

This summary is not available. Please click here to view the post.

14/08/2009

Clear | Remove Query Strings From Post Backs (ASP.Net, SharePoint)

As part of an unorthodox request I was asked to make a TabStrip component SEO friendly. My first thought was to completely rewrite the control to make use of GET requests rather than continuing to POST the data back to the server.

Immediately I ran into a problem with this approach as the developers of this site have implemented the majority of these TabStrip controls inside the ASP.Net UpdatePanel (don't get me started with these) which does not recognize GET requests as Async events.

The architect of this site (actually a SharePoint site) failed to recognize that the SharePoint indexing service would not be able to index information on any tab other than the default one (as subsequent requests for tab data are done using Asynchronous Events). When project management asked him to modify the tabs for accessibility he told them it was impossible without a complete redesign.

As a solution to this problem I modified the TabStrip control such that it renders an anchor tag rather than a link button and added some fancy JavaScript to cancel the Anchor tag click event and trigger the appropriate __doPostBack option. I now have a crawl able anchor tag, which works like a link button, and triggers the appropriate update.

Moreover, when the TabStrip is initialized (OnInit) it looks for a specific query string variable indicating the ID of the selected tab. This is when the real problem starts:
  1. Indexing service crawls the anchor and builds a GET string reference to the selected tab id.
  2. Page is loaded into browser.
  3. User selects different tab.
  4. TabStrip is initialized finding the previous (last selected tab) tab id.
  5. TabStrip raises MenuItem Click event ignoring the actual new selected tab id.
The problem then becomes: How do I Clear The Query String From Subsequent Post Back Operations?

My quest turned to the Google.

First I found this approach which actually removes the query string VIA triggering a post back and is therefore too wasteful to be my solution.

I then found the following approach which unfortunately fails to load as it uses the ugly document.all JavaScript method which isn't available until after page load (therefore causes a client side exception - even when registered properly as a StartupScript).

I put together a slightly different JavaScript routine that looks like this:

if(window.onload != null) {
var wol = window.onload;
window.onload = function(e) {
wol(e);
document.forms[0].action = "Index.aspx";
}
} else {
window.onload = function() {
document.forms[0].action = "Index.aspx";
}
}


This JavaScript Method then rolls nicely into an ASP.Net Server Control like so:
///
/// Attempt to remove the tab id from the query string
///

private void AddRemoveTabIdQueryString()
{
const string key = "REMOVETABIDQUERYSTRING";
if (!Page.ClientScript.IsStartupScriptRegistered(GetType(), key))
{
Page.ClientScript.RegisterStartupScript(this.GetType(), key,
string.Format("if(window.onload != null) {{var wol = window.onload;window.onload = function(e) {{wol(e);{0};}}}} else {{window.onload = function() {{document.forms[0].action = \"{0}\";;}}}}", GetRequestPageName()), true);
}

// Get the page Name of the request
private string GetRequestPageName()
{
string rawUrl = Page.Request.RawUrl;
int pos = rawUrl.LastIndexOf("/");
int qpos = rawUrl.LastIndexOf("?");
return qpos > -1 ? rawUrl.Substring(pos + 1, qpos - pos - 1) :
rawUrl.Substring(pos + 1, rawUrl.Length - pos - 1);
}

I hope this is helpful to others.

Over and Out

13/08/2009

SPJobDefinition Quirks For Developers

I wanted to write a quick heads up on a couple quirks relating to the SPJobDefinition and wiring up Timer Jobs (may be relevant for deployments where the Timer Jobs are modified). We are building our solutions on Windows 2003 Server with MOSS 2007.

To debug SPJobDefinitions attach VS debugger to OWSTIMER.exe process after following install instructions below.

OWSTIMER is caching the SPJobDefinition somewhere and is tricking Visual Studio into thinking we are actually debugging the most recent compiled version when we are debugging the last loaded version.

To fix this, kill the OWSTIMER process in process explorer (or restart the Windows Sharepoint Services Timer by typing the following at the command prompt: net stop sptimerv3 & net start sptimerv3) and then refresh the portal you are performing development on (this will force a restart of OWSTIMER.EXE and clear the cache).

Between tests ensure you completely remove the SharePoint feature (deactivate + uninstall) from Sharepoint (see below). Then kill the OWSTIMER process, iisreset, rebuild the solution and reinstall / activate the solution again (see below).

Here are a couple batch files convenient for removing / installing the jobs (where ProvisioningVX is the name of the feature you are trying to install):

Uninstall Batch File

@ECHO OFF

set SPAdminTool=%CommonProgramFiles%\Microsoft Shared\web server extensions\12\BIN\stsadm.exe
set TargetUrl=http://servername/sites/name

echo "Deactivating Feature"
"%SPAdminTool%" -o deactivatefeature -name ProvisioningVX -url %TargetUrl% -force

echo "Uninstalling Feature"
"%SPAdminTool%" -o uninstallfeature -name ProvisioningVX -force

iisreset

PAUSE

Installing and activating the feature

@ECHO OFF

set SPAdminTool=%CommonProgramFiles%\Microsoft Shared\web server extensions\12\BIN\stsadm.exe
set TargetUrl=http://servername/sites/name

echo "installing feature"
"%SPAdminTool%" -o installfeature -name ProvisioningVX -force

echo "activating feature"
"%SPAdminTool%" -o activatefeature -name ProvisioningVX -url %TargetUrl% -force

iisreset

PAUSE

12/08/2009

How To: Debug SPJobDefinition in Visual Studio

The solution is remarkably simple.

Click Debug -> Attach To Process

Note: At this point, ensure the checkbox "Select processes from all users" is selected.

Select OWSTIMER.EXE from the list.

Setup a breakpoint on the Execute override method.

Be patient and wait for the timed job to execute.

26/06/2009

Setup Visual Studio To Easily Pull PublicKeyTokens

Interesting article here: http://blogs.msdn.com/kaevans/archive/2008/06/18/getting-public-key-token-of-assembly-within-visual-studio.aspx

The article explains a couple tricks as to how to get PublicKeyTokens out of your signed assemblies in a quick and simple manner.

Enjoy.

Over And Out

06/05/2009

.Net Custom Panel Control with Transparent Background (no png's, css hacks, or problems)

I'm making a really quick post on how you can wrap the jQuery fadeBack control into a .Net Web Custom Control. If you haven't read the article on the fadeBack control, you will have to go here and grab the source.

Save the scripts in a script folder inside your Web Site / Web Application.

To use this control you need to add a reference to the Web Server Control project you have built the code in.

To use this control in your WebForm please Register the Web Server Control dll and namespace on the page like:
<%@ Register Assembly="<<NAME OF WEB SERVER CONTROL PROJECT DLL>>" Namespace="<< THE NAME OF THE NAMESPACE>>" TagPrefix="ctl" %>

Then you can start using the control like so:

<ctl:TransBackPanel ID="backTest" runat="server"
Width="400px" Opacity="20" BackColor="Aquamarine"
BorderColor="Red" BorderWidth="10px" BorderStyle="Solid">
<ctl:TransBackPanel ID="TransBackPanel1" runat="server"
Width="300px" Opacity="20" BackColor="Red"
BorderColor="Green" BorderWidth="10px" BorderStyle="Solid">
<div>Hello World!</div>
</ctl:TransBackPanel>
</ctl:TransBackPanel>

Below is the source code for the .Net Web Custom Control, add this to a Web Server Control project and build:

[ToolboxData("<{0}:TransBackPanel runat=server></{0}:TransBackPanel>")]
public class TransBackPanel : Panel
{

// the jQuery script reference
public const string JQUERY_KEY = "jquery-1.3.2.min.js";
public const string JQUERY_URL = "script/jquery-1.3.2.min.js";

// the transparent background plugin reference
public const string TRANSBACKPANEL_KEY = "jQuery.fadeBack.js";
public const string TRANSBACKPANEL_URL = "script/jQuery.fadeBack.js";

/// <summary>
/// Declare a local variable with the default opacity
/// </summary>
private int _Opacity = 20;

/// <summary>
/// Get / Set opacity to an int - 100 to 0 with 100 being a completely transparent background.
/// </summary>
public int Opacity { get { return _Opacity; } set { _Opacity = value; } }

/// <summary>
/// Override the create child controls method and add the scripts from our constants
/// </summary>
protected override void CreateChildControls()
{

// Register jQuery like so
if (!Page.ClientScript.IsClientScriptIncludeRegistered(JQUERY_KEY))
Page.ClientScript.RegisterClientScriptInclude(JQUERY_KEY, JQUERY_URL);

// Register the fade back external script
if (!Page.ClientScript.IsClientScriptIncludeRegistered(TRANSBACKPANEL_KEY))
Page.ClientScript.RegisterClientScriptInclude(TRANSBACKPANEL_KEY, TRANSBACKPANEL_URL);

base.CreateChildControls();
}

/// <summary>
/// Render the panel control
/// </summary>
/// <param name="writer"></param>
protected override void Render(HtmlTextWriter writer)
{

// Register the startup script to fade the background to another color
if (!Page.ClientScript.IsStartupScriptRegistered(this.ID))
Page.ClientScript.RegisterStartupScript(typeof(string), this.ID, GetOnloadScript(), true);

base.Render(writer);

}

/// <summary>
/// Produce a jQuery on load thingy to geter done.
/// </summary>
/// <returns></returns>
private string GetOnloadScript()
{
return "$(document).ready(function() {\n" +
"$('#" + this.ClientID + "').fadeBack({opacity:" + Convert.ToDouble(Opacity) / 100 + "});\n" +
"});";
}

}

17/10/2008

Generic Self Inherited List

What do you think about this fully legal .Net class name:

public class DynaSeries : List { }

Hmmmm a class that inherits a generic list of itself.

Strange.

Over and Out

22/07/2008

C#: Some useful String Manipulation Functions

String Starts or Ends With Sequence of Characters

This method returns a boolean value if the initial string either starts with or ends with the sought after string (startOrEndsWithTest).

private bool StringStartsOrEndsWith(string initialString,
string startOrEndsWithTest)
{
if (initialString.StartsWith(startOrEndsWithTest)) return true;
int intCheckLen = startOrEndsWithTest.Length;
if (initialString.Length >= intCheckLen)
return (initialString.Substring(initialString.Length -
intCheckLen, intCheckLen) == startOrEndsWithTest);

return false;
}

String Insert Before Search String Method

The following method inserts a string (textToBeInserted) before a search string (insertBeforeText) located in the initial string (initialString).

private string StringInsertBefore(string initialString,
string insertBeforeText, string textToBeInserted)
{
int intPos = initialString.IndexOf(insertBeforeText);
if (intPos == -1) return initialString;
return String.Concat(initialString.Substring(0, intPos),
textToBeInserted,
initialString.Substring(intPos, initialString.Length - (intPos)));
}

String Insert After Search String Method

The following method inserts a string (textToBeInserted) after a search string (insertBeforeText) located in the initial string (initialString).

private string StringInsertAfter(string initialString,
string insertAfterText, string textToBeInserted)
{
int intPos = initialString.IndexOf(insertAfterText);
if (intPos == -1) return initialString;
int insertAfterTextLen = insertAfterText.Length;
return String.Concat(initialString.Substring(0, intPos + insertAfterTextLen),
textToBeInserted,
initialString.Substring(intPos + insertAfterTextLen,
initialString.Length - (intPos + insertAfterTextLen)));
}

09/04/2008

C#: Creating Tables in Open Office using C#.... Open Office Sucks and So Does Your Face

OK ... you're going to have to use your imagination a bit here because there is too much code to put everything in here ... the basic premise is as such:

// get the row counts out of my parameter => MyUserDefinedCustomTableObject is obviously a class in my app - and no, it is not a DataTable it is a Generic Matrix.
int RowCount = MyUserDefinedCustomTableObject.Rows.Count;

// get the col counts out of ma parameter
int ColCount = MyUserDefinedCustomTableObject.Rows[0].Cells.Count;

// create a context consisting of the oo bootstrap
unoidl.com.sun.star.uno.XComponentContext localContext = uno.util.Bootstrap.bootstrap();

// create a service factory to get shit from
unoidl.com.sun.star.lang.XMultiServiceFactory multiServiceFactory = (unoidl.com.sun.star.lang.XMultiServiceFactory )localContext.getServiceManager();

// create a component loader to get stuff from
XComponentLoader componentLoader = (XComponentLoader)multiServiceFactory.createInstance( "com.sun.star.frame.Desktop");

// create a frame which is basically the document reference
XFrame frame = ((unoidl.com.sun.star.text.XTextDocument)xComponent).getCurrentController().getFrame();

// the tricky part, create a dispatch helper - this is the work horse
XDispatchHelper xDispatchHelper = (XDispatchHelper )multiServiceFactory.createInstance( "com.sun.star.frame.DispatchHelper");

// this is only used if you want to set bookmark text within the table cells ... we use bookmarks as placeholders where there will be text in the future.
XNameAccess xna = ((XBookmarksSupplier)xComponent).getBookmarks();

// Create the property values - this uses a local function that I'm not nice enough to give you but on a primitive level it is propertyvalue.Name = first param, propertyvalue.value = 2nd param.
PropertyValue[] tableArgs = new unoidl.com.sun.star.beans.PropertyValue[4];
tableArgs[0] = CreateNewProperty("TableName", new uno.Any(MyUserDefinedCustomTableObject.TableName));
tableArgs[1] = CreateNewProperty("Columns", new uno.Any(ColCount));
tableArgs[2] = CreateNewProperty("Rows", new uno.Any(RowCount));

// check to determine if we should show borders
if (MyUserDefinedCustomTableObject.ShowBorders)
tableArgs[3] = CreateNewProperty("Flags", new uno.Any(9));
else
tableArgs[3] = CreateNewProperty("Flags", new uno.Any(8));

// dispatch the table creation event to the UI ...
xDispatchHelper.executeDispatch((XDispatchProvider)frame, ".uno:InsertTable", "", 0, tableArgs);

// you have a table in your document, the cursor is usually in the first cell of the table so you can use this function to jump between cells and insert text / bookmarks.
xDispatchHelper.executeDispatch((XDispatchProvider)frame, ".uno:JumpToNextCell", "", 0, new unoidl.com.sun.star.beans.PropertyValue[0]);

// if you are in a table cell and want to set the text of that cell then you can use this
cellTextArgs[0] = CreateNewProperty("Text", new uno.Any("My lovely text i love you text"));
xDispatchHelper.executeDispatch((XDispatchProvider)frame, ".uno:InsertText", "", 0, cellTextArgs);

// if you want to insert a bookmark into the cell you could try this (note you do not have to be in a table cell for this to insert a bookmark).
PropertyValue[] cellBkmkArgs = new unoidl.com.sun.star.beans.PropertyValue[1];
cellBkmkArgs[0] = CreateNewProperty("Bookmark", new uno.Any(cell.CellBookmark));
xDispatchHelper.executeDispatch((XDispatchProvider)frame, ".uno:InsertBookmark", "", 0, cellBkmkArgs);

Over and Out