Thursday, August 27, 2009

Find All Occurences of a Specific Field Name in SQL Server

Here's a useful T-SQL script that will identify every table that has a field with a specific name:
select sysobjects.name
from syscolumns
left join sysobjects on sysobjects.id = syscolumns.id
where syscolumns.name like 'myFieldName'
order by 1
Source - Steve Gray

Wednesday, August 26, 2009

Developer AutoLogin & Redirect

A large project I'm working on these days includes a Login page which each user must pass through before being able to access the rest of the site. There is code similar to this that prevents unauthorized entry onto every page:












For some time I would just comment out this code until the rest of the module was complete. The problem with that is that as the application became more & more sophisticated, there was assorted initialization code elsewhere that has to be executed each & every time.

For the Run-Debug cycle it became exceptionally time consuming (and annoying) to manually go through the entire login process every time. Here's an example of the steps involved:







































Oh sure, it's just a few keystrokes and mouse clicks each time but repeated dozens (or hundreds!) of times per day, one soon hopes for a way to automate the process. And I found it!



In Visual Studio's Solution Explorer, right-click on whatever page you're working on and choose "Set As Start Page" from the popup menu. Note: You've probably already done this!

Now in the Page_Init event handler of your Master Page (FYI all my projects use Master Pages) add this code:

protected void Page_Init(object sender, EventArgs e)
{
if (!IsPostBack)
{
// If we're on a development machine then record the Start Page that Visual Studio is set to
string currPage = Page.ResolveUrl(Request.ServerVariables["URL"].ToString());
if (System.Diagnostics.Debugger.IsAttached && SessionData.GetCurrentUser() == "")
if (SessionData.GetSessionObject("CurrentDebugPage") == null)
SessionData.SaveSessionObject("CurrentDebugPage", currPage);
}
}

Then in the Page_Load event handler of your login page add this code:

// Note: This must be set above: using System.Web.Security;
protected void Page_Load(object sender, EventArgs e)
{
// This tests whether we're running on a development machine. If so, we'll automatically login.
if (System.Diagnostics.Debugger.IsAttached && SessionData.GetCurrentUser() == "")
{
string currUser = "your_username";

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(currUser, false, 5);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);

// If a specific page has been set as the Start Page then redirect to it; otherwise go to the Default page
string currDebugPage = SessionData.GetSessionObject("CurrentDebugPage").ToString();
HttpContext.Current.Response.Redirect((currDebugPage == null) ? "~/default.aspx" : currDebugPage, true);
}
}

Note: The various SessionData methods are just simple ones I've constructed to ease the process of storing & retrieving variables in the Session State. I will gladly provide them upon request.



The result is that now, every time I run my project in Visual Studio, it jumps right to the desired web page, logging me in automatically. And yet when run in non-Debug mode it works normally. So I don't have to alter any code whenever I release a new production version.

In case you're wondering how this works, the process is quite straightforward:
  1. The Master page's Page_Init event handler is run before every Content page's Page_Load event handler. It records the start page that the developer wanted to go to, placing this string into a Session variable.
  2. When that desired page's Page_Load event handler is initially entered, the security checks therein reject entry because the user is not logged in. They then redirect to the Login page.
  3. In the Login page the special test in Page_Load passes because the code is being run from Visual Studio and because the user is not yet logged in.
  4. A FormsAuthenticationTicket is instantiated and then placed in a Cookie. This allows one to artificially login through the ASP.Net Login mechanism.
  5. The desired start page, originally stored by the Master Page, is retrieved from the Session State and control is redirected to that page.
  6. This second time the security checks in the desired page's Page_Load event handler pass because the user is now officially logged in.
It actually works really well and will save you a lot of time! If you have any questions, please just leave a comment.

Monday, August 17, 2009

A "Subtle" MessageBox

For years now, whenever I wanted to display a message box to the user I'd use some variation of the following:

// Displays an alert message box to the user.
public static void ShowMessage(string msg)
{
msg = Tools.FixJavaScriptString(msg);
Page page = HttpContext.Current.CurrentHandler as Page;
ScriptManager.RegisterStartupScript(page, page.GetType(),
Guid.NewGuid().ToString(), "alert('" + msg + "');", true);
}

// A single apostrophe is not allowed in a SQL string
// on its own so we need to prefix it with a backslash
.
public static string FixJavaScriptString(string text)
{
string text2 = text;
if (text.IndexOf("'") != -1)
text2 = text.Replace("'", "\\'");

return text2;
}

This works fine but the drawback is that the user must press the OK button on every Alert box.

Inspired by a feature I first noticed in FaceBook, I decided to create a MessageBox that would appear but then fade away after a developer-defined period of time. You can see it in action in this video:
video

The solution works with all of the following, which I use in most of my web development work:
  • The ASP.Net AJAX UpdatePanel
  • C#
  • jQuery
To get it working, first you must add this markup code to every page you wish to display a Subtle MessageBox on:




I always place this code right near the bottom of every Content page, just above "".

Then add the following server-side code to your web app (I have it in a shared code file called "Common.cs") :

// Displays a message box that disappears on its own.
public static void ShowSubtleMessage(string msg, int duration, string[,] cssParams)
{
msg = Tools.FixJavaScriptString(msg);
string script = "$('div#msg').empty().html('" + msg + "'); $('div.subtleMsg')";

if (cssParams != null)
{
string property = "";
foreach (string cssItem in cssParams)
{
if (property == "")
property = cssItem;
else
{
string propVal = cssItem;
script += ".css('" + property + "', '" + propVal + "')";
property = "";
}
}
}

Page page = HttpContext.Current.CurrentHandler as Page;
script += ".fadeIn(1000).animate({ opacity: 1.0 }, " + duration.ToString() + ").fadeOut(2000);";
ScriptManager.RegisterStartupScript(page, page.GetType(), Guid.NewGuid().ToString(), script, true);
}

Here is the CSS code that I use:

div.subtleMsg
{
display:none;
float: left;
position:absolute;
left:360px;
top:220px;
width:300px;
height:100px;
background:#0e90e6 url(../Images/Gradients/blueRectGradient4.jpg);
text-align:center;
padding:10px;
font-size:16px;
font-weight:bold;
color:White;
border:ridge 5px darkgray;
}


And here's a typical call to the method:

string msg = "Blank descriptions are not allowed!";
Common.ShowSubtleMessage(msg, 2000, new string[,] { { "left", "470px" }, { "top", "310px" }, { "width", "330px" }, { "height", "60px" } });



There are several improvements that could be made:
  • The HTML markup code could potentially be created with jQuery, via a call from the server-side code. I tried to do this but after several hours gave up. Perhaps someone reading this will come up with a solution!
  • Potentially the minimum required dimensions of the message box could be automatically calculated using some method in the .Net library.
But I think it's a good start and it works well for me! You can download a copy of everything here.