MSBuild Task Reference and Ajax Minification

image

I’m not one for dumping all scripts into a single folder and calling it a day.

The template project for ASP.NET MVC 3 does that unfortunately. So, after a bit of cleanup and adding a few more JavaScript libraries that I needed, I’m left with a reasonably organized folder structure.

I’ve added a folder for JavaScript files associated with Views, in this case, it’s located here: Scripts\Views\ViewName\…

I want to create minified versions of scripts, yet not minify scripts that have already been minified by other processes. The Microsoft Ajax Minifier (download here) includes a msbuild task, making the effort of creating minified scripts painless.

I followed these basic instructions for adding the build task:

http://www.asp.net/ajaxlibrary/AjaxMinQuickStart.ashx

I did not however, as I mentioned, want to compress all JavaScript files.

So, based on this documentation (MSBuild Items), I changed the basic Include settings to reflect my folder structure.

  <Import Project="$(MSBuildExtensionsPath)\Microsoft\MicrosoftAjax\ajaxmin.tasks" />
  <Target Name="AfterBuild">
    <ItemGroup>
      <JS Include="Scripts\Views\\**\*.js" Exclude="Scripts\Views\\**\*.min.js;" />
    </ItemGroup>
    <ItemGroup>
      <CSS Include="**\*.css" Exclude="**\*.min.css" />
    </ItemGroup>
    <AjaxMin JsSourceFiles="@(JS)" JsSourceExtensionPattern="\.js$" JsTargetExtension=".min.js" CssSourceFiles="@(CSS)" CssSourceExtensionPattern="\.css$" CssTargetExtension=".min.css" />
  </Target>

What I wanted specifically, is to only process JavaScript files found in the Scripts\Views subfolders. So, I changed the Include attribute to:

Scripts\Views\**\*.js

Roughly translated to English, the above:

  1. Recursively, find all JavaScript files under the folder Scripts\Views
  2. Skip anything that is already named *.min.js
  3. Minify.

Bad Error Handling by Visual Studio 2010

SNAGHTML40442868

Something bad happened. I’d like to tell you more about it, but only if you can remember to start Visual Studio with an additional command-line parameter, and then recreate the conditions that caused it.

Even a stack trace would have been more useful than the general “Oh, crud” dialog.

Or, just hit the OK button. Smile with tongue out

image

(I’ve noticed this error happening with some regularity now that I’ve been exploring ASP.NET MVC 3 with Razor syntax more. Have you seen this error?)

Translating Controller, Action, and Route Data to a JavaScript Object in ASP.NET MVC 3

To enable a more rich JavaScript/Ajax experience on a web page, I had need of more detailed information regarding the route that resulted in the current View being displayed. I checked around a few sites, and nothing popped out as obviously awesome.

As I was putting the JavaScript in the Layout/Master page, I had few direct assumptions about the location of the View/route that was currently being executed.

Here are the two options I created this evening.

Option one is admittedly more limited, but it serves to demonstrate the basic technique:

<script type="text/javascript">
        
    var _servedFromUrl = "@Url.RouteUrl(this.ViewContext.RouteData.Values)";
    @{ 
        string action = ViewContext.RouteData.Values["action"].ToString();
        string controller = ViewContext.RouteData.Values["controller"].ToString();
    }
    var action = "@action";
    var controller = "@controller";
    
</script>

Note that the code above is contained within a <script> block, as the final destination goal is to make these values available within JavaScript in the browser.

Above, there are actually 2 different options. The first option, results in a string that could look something like this:

/Discussions/Edit/5522

It could be useful to someone. However, it wasn’t useful to me. The next step was to discretely retrieve the action and controller. As you can see, these result in two JavaScript variables, aptly named, action and controller.

var action = "Edit";
var controller = "Discussions";

In this case though, I wanted access to all the values, in a more natural JavaScript format: A JavaScript Object with named (ad-hoc) properties.

<script type="text/javascript">        
    var route = {
        @{                 
            string comma = "";
            foreach (var name in ViewContext.RouteData.Values.Keys)
            { 
                string val = ViewContext.RouteData.Values[name].ToString();
                @: @comma'@name': '@val'
                comma = ",";
            }    
        }                   
        };
</script>

The code above loops through all of the RouteData Keys, and adds each and the corresponding value to a JavaScript object instance named route.

The results:

<script type="text/javascript">
    var route = {             'id': '5522'
                 , 'action': 'Edit'
                 , 'controller': 'Discussion'
    };

</script>

Simple, with discrete values.

WebMatrix and SQL Server Compact 4.0 Table Editing workaround

Occasionally, I encounter the following error when editing a  SQL Server Compact 4.0 database table within WebMatrix.

Alter table only allows columns to be added which can contain null values. The column cannot be added to the table because it does not allow null values.

image

The issue arises when adding a new column to an existing table, and specifying that the column should not allow Nulls (Allow Nulls = False).

The fix isn’t as obvious as I’d like, but it’s simple. In this case, the table does not have any data, which added further confusion. I understand that if I were to try to add a column to a table that had data, and the column was set to require a value, that it doesn’t make much sense (if the column is required, what value would be associated with the column for existing rows?).

However, the table is empty. There is a simple work around however.

  1. Set Allow Nulls to False.
  2. Put in a Default Value, appropriate for the Data Type specified.
  3. Save the table (CTRL+S)
  4. Remove the Default Value.
  5. Save the table (CTRL+S)

(I’m using WebMatrix until VS 2010 includes non-beta support for editing SQL Server Compact 4.0 databases)

Making Android development a little more like Microsoft development

All aboard the Android train!

By day, I mostly use Microsoft development tools, and have used them for YEARS. I’ve been experimenting with some Android development recently, and was annoyed by several missing handy tricks that Microsoft tools have done for years. So, I just coded one replacement.

Commonly, in Microsoft platforms, when you create a user interface element (from VB3 to WPF and Silverlight) and give it an ID/Name, that named element is readily available in code-behind, without any extra effort. Nice.

Android development, apparently, is lacking that feature. So, I created a simple pattern to make it convenient for me. Imagine the following UI element defined in an Android Layout:

<Button android:id="@+id/btnSend" android:layout_width="fill_parent"
     android:layout_alignParentBottom="true" 
    android:layout_height="wrap_content" android:text="@string/send_message" />

As you can see, the id of the Button is btnSend.

Normally, in the backing Java class if you wanted to access that UI element, you’d add code like this:

Button btn = (Button) findViewById(R.id.btnSend);

Simple, but annoying for commonly accessed UI elements (or Views).

I’m not the best Java coder by any means as I’ve not done it full time for more than 10 years and my knowledge of any recent Java innovations is zero. So, take this code with a pinch of skepticism.

private void autoWire() {
    Field[] privateFields = this.getClass().getDeclaredFields();
            
    for(Field f : privateFields){
        f.setAccessible(true);            
        ViewId viewId = f.getAnnotation(ViewId.class);
        if (viewId != null ){
            try {
                f.set(this, (Object)this.findViewById(viewId.Id()));
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

Now, in the onCreate method that is typical of an Android Activity, I call the method above, autoWire.

This Java code looks at the current class for declarations like this:

@ViewId(Id=R.id.btnSend)
private Button btnSend;

It’s just an annotation (ViewId), followed by the Id of the control.

The annotation definition is:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author WiredPrairie
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ViewId {
    int Id();
}

Using autoWire, btnSend is automatically set and ready to rock and roll.