Website and UI

KnockoutJS and WebAPI tricks are for POCO, kids.

Below are notes – mostly for me – on trying to get a KnockoutJS/MVVM/EF6 going with an existing database. I’m not going to presume that what I attempted is impossible, but for now I’m stepping back from MVVM and going to MVC/EF6. Here’s why.

I’ll cut things short and give it to you straight. You’ll find most of the webAPI samples you see out there are code-first. I think there’s a reason for that. For MVC applications, maybe a straight up EF6 model, database-first, is the way to go – with Linq to SQL. There it is, for now.

Walkthrough

Here’s the general pattern I as going for: (Thanks Mike Wasson, you rock!)

 

In more detail – we’d like a wire format like the following. This works, just great, if you follow Mike’s article below explicitly, and use POCO code-first approach. It bogs down, as we’ll see, with db-first.

 

In review: Knockout.js is a Javascript library that makes it easy to bind HTML controls to data. Knockout.js uses the Model-View-ViewModel (MVVM) pattern.

  • The model is the server-side representation of the data in the business domain (in our case, products and orders).
  • The view is the presentation layer (HTML).
  • The view-model is a Javascript object that holds the model data. The view-model is a code abstraction of the UI. It has no knowledge of the HTML representation. Instead, it represents abstract features of the view, such as “a list of items”.

The view is data-bound to the view-model. Updates to the view-model are automatically reflected in the view. The view-model also gets events from the view, such as button clicks, and performs operations on the model, such as creating an order.

 

Our goals:

  1. Build a SPA and be able to log in with our SQL db
  2. Demonstrate ability to fire off a sproc to create a serial number
  3. Admin tools – Basic editable view of Processes and Steps.
  4. Display, entry and validation of a basic workflow on one process in buildHistory.

To do this I tried the following steps:

  1. Created a new ASP.NET website using the Single Page Application template.
  2. Changed the database connection to point to my SQL database. This has a set of tables we’ll need populated (AspNetUsers, Roles, etc.)
  3. Built and tried to log in – successful!
  4. Create a subfolder off Models called AutoGenerated and right click on it to add a new model to your existing db:
  5.  

You’ll see the following:

 

Go through ProductType.cs and copy and paste it to the main Models folder. Then go nuts on it. Add a reference to System.ComponentModel.DataAnnotations, and add some attributes. Make the ID fields so they don’t scaffold; add some Required attributes, etc.

 

There’s all kinds of cool things you could do above. Add CustomValidationAttributes, link to enums for dropdown lists, data type attributes, rangeattributes, regular expression and string length validators… the world is your oyster. Side note – I saw a ref to System.ComponentModel.DataAnnotations in the project, but couldn’t refer to it in the class. Turns out, when I chose the SPA template as my starting point, it was pointed to an older .NET framework version – .NET 4.5 versus .NET 4.5.1. Big difference!

Then go into App_Start and add events using Entity Framework for the Product class.

Build. You’ll need reflection to be up to date for the next step.

Now, right click on Controllers, and select Web API 2 Controller with actions, using Entity Framework.

In the next screen enter a good logical name for your Controller. Here I’m shortening the table to Product. Below I clicked on the new data context button – but don’t do this, just use the context you used with EntityFramework that’s already in your web.config.

Build it in your browser. Log in, and click on the API menu item. Look at the snazziness! Your new Product API class is available and – does it serve up data?

 

Punch in {yoursitename}/api/Product, and voila – hot steaming cup of JSON! (And, turns out, not so much – when I added new entities to the model, it returned EVERYTHING.)

Side Note

Trying to create a model initially didn’t show asynchronous methods available, which I favor. EntityFramework didn’t show in NuGet. However, running Install-Package EntityFramework in PackageManager Console did the trick. Now I see the following:

However, I’m still not getting reliable results. WebAPI, you’re out of time… for now. Sorry, would have been terrific if it was truly code-first.

In Summary

So, very frustrated. I think I’m trying to beat a square peg into a round hole. I’m getting [] JSON responses on my web services. Code that SHOULD work doesn’t; I honestly think WebAPI is meant for code-first/POCO approaches. There’s LOTS of examples, some very elaborate, of getting WebAPI to work – I’m thinking in particular this one and this one – without an existing db. But EF generated entities just aren’t working for us with a db-first approach. I’m running out of time; bagging it, and going with what I do know works – EF6, MVC generated controllers, so long MVVM/KnockoutJS. Simply put I don’t think we can guarantee delivery in the time the client demands at this point.

 

 

 

Helpful Links and References

 

 

 

Advertisements

The bloody arena – Elmah and custom error pages.

 

Let’s start with a great quote from TR Roosevelt – a man who knew the value of a little drama:

It is not the critic who counts; not the man who points out how the strong man stumbles, or where the doer of deeds could have done them better. The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood; who strives valiantly; who errs, who comes short again and again, because there is no effort without error and shortcoming; but who does actually strive to do the deeds; who knows great enthusiasms, the great devotions; who spends himself in a worthy cause; who at the best knows in the end the triumph of high achievement, and who at the worst, if he fails, at least fails while daring greatly, so that his place shall never be with those cold and timid souls who neither know victory nor defeat.

  • T.R. Roosevelt

Ties in well with Plato’s “Be kind, for everyone you meet is fighting a great battle”, no?

Elmah – the courageous “little” error logging handler that could

Kind of a jump but let’s skip from the bloody arena to the even bloodier arena of exception handling. Scott H has been very vocal in how unfair it is on the amount of attention ELMAH hasn’t gotten. And the excellent CodingHorror site (GOD bless you sirs!) notes the compelling arguments behind exception driven development – where teams use exception logs as a defacto to-do list, checking them almost hourly:

  • 5-10% of application code is devoted to error handling. That’s significant – it’s not so “little” in terms of impact – and by its nature often isn’t reliably tested. So, the golden rule is –when a problem occurs in your application, always check first that the error was handled appropriately. If it wasn’t, always fix the handling code first. Always fix error handling before fixing errors. It’s like the airline rule of putting an oxygen mask on yourself before putting one on your child.
  • Broad-based trend analysis of error reporting data shows that 80% of customer issues can be solved by fixing 20% of the top-reported bugs. Even addressing 1% of the top bugs would address 50% of the customer issues. The same analysis results are generally true on a company-by-company basis too.
  • If I fix a bug that no actual user will ever encounter, what have I actually fixed? While I love TDD, as a bug-fixing mechanism its too much like premature optimization… I’d rather fix bugs that are problems in practice rather than theory. (Hmmmmm.) Bug-driven development has the inherent shortcoming of being hard to test/reproduce and crisis-driven. Like the guy with the leaky roof – when its raining, you can’t fix it because its raining out, and when it isn’t raining, there’s no leak!
  • Exception logs are possibly the most powerful form of feedback your customers can give you. It’s feedback based on shipping software that you don’t have to ask or cajole users to give you. Nor do you have to interpret your users’ weird, semi-coherent ramblings about what the problems are. The actual problems, with stack traces and dumps, are collected for you, automatically and silently. Exception logs are the ultimate in customer feedback.

 

Note that Scott’s blog, normally oh-so-reliable, only shows part of the steps you’ll need to get Elmah up and running for your app. Microsoft (in a rare exception) actually has a good post on start-to-finish implementation of Elmah.

Basically we’ll be following these steps:

  1. Download ELMAH and add Elmah.dll to your web app.
  2. Register ELMAH’s HTTP Modules and Handler in web.config
  3. Specify config options
  4. Create error log source infrastructure

 

Let’s get started. Go into NuGet and select ELMAH:

 

 

Let’s check our Web.config. What changes do we see?

A new HTTP handler has been configured in your application for consulting the

error log and its feeds. It is reachable at elmah.axd under your application

root. If, for example, your application is deployed at http://www.example.com,

the URL for ELMAH would be http://www.example.com/elmah.axd. You can, of

course, change this path in your application’s configuration file.

 

If I was to look in packages.config I see the following two lines (and a new “Elmah” node under References):

<package
id=elmah
version=1.2.2
targetFramework=net45 />

<package
id=elmah.corelibrary
version=1.2.2
targetFramework=net45 />

 

So far so good. Let’s get this actually hooked up to our app. I pulled the latest source code from the code site for Google and opened up SqlServer.sql, and ran the footer of the script on my local database instance. This created one table and three sprocs – nice and neat:

  • Elmah_Error (table)
  • Elmah_GetErrorXml (sproc)
  • Elmah_GetErrorsXml (sproc)
  • Elmah_LogError (sproc)

 

Now I add the following to web.config:

 

<configuration>

<configSections>

<!– For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 –>

<section
name=entityFramework
type=System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
requirePermission=false />

 

 

<sectionGroup
name=elmah>

<section
name=security
requirePermission=false
type=Elmah.SecuritySectionHandler, Elmah/>

<section
name=errorLog
requirePermission=false
type=Elmah.ErrorLogSectionHandler, Elmah />

<section
name=errorMail
requirePermission=false
type=Elmah.ErrorMailSectionHandler, Elmah />

<section
name=errorFilter
requirePermission=false
type=Elmah.ErrorFilterSectionHandler, Elmah/>

</sectionGroup>

 

</configSections>

 

 

To the location path where I set up folder-level rolebased security, I added this node:

 

<!– AND lock down our exception logging page –>

<location
path=elmah.axd>

<system.web>

<authorization>

<allow
roles=Admin />

<deny
users=* />

</authorization>

</system.web>

</location>

 

 

 

… and right above system.web I added this node

 

<!– This must be on same level as <system.web> nod. NOTE – allowRemoteAccess means its visible remotely, a potential security risk

dev points to our database instance –>

<elmah>

<security
allowRemoteAccess=1 />

<errorLog
type=Elmah.SqlErrorLog, Elmah
connectionStringName=dev />

<errorMail
from=support.perceptive@microsoft.com


to=v-davhar@XXX.com


subject=Perceptive Site Runtime Error


async=true />

 

<!– to filter

<errorFilter>

<test>

<equal binding=”HttpStatusCode” value=”404″ type=”Int32″ />

</test>

</errorFilter> –>

 

</elmah>

 

<system.web>

 

Under <system.webserver> I added the following:

<system.webServer>

<validation
validateIntegratedModeConfiguration=false />

 

<modules>

<remove
name=FormsAuthenticationModule />

<add
name=Elmah.ErrorLog
type=Elmah.ErrorLogModule, Elmah
preCondition=managedHandler />

<add
name=Elmah.ErrorLog
type=Elmah.ErrorLogModule, Elmah
preCondition=managedHandler />

<add
name=Elmah.ErrorMail
type=Elmah.ErrorMailModule
preCondition=managedHandler />

</modules>

<handlers>

<remove
name=ExtensionlessUrlHandler-Integrated-4.0 />

<remove
name=OPTIONSVerbHandler />

<remove
name=TRACEVerbHandler />

<add
name=ExtensionlessUrlHandler-Integrated-4.0
path=*.
verb=*
type=System.Web.Handlers.TransferRequestHandler
preCondition=integratedMode,runtimeVersionv4.0 />

<!– DH added the following –>

<add
name=Elmah
path=elmah.axd
verb=POST,GET,HEAD
type=Elmah.ErrorLogPageFactory, Elmah
preCondition=integratedMode />

</handlers>

</system.webServer>

Above, if this was targeting an IIS6 webserver it would be under HttpHandlers and HttpModules.

I run the project and get a very … not too informative page. Let’s try to throw an error, shall we? Append a “/test” at the end of your elmah.axd call and then refresh – and you’ll see the following:

 

Clicking on the details gives us that treasured “yellow screen of death” that provides such awesome information in capturing and reproducing issues.

Let’s generate a few more just to be on the safe side. I add a few lines to my forms, one generating a DivideByZeroException within a try/catch block, the other straight up (where a naughty programmer forgot to wrap his logic in try/catch).

I get the above screen, the famed Yellow Screen of Death – and pointing the browser to elmah.axd gives me all the generated error messages. I can view them in the new ELMAH_Error table in SQL Server, and subscribe to it via a RSS feed. Very nifty!

Here’s the Catch logic I used to call the newer form of the elmah API:


catch(Exception ex)

{


//older API


//Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(new Elmah.Error(ex));


//newer API


//This applies ELMAH filtering rules to exception, is subscription based (i.e. multi logger enabled)

Elmah.ErrorSignal.FromCurrentContext().Raise(ex);

}

Adding a Custom Error Page

Note that all we’ve done is trap application exceptions in one handy location. So, how do we trap these so the user is presented with a better, more friendly experience when the unexpected occurs?

Scott Mitchell put it best – “Every web application should have a custom error page. It provides a more professional-looking alternative to the Runtime Error YSOD, it is easy to create, and configuring the application to use the custom error page takes only a few moments.” Fair enough, and I WHOLEHEARTEDLY agree. So, how to add this to my app?

As my five year old would say, “Easy-peasy!” Add a new page to your application called “ErrorForm” – and link to a master page so its nice and spiffy. The code couldn’t be simpler:

<asp:Content
ID=”Content1″
ContentPlaceHolderID=”MainContent”
runat=”server”>


<h2>Oops!!!</h2>


<br
/><br
/>


<p>Looks like we’re having problems now with the application. Our site admins have been alerted: please follow the link below to go back to Home.</p>


<ul>


<li>


<asp:HyperLink
runat=”server”
ID=”lnkHome”
NavigateUrl=”~/Default.aspx”>Return to the homepage</asp:HyperLink>


</li>

 


</ul>

</asp:Content>

 

And add the following to your web.config:

<!– Remoteonly should be our default setting for local debugging on dev, Off to show explicit error messages outside of elmah –>

<customErrors
mode=RemoteOnly
defaultRedirect=~/ErrorForm.aspx />

 

 

 

More information on error filtering – i.e. only throwing “top 20” errors like 404 etc – is found here: http://code.google.com/p/elmah/wiki/ErrorFiltering. There’s some great information on ELMAH here –

 

This doesn’t mean that TDD is a waste of time and test projects are a brake on development speed. In our project, we’re remarkably weak still in not having a test project – that’s basic, and I pity the fool that doesn’t have “time” to write unit tests! This will be addressed over the next two weeks – it’s like not taking the time to buckle a seat belt before getting in and driving. Regression errors are starting to drive us crazy, and TDD/BDD or some form of this is the standard answer. That being said – THANKS ELMAH for making my life that much easier and not having to write some custom library to capture and log errors. This kind of direct feedback from the user community is too valuable to let go to waste.

And, side note, I’m loving GIMP for image editing. Cheaper than Photoshop, and much more functional than Paint.NET or Picasa. Yay open source!!!

Messing around with ListViews

I do like this simple walkthrough here on ListViews. Note it’s much easier to scaffold this stuff without sprocs – MSFT seems to be (esp with innovations in EF, Code-First and POCO) moving away from old-school procedural logic in our business layer.http://msdn.microsoft.com/en-us/library/bb515102(v=vs.100).aspx (there’s an accompanying article showing inserts/updates).

Notice how easy VS makes it for us to scaffold out ListViews as we would a Controller/View in MVC using EF. Basically it’s a three step process:

  1. Drag on a ListView, and view it in Design Mode. click on the SmartTag on the right, and select Choose a data source. Fill in a SELECT statement.
  2. Select Advanced and generate Insert, Update, and Delete statements.
  3. Go back to Configure Listview in the smart tag and select the Enable Editing, Inserting, and Deleting checkboxes, and pagination if you swing that way.
  4. Treat yourself to a Banquet Beer. (added this last one)

VS adds in a TON of coding here without you having to lift a finger, or slave away over a hot stove writing sprocs. And, you can replace this down the road with sprocs if you so desire and use it as a template. Super groovy…

So, that’s good for generating plain vanilla listviews like the below. What if, shudder, you want to extend it a little?

I’m embarrassed to say, it took me a few hours yesterday to figure out which events I should hook into – and ListView has a TON of them – to update/save rows on my listview. I’m attaching the code below – suffice to say, the _DataBound, _ItemInserting and _ItemUpdating are your friends here. See the following code…. the main page is here.

More details – another halfway decent post: http://www.codedigest.com/Articles/ASPNET/105_EditUpdateDelete_and_Insert_in_ListView_Control.aspx

jQuery Explorations

According to this posting and this one, it’s faster to use a CDN than host it internally. (Redundancy, geolocation, more servers/bandwidth, etc). (love the snarky “So I assume you’re shipping a deprecated browser as well” comment). The redoubtable Scott H did a great writeup on having a backup for a CDN so you can fall back to local… should I find that necessary. However, for my purposes, it’s enough to note that using this:

<link
rel=”stylesheet”
href=”http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css”&gt;


<script
src=”http://code.jquery.com/jquery-1.9.1.js”></script>


<script
src=”http://code.jquery.com/ui/1.10.3/jquery-ui.js”></script>

instead of local sources (href=”~/Content/jquery-ui.css”) will not slow down my code execution and in fact offers significant caching advantages.

Anyway, the long story short is, this little nugget of code is all I needed – in the end – to use the jquery datepicker.

<link
rel=”stylesheet”
href=”http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css”&gt;


<script
src=”http://code.jquery.com/jquery-1.9.1.js”></script>


<script
src=”http://code.jquery.com/ui/1.10.3/jquery-ui.js”></script>


<script>

$(document).ready(function () {

$(function () {

$(“#<%= DateStartText.ClientID %>).datepicker();

$(“#<%= DateEndText.ClientID %>).datepicker();

});

});


</script>

 

I’m messing around with Accordions and tabbed panels now. From a design standpoint it couldn’t be easier to drag on these controls and limit what users see. From a UI perspective, it’s not great practice to stuff hundreds of fields and master/detail views on a form and show/reveal in tabs… There’s a reason why MVC encourages us to think in terms of very simple View logic (Edit/Index/List/Delete/Insert) instead of old-school VB6-type parent/child views. (Yes you CAN do this in MVC with little trouble, but IMHO it’s easier to create and especially scaffold your views in atomic pieces.)

Postings to look at in reference: http://weblogs.asp.net/stevewellens/archive/2010/09/04/goodbye-ajax-toolkit-hello-jquery-ui.aspx… and from jquery – http://jqueryui.com/datepicker/

jquery and bootstrap hassles…

 

 

Had an issue the other day where I was creating a new project (part of spring cleanup!) and adding in security like I wanted. Then this bad boy came around:


‘jquery’ is not a valid script name.  The name must end in ‘.js’.

Hmmm. What causes this?

 

Look at Global.asax – see the BundleConfig pointer?

 

So, this gives us our starting place. We need to make changes to BundleConfig.cs (under App_Start) and the Site.Master page.

 

So for example to add a “bootstrap” name we can point to in our site master, we use the following snippet:


ScriptManager.ScriptResourceMapping.AddDefinition(“bootstrap”, new
ScriptResourceDefinition

{

Path = “/scripts/bootstrap.min.js”,

DebugPath = “/scripts/bootstrap.js”,

LoadSuccessExpression = “bootstrap”

});

 

Now in Site.Master the following ScriptReferences should work with no errors: