Archive for the ‘ Custom Applications ’ Category

HTML5/Javascript as Assembly Language

This is the continuation of this post on the future of Microsoft development.

Scott Hanselman had an interesting post about how HTML5 and Javascript are assembly language for the web.  I won’t repeat his post (you should read it yourself), but basically it’s Turing Complete so you can write any program in it, it will be runnable by any browser soon, and we don’t necessarily need to read it.  There are already options to program in higher-level languages and compile to Javascript.

Okay, so in my last post I commented on the whole Microsoft-HTML5-Silverlight debate.  Here’s my subversive idea:

We’re already seeing systems where the build target is variable.  For example, Microsoft’s recent release of Visual Studio Lightswitch can build your business apps for the desktop or the web.  And they’ve stated there’s no reason it couldn’t compile to HTML5.

Microsoft should implement the CLR in Javascript.  Let me repeat that.  Microsoft should implement the CLR in Javascript.  And the Silverlight framework.

Imagine if you had a choice of deployments!  If speed is an absolute necessity, run your application in the Silverlight plugin.  If portability is the desire, just reference a javascript file that implements the Silverlight framework.

Think about it:

  • XAML is much more productive than HTML.  C# is much more productive than Javascript.  You could use the right tools to build your site or app, and the right tools to deploy your site or app.
  • Universal Silverlight.  It would run on an iPad, or an Android phone, or any future device that implements HTML5. (Which will be all of them.)  No need to make deals with the other platforms.  Silverlight would be able to run anywhere.
  • No more need for the plugin.  Some corporate environments don’t allow it.  Some folks at home don’t want to install it.  But it wouldn’t be necessary anymore.
Microsoft has always focused on developers and made tools for professionals.  This would be an amazing way to make professional development possible in any environment.  Can it be done?  It would certainly be a task to reimplement the CLR.  But the Mono team has done it.  It’s not impossible.  And it would make a huge number of Microsoft .NET-based systems (even existing ones) instantly web-enabled and portable across all mobile devices.  Microsoft:  Go for it!  C# is for coding.  Javascript is for execution.  Shake the world up.
Advertisements

Generalized Properties in C#

We’re all familiar with properties in C#.  Objects can have properties, property values can be got and set, and you can run code when they are got or set.  Simple, powerful, used all the time.

But they have a weakness.  Unless you get into the messy business of reflection, the compiler has to know at compile-time how you’re going to use the properties.  What do I mean by that?  I mean that to use a property on an object, you need to have a reference to that object, you need to know the type of that object, and your code needs to know both the name and type of the property.  The compiler needs to be able to resolve the whole usage.

Okay, but what if you need to make decisions about how to get or set properties at run-time?  Imagine you have a component that needs to do work on properties from a lot of different sources.  Let’s say it only knows the type of the properties and knows it needs to set them, but shouldn’t know about the parent objects or the real name of the properties?

What do we need?  Generalized properties!

Okay, so let’s distill a property down to it’s most basic form.  It has a value.  You can get that value.  You can set that value.  For simplicity’s sake and for now, let’s say we don’t even need to know the type of the value.  We’d like it to be easily portable.  BAM, let’s make it an object:

/// <summary>
    /// A PropertyProxy is an object that behaves like a property.  It has a Value that you can get or set.
    /// It can be databound to, allowing databinding decisions to be made at run-time.
    /// </summary>
    public abstract class PropertyProxy
    {
        public object Value
        {
            get
            {
                return this.getValue();
            }
            set
            {
                this.setValue(value);
            }
        }

        protected abstract object getValue();
        protected abstract void setValue(object value);
    }

This is the abstract base class.  In actual usage, we’d subclass it and provide a specific implementation for getValue and setValue.  Now we can instantiate one of these and pass it around, and client code doesn’t need to know about what’s actually happening when you get or set the value.

Other advantages:

– Complex databinding decisions can be made at run-time.

– It can be used to protect our data objects from meddling.  They have control over how they are used.

– We can run arbitrary code in getValue and setValue.  They don’t actually HAVE TO hook up to the getters and setters of real C# properties.  Imagine hooking setValue up to an Undo/Redo system.

Next time I’ll talk about how the PropertyProxy can be extended, and the real reason why we built it.  Why would we need to generalize properties?  I’ll let you sit with that.

ASP.NET MVC: Maintaining URL Permanence with Legacy Routes

What makes a cool URI?
A cool URI is one which does not change.
What sorts of URI change?
URIs don’t change: people change them.

– Tim Berners-Lee, creator of the interwebs

While working on our current ASP.NET MVC 3 project, we came across a requirement to maintain a large directory of .htm files that were used as content generated by users of the website.  While blowing off the dust and looking inside of the files we realized that there we lots of URLs that are supposed to be active pages.  Some of these were locations of images that were moving, while others were old ASP pages that are still redirected and even still register is the top 10 of search results for their associated keywords.  Immediately one of our developer’s heads began pounding with the pain of regular expression string replacement.

But wait!  These are permanent URLs that still have active SEO functionality.  Our client needs these links to stay active and not 404 their way into irrelevance.  Plus, it would be a pain to either:

  1. Go through each HTM file and string replace as many combinations we can find, or
  2. Use string replace each and every time we try to load the file

Enter Routing made easy with ASP.NET MVC 3.

First, we had to make sure the linked images in these files still display images when loaded up in the browser.  Most are located at the address:

<img src="http://www.mydomain.com/images/feature/myimage.jpg" />

..or something similar.  However, with the new design these images no longer lived at this physical location.  Hmm . . . to the Routes!

routes.MapRoute(
                "FeatureImage",
                "images/feature/{filename}",
                new { controller = "Image", action = "Feature" }
            );

Okay, great you defined a route.  But how do you give an image as a “View”?  Well, thankfully in ASP.NET MVC there is a FilePathResult.

public ActionResult Feature(string filename)
        {
            return File("~/content/images/features/" + filename, "image/jpeg");
        }

public class ImageController : Controller
    {
        public ActionResult Feature(string filename)
        {
             return File("~/content/images/features/" + filename, "image/jpeg");
        }
    }

There is also the option to actually create a stream and return a FileStreamResult as well, but this lets us do the same without having to open/close a stream reader.

So now that we have the image URL out of the way, what about those legacy ASP/ASPX routes that will no longer be valid?  And how can we do it without losing SEO value that our client has built up over the years?  Hmm . . . to the Routes!

Imagine we have the legacy route “/feature/showFeature.asp?fid={id}”

routes.MapRoute(
                "LegacyRoute",
                "feature/showFeature.asp",
                new { controller = "Features", action = "BackwardsCompatibleDetail" }
            );

And so the legacy route is now generated and matched, but how to handle that query string parameter?  Well you can define those in the Routing, but they are passed on as Nullable parameter objects to your methods on your controllers.

public ViewResult BackwardsCompatibleDetail(int? fid)
        {
            return View("Detail", _repository.GetById(eid.GetValueOrDefault()));
        }

And there you go!  You’re legacy route is now generated in the new MVC route table!

So that’s great and all, but what I really want is for those URLs to no longer be generated and instead just issue 301 redirects to the new URL path for this resource.  Phil Haack (Best. Name. Ever.) comes to the rescue with his RouteMagic library, available I might add via NuGet.  His example:

var route = routes.MapRoute("new", "bar/{controller}/{id}/{action}");
routes.Redirect(r => r.MapRoute("old", "foo/{controller}/{action}/{id}"))
  .To(route);

And the best part is a lot of this Routing framework is extendible, so we can create our own handlers and such to do even more complex things with the Routing.  But out of the bag, there are plenty of options with dealing with your SEO URL permanence and making sure those continue to bring in the traffic you need.  Viva Routing + MVC!

Enabling MSChart ImageMap and AJAX functionality

    In a previous post I talked about utilizing MSChart in an SSRS report. In this post we will talk about how to use the image map capabilities of the MSChart control. You will need to create two identical charts, one set with a render type of imagemap, the other set to binarystreaming. The easiest way to do this without having duplicate code is to create a user control containing your chart.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="graph.ascx.cs" Inherits="graph" %>
<%@ Register Assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI.DataVisualization.Charting" TagPrefix="asp" %> 
<asp:chart id="mainChart" runat="server" height="296px" width="412px"
    imagetype="Png" palette="BrightPastel" backcolor="LightBlue" rendertype="BinaryStreaming"
    borderdashstyle="Solid" backgradientstyle="TopBottom" borderwidth="2" bordercolor="181, 64, 1">
    <titles>
        <asp:Title ShadowColor="32, 0, 0, 0" Font="Trebuchet MS, 14.25pt, style=Bold" ShadowOffset="3" Text="Binary Streaming" ForeColor="26, 59, 105"></asp:Title>
    </titles>
    <legends>
        <asp:Legend Enabled="True" IsTextAutoFit="True" Name="Default" BackColor="Transparent" Font="Trebuchet MS, 8.25pt, style=Bold" Alignment="Center" Docking="Bottom"></asp:Legend>
    </legends>
    <borderskin skinstyle="Emboss" />
    <series>
        <asp:Series XValueType="String" Name="Targets" ChartType="SplineArea" BorderColor="180, 26, 59, 105" Color="220, 0, 0, 0" YValueType="Double"/>
        <asp:Series XValueType="String" Name="Actuals" ChartType="SplineArea" BorderColor="180, 26, 59, 105" Color="127, 255, 255, 0" YValueType="Double"/>
        <asp:Series XValueType="String" Name="ActualPoints" ChartType="SplineArea" BorderColor="180, 200, 59, 105" Color="127, 65, 140, 240" YValueType="Double"/>
    </series>
    <chartareas>
        <asp:ChartArea Name="MainChartArea" BorderColor="64, 64, 64, 64" BorderDashStyle="Solid" BackSecondaryColor="White" BackColor="OldLace" ShadowColor="Transparent">
            <axisy linecolor="64, 64, 64, 64">
                <labelstyle font="Trebuchet MS, 8.25pt, style=Bold"/>
                <majorgrid linecolor="64, 64, 64, 64"/>
            </axisy>
            
            <axisx IsMarginVisible="False" linecolor="64, 64, 64, 64">
                <labelstyle font="Trebuchet MS, 8.25pt, style=Bold"/>
                <majorgrid linecolor="64, 64, 64, 64"/>
            </axisx>
        </asp:ChartArea>
    </chartareas>
</asp:chart>

In the code behind of your graph user control you will want to publicly expose the chart control.

 public System.Web.UI.DataVisualization.Charting.Chart MainChart
    {
        get
        {
            return mainChart;
        }
    }

The Page Load event should go about parsing the query string for any data needed to generate the chart itself.

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            int kpiID = 0;
            int organizationID = 0;
            int programID = 0;
            int fiscalYearID = 0;
            int height = 0;
            int width = 0;

            int.TryParse(Request.QueryString["kpiID"], out kpiID);
            int.TryParse(Request.QueryString["organizationID"], out organizationID);
            int.TryParse(Request.QueryString["programID"], out programID);
            int.TryParse(Request.QueryString["fiscalYearID"], out fiscalYearID);
            int.TryParse(Request.QueryString["height"], out height);
            int.TryParse(Request.QueryString["width"], out width);

            if (height == 0)
                height = 296;

            if (width == 0)
                width = 412;

            mainChart.Height = Unit.Pixel(height);
            mainChart.Width = Unit.Pixel(width);


            string kpiName = Request.QueryString["kpiName"];

            if (kpiID != 0)
                BuildGraph(kpiID, fiscalYearID, organizationID, programID, kpiName);
        }
    }

    The next step is to create two web pages: graph.aspx, and graphImageMap.aspx.  Each page will contain nothing but your newly created graph user control, however, their code behinds will differ slightly.

GraphImage.aspx content:

Page Content for graphImage.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="graphImage.aspx.cs" Inherits="graphImage" %>
<%@ Register src="ascx/graph.ascx" tagname="graph" tagprefix="uc1" %>
<uc1:graph ID="graph1" runat="server" />

Code Behind for graphImage.aspx:

public partial class graphImage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            graph1.MainChart.RenderType = System.Web.UI.DataVisualization.Charting.RenderType.BinaryStreaming;
        }
    }
}

GraphImageMap.aspx content:

Page Content for graphImageMap.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="graphImageMap.aspx.cs" Inherits="graphImageMap" %>
<%@ Register src="ascx/graph.ascx" tagname="graph" tagprefix="uc1" %>
<uc1:graph ID="graph1" runat="server" />

Code Behind for graphImageMap.aspx:

public partial class graphImageMap : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            graph1.MainChart.RenderType = System.Web.UI.DataVisualization.Charting.RenderType.ImageMap;
            graph1.MainChart.ImageLocation = "graphImage.aspx?" + Request.QueryString.ToString();
        }
    }
}

 

In the code behind of the graphImage web page, set the exposed chart control property of the graph user control to binary streaming. In the code behind of the graphImageMap web page, set the exposed chart control property of the graph user control to imagemap. Also, set the ImageLocation property to reference graphImage webpage and pass along the query string. This will ensure that the imagemap page is creating the exact same chart as the image page chart. To try out this new MS Chart functionality, we used JQUERY to setup a real world example. Let’s say you want to pop up an interactive chart when a user hovers over a link on a webpage.

<html>
<head>
 <script type="text/javascript" src="js/jquery-1.4.4.min.js"></script>
    <script type="text/javascript" src="js/jquery-ui-1.8.6.custom.min.js"></script>
    
     <script type="text/javascript">
         function ShowDialog(imgURL) {
             var uniqueTime = new Date().getTime();
             $("#graphImage").attr("src", imgURL + '&time=' + uniqueTime);
             $("#dialog").dialog("open");
         }
         // we will add our javascript code here
         $(document).ready(function() {
             $("#dialog").dialog({
                 autoOpen: false,
                 height: 350,
                 width: 440,
                 modal: false,
                 closeOnEscape: true,
                 show: 'fade',
                 hide: 'fade'
             });


         });

     function ShowDialog(imgURL) {
             $("#graphImage").attr("src", imgURL);
             $("#dialog").dialog("open");
         }
         // we will add our javascript code here
         $(document).ready(function() {

             $(".test").mouseenter(function() {
                 $.ajax({
                     url: "graphImageMap.aspx?kpiID=2004&fiscalYearID=5&organizationID=4&programID=219&kpiname=AmazingMetric",
                     cache: false,
                     async: false,
                     success: function(html) {
                         $("#dialogInner").replaceWith(html);
                     }
                 });
                 $("#dialog").dialog("open");
             });
     </script>  
</head>
<body>
    <a id='link' class="test">hello world</a>
        <div id="dialog" title="My Graph">
            <div id="dialogInner"></div>
        </div>
</body>
</html>

I hope you found this post helpful in creating an interactive MS Charting solution.  Now get coding!

Silverlight Pivot Viewer – Automatic Pivot Collection Generation via Customized Pauthor tool

    The Microsoft Silverlight Pivot Viewer is a new innovative way to look at a massive amount of data in a fast visually comparative way. PivotViewer utilizes Microsoft’s Deep Zoom technology which enables it to take advantage of high resolution imagery without taking a hit on performance.

    Lately, we have been utilizing PivotViewer for Business Intelligence applications. If you are using PivotViewer to simply navigate and categorize images, the images themselves aren’t very important. However, if you are intending to utilize PivotViewer for a BI application, you will want to communicate the business information visually, that is the point after all, isn’t it? There are several ways to generate PivotViewer collections. The pivot collection creator for excel (here) provides a fast, simple way to generate PivotViewer collections. The main drawback of the excel tool is that the images for each item must already exist, plus this is still a very manual process. This is where the Pauthor tool comes into play.

    The Pauthor tool is an open source command line tool for generating pivot collections from various formats, such as excel, csv, and cxml formats. Pauthor allows for the generation of pivot images from an html template, as well as the creation of new data sources and target sources that implement an OLE DB driver. We created a SQL Server datasource based on the OleDBCollectionSource.  This allowed us to use tables, or views, or even stored procedures to generate the pivot collection facet categories, items, and collection text.

public class SqlCollectionSource : OleDbCollectionSource
    {
        /// <summary>
        /// Creates a new Excel collection source and sets its <see cref="BasePath"/>.
        /// </summary>
        /// <param name="basePath">the path to the Excel file containing the collection's data</param>
        public SqlCollectionSource(String serverName, String dbName, String collectionTableName, String facetTableName, String itemTableName)
            : base(String.Format(ConnectionStringTemplate, serverName, dbName), ".")
        {
            m_serverName = serverName.ToLowerInvariant();
            m_dbName = dbName.ToLowerInvariant();
            m_collectionTableName = collectionTableName.ToLowerInvariant();
            m_facetTableName = facetTableName.ToLowerInvariant();
            m_itemTableName = itemTableName.ToLowerInvariant();
        }

        protected override void LoadHeaderData()
        {
            this.ConnectionString = String.Format(ConnectionStringTemplate, m_serverName, m_dbName);
            this.UpdateDataQueries();

            base.LoadHeaderData();
        }

        private void UpdateDataQueries()
        {
            //String connectionString = String.Format(ConnectionStringTemplate, this.BasePath);
            using (OleDbConnection connection = new OleDbConnection(this.ConnectionString))
            {
                connection.Open();
                DataTable schema = connection.GetOleDbSchemaTable(
                    OleDbSchemaGuid.Tables, new Object[] { null, null, null, "TABLE" });
                
                String firstTableName = null;
                foreach (DataRow row in schema.Rows)
                {
                    String table = row["Table_Name"].ToString();
                    String lowerTable = table.ToLowerInvariant();
                    if (lowerTable == m_collectionTableName)
                    {
                        this.CollectionDataQuery = String.Format(CommandTemplate, table);
                    }
                    if (lowerTable == m_facetTableName)
                    {
                        this.FacetCategoriesDataQuery = String.Format(SortedCommandTemplate, table);
                    }
                    if (lowerTable == m_itemTableName)
                    {
                        this.ItemsDataQuery = String.Format(SprocTemplate, table);
                    }
                    if (firstTableName == null) firstTableName = table;
                }

                schema = connection.GetOleDbSchemaTable(
                    OleDbSchemaGuid.Procedures, new Object[] { null, null, m_itemTableName, null });

                
                foreach (DataRow row in schema.Rows)
                {
                    String table = row["Procedure_Name"].ToString();
                    table = table.Remove(table.IndexOf(';'));
                    String lowerTable = table.ToLowerInvariant();
                    
                    if (lowerTable == m_itemTableName)
                    {
                        this.ItemsDataQuery = String.Format(SprocTemplate, table);
                    }
                
                }

                if (this.ItemsDataQuery == null)
                {
                    this.ItemsDataQuery = String.Format(CommandTemplate, firstTableName);
                }
            }
        }

        private const String ConnectionStringTemplate = "Provider=SQLNCLI10; Server={0};" +
            "Database={1}; Trusted_Connection=yes;";

        private const String CommandTemplate = "SELECT * FROM [{0}]";
        private const String SortedCommandTemplate = "SELECT * FROM [{0}] order by sort";
        private const String SprocTemplate = "exec [{0}]";
        private String m_serverName = string.Empty;
        private String m_dbName = string.Empty;
        private String m_collectionTableName = string.Empty;
        private String m_facetTableName = string.Empty;
        private string m_itemTableName = string.Empty;
    }

Customizing the HTML template functionality

    The base HTML template functionality allows you to specify an html file incorporating meta tags like {name} {href} and any other custom pivot facet categories your items use within the html itself. Pauthor then iterates through the collection item datasource and creates a new html file for each one by replacing all of these tags with the item data source values. A web browser control is then run within the code to load up the newly generated html file and save an image out to the file system. Deep zoom images are then created for the pivot collection based off of this saved custom image as well as the xml of the pivot collection itself. We also customized the html template functionality allowing for a template query string to be used.

Example: /html-url http://www.example.com/PivotCard?itemPrimaryKey={itemPrimaryKey}

    This immediately increases the flexibility of the images we create, as we can now generate any html we want using standard web technology based on the values we receive off of the query string as opposed to scattering meta tags in an html file. Managing a web page which generates these Pivot Images is much easier to maintain than trying to generate images manually using a graphics library. You can imagine the time involved in changing an image template, moving lines around, drawing text with wrapping capabilities, etc, each time your Pivot Card format changes.

Pivot Collection Generation

    Pivot collection generation is now a breeze! There are no longer any manual steps with having our data in a database and images automatically generated and saved on the web server which serves up the pivot collection.  Collection generation can now be kicked off with a nightly scheduled task or even more frequently if needed. We are currently working on creating a means of generating pivot cards on a one off basis so that the collection can be maintained in near real time without incurring the cost of generating the entire collection each time an item changes. Stay tuned!

ASP.NET MVC: Don’t Fear the ViewBag

As we continue to work on our ASP.NET MVC3 project, I’m continuing to be impressed with how quick and lean the development process has gone so far.  Already, our small team is swarming and are empowered with figuring out the problems that are common at the start of a project.  One of these was a UI requirement that turned out to be an eye-opening use of one of MVC3’s more divisive features:   ViewBag.

Why the divisiveness?  Because the ViewBag is a dynamically-typed object.  If you’re a Ruby, Python, or Javascript programmer, you know all about everything being a nail.  For C# programmers comforted by a strongly-typed language, this is the type of stuff that we lose sleep on.  Properties on a dynamic object are defined at run-time, so to add a new property you just use it!  In fact, one of the first uses of this that you come across in an MVC project is the following:

@{
	ViewBag.Title = "My Home Page";
}

What is “Title”?  It’s a property on the dynamic ViewBag that is defined as soon you get or set the property.  We had this in prior verisons of MVC as ViewData, but notice the difference.

ViewData["MyObj"] = myObj;
MyObject o = ViewData["Title"] as MyObject;

ViewBag.MyObj = myObj;
var o = ViewBag.MyObj;

The ViewData was object typed, so you had to always cast it when trying to get the value.  This usually lead to a mess if you abused the ViewData and ended up with casts all over the place.

Now, let me say that I feel that dynamic objects in a strongly-typed language should be treated as if they were loaded weapons:  know how to use it, use it only if necessary, and keep the safety on!  So it was the other day that we found a great use to fire our ViewBag!!

We had a UI requirement that depending on where the user was in the site, that the color of some elements would change.  This was purely view-related logic and had nothing to do with our underlying model or business logic.  We quickly brought up a few options:

  • Pass some string value via the Controller using view models
  • Pass some string value via the Controller using the ViewBag
  • Use JQuery to do some CSS toggling
  • Create an extension method when creating the object that would determine the right CSS string

None of these options “smelled” right.  I didn’t want a pure view-related item like a CSS class name in my Controller code, JQuery seemed silly, and an extension method would require compiling code if something changed.  Then, I had a quick glance at that ViewBag.Title code and it clicked!  At the top of each of our sub-layout pages, we add this line of code that specifies the CSS class to be use to customize the color of our element for all pages that derive from the sub-layout page.

@{
    ViewBag.NavStyle = "nav_color_blue";
}

Then in our partial view that renders the element:

<a class="nav_global @ViewBag.NavStyle" href="@Url.Action(" Index", "Home")">home</a>

In minutes, we had our solution for this purely view-only requirement and didn’t have to clutter up code in our Controller or add silly workarounds.  This fits!  And if for some reason a page does not define the NavStyle property, it just defaults to empty string and the default color in the first CSS class.

So I have found a great use for ViewBag that doesn’t make the strongly-typed hairs on my back to raise in horror.  And you know what?  It felt gooooooood!  Yes, I will continue to make sure this dynamic object is used only if absolutely needed, but in this case we embraced the “get ‘er done” attitude and completed this requirement quickly and in a way that makes sense.  I look forward to other creative ways we can use the dynamic property to solve view-related issues and requirements.

ASP.NET MVC3 And Other Microsoft Web Development Goodies

Last week, Microsoft unleashed a whole slew of new web development products for us to get to get excited about here at Affirma.  In fact, I think I’ll still Vishal Joshi’s sentiment of feeling like we are in a “Web Development Candy Store”!  The timing couldn’t have been more perfect as well, as we are just kicking up a new web development project that I have determined to use ASP.NET MVC3 along with some of these other new tools.  So I thought I’d take a moment to post some of my favorite bits that I have experienced so far.

Razor View Engine

Maybe it’s me, but when I was previously working on ASP.NET MVC projects, I always felt like I had some code-smell funk emanating from me when I’d look at those view pages filled with server code syntax that I’ve been seeing from WebForms and even ASP development.  MVC development is quick and lean to me and I always wanted a syntax that matched.  Enter Razor!

Old Way  Sad smile

<div class="contacts">
<% foreach (var c in contacts) { %>
<b><%= c.Name %></b> - (<%= c.PhoneNumber %>)<br>
<% } %>
</div>

New Way Smile

<div class="contacts">
@foreach (var c in contacts) {
<b>@c.Name</b> - (@c.PhoneNumber)<br>
}
</div>

And it has all the in-line, multi-line, nesting, and HTML helper support that I would expect.  Just keeps things clean and development fluid.

Razor Layouts/Sections

Like master pages, only better!  Okay, so that may be debatable, but being able to define the body or sections for widgets and other partials in a clean and simple manner just makes more sense to me.

@if (IsSectionDefined("widget"))
{
    <div class="widget">
    @RenderSection("widget")
    </div>
}

@section widget {
<h3>Featured Articles</h3>
@Html.Action("Featured", "Articles")
}

SQL Compact 4

Okay, so we probably aren’t going to be deploying any of our website projects using SQL CE 4.  However, being an environment we many of us are on the go and working from different locations, it servers as a nice, lightweight database that our developers can use to whip up some code and features without having to make sure there is a SQL Server box to connect and query against.  Also, I think there are some cool rapid prototyping opportunities here to help us engage prospective clients.
NuGet

Just started using this, but I’m already a fan.  What is NuGet?  Simply put, it’s a quick and easy to way to integrate all those tools and packages you use to develop right into Visual Studio.  Starting up my new MVC3 project, I knew I wanted NUnit, RhinoMocks, Fluent Route testing, as well as some other tools that I knew were scattered around on my hard drive but wasn’t sure if they were up to date.  No worries!  Just open up the console and type “Install-Package MvcContrib.Mvc3.TestHelper-ci” and boom!  My test project is almost set up!  I foresee a lot of value with this tool moving forward, so I’m looking forward into how it develops.

MvcScaffolding

Speaking of NuGet, this is probably the coolest library I’ve downloaded so far from NuGet.  It integrates right into the console and allows me to quickly code-gen, or “scaffold”, some of the basic MVC structures I’ll need for my project.  I created my business object, and then via one line I was able to generate an Entity Framework Code-First context, Repository, Controller, and all the views for CRUD operations.  Now, I didn’t need all the CRUD operations, but so what!  It’s easy to go in and delete or tweak what I didn’t need.  The tool is great for stubbing out the very basic bones of your project that you can then go in and build on top of.  Plus, it supports T4 templates so who knows what other cool scaffolds will be created by the open source community!

I’ll continue to post other nuggets of goodness I come across while working on this project, but for now there is definitely an abundance of web development candy for me to geek out over the next few weeks.  Just ask some of the folks around the office, I’ve been a jabbering fool on a sugar-high all week!

%d bloggers like this: