Wizmo: Have Windows go to sleep on commad

on Thursday, December 24, 2009

I can’t find the original blog post which pointed out Wizmo. But, it’s a command line utility which handles a lot of the shutdown/restart/sleep mode capabilities of windows. I needed it to turn my monitors off when I leave home.

When I go out I like to turn off my monitors. It would be nice to think I was saving electricity, but really I just want to save the monitors. Unfortunately, when I turn off the monitors all of my open windows rearrange themselves onto a single screen. My setup isn’t normal, so I wouldn’t expect for any software or hardware vendor to accommodate it.

However, Wizmo is able to handle the problem. By creating a simple desktop shortcut, I can turn off all the screens without any of the problems which DisplayPort creates.

The command line shortcut:

"C:\Program Files (x86)\Wizmo\wizmo.exe" monoff


jBreadCrumb: 0.3.0

http://code.google.com/p/jbreadcrumb/

jBreadCrumb gains the ability to start working in a Web 2.0 world. The addition of methods for ‘add’, ‘remove’, and ‘clear’ allows for a webpage which dynamically loads content into a sub-div or iframe to also update the breadcrumb trail. It’s definitely not perfect, but allows for breadcrumbs to start becoming a dynamic part of the webpage design.

The new methods can be used by:

(*note: #addBreadCrumb, #removeBreadCrumb, and #clearBreadCrumb are input buttons on the page. #breadCrumbAdd is the breadcrumb list element to update.)

Add:

The options are:

  • text: (required) the text to display on screen.
  • url: (optional, default: ‘#’) the url to apply to the hyperlink
  • index: (optional, default: add the breadcrumb to the end of the list) the position to place to breadcrumb (1 based index)
$('#addBreadCrumb').click(function(e) {
var options = {
text: $('#addDisplayValue').val(),
url: $('#addUrl').val(),
index: $('#addIndex').val()
};

$('#breadCrumbAdd').jBreadCrumb('add',options);

e.preventDefault();
});

Remove:

The options are:

  • index: (optional, default: the last breadcrumb) the position to remove (1 based index)

$('#removeBreadCrumb').click(function(e) {
var options = {
index: $('#removeIndex').val()
};
$('#breadCrumbAdd').jBreadCrumb('remove',options);
e.preventDefault();
});

Clear:

$('#clearBreadCrumb').click(function(e) {
$('#breadCrumbAdd').jBreadCrumb('clear');
e.preventDefault();
});

These functions are useful for my usages. But, do they do what you need?

Using JSONP with ASP.NET MVC

on Thursday, December 17, 2009

(I am using the Beta 2 of ASP.NET MVC. It isn’t supposed to be ready for production; but it seems pretty stable.)

Earlier today I needed create some Cross Domain javascript requests. At first I tried to use the ASP.NET MVC JsonResult to provide data for these requests, but the serialized objects that were returned were unable to be used through JSONP (the cross domain javascript).

After a little research on StackOverflow (what a great site), I was able to find some JSONP code to use. This was a real timesaver, and it was documented to boot.

The creators of this code posted their code at:

http://stackoverflow.com/questions/758879/asp-net-mvc-returning-jsonp

http://blogorama.nerdworks.in/entry-EnablingJSONPcallsonASPNETMVC.aspx

I’ve added a small update. Just enough to make the Controller handle the new ASP.NET MVC 2 JsonRequestBehavior. I hope someone will improve on this code and add an “extensions” library to allow for Jsonp to be available in all controllers without using the JsonpController or JsonpFilterAttribute.

JsonpResult.cs:

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace Ucsb.Sa.Enterprise.Utility.Web.Mvc
{
/// <summary>
/// A Jsonp wrapper for the JsonResult.
///
/// Created by:
/// stimms (http://stackoverflow.com/questions/758879/asp-net-mvc-returning-jsonp)
/// Ranju V (http://blogorama.nerdworks.in/entry-EnablingJSONPcallsonASPNETMVC.aspx)
/// </summary>
public class JsonpResult : JsonResult
{

#region constructor

/// <summary>
/// Initializes a new instance of <see cref="JsonpResult" />.
/// </summary>
public JsonpResult()
{
// http://compactprivacypolicy.org/compact_token_reference.htm
CompactPolicy = "NON DSP COR STP COM";
}

#endregion

#region properties

/// <summary>
/// Gets or sets the javascript callback function that is
/// to be invoked in the resulting script output.
/// </summary>
/// <value>The callback function name.</value>
public string Callback { get; set; }

/// <summary>
/// Gets or sets the compact policy values. By default the compact policy
/// says "We provide noinformation to 3rd party sources".
/// </summary>
public string CompactPolicy { get; set; }

#endregion

#region methods

/// <summary>
/// Enables processing of the result of an action method by a
/// custom type that inherits from <see cref="T:System.Web.Mvc.ActionResult"/>.
/// </summary>
/// <param name="context">The context within which the
/// result is executed.</param>
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}

HttpResponseBase response = context.HttpContext.Response;

if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}

if ( string.IsNullOrEmpty( Callback ) )
{
Callback = context.HttpContext.Request.QueryString["callback"];

if ( string.IsNullOrEmpty( Callback ) )
{
Callback = context.HttpContext.Request.QueryString["jsoncallback"];
}
}

if( string.IsNullOrEmpty( CompactPolicy ) == false )
{
// TODO: uncomment when we get an IIS 7 server
//response.Headers.Add( "compact-policy", CompactPolicy );
}

if (Data != null)
{
// The JavaScriptSerializer type was marked as obsolete prior to .NET Framework 3.5 SP1
#pragma warning disable 0618
var serializer = new JavaScriptSerializer();
var ser = serializer.Serialize(Data);
response.Write(Callback + "(" + ser + ")");
#pragma warning restore 0618
}
}

#endregion

}

}


JsonFilterAttribute.cs:



using System;
using System.Web.Mvc;

namespace Ucsb.Sa.Enterprise.Utility.Web.Mvc
{
/// <summary>
/// A Jsonp attribute to override older JsonResult objects.
///
/// Created by:
/// stimms (http://stackoverflow.com/questions/758879/asp-net-mvc-returning-jsonp)
/// Ranju V (http://blogorama.nerdworks.in/entry-EnablingJSONPcallsonASPNETMVC.aspx)
/// </summary>
public class JsonpFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if(filterContext == null)
throw new ArgumentNullException("filterContext");

//
// see if this request included a "callback" querystring parameter
//
string callback = filterContext.HttpContext.Request.QueryString["callback"];
if (callback != null && callback.Length > 0)
{
//
// ensure that the result is a "JsonResult"
//
JsonResult result = filterContext.Result as JsonResult;
if (result == null)
{
throw new InvalidOperationException("JsonpFilterAttribute must be applied only " +
"on controllers and actions that return a JsonResult object.");
}

filterContext.Result = new JsonpResult
{
ContentEncoding = result.ContentEncoding,
ContentType = result.ContentType,
Data = result.Data,
Callback = callback
};
}
}
}
}


JsonController.cs:



using System.Text;
using System.Web.Mvc;

namespace Ucsb.Sa.Enterprise.Utility.Web.Mvc
{
/// <summary>
/// Controller which adds Jsonp ActionResults to the base Controller.
///
/// Created by:
/// stimms (http://stackoverflow.com/questions/758879/asp-net-mvc-returning-jsonp)
/// Ranju V (http://blogorama.nerdworks.in/entry-EnablingJSONPcallsonASPNETMVC.aspx)
/// </summary>
public abstract class JsonpController : Controller
{

/// <summary>
/// Creates and returns a Jsonp result.
/// </summary>
/// <param name="data">The data/object to serialize.</param>
/// <returns>A Jsonp ActionResult.</returns>
protected internal JsonpResult Jsonp(object data)
{
return Jsonp(data, null /* contentType */);
}

/// <summary>
/// Creates and returns a Jsonp result.
/// </summary>
/// <param name="data">The data/object to serialize.</param>
/// <param name="behavior">Allow Get requests.</param>
/// <returns>A Jsonp ActionResult.</returns>
protected internal JsonpResult Jsonp(object data, JsonRequestBehavior behavior )
{
return Jsonp(data, null /* contentType */, behavior );
}

/// <summary>
/// Creates and returns a Jsonp result.
/// </summary>
/// <param name="data">The data/object to serialize.</param>
/// <param name="contentType">The contentType to return.</param>
/// <returns>A Jsonp ActionResult.</returns>
protected internal JsonpResult Jsonp(object data, string contentType)
{
return Jsonp(data, contentType, null);
}

/// <summary>
/// Creates and returns a Jsonp result.
/// </summary>
/// <param name="data">The data/object to serialize.</param>
/// <param name="contentType">The contentType to return.</param>
/// <param name="behavior">Allow Get requests.</param>
/// <returns>A Jsonp ActionResult.</returns>
protected internal JsonpResult Jsonp(object data, string contentType, JsonRequestBehavior behavior)
{
return Jsonp(data, contentType, null, behavior);
}

/// <summary>
/// Creates and returns a Jsonp result.
/// </summary>
/// <param name="data">The data/object to serialize.</param>
/// <param name="contentType">The contentType to return.</param>
/// <param name="contentEncoding">The contentEncoding type.</param>
/// <returns>A Jsonp ActionResult.</returns>
protected internal virtual JsonpResult Jsonp(object data, string contentType, Encoding contentEncoding)
{
return Jsonp( data, contentType, contentEncoding, JsonRequestBehavior.DenyGet );
}

/// <summary>
/// Creates and returns a Jsonp result.
/// </summary>
/// <param name="data">The data/object to serialize.</param>
/// <param name="contentType">The contentType to return.</param>
/// <param name="contentEncoding">The contentEncoding type.</param>
/// <param name="behavior">Allow Get requests.</param>
/// <returns>A Jsonp ActionResult.</returns>
protected internal virtual JsonpResult Jsonp(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
{
return new JsonpResult
{
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior
};
}

}
}


I hope this helps others get around the JSONP problem until ASP.NET MVC implements a standard method for this.

From Ubuntu to Windows 7

A couple years ago I swore that I would never pay for an Operating System again. It just seemed pointless. No matter what Operating System you choose (Windows, Mac, Linux) you would always have problems. And I hated the idea that I was paying for those problems. So, I made a deal with my workplace (which is a Microsoft shop); if they provided me with an operating system for home then I would remote in when needed. This was just a polite gesture on both of our parts. I was going to remote in anyways and they knew I was going to remote in. So, they were kind enough to provide me with a Windows XP Home copy to use for remote desktoping.

However, at the time, I had already switched to Ubuntu as my home environment. So, Windows XP was loaded up in a VMWare virtual machine (I have used the free version of VMWare for over 6 years and am a big supporter of their virtual software … it’s easy to use and easy to install).

But, after 7+ years of using Linux/Ubuntu as my home Operating System I have switched back to Windows 7. It wasn’t an easy transition because there are a lot of command line features that I loved in Ubuntu which aren’t replicated in Windows. PowerShell (for Windows) really helps bridge the gap, but it’s not the same. The best analogy I can come up with is …

* using the Linux command line is like talking to a college valedictorian. They get it right away.

* using Window’s Poweshell is like talking to a high school valedictorian. They know what your talking about, but you have to be verbose.

* using Window’s normal command line is like talking to a retarded (“mentally-disabled”) high schooler. It doesn’t matter how many times you try to explain it, they still won’t get it.

The switch over was pretty painless. I was able to copy almost all the files I wanted to keep onto a thumb drive, because most of my work was replicated online (For the less Linux established this is a slight at Windows … Linus Torvalds, “Only wimps use tape backup: _real_ men just upload their important stuff on ftp, and let the rest of the world mirror it”).

I was able to get up and running on Windows 7 within less than an hour. So, good on ya’ Windows. The only thing that I had a problem with was rebooting the system. Apparently the Windows copy I bought did something really spectacular!!

Buying a real version of Windows still seems, to me, like paying for an Operating System with problems. So, I choose the cheapest option I could find for my purposes. I wanted to remote desktop into work, and I wanted to make that remote desktop experience the best possible. Only Windows 7 Ultimate had the feature to remote desktop with multiple displays, so I bought Ultimate (a waste of money for 99% of users). But, I didn’t want to pay full price; so I bought a “System Builders” version. The system builder version comes with a couple of ridiculous stipulations which all boil down to one point: You will NOT get support from Microsoft if something goes wrong. It is about $100 cheaper to buy this version, but if something doesn’t work then you need to be really good with Google.

Of course, I had a problem right off the bat. The System Builders version doesn’t overwrite the MBR. Which means, if you restart the system, it will use your old MBR and hang if that MBR doesn’t point to anything usable. Since I had Ubuntu installed before, the MBR was a GRUB loader and pointed to a non-existent partition (since I erased/overwrote all the partitions with the Windows install).

If you have Linux installed on the system, your normal boot sector won’t be overwritten. That makes the “System Builders” version of Windows the perfect installer for dual-boot users. Unfortunately, I wasn’t trying to be a dual-boot user. So, after some searching on the Microsoft website I was able to find a MBR installer. The searching only took about 20 minutes (about 1/10th the amount of time it takes to solve a linux problem), so I was pretty happy with the easy install and quick fixes.

AFTK explanation …

So, not posting to a blog which is rarely read is not a big deal. And, I’m not going to say this was any different.

I stopped posting when I found out that I had to learn SAP for a new Student Information System (SIS) at UCSB. It was supposed to take at least a year to learn SAP and another year to implement a UCSB SIS system. Fortunately, after two months we found out that all the promises that SAP gave us were wrong (the salesman lied, whats new). Their SIS system could not handle UCSB’s grading or graduation logic.

Within the two months of training on SAP I did learn all that anyone really needs to know about SAP. STAY AWAY! STAY FAR AWAY! It is a mainframe system that was too big to translate into the new world; so SAP decided to replicate the mainframe environment into a pseudo virtual machine. If you want to speed things up, then add more hardware and deploy more virtual machines. That will load balance the systems. Of course, it doesn’t help solve the central issue … SAP is slow. Really slow! And, it also doesn’t help that the system is still based on a mainframe. Which means modern day web programming is like pulling teeth from a lion. Hard and your efforts usually get butchered in the process. (for you SAP developers out there, /se80 … WTF!!!)

After that I started going full time on an imaging project in .NET. Our division decided to use Atalasoft’s DotNet Imaging for both the Windows and Web frameworks. It’s a pretty well developed product considering the application space. But, it’s far from “easy to use”. I have been working on the web side, and I hope to put up some posts on how to use the product with ASP.NET MVC within the next couple weeks. Atalasoft doesn’t officially support ASP.NET MVC, but they are very excited about the idea of integration; so they have provided some support during the process (the sales team seemed excited; but I dare not mention MVC within the support requests). All-in-all Atalasoft has a product which deals with a difficult area of web development and they are trying to do the best they can with the resources they have.

Other than that, I’m trying to find time to develop a jQuery breadcrumb plugin (http://code.google.com/p/jbreadcrumb/). I’m not finding much time to work on it … but, plugins are a step-by-step process.

Microsoft and Google CDN Response Times

on Saturday, September 26, 2009

Last week Microsoft announced that it would be hosting some of the common javascript files used with ASP.NET applications (jQuery, Microsoft AJAX, etc). Google had been doing this for a while through both standard CDN and ajax library calls, but it was great to see Microsoft also put up a resource which hosted the MS specific javascript files that you can’t find else where.

The applications that I work with are already using the Google CDN to load jQuery and jQuery-UI, but I wanted to know if there would be a benefit to switching. The most important thing for a CDN is to be fast, and Microsoft/Akamai is pretty darn fast. Below are the results of a ping test to the servers:

smaglio@sensei:~$ ping ajax.microsoft.com
PING a1363.g.akamai.net (70.183.191.139) 56(84) bytes of data.
64 bytes from a-70-183-191-139.deploy.akamaitechnologies.com (70.183.191.139): icmp_seq=1 ttl=60 time=13.8 ms
64 bytes from a-70-183-191-139.deploy.akamaitechnologies.com (70.183.191.139): icmp_seq=2 ttl=60 time=16.1 ms
64 bytes from a-70-183-191-139.deploy.akamaitechnologies.com (70.183.191.139): icmp_seq=3 ttl=60 time=16.5 ms
64 bytes from a-70-183-191-139.deploy.akamaitechnologies.com (70.183.191.139): icmp_seq=4 ttl=60 time=26.7 ms
64 bytes from a-70-183-191-139.deploy.akamaitechnologies.com (70.183.191.139): icmp_seq=5 ttl=60 time=15.2 ms
^C
--- a1363.g.akamai.net ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 13.854/17.711/26.758/4.620 ms
smaglio@sensei:~$ ping ajax.googleapis.com
PING googleapis-ajax.l.google.com (209.85.225.95) 56(84) bytes of data.
64 bytes from iy-in-f95.google.com (209.85.225.95): icmp_seq=1 ttl=55 time=73.2 ms
64 bytes from iy-in-f95.google.com (209.85.225.95): icmp_seq=2 ttl=55 time=77.7 ms
64 bytes from iy-in-f95.google.com (209.85.225.95): icmp_seq=3 ttl=55 time=76.2 ms
64 bytes from iy-in-f95.google.com (209.85.225.95): icmp_seq=4 ttl=55 time=74.6 ms
64 bytes from iy-in-f95.google.com (209.85.225.95): icmp_seq=5 ttl=55 time=71.3 ms
64 bytes from iy-in-f95.google.com (209.85.225.95): icmp_seq=6 ttl=55 time=69.5 ms
^C
--- googleapis-ajax.l.google.com ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5007ms
rtt min/avg/max/mdev = 69.592/73.815/77.725/2.772 ms

Adding Schema & Sproc Prefix to ELMAH

on Tuesday, June 23, 2009

Background: ELMAH (Error Logging Modules and Handlers) is a great tool for any web developer that doesn’t want to go through the pain of adding in error logging to their web applications. A great tutorial on it was written up by Simone Busoli.

One of the features that ships with ELMAH is a database script for setting up the SQL Server table and stored procedures. And, unfortunately you can’t alter the names of the stored procedures out of the box, because the names are hardcoded in the ELMAH dll. This causes a bit of a problem with our environment and SQL Server 2008, because the script is designed for SQL Server 2000. All of the stored procedures are created under the owner [dbo].

While you can setup the schema of ‘dbo’ in SQL Server 2008, it’s not the most flexible way to go. Also, using the dbo schema would enforce the rule that you must have only one ELMAH error table in the database. Which would require making a separate database for each website.

This constraint didn’t work for our environment, so I went through the source code and found that it was a pretty straight forward process to add in Schema & Stored Procedure Prefixes while keeping the dll backwards compatible. Since ELMAH uses Inversion of Control to make it more reusable, you only need to update one file, SqlErrorLog.cs.

First you add in new properties for the Schema and SprocPrefix. And, then initialize them in the constructor:

/// <summary>
/// The schema name to use in place of 'dbo' on 2005/2008 Sql Server instances.
/// </summary>
internal virtual string Schema { get; set; }

/// <summary>
/// The stored procedure prefix. When used this will allow multiple applications
/// to use the same database (but, different sprocs/tables) to store exception
/// logs.
/// </summary>
internal virtual string SprocPrefix { get; set; }
public SqlErrorLog(IDictionary config)
{
// ... left out for clarity

// grab the schema if provided, else use 'dbo' as default
Schema = config["schema"] == null ? "dbo" : config["schema"].ToString().Trim();

// grab the stored procedure prefix if one is provided. the default value is an empty string.
SprocPrefix = config["sprocPrefix"] == null ? string.Empty : config["sprocPrefix"].ToString().Trim();
}

After that, all that’s left is updating the private Commands classes method signatures to require the schema and sprocPrefix variables. Like so:

public static SqlCommand LogError(
Guid id,
string appName,
string hostName,
string typeName,
string source,
string message,
string user,
int statusCode,
DateTime time,
string xml,
string schema,
string sprocPrefix)
{
var commandText = string.Format( "[{0}].[{1}ELMAH_LogError]", schema, sprocPrefix );
var command = new SqlCommand(commandText);

// ... left out for clarity
}

And, finally update the code which calls those methods.

Then you can use the ‘schema’ and ‘sprocPrefix’ attributes in the configuration file.

<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="XYZ" schema="Ent" sprocPrefix="WebApp1_" />

Thanks Atif Aziz for making it so easy.

The error message just isn’t helpful

on Tuesday, June 16, 2009

(Heads Up: This is not my code. I’m trying to help out.)

In our systems there is a web application (not website) which has an automated Cruise Control (ccnet) build. And that ccnet build has worked for a couple of weeks until I added a  new webpage.

Unfortunately, once I added the webpage to the build I started to receive this error  from the asp compiler (when I removed the webpage the error went away):

/Announcements/ArchiveFeed.aspx(2): error ASPPARSE: Could not load type 'ArchiveFeed'.


I looked at both the aspx and aspx.cs file which created the error and could not understand why the error message was being generated:



ArchiveFeed.aspx:



<?xml version='1.0' encoding = 'utf-8'?>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ArchiveFeed.aspx.cs" Inherits="ArchiveFeed" Title="Announcement Archives" %>

<rows>
<page>1</page>
<total>2</total>
<records>15</records >

<asp:Repeater ID="repeater1" runat="server">

<HeaderTemplate>
</HeaderTemplate>

<ItemTemplate>
<row id='<%# DataBinder.Eval(Container.DataItem, "Id") %>'>
<cell><%# DataBinder.Eval(Container.DataItem, "Id") %></cell>
<cell><%# DataBinder.Eval(Container.DataItem, "Subject") %></cell>
<cell><%# DataBinder.Eval(Container.DataItem, "Message") %></cell>
<cell><%# DataBinder.Eval(Container.DataItem, "Editor") %></cell>
<cell><%# DataBinder.Eval(Container.DataItem, "Tr") %></cell>
</row>
</ItemTemplate>

<FooterTemplate>
</FooterTemplate>

</asp:Repeater>

</rows>


 



ArchiveFeed.aspx.cs:



using System;
using System.Collections;
using System.Web.UI;
using Ucsb.Sa.Registrar.Herald;
using Ucsb.Sa.Registrar.Herald.Services;


public partial class ArchiveFeed : Page
{
private AnnouncementService _servAnnounce = AppSettings.GetAnnouncementService();
private ArrayList list1 = new ArrayList();
protected void Page_Load(object sender, EventArgs e)
{
/*if (Session["validated"] == null || !Session["validated"].Equals("true"))
{
Response.Redirect("Login.aspx");
}*/
Response.ContentType = "text/xml";
AnnouncementList aList = _servAnnounce.getAllAnnouncements();
for (int i = 0; i < aList.Announcements.Count; i++)
list1.Add(new ArchiveInformation(aList.Announcements[i].ID,aList.Announcements[i].Subject,aList.Announcements[i].Message,
aList.Announcements[i].Editor,aList.Announcements[i].ActiveTimeRange));
//lists.Add(aList.Announcements[i].ID);
this.repeater1.DataSource = list1;
this.repeater1.DataBind();
}
}



After asking some of the other developers in the department about the problem, a unanimous conclusion was made: “That’s just weird”. So what the heck is going on?



Any help would be appreciated.



UPDATE: The code behind for the page wasn't able to compile because a referenced assembly wasn't updated in the source control system. I have become too reliant on the source control system's Visual Studio integration.

List of useful commands: Remote Commands

on Monday, June 15, 2009

When using remote desktop a number of problems can occur which will make your remote system unresponsive. The worst of which is a system freeze, which requires a hard boot. But, here’s a couple things to try before driving into the office. In order to use these commands you will need to remote into another system on the same network.

Attempt a remote reboot of the system: shutdown –m \\XXX.XXX.XXX.XXX  -r

Sometimes, after attempting a remote restart the shutdown process seems to hang or become unresponsive. If that occurs, then you can use psexec to attempt to run remote commands: psexec \\XXX.XXX.XXX.XXX cmd.exe

Once you have a command prompt on the remote system, you can get a list of active processes using: tasklist

And, you can kill a process using: taskkill /PID XXXX or taskkill /IM notepad.exe

To exit psexec use Ctrl-C.

Windows 7 RC, VS 2010 Beta & SQL Server 2008 SP1

on Saturday, June 13, 2009

Near the end of the VS 2010 Beta installer SQL Server Express 2008 is installed. The installer will pause for a moment and display a warning dialog stating that SQL Server has known compatibility issues with this version of Windows. An installation helper is provided which offers a solution of installing SQL Server 2008 SP1. The given link to the SP1 installer is: http://www.microsoft.com/downloads/details.aspx?familyid=01AF61E6-2F63-4291-BCAD-FD500F6027FF&displaylang=en#filelist.

Unfortunately, all of the downloads on the page are install for SQL Server Express editions, not SP1. There are links on the bottom of the page which lead to the SP1 download: http://www.microsoft.com/downloads/details.aspx?familyid=66AB3DBB-BF3E-4F46-9559-CCC6A4F9DC19&displaylang=en.

Hopefully, this write up will clear up a little bit of the confusion. It’s also likely that a future version of the installer will include the service pack.

PS. After a little bit more searching on MSDN, I ran across a much more thorough write-up by Weston Hutchins: http://social.msdn.microsoft.com/Forums/en-US/setupprerelease/thread/4c740329-7366-43ca-b9f4-207a391b311b

iPhone and Microsoft Exchange

on Monday, June 1, 2009

At work we use a Microsoft Exchange server for all email. It’s a stable email server and the Microsoft Outlook client has a really polished UI. The 3rd party extensions aren’t as mature (IMHO) as the Thunderbird extensions, but the Calendar integration is pretty top notch.

I try to keep all my calendar events using the Exchange calendar system because it’s so easy to use. And I have integrated the Exchange Calendar with Google Calendar in order to have easy access to the system from home. The Google Calendar Sync service does a pretty good job of providing synchronization, but I’ve seen it miss a few appointments/meetings here and there. For the most part, it’s accurate and efficient.

Recently, I got an iPhone and have been blown away by the integration and accuracy. I haven’t been using the iPhone as long as the Google Calendar Sync; so this might be a premature evaluation.

However, I have found a couple of the features to be really compelling.

First, the easiness of adding my email account to the iPhone was amazing. Of course I had to put in my email address & password. But, here was the great part: To hook up the phone to the web interface of Exchange meant 1) entering the domain name that the Exchange server was on (eg. somedomain.com) and then 2) click “Next”. The phone searched the domain network for a web access point and returned with the correct dns information (eg. webmail.somedomain.com). That was it.

Second, I’ve compared the iPhone’s calendar with my Google Calendar and the iPhone caught all of the appointments/meetings which the Google Calendar missed.

Third, the iPhone is actually receiving emails a few seconds before the Outlook client on my work computer is. And, the Calendar is automatically being updated when the email arrives.

A Big THANK YOU to the iPhone designers for making this such an easy process!

 

The other phone I was considering was the Google phone. Does anyone have experience with that phone? How does the email/calendar integration on the G1 compare with the iPhone email/calendar integration?

Render View Inline

on Wednesday, May 6, 2009

For one reason or another I wanted to render a view within a controller in order to add the html output to a JSON reply. This isn’t the way ASP.NET MVC was designed, but it is a useful feature to add in.

Because ASP.NET wasn’t designed to run views from Controllers and manipulate/reuse the result after processing was finished, the ViewResult.ExecuteResult method does not return any handle to the html string produced.

You can get around this, by replacing the underlying HtmlTextWriter class which the ViewResult uses with a StringBuilder. Once ExecuteResult is finished, the properly formatted html will be available through the StringBuilder.

Here is a method which swaps in the StringBuilder and executes the View:

public static StringBuilder ExecuteResult( ViewResult view, ControllerContext context )
{
var responseWrapper = context.HttpContext.Response;
var response = ReflectionUtil.GetPrivateVariable( responseWrapper, "_httpResponse" );
var originalWriter = ReflectionUtil.GetPrivateVariable( response, "_writer" );

var builder = new StringBuilder( 1000 );
var writer = new HtmlTextWriter( new StringWriter( builder ) );

ReflectionUtil.SetPrivateVariable( response, "_writer", writer );
view.ExecuteResult( context );
ReflectionUtil.SetPrivateVariable( response, "_writer", originalWriter );

return builder;
}

ReflectionUtil.SetPrivateMethod is a wrapper for some of the common reflection usages (just to save a couple of keystrokes):

/// <summary>
/// Utility containing short-cut methods for the System.Reflection namespace.
/// </summary>
public class ReflectionUtil
{

/// <summary>
/// Changes the objects internal value.
/// </summary>
/// <param name="obj">Object to alter</param>
/// <param name="variableName">Private variable name</param>
/// <param name="newValue">Value to change the variable to.</param>
public static void SetPrivateVariable(
object obj,
string variableName,
object newValue
) {
SetInvoke(
obj,
variableName,
newValue,
BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance
);
}

/// <summary>
/// Retrieves a private variables value using reflection.
/// </summary>
/// <param name="obj">Object to retrieve the value from.</param>
/// <param name="variableName">The variable to read.</param>
/// <returns>The variable's contents as an object.</returns>
public static object GetPrivateVariable(
object obj,
string variableName
) {
FieldInfo info = obj.GetType().GetField(
variableName,
BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance
);

return info.GetValue( obj );
}

/// <summary>
/// Changes the objects internal value.
/// </summary>
/// <param name="obj">Object to alter</param>
/// <param name="variableName">Private variable name</param>
/// <param name="newValue">Value to change the variable to.</param>
public static void SetPrivateProperty(
object obj,
string variableName,
object newValue
) {
SetInvoke(
obj,
variableName,
newValue,
BindingFlags.SetProperty | BindingFlags.NonPublic | BindingFlags.Instance
);
}

/// <summary>
/// Changes the objects internal value.
/// </summary>
/// <param name="obj">Object to alter</param>
/// <param name="variableName">Private variable name</param>
/// <param name="newValue">Value to change the variable to.</param>
/// <param name="bindingFlags">The binding flags to look through.</param>
public static void SetInvoke(
object obj,
string variableName,
object newValue,
BindingFlags bindingFlags
) {
var t = obj.GetType();
var lastException = new Exception( "NULL" );

while( t != null ) {
try {
t.InvokeMember( variableName, bindingFlags, null, obj, new [] { newValue } );
return;
} catch( Exception e ) {
lastException = e;
t = t.BaseType;
}
}

if( lastException.Message != "NULL" ) throw lastException;
}

}

UPDATE: I ran into a posting by Mike Hadlow which was trying the same thing, but ran into a snag with the Response Headers being marked as written after ExecuteResult completed. He also has a way to get around the problem.


Technorati Tags: ,,

MVC Static Content DNS Helper

on Thursday, April 30, 2009

A website I was working on needed a way to include references to static content (images/css/js) which could dynamically point to the correct server for the build environment (dev,test,prod). This was accomplished by creating extension methods for the HtmlHelper.

I recently wrote about using a static content website on a previous post.

We already had an enumeration setup to describe the environment (listed below the post). We just needed a way to parse string values and add the dns name. To do this, we made a class for ASP.NET 2.0 websites and for ASP.NET MVC websites. It also needed to add the “.min.js” extension for production javascript.

ASP.NET 2.0:

using System.Web;
using Ucsb.Sa.Registrar.Util;

namespace Ucsb.Sa.Enterprise.Utility.Web
{
/// <summary>
/// Static content extension methods for <see cref="HtmlHelper" />. This file requires that the web
/// application contains a static AppSettings file with property BuildEnvironment.
/// </summary>
public static class StaticContentExtensions
{

#region variables

private const string BaseImageUrlFormat = "{0}://static.{1}sa.ucsb.edu/{2}";
private const string BasePlaceholder = "~";
private const string Image = "images";
private const string Css = "css";
private const string Js = "js";
private const string JQuery = "js/jquery";

#endregion

#region properties

/// <summary>
/// Gets and Sets the <see cref="BuildEnvironmentType" /> for the application. This
/// should be set before the first call to these extension methods.
/// </summary>
public static BuildEnvironmentType BuildEnvironment { get; set; }

/// <summary>
/// http or https
/// </summary>
public static string Scheme
{
get { return HttpContext.Current.Request.Url.Scheme; }
}

#endregion

#region public methods

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/bottom_header.jpg&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/bottom_header.jpg&quot;).
/// </summary>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetImageUrl( string partialUrl )
{
return GetUrl( partialUrl, Image );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/site.css&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/site.css&quot;).
/// </summary>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetCssUrl( string partialUrl )
{
return GetUrl( partialUrl, Css );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/jquery.js&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js&quot;).
/// </summary>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetJsUrl( string partialUrl )
{
var url = GetUrl( partialUrl, Js );
return RewriteForMinJs( url );

}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/jquery.js&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js&quot;).
/// </summary>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetJQueryUrl( string partialUrl )
{
var url = GetUrl( partialUrl, JQuery );
return RewriteForMinJs( url );
}

/// <summary>
/// Creates the javascript code to load javascript libraries from google.
/// This will ensure that the uncompressed version of the code is loaded on the developer
/// systems.
/// </summary>
/// <param name="package">The name of the javascript library to load.</param>
/// <param name="version">The version number to retrieve.</param>
/// <returns>The string to be injected into a &lt;script&gt; section.</returns>
public static string GetGoogleLoad( string package, string version )
{
const string format = "google.load('{0}', '{1}'{2}";
const string compressed = ");";
const string uncompressed = ", {uncompressed:true});";

return string.Format(
format,
package,
version,
BuildEnvironment == BuildEnvironmentType.Local ? uncompressed : compressed
);
}

#endregion

#region private methods

private static string GetUrl( string partialUrl, string subDirectory )
{
var baseUrl = string.Format( BaseImageUrlFormat, Scheme, GetEnvironmentString(), subDirectory );
return partialUrl.Replace( BasePlaceholder, baseUrl );
}

private static string GetEnvironmentString()
{
var env = string.Empty; // default value for pilot and production

switch( BuildEnvironment )
{
case BuildEnvironmentType.Local:
case BuildEnvironmentType.Development:
case BuildEnvironmentType.Integration:
env = "dev.";
break;

case BuildEnvironmentType.Test:
env = "test.";
break;
}

return env;
}

private static string RewriteForMinJs( string url )
{
if( BuildEnvironment != BuildEnvironmentType.Production ) return url;
if( string.IsNullOrEmpty( url ) ) return url;

var len = url.Length;
if( len < 3 ) return url;

const string ext = ".js";
if( url.Substring( len - 3 ) != ext ) return url;

const string minExt = ".min.js";
if( url.Substring( len - 7 ) == minExt ) return url;

const string format = "{0}.min.js";
return string.Format( format, url.Substring( 0, len - 3 ) );
}

#endregion

}
}


And the corresponding ASP.NET MVC wrapper:



using System.Web.Mvc;
using Ucsb.Sa.Registrar.Util;

namespace Ucsb.Sa.Enterprise.Utility.Web.Mvc
{
/// <summary>
/// Static content extension methods for <see cref="HtmlHelper" />. This file requires that the web
/// application contains a static AppSettings file with property BuildEnvironment.
/// </summary>
public static class HtmlHelperStaticContentExtensions
{

#region properties

/// <summary>
/// Gets and Sets the <see cref="BuildEnvironmentType" /> for the application. This
/// should be set before the first call to these extension methods.
/// </summary>
public static BuildEnvironmentType BuildEnvironment
{
get { return StaticContentExtensions.BuildEnvironment; }
set { StaticContentExtensions.BuildEnvironment = value; }
}

#endregion

#region public methods

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/bottom_header.jpg&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/bottom_header.jpg&quot;).
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetImageUrl( this HtmlHelper html, string partialUrl )
{
return StaticContentExtensions.GetImageUrl( partialUrl );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/site.css&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/site.css&quot;).
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetCssUrl( this HtmlHelper html, string partialUrl )
{
return StaticContentExtensions.GetCssUrl( partialUrl );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/jquery.js&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js&quot;).
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetJsUrl( this HtmlHelper html, string partialUrl )
{
return StaticContentExtensions.GetJsUrl( partialUrl );
}

/// <summary>
/// Converts an ASP url (eg. &quot;~/insideSa/jquery.js&quot;)
/// into a full url (eg. &quot;http://static.dev.sa.ucsb.edu/images/insideSa/jquery.js&quot;).
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="partialUrl">The folder and file name under the static images directory.</param>
/// <returns>The full path to the static website with the sub-folder and file name appended.</returns>
public static string GetJQueryUrl( this HtmlHelper html, string partialUrl )
{
return StaticContentExtensions.GetJQueryUrl( partialUrl );
}

/// <summary>
/// Creates the javascript code to load javascript libraries from google.
/// This will ensure that the uncompressed version of the code is loaded on the developer
/// systems.
/// </summary>
/// <param name="html">The object to add this extension method to.</param>
/// <param name="package">The name of the javascript library to load.</param>
/// <param name="version">The version number to retrieve.</param>
/// <returns>The string to be injected into a &lt;script&gt; section.</returns>
public static string GetGoogleLoad( this HtmlHelper html, string package, string version )
{
return StaticContentExtensions.GetGoogleLoad( package, version );
}

#endregion

}
}


Then we used the static classes in a PartialView for rendering:

<%@ Import Namespace="Ucsb.Sa.Enterprise.Utility.Web.Mvc"%>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<link href="<%= Html.GetCssUrl( "~/reset.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetCssUrl( "~/blueprint/0_8/ie.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetCssUrl( "~/blueprint/0_8/screen.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetCssUrl( "~/blueprint/0_8/print.css" ) %>" rel="stylesheet" type="text/css" media="print" />
<link href="<%= Html.GetJQueryUrl( "~/1_3_2/themes/ucsb/ui.base.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetJQueryUrl( "~/1_3_2/themes/ucsb/jquery-ui-1.7.1.custom.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetJQueryUrl( "~/dataTables-1_4/css/datatables.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetJQueryUrl( "~/mbMenu-2_2/css/menu.css" ) %>" rel="stylesheet" type="text/css" media="screen" />
<link href="<%= Html.GetCssUrl( "~/InsideSa/InsideSaLayout-0.0.0.1.css" ) %>" rel="Stylesheet" type="text/css" media="screen" />


Which generated html that looked like this:

<link href="http://static.dev.sa.ucsb.edu/css/reset.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/css/blueprint/0_8/ie.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/css/blueprint/0_8/screen.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/css/blueprint/0_8/print.css" rel="stylesheet" type="text/css" media="print" />
<link href="http://static.dev.sa.ucsb.edu/js/jquery/1_3_2/themes/ucsb/ui.base.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/js/jquery/1_3_2/themes/ucsb/jquery-ui-1.7.1.custom.css" rel="stylesheet" type="text/css" media="screen" />

<link href="http://static.dev.sa.ucsb.edu/js/jquery/dataTables-1_4/css/datatables.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/js/jquery/mbMenu-2_2/css/menu.css" rel="stylesheet" type="text/css" media="screen" />
<link href="http://static.dev.sa.ucsb.edu/css/insideSa/InsideSaLayout-0.0.0.1.css" rel="Stylesheet" type="text/css" media="screen" />


Here is the code for the environment variables:

namespace Ucsb.Sa.Registrar.Util
{
/// <summary>
/// Enumeration for each build environment. eg. Development, Test, etc.
/// </summary>
public enum BuildEnvironmentType
{
/// <summary>
/// local, localhost
/// </summary>
Local,

/// <summary>
/// dev, development
/// </summary>
Development,

/// <summary>
/// int, integration
/// </summary>
Integration,

/// <summary>
/// test, qa, quality assurance
/// </summary>
Test,

/// <summary>
/// pilot
/// </summary>
Pilot,

/// <summary>
/// prod, production
/// </summary>
Production
}
}


using System;

namespace Ucsb.Sa.Registrar.Util
{
/// <summary>
/// Attempts to parse string values to BuildEnvironmentType Enumerations.
/// </summary>
public static class BuildEnvironmentTypeParser
{

/// <summary>
/// <para>
/// Parses a string value into the corresponding environment type. Some partial and exact matches can be parsed.
/// </para>
/// <para>ie. Development, dev, prod, test, Production, etc.</para>
/// </summary>
/// <param name="environmentName">string to parse</param>
/// <returns>BuildEnvironmentType from parsed string.</returns>
/// <exception cref="ArgumentException">If the argument is unknown.</exception>
public static BuildEnvironmentType Parse( string environmentName ) {
if( string.IsNullOrEmpty( environmentName ) )
throw new ArgumentException( "Argument environmentName was null or empty." );

switch( environmentName.ToLower().Trim() ) {
case "local": case "localhost":
return BuildEnvironmentType.Local;

case "dev": case "development":
return BuildEnvironmentType.Development;

case "int": case "integration":
return BuildEnvironmentType.Integration;

case "qa": case "quality assurance": case "test":
return BuildEnvironmentType.Test;

case "pilot":
return BuildEnvironmentType.Pilot;

case "prod": case "production":
return BuildEnvironmentType.Production;
}

throw new ArgumentException( "Argument environment name, " + environmentName + ", is of an unknown type." );
}

}
}

Development Guide: UCSB static content website

(This entry has to do with my personal opinion about the way a static website should be built at UCSB and does not reflect the opinions of UCSB)

A static content website at UCSB would help with performance for a couple of the “high visibility” websites. But, it is not required. A couple of reasons why to use a static content website are described by YSlow (a plugin for Firefox): http://developer.yahoo.com/performance/rules.htm

At UCSB we should/will be creating a static content website for a couple more reasons:

  1. We copy a lot of static content into multiple of our websites (mostly for MasterPages). This causes:
    1. Duplicate content in the source control system.
    2. Maintenance issues when updating websites.
    3. Excessive copy times when deploying websites (well, this may not be a very big issue).
  2. A common infrastructure to look for images that are copyrighted/available for use on SA websites.

It seems that there is a need for all the developers to be on the same page when using a communal share for website static content. And in that vein here are a few Development Guidelines.

Development Guidelines:

  1. The static content website urls are at:
    1. Dev: http://static.dev.sa.ucsb.edu/ (only available within the SA network)
    2. QA/Test: http://static.test.sa.ucsb.edu/ (only available to UCSB IPs)
    3. Prod: http://static.sa.ucsb.edu/ (public)
  2. The base folder (/) should have sub-directories for common groupings. A few upfront common groupings are:
    1. js
    2. css
    3. images
  3. Any commonly used js/css/images should be kept under the appropriate subfolder.
  4. Any project specific js/css/images should be kept under a subfolder for the application.
    1. Examples: js/InsideSa, css/AAA
    2. If the website name is already taken, please use a new and appropriate name which describes the website the content is for. No restrictions, just don’t duplicate.
  5. For third party components (eg: jquery) place a parent directory under the appropriate top directory (eg: js/jquery), but then place version directories underneath it.
    1. js/jquery/1_2_6
    2. js/jquery/1_3_2
  6. For third party components to third party compents (eg: jqGrid) place a parent directory under appropriate third party diretory (eg: js/jquery/jqGrid), but then place version directories underneath it.
    1. js/jquery/jqGrid/1_4_3
  7. Never allow dots (.) in a directory name before the static content. I haven’t found any official documentation on it, but it seems like IIS will stop looking for sub-directories once the first dot is found.
    1. For Example: If you have /js/jquery/1.2.6/jquery-1.2.6-min.js, then IIS will return a “404 File Not Found” error message for file “1.2.6”; because it considers the first dot name (1.2.6: a directory) to be the name of the file.
    2. Please use underscores (_) in place of dots in directory names.
  8. When putting content into the static website always add a Version Stamp to the filename.
    1. CSS:
      1. Use a version number.
        1. Please use the same version number of your website update as the filename addition. For example: css/insideSa/InsideSaLayout-0.0.0.1.css
        2. ** alternative suggestion
    2. Javascript:
      1. Use a version number.
        1. Please use the same version number of your website update as the filename addition. For example: js/InsideSa/insideSa.menu-0.0.0.1.js
        2. ** alternative suggestion
    3. Images:
      1. Use a date/time stamp.
        1. Use the format <image name>_yyyyMMddHHmm.<ext>. For example: images/InsideSa/background_200903260203.jpg
        2. A date/time is used because multiple images with the same name can be created during development.
  9. Because versioning is done in the filename, you don’t have to delete any files. Please don’t delete any files in the “common area” of the folders. The project specific folders can have files deleted if the developer(s) feel it’s okay; but we strongly suggest you don’t. Just incase some unknown project is referencing the static content.
    1. Don’t worry about the disk space, it really shouldn’t eat up too much room. And if it becomes a problem we’ll work with the systems team to come up with a good solution.
  10. Javascript files should have a development version and a minified version (for production).
    1. The development (human readable) version should be formatted like the example in section 8.2.
    2. The minified version should have the same format as section 8.2 but with the extension .min.js.
      1. This means that sometimes you will have to change the names of javscript files you download. For example, Microsoft uses .js for the minified version and .debug.js for the development version.
      2. You can use jsmin.exe to minify your javascript files after development has finished.
      3. Before and after you use jsmin.exe you should run your file through jslint. jslint has a yahoo widget for it. If anyone knows of a google gadget for it, let me know. Or even a command line version, so we can add it to an automated build script.
    3. Mozilla has a great list of links for standard javascript tools.
  11. New Common sub-groupings do not need to be vetted (aka, submitted for approval), just make sure that there is no appropriate sub-directory already in existence.
    1. For example: RadControls. They require that the base sub-directory be the root for all js/css/images used within their Q3 2006 dll. (This has not been done yet, because RadControls integration with MVC is not “great” yet.)
      1. Sidenote to Telerik: We really liked your Blue theme from your 2006 components. But, those Blue themes were not added to your dll’s when you started compiling your resources into them. Which makes it difficult to easily upgrade from your website based components to your web application based dlls. =(
  12. The dev area will be hooked up to the source control system.
    1. The dev area will be automatically updated into the source control system on Friday.
    2. Please update your changes into the source control system before Friday when you see fit.
  13. (UPDATE) Websites which are SSL encrypted must retrieve content through an SSL request.
    1. This is due an error message which only occurs on IE. The problem has been reported multiple times (387991,388636), but the people who report it don’t suggest removing the warning. (Firefox, Safari, Opera, and Chrome do not have an error/warning message).
    2. When the IE feedback stops giving me an error message after I sign in, I will add a “feedback” post which requests that the feature be dropped. The link to that “feedback” post will be attached here, so others may second the feature drop. (IE Team: please stop producing this error/warning message; its so unnecessary).

** alternative suggestion: Add version subdirectories for our applications. It can simplify things for the program. But it does complicate maintenance for the developer. Not much though. Please, ask for this if you think it will be less maintenance.

Remember: This can always be updated. And as things change this should be updated.

Technorati Tags: ,,

SiteMapProvider Exception Crashes the Website

on Saturday, April 25, 2009

Problem

I’m getting this error message from Visual Studio (The debugger cannot continue running the process. Process was terminated.):

image

The error message is appearing when debugging a ASP.NET MVC application in Visual Studio 2008. The lines of code which are being executed at taking a object tree and converting it to populate a SiteMapProvider. The error is occuring when stepping from line 10 to line 16. Line 16 is highlighted when error occurs:

Code Snippet 1 (CS1)

   1: private static InsideSaSiteMapNode CreateMvcNode( InsideSaSiteMapNodeDTO dto )
   2: {
   3:     var node                = new InsideSaSiteMapIntegrationNode( _Provider, dto.Href );
   4:     node.Href               = dto.Href;
   5:     node.Title              = dto.Title;
   6:     node.JavascriptAction   = dto.JavascriptAction;
   7:     node.IconFilename       = dto.IconFilename;
   8:     node.Target             = dto.Target;
   9:  
  10:     foreach( var child in dto.ChildNodes )
  11:     {
  12:         var childNode    = CreateMvcNode( child );
  13:         node.ChildNodes.Add( childNode );
  14:     }
  15:  
  16:     return node;
  17: }

As a bonus, the “Process” being referenced in the error message is the ASP.NET Development Server which is running the website. So, the website crashes.

Analysis

The error first started when I added a line of to the SiteMapProvider method, GetChildNodes. The new code is on line 11 (commented out).

CS2

   1: /// <summary>
   2: /// When overridden in a derived class, retrieves the child nodes of a specific <see cref="T:System.Web.SiteMapNode"/>.
   3: /// </summary>
   4: /// <returns>
   5: /// A read-only <see cref="T:System.Web.SiteMapNodeCollection"/> that contains the immediate child nodes of the specified <see cref="T:System.Web.SiteMapNode"/>; otherwise, null or an empty collection, if no child nodes exist.
   6: /// </returns>
   7: /// <param name="node">The <see cref="T:System.Web.SiteMapNode"/> for which to retrieve all child nodes. 
   8: /// </param>
   9: public override SiteMapNodeCollection GetChildNodes( SiteMapNode node )
  10: {
  11:     //return node.ChildNodes;
  12:     return null;
  13: }

I realize that your not supposed to use the incoming node to return the child values. But, that line of code has not been called yet in the program. The error occurs in line CS1:16. The value being returned was made by a call from CS1:12; which might mean that CS1:13 is “pre-executed” when the return value is known. The frustration really lies in the idea that node.ChildNodes (which returns a null value) causes an exception which crashes the web server while returning null produces an exception which is handled in the debugger.

Solution

As you can see in the code above, the offending line of code was commented out. But, it was a good lesson to learn about SiteMapProvider development. When calling the Add method on a SiteMapNode the provider’s abstract methods will get called; and they’re a bit touchy.


Technorati Tags: ,,,

Assembly NullReferenceException & .NET Reflector

on Monday, April 20, 2009

Problem

I was receiving a NullReferenceException when running a third party dll through NUnit. Which made it difficult to debug, because I couldn’t step through/alter the third party dll’s source code.

Analysis

Thankfully the stack trace showed the class, method, and line number of the error. I was able to look through the third party dll using Reflector, and found this line:

builder.AppendLine(Assembly.GetEntryAssembly().Location);

It seemed pretty straight forward that the GetEntryAssembly() method call was returning a null value. But, why?

The explanation came from the remarks section (among other places on the page) of the MSDN documentation:

The GetEntryAssembly method can return null (Nothing in Visual Basic) when a managed assembly has been loaded from an unmanaged application. For example, if an unmanaged application creates an instance of a COM component written in C#, a call to the GetEntryAssembly method from the C# component returns null, because the entry point for the process was unmanaged code rather than a managed assembly.

I had always thought that NUnit was managed code, but maybe there was an intermediate level of unmanaged code which was executing NUnit. This seemed probable because NUnit was being called from NAnt which was being called from CruiseControl.Net. And, the error was not happening when I was ran NUnit through ReSharper within Visual Studio.

I just needed a way to update the third party source code to remove/rewrite the offending line.

Solution

Reflector has a FileDisassembler addin which can take the decompiled output and write it to disk. It can even take an entire dll and create a Visual Studio project when exporting the code.

The decompiled output for this assembly had a few compile errors, but started working after a few redundant “compile-fix-error” steps in Visual Studio.

Once the solution was updated to use the decompiled code, I added in a static method which replaced all calls to Assembly.GetEntryAssembly() within the project:

using System.Reflection;
 
namespace Some.Namespace
{
    /// <summary>
    /// This class handles retrieving assemblies which have the potential of returning null values.
    /// </summary>
    public static class AssemblyHandler
    {
 
        /// <summary>
        /// Retrieves the entry assembly when available. If it is not available then the calling
        /// assembly is returned.
        /// </summary>
        /// <returns>The highest level executing assembly which can be found within executing AppDomain.</returns>
        public static Assembly GetEntryAssembly() {
            Assembly    asm    = Assembly.GetEntryAssembly();
            if( asm == null )    asm    = Assembly.GetCallingAssembly();
            return asm;
        }
 
    }
}


After a new compile, the NullReferenceException disappeared.




Creative Commons License
This site uses Alex Gorbatchev's SyntaxHighlighter, and hosted by herdingcode.com's Jon Galloway.