Monday, June 15, 2009

Access 2007 Trap: Life without @@identity()

I came across some interesting behavior in Access 2007 that tripped me up for a little while.I needed to add a record to a table and then get the primary key value of the newly added record.

I wrote the code that I expected to work and I always got back the same number for the primary key every time I ran the code; the value of the primary key value of the first record.But I wanted the primary key value of the last record, the record that I just created. So, I added .MoveLast to get the last record.

   Dim rs As Recordset2
   Dim recordId As Integer
   Set rs = Application.CurrentDb.OpenRecordset("Table_1")
   With rs
       .AddNew
       !field_1 = "Field_1"
       !field_2 = "Field_2"
       ' I expected the the primary key value to be loaded here:
       .Update
       ' When you open a recordset, there is an implied "MoveFirst" call
       ' For whatever reason, Access doesn't refresh values after writing
       ' the record:
       .MoveLast
       ' Without the MoveLast, you get the record_id of the first record:
       recordId = !record_id
       .Close
   End With
   Set rs = Nothing

I guess the thing that screwed me up is that I expected all of the fields in the current record of a RecordSet2 point to the same record. In my mind, when I call Update, the value of the primary key should be retrieved and ready for me to reference.

In ADO.NET, the DataSet has the AcceptChanges() method. This is logical to me because a DataSet is disconnected. I guess a Recordset2 is "loosly" connected.

Access continues to weird me out.

Friday, May 22, 2009

Stackoverflow Flair without the image

Scott Hanselman tweeted about how cool it would be to have a Stackoverflow flair without a tje gravatar. This is my solution using CSS

<html>
<head>
    <title>Stack Overflow Flair Demo</title>
    <style type="text/css">
.valuable-flair
{
    background-color: #ffffff;
    font-family: Arial, Helvetica, sans-serif;
    font-size: 12px;
    height: 50px;
    padding: 3px;
    width: 50px;
}
.gravatar
{
 display: none;
}

.valuable-flair .badge1
{
    color: #ffcc00;
}
.valuable-flair .badge2
{
    color: #c0c0c0;
}
.valuable-flair .badge3
{
    color: #CC9966;
}

</style>
</head>
<body>
<script src="http://stackoverflow.com/users/flair/3819.js?theme=none" type="text/javascript"></script>
</body>
</html>

Thursday, May 14, 2009

ASP.NET Cookieless sessions and JQuery AJAX

I was trying to get some jquery ajax calls to work after converting a site to cookie-less sessions (don't ask). I noticed the following code wouldn't work:

$.post("/bin/getsomedata.dll", {'id': id},
   function(data)
   {
       doSomething(data);
   }
);

I changed it to:

$.post("<%=Response.ApplyAppPathModifier("/bin/getsomedata.dll")%>", {'id': id},
   function(data)
   {
       doSomething(data);
   }
);

and all was groovy

I also noticed that when I turn off cookieless sessions, everything still works. It appears that Response.ApplyAppPathModifier() only alters the URL when I am in cookieless sessions

Thursday, May 07, 2009

Photoviewer

Today I needed to write a pop up form that would show any image without any extra IE (or Firefox, Chrome, Safari, etc.) toolbars, etc. To get a web form to display an arbitrary image, I have a simple page that takes the URL of the image in the query string. The web form takes that string and uses it to set ImageUrl of an asp.image control.

photoviewer.aspx:
<%@ Page Language="C#" EnableViewState="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">    private void Page_Load()
    {        string file = Request.QueryString["file"];
        if (file != null)
            myImage.ImageUrl = Server.UrlDecode(file);
    }
</script>
<html>
<head>
    <title>My Image Viewer</title>
</head><body>
    <form id="Form1" method="post" runat="server">
    <table style="border:0;">
        <tr>
            <td>
                <asp:Image runat="server" ID="myImage" EnableViewState="false" />
            </td>    
        </tr>
        <tr>
            <td>
                <input type="button" onclick="javascript: window.close();" 
                    value="close" />
            </td>
        </tr>
    </table>
    </form>
</body>
</html>

To get rid of extra browser features and to size the popup, I call window.open() I set the height and width to values that will ensure that I have enough room for the image (I can use to get the dimensions of an image and add some buffer around the image so the popup isn’t all picture). I suppress status, toolbar, menubar. Location and scrollbars by setting them all to “0”.

feature_win.js
// declared outside of the scope of the function so it will persist on the page:
var newWindow;
function featureWin(height, width, url)
{
    var lHeight = height;
    var lWidth = width;
    
    if (newWindow && !newWindow.closed) 
    {
      newWindow.close()
    }
    newWindow = window.open(url, null, 'height=' + height +  
       ',width=' + width + ',status=0,toolbar=0,menubar=0,location=0,scrollbars=0');
}

Here we put it all together.

default.html
<html>
<head>
    <title>Test My Image Viewer</title>
    <script type="text/javascript" src="feature_win.js"></script>
</head>
<body>
<a href="javascript: featureWin(825, 1050, 'photoviewer.aspx?file=Garden.jpg');">
    Garden</a>
</body>
</html>

Sunday, April 26, 2009

URL Builder Functions

I am working on an internal web application that does some state management through the query string. That being the case, I have to add, remove and change paramters in the query string. Here are the functions that I use to edit the URL to change these varables

// Takes a URL with parameters and replaces the current value of a given parameter 
// with the new value provided
public static string replaceParameterInUrl(string theUrl, string param, string newValue)
{
    StringBuilder sb = new StringBuilder();
    string[] parts = theUrl.Split(new char[] { '?', '&' });
    sb.Append(parts[0]).Append("?");
    for (int i = 1; i < parts.Length; ++i)
    {
         string thisParam = parts[i];
         string[] paramParts = thisParam.Split(new char[] { '=' });
         if (paramParts[0] != param)
             sb.Append(thisParam).Append("&");
    }
    sb.Append(param).Append("=").Append(newValue);
    return sb.ToString();
}
/// Takes a URL with parameters and replaces the current value of a given parameter 
/// with the new value provided
public static string removeParameterFromUrl(string theUrl, string param)
{
    StringBuilder sb = new StringBuilder();
    bool isFirstItem = true;
    string[] parts = theUrl.Split(new char[] { '?', '&' });
    sb.Append(parts[0]).Append("?");
    for (int i = 1; i < parts.Length; ++i)
    {
        string thisParam = parts[i];
        string[] paramParts = thisParam.Split(new char[] { '=' });
        if (paramParts[0] != param)
        {
            if (!isFirstItem)
                sb.Append("&");
            sb.Append(thisParam);
            isFirstItem = false;
        }
   }
   return sb.ToString();
}

If I was going to use these functions in a public facing site,I'd probably sort the parameters alphabetically, so there would be less flux in the URLs that Google would see

Sunday, April 19, 2009

On Small, Low Margin Projects

Part 3: Framework and Starter Application

To get off to a quick start, I would imagine finding or building (or a combination of the two) an application framework before I start selling my services to the small business-person. Most small business applications need CRUD and List forms; user accounts and various levels of access; logging;; an about window; error and audit logging; etc.

The platform doesn’t really matter as long it is robust enough to solve the business problem. You need something that is robust enough to solve the current business problem and accept the changes that will take place (sooner: you misread a requirement, later: new work and more revenue). The toolset should support modern scalable designs; the software may be the seed of an enterprise system.

I know that this is like having a hammer and making everything into a nail. At this kind of margin, you can’t afford to handle any technology that the customer may want to use. If it isn’t a nail and can’t be made into a nail, have someone else do it; margins are too tight to take anything.

The first few projects will probably be losers as you work out the kinks in the framework and your process.

With a starting point, we can get our customer something to show them after the first sprint. We can show the customer something quickly and have something to talk about when we plan the second sprint. If we come back to them quickly with something to show, they will feel involved in the process.

Monday, April 13, 2009

On Small, Low Margin Projects

Part 2: Short Interactions and Feedback

In a previous post, I wrote about some of the issues I have experienced with small projects and suggested that Waterfall, Cave of Solitude solutions tend to blow up in your face.

If we come back to the customer every 2 to 4 weeks, we can both learn about the other side of the transaction:


  • I can teach the customer how the process works, what is possible, what is easy and isn’t going to happen. If you are going to buy custom software you need to learn the process. It is like buying a new building; you aren’t going to use the gold plated faucets in the penthouse when we are still pouring concrete (I will restrain myself from going on for hundreds of words of half baked analogies).

  • The customer can teach me more about his business, what he expected the software to do and I missed on the first time around. What is important? What is a nice to have? I may have the opportunity to see the processes that are too complex to explain.

  • Customers like to feel that they are part of the process. If you are going to spend a few grand on something, you want a sense of what is going on. Buying custom software is a big part of the company’s activities and the owner may want to boast about it on his blog on in the local watering hole.

If we started at ground zero and only used Scrum like sprints but no initial framework, the first couple of sprints would give the customer little sense of satisfaction.