Monday, November 25, 2013

Grouping with Linq

Linq offers pretty much the same aggregate functions that SQL does.  And like SQL, often times you want to group results together when aggregating.  Grouping is a little less intuitive with Linq especially when using VB to write your queries.  Here is an example:

Dim MostRecentByCategory = (
    From mt In MyTable
    Group mt By mt.CategoryId Into g = Group
    Select CategoryId, MostRecentDate = g.Max(Function(mt) mt.CreatedDate) )

In our example, we have a table called MyTable. Each record has a category specified by a CategoryId field. If you wanted the most recent date that a record was created in each category, this query should do the trick. Of course, this is not real practical. More than likely, you are going to want the whole record. In other words, you're going to want a result set that represents the most recent record for each category (not just the date). As far as I know, this cannot be accomplished in just one Linq query.  To accomplish this, I would just create a new linq query and join MyTable to the result set we just queried (on CreatedDate and CategoryId).

As far as I can tell, you can only group when a single table or result set exists in your query.  If you want to group across multiple tables, you'll need to join the tables in a result set and then group the single result set.

For example, let's say there is a table named Category and each record in that table has CategoryId and Description.  How can we group MyTable by CategoryId and display the description of each category?  First we need to join the tables in a result set like this:

Dim Records = ( _
    From a In MyTable
        Join b In Category
            On a.CategoryId Equals b.Category
    Select New With {.CategoryId = a.CategoryId, .CategoryDescription = b.Description})

Now, have a single result set with the field that we need (Description) in it.  Then group this result table like above:

Dim CountsByCategory = (
    From r In Records
    Group r By r.CategoryDescription Into g = Group
    Select CategoryDescription, NumberFound = g.Count() )

Shortcut to "Document is ready" code in jQuery

When you want to execute some jQuery you normally encapsulate the code inside one of these:
$(document).ready(function () {
    // Code that executes when document is ready.
});
However, when looking around at examples in the API documentation, you'll sometimes see this which apparently is equivalent:
$(function() {
    // Code that executes when document is ready.
});

Wednesday, November 13, 2013

ASP.NET View State

The "state" of a web page is the properties of the controls on the page.  When you do a post back, it is desirable to save this info if you are posting back to the same page.  For example, if you are just paging through a grid or something.  ASP just sticks the view state in a hidden input field named "__ViewState".

It is not stored in English though.  It is encoded using Base64.  However, since anyone can decode a Base64 string, the view state data is considered openly readable by anyone.  Plus, a malicious user could tamper with the view state to do something evil.  To deal with this, ASP will "hash" the view state and then store the result of the "hash" in the __ViewState field.  ASP runs the view state and the MAC (Machine Authentication Code) and runs them through a hashing algorithm to produce the hash value stored in the source.  Hashing the view state protects the view state from being tampered with.  However, the view state data can still be viewed even though it has been hashed.  Not sure how at the time of this writing, but apparently, it can be done.  Anyway, if there is something especially confidential in the view state you can encrypt it.

If you want to see what is in the __ViewState field, just run Fiddler and post a web page in a browser.  Look at the source and locate the __ViewState field.  Select the gobblygook, right click and sent it to the TextWizard.  Decode it from Base64 to see the data.  If it is still gobblygook, then it has been hashed or encrypted or both.  You'll need to turn off hashing and encrypting the view state.  You can do this in the web.config file by adding this inside the system.web node:
<pages viewStateEncryptionMode="Never" enableViewStateMac="false" ></pages>
Recently, I was told that some of our .net 2.0 applications were not encrypting the view state.  In fact, when I viewed it in Fiddler, it wasn't even hashed!  So I added this to the system.web node in the web.config file:
<pages viewStateEncryptionMode="Always" enableViewStateMac="true" ></pages>
Interestingly, I had to add this:
<machineKey validation="3DES" />
inside the system.web node as well.  I'm not sure why I had to do this on one site but not the other.  I the Machine Key section in IIS for the site was configured differently, but I'm not positive.  Just make sure the view state is actually being encrypted by using Fiddler.

It appears that the hashing and encryption of the view state is done by default in later versions of the .NET Framework.

Tuesday, November 12, 2013

HTTP, Fiddler, and Telnet

HTTP is the "language" that browsers (clients) use to communicate with web servers.  Browsers send "request" messages to the web server.  The web server sends back "response" messages to the browser.  Each message consists of:

  1. An initial line that summarizes the message.
  2. A "headers" section that contains helpful information about the message.
  3. The body of the message.

The intial line of a request contains the "verb".  HTTP consists of only a handful of verbs that tell the web server what kind of request they are making.  GET is the most popular request made by a browser.  The browser is requesting a particular resource (html, image, other file, etc.) which is specified in the initial line of the message by indicating its URL.

The intial line of a response contains a status code and a very short description.  For example, "HTTP/1.1 200 OK".  The body of a response contains the actual resource.  For example, it would contain the html if that is what was requested.

You can actually see these messages going back and forth with a little program called Fiddler.  Just download Fiddler, install it, and run it.  If you type in a URL in a browser, you will see the corresponding GET request message in Fiddler.  Click on the Inspectors tab to see the initial line and "headers".

If you want to see the response messages, you have to download an add on called Syntax Highlighting AddOns.  There should be a link below the box that displays the details of the request message.  Once you install this, add on, you can see the details of the response for each request.  Pretty cool.

Going a step further, you can make GET requests manually independent of a browser by using Telnet.  By default, in Windows 7, Telnet is not enabled.  You have to go into Control Panel and Add/Remove Windows Features.  Enable the Telnet Client.  Then, just open up a command prompt and type as an example:

Telnet localhost 3405

-Ctrl ]-

set localecho

-Enter-

-Enter again-

GET /test.html HTTP/1.1
Host: localhost

-Enter-

-Enter again-

Now you see the response message from the web server.

Pretty cool.

Here's a good link to some helpful (if a bit dated) info on HTTP:
http://www.jmarshall.com/easy/http/

Thursday, November 7, 2013

Be aware of binding peculiarities when posting a form more than once using MVC

Occasionally, you will find yourself in a situation where you might need to post more than once.  For example, when the form doesn't pass validation, the user is returned to the form, and must post again once they have made corrections.

You may want to change some fields on the page during this first post, so that when the user returns, he sees something different.  Or, you may want to set a hidden field to indicate something.  You cannot do this if the model field is bound to an element on the view.  It is important to understand that the model is bound to the element and only element.  If you are going to return to the view, you can't break this binding even if you set the field to something else in the action method.

If you absolutely need to do this, you can use JavaScript/jQuery connected to the submit button to set the field on the page.