I have a new set of videos on Pluralsight covering the Twitter Bootstrap framework.
Bootstrap is a sleek, intuitive, and powerful front-end framework for faster and easier web development. In this course we'll see how to use Bootstrap's CSS and JavaScript to turn plain HTML into navigational menus, picture carousels, split buttons, alerts, modal dialogs, and more.
If there is enough interest, I was thinking of a future set of videos showing how to use Bootstrap's LESS files with a server framework like ASP.NET MVC.
The SqlBulkCopy class is invaluable for moving large amounts of data into SQL Server from a .NET application. I've been working with the class recently and taking notes on a few quirks and features.
Like most other areas of the .NET framework, SqlBulkCopy provides await-able methods for C# 5. In fact, the number of awaits in a bulk copy operation is remarkable (3 awaits across 4 async calls):
public async Task Execute() { using(var sourceConnection = new SqlConnection(_sourceConnectionString)) using(var targetConnection = new SqlConnection(_targetConnectionString)) using(var sourceCommand = new SqlCommand(_selectQuery, sourceConnection)) using(var bulkCopy = new SqlBulkCopy(targetConnection)) { await Task.WhenAll(sourceConnection.OpenAsync(), targetConnection.OpenAsync()); var reader = await sourceCommand.ExecuteReaderAsync(); bulkCopy.DestinationTableName = _targetTable; await bulkCopy.WriteToServerAsync(reader); } }
An obvious statistic you'll want to know about is how many total records have moved into the target table. Unfortunately, SqlBulkCopy makes this difficult. Although the class does have a SqlRowsCopied event, the event doesn't fire at the end of execution, but only on every N number of records (where N is configurable). Thus, if N is set to 50,000, you'll know when you copy 50,0000 records and 100,000 records, but won't know if you copied 29,000 more records after the first 50,000.
bulkCopy.NotifyAfter = 50000; bulkCopy.SqlRowsCopied += (sender, args) => { Console.WriteLine(args.RowsCopied); };
There are several workarounds, as suggested in a StackOverflow post:
- Use reflection to dig out the value of _rowsCopied (a private field in a SqlBulkCopy object).
- Execute a SELECT COUNT on the target table after the bulk copy completes (possibly not accurate).
- Provide your own wrapper/adapter for IDataReader and count the number of MoveNext calls with your own code. This is slightly painful since you can't inherit from SqlDataReader (because of an internal constructor), and need to implement dozens of methods on IDataReader (just forwarding calls to the inner reader). It's scenarios like this where I wish C# had an easy way to delegate member invocations (like Groovy).
SqlBulkCopy is particular about matching columns in the source and destination, so chances are you won't be able to bulk copy without configuring a column mapping for the operation. SqlBulkCopy is also particular about data types, and here there is limited flexibility in code. For example, if you want to copy a NULL value into a textual destination column, you'd think it would this easy:
SELECT Column1, NULL as Column2, Column3 FROM Table
This gives a runtime error, however:
System.InvalidOperationException: The locale id '0' of the source column and the locale id '1033' of the destination column do not match.
The only way I found to avoid the error is to make sure the NULL value is a "textual" NULL value (where the CAST type doesn't have to exactly match the destination column type, i.e. for this example the destination could be nchar(10), but the query still works):
SELECT Column1, CAST(NULL as varchar(1)) as Column2, Column3 FROM Table
Numbers can also present some difficulties. If I want to copy a decimal(20,7) column to a decimal(20,7) column there is no problem, but if I want to aggregate a decimal(20,7) column and place the result into a decimal(20,7) column, there will be an exception. In other words, the following query:
SELECT Column1, SUM(aColumn) as Column2 ...
Will throw an InvalidOperationException (The given value of type SqlDecimal from the data source cannot be converted to type decimal of the specified target column.). I believe this is because SUM takes a decimal(20,7) and returns a decimal(38,7). Again, the only work around I found was an explicit convert in the query to keep the data types as decimal(20,7).
Hope that helps anyone working with SqlBulkCopy.
Recently I was asked to look at a "I click and the wrong thing happens" type error. I didn't know the codebase, and I wanted to start by seeing the JavaScript for the click event handler. In a project with thousands of lines of JavaScript this can be hard, but I found Visual Event 2 after a little searching and the tool took me right to the code.
Visual Event 2 is a bookmarklet, so the install is as simple as dragging a link into the bookmark area of a browser (though it took some hunting to find the link on the Visual Event 2 page - look under the section titled Make It Go).
Once I got to the page with a problem, I clicked the bookmark and the tool found all the events wired in the DOM.
All of the DOM elements with events attached become color coded, and I could hover over elements for details. In most cases, Visual Event could give me the exact line and file where the event handler lives.
Unlike the Event Listeners tab in Chrome developer tools, Visual Event understands jQuery events (even live events), as well as YUI, MooTools, Prototype, and more.
Great tool, and free!
I've put together this list of tricks in response to some recent questions. I hope you can find something new and useful.
In Razor you can create blocks of code nearly anywhere using @{ }. A block of code doesn't emit anything into the output, but you can use the block to manipulate a model, declare variables, and set local properties on a view. Be extremely careful about having too much code in a view, however, because it's not the best place for logic.
@{ var message = "Hello, World!"; } @message @for (var i = 0; i < 10; i++) { <div> @message </div> }
In the above code you can see the declaration for a string variable named message. We can use the message variable throughout the rest of the view.
If you are wondering why it is legal to use the message variable outside the block defined by { and } (which would be illegal in a .cs file), then you should know that a Razor code block doesn't define an actual C# statement block. You can see this if you look at the source code generated from the Razor template. An easy way to see the code is to intentionally add a compiler error in the view, run the app, then click the "Show Complete Compilation Source" link that appears in the resulting error page. Another approach, if you want to see the real source code, is to output or inspect the value of Assembly.GetExecutingAssembly().CodeBase. The result will be the temporary folder with all the generated code for the application.
For the last sample, the generated code looks something like this:
public class TheView : WebViewPage<dynamic> { public override void Execute() { var message = "Hello, World!"; Write(message); for (var i = 0; i < 10; i++) { WriteLiteral("<div>"); Write(message); WriteLiteral("</div>"); } } }
I simplified the code, but now it is easy to see the true scope of the message variable.
Razor makes it easy to transition between C# code and HTML, but there are a few edge cases. One edge case is when you need to have literal text in front of a code expression (which outputs a value). For example, adding a "PN" prefix using literal text in front an expression to output a part number.
PN@Model.PartNumber
In this case, Razor is a little too smart and thinks the code represents an email address, so what you'll see on the screen is PN@Model.PartNumber. To solve the problem we need to use an explicit code expression with parentheses around the code.
PN@(Model.PartNumber)
This will produce the desired output, like "PN10400".
Another edge case is transitioning from C# code into literal text. Razor does this seamlessly when the text is markup and starts with a <.
@foreach(var item in Model) { <div>@item</div> }
However, Razor won't make the transition if you want to output plain text.
@foreach(var item in Model) { Item: @item }
In this case, Razor thinks "Item:" is part of your C# code, so you'll have a compiler error. The easiest solution to this edge case is to use @: to switch from C# into text.
@foreach(var item in Model) { @:Item: @item }
Comments in Razor can start with @* and end with *@. Nothing inside a comment will execute or appear in the output, not even HTML markup.
@*
<span>You won't see any of this</span>
@foreach(var item in Model) {
@:Item: @item
}
*@
Not necessarily a Razor trick, but when using an HTML helper you'll often want to add additional attributes into an HTML element. Adding a class attribute for style or a data- attribute for scripting are quite popular. Fortunately, many HTML helpers allow you to pass along an anonymously typed object as an "htmlAttributes" parameter. The helpers will pick the properties out of the object, and add these properties as attributes in the HTML. This all sounds easy until you realize class is a reserved keyword in C# (so it causes problems if you try to use it as a property name), and the – character is illegal in a property name.
The following code then, has two syntax errors.
@Html.ActionLink("Help", "Help", null, htmlAttributes: new { class="special", data-ajax="true"})
You can fix one problem by using data_ajax instead of data-ajax, because the MVC runtime will turn underscores into dashes when it picks out the property names. The other problem you can fix with the @ sign, which in C# you can use to preface a reserved and the C# compiler will teat the word as a symbol. In other words, the following code ...
@Html.ActionLink("Help", "Help", null, htmlAttributes: new { @class="special", data_ajax="true"})
... will give you the output you desire ...
<a class="special" data-ajax="true" href="/Home/Help">Help</a>
If Razor is the only view engine you use in an ASP.NET MVC application, then it makes sense to remove the Web Forms view engine and save some cycles. Otherwise, the MVC runtime will go looking for .aspx and .ascx files when it tries to locate a view or template. A small savings, but just 2 lines of code required during application startup.
ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new RazorViewEngine());
A @helper in Razor ultimately defines a function you can invoke from anywhere inside the view. The function can output literal text and can contain code blocks and code expressions. Again I'll remind you that heavy amounts of code in a view can lead to grief, but the following example shows how you could use a helper to produce the text "You have 3 octopuses in your collection" (when Model.Count == 3).
You have @PluralPick(Model.Count, "octopus", "octopuses") in your collection. @helper PluralPick(int amount, string singular, string plural) { <span> @amount @(amount == 1 ? singular : plural) </span> }
If you want to use the PluralPick helper in more than one view, you can define the helper in a view living in the App_Code folder.
The App_Code folder is a magic folder in ASP.NET. The runtime will parse and compile views you place in this folder, but they won't be normal views derived from WebViewPage<T> that you can execute to produce HTML. Instead, views here derive from HelperPage and will expose any @helper functions defined inside as public, static members.
In other words, if I create an App_Code folder in an MVC project, and create a Helper.cshtml view inside, I can add the PluralPick helper to the new view. The runtime will use the view to create a class named Helper, so I can now use PluralPick from any view in the application like this:
You have @Helper.PluralPick(Model.Count, "outopus", "octopuses") in your collection.
Of course you can also build an HTML Helper extension method to make a helper globally available. The advantage to an extension method is that the method builds when you build the project, is easy to unit test, and is easy to package into a class library to share across multiple projects. The downside to an extension method is that extension methods have to work hard to create and manipulate HTML. Views in the App_Code folder, like any Razor view by default, will not compile until runtime, are not reachable from a unit test project, and can only be shared by copying the file to another project, but they do make it easy to intermingle HTML and C# code.
There is a way to avoid some of the App_Code downsides, however.
It is possible to build Razor views when building a project. Flipping on this switch will slow down a build, of course, but also will let you catch errors in Razor files before runtime. You might want to only build views during a Release mode build.
Just building the views doesn't package the view code into your assembly, however. For this, the Razor Generator project is available. The Razor Generator will force the Razor code generation to happen before compilation (similar to T4 templates), so you can include the generated code in your assembly.
For helpers, this means you can have helpers available for testing, or even create a shared library of helpers built from Razor views, and the helper views do not need to live in the App_Code folder.
The Razor Generator project page has all the details, but the current process looks like this:
- Install the Razor Generator extension (and restart VS).
- Set the Helper.cshtml file's "Custom Tool" property to RazorGenerator (and move the file out of App_Code).
- After saving, you should see Helper.generated.cs appear as a file behind Helper.cshtml.
Now the helper code is available at build time, and you could write tests for the trickier helpers.
var result = Helper.PluralPick(1, "octopus", "octopods"); var html = result.ToHtmlString(); Assert.True(html.Contains("octopus"));
Another approach to building helper type code is to take advantage of the fact that a chunk of Razor syntax will convert to a Func<T, HelperResult>. Instead of calling to a helper from Razor code, a templated delegate will let you do the inverse and pass Razor code to other methods. Since this post is getting rather long, I'm going to punt now and pass you along to Phil's post on the topic, which is excellent, like Phil himself.
The Bootstrap grid system makes page layout fast and easy.
If you just want to play with layouts using the Bootstrap grid system, try my Bootstrap layout sample. The sample will let you dynamically add and remove the Bootstrap style sheet and the Bootstrap responsive style sheet. The initial load will not have Bootstrap in place, so all the grid columns pile on top of each other.
Using the sample you can see how the Bootstrap grid and fluid grid behave inside and outside of the Bootstrap container. Try resizing the browser window or visit the page with a small device to see how the different layouts react with and without the responsive design style sheet. Fork the project and try your own HTML.
The term “page layout” makes me think about arranging content on a web page, but page layout has been around since humans started writing on papyrus, so “page layout” predates the web by several centuries. One popular approach to page layout in both print and the web has been the grid based layout.
Grids are popular for several reasons, but primarily grids are about providing structure. For web designers a grid defines the horizontal and vertical guidelines for arranging content and enforcing margins. Grids also provide an intuitive structure for viewers, because it is easy to follow a left to right (or a right to left) flow of content moving down a page. The grid itself is not a visible component, but only exists to provide order, alignment, and consistency. Usability thrives on consistency, which makes consistency a high priority, despite what Ralph Waldo says.
Web browsers and grids work together well. Every HTML element is a rectangle, and a grid can easily constrain and arrange rectangles. As the browser changes size, the grid can expand or contract, and also match the various display sizes of today’s devices.
In the late 1990s I (unknowingly) built pages with a grid based layout using <table> elements and arranging content into table cells. As CSS became more mature the web world started to avoid tables for layout, and eventually a number of CSS frameworks for grid based layout started to appear. These included Blueprint, 960.gs, YUI grids, and others. Bootstrap is one of the more recent CSS frameworks to include a grid system amongst its features.
By default, the Bootstrap grid consists of 12 columns and is 940 pixels wide. Create a row in the grid using the "row" class, and create columns inside using span1 through span12 classes. span1 is 1 unit wide, and span7 is 7 units wide. The goal is use a total of 12 units per "row" container.
For a visual example, consider the following HTML:
<div class="container"> <div class="row"> <div class="span3">3</div> <div class="span4">4</div> <div class="span5">5</div> </div> <div class="row"> <div class="span5">5</div> <div class="span7">7</div> </div> <div class="row"> <div class="span3">3</div> <div class="span7 offset2">7 offset 2</div> </div> <div class="row"> <div class="span12">12</div> </div> </div>
The HTML will give us the following layout (text-centering added by me):
As you can see, span12 will give you a single column layout, and using different combinations of spans and offsets can give you 2 column layouts, 3 column layouts, and layouts with offsets and white space.
With no other settings in place, the fixed grid in a container will always use 940 pixels of horizontal space. In a small browser window you'll see horizontal scroll bars. In a large browser window you'll see the container centered and white space on the left and right. If you don't like the content to appear inside a fixed 940 pixels you can go fluid, or go responsive (or both).
A fluid row (using class "row-fluid") will horizontally size a column using a percentage instead of a fixed pixel value. Using a percentage means a fluid row can expand to fill all available horizontal space when it is in a large container, and shrink columns to keep them from vertically stacking as the container shrinks. You can see the difference below in a zoomed out screen shot of a 1400 pixel wide browser window (fixed grid on top, fluid grid on bottom), or watch the results in the sample page for yourself.
Note that for the fluid row to work properly and be stretchy, you can't put it inside an element with the "container" style as in the previous sample. The container style will enforce the 940 pixel width. You can use fluid rows outside of container elements, or inside of elements with container-fluid, which doesn't constrain the width.
Adding in the Bootstrap responsive design style sheet will allow the grid to change appearance to match the screen size of a device. For phones, and devices with a horizontal resolution <= 767px, columns switch to being fluid and stack on top of each other vertically. This avoids horizontal scroll bars on small devices where it is easier to scroll vertically. As the resolution increases from 768 to 980, and from 980 to 1200, the Bootstrap styles will grant a greater column width and allow columns to float up beside each other. Fluid rows continue to match the size of a window by filling all available space, but responsive design steps in to stack the columns vertically on small devices. The easiest way to see the difference is to try the sample.
If you haven't used a CSS framework for a grid layout, you might want to try one and see how much time it saves in development. Keep in mind that grids aren’t the only approach to layout. Unique designs will turn to circular layouts, tilted grids, and nonconforming arrangements that have a touch of chaos. The best layout depends on the type of site you are trying to build, and the audience. Don’t forget the audience.
In "Capturing HTML 5 Video To An Image", Chris asked if we could upload a captured image to the server.
Yes we can!
We will use the same markup from the previous post, but make a simple change to the script. Instead of creating an image on the client, we'll send the image to the server by passing the dataURL generated from the canvas.
(function() { "use strict"; var video, $output; var scale = 1; var initialize = function() { $output = $("#output"); video = $("#video").get(0); $("#capture").click(captureImage); }; var captureImage = function() { var canvas = document.createElement("canvas"); canvas.width = video.videoWidth * scale; canvas.height = video.videoHeight * scale; canvas.getContext('2d') .drawImage(video, 0, 0, canvas.width, canvas.height); $.post("/image/upload", { dataUrl: canvas.toDataURL() }) .done(showImage); }; var showImage = function(url) { var img = document.createElement("img"); img.src = url; $output.prepend(img); }; $(initialize); }());
On the server we need to parse the incoming data URL. The data URL for an image will contain base 64 encoded bits, like the following:
data:image/png;base64,F12VBORw0KGgoAAAAN...==
The ImageDataUrl class will use a regex to pick apart the string and decode the bytes inside.
public class ImageDataUrl { public ImageDataUrl(string dataUrl) { var match = _regex.Match(dataUrl); MimeType = match.Groups["mimeType"].Value; Format = match.Groups["mimeSubType"].Value; Bytes = Convert.FromBase64String(match.Groups["data"].Value); } public byte[] Bytes { get; protected set; } public string MimeType { get; set; } public string Format { get; protected set; } public string SaveTo(string folder) { var fileName = Guid.NewGuid().ToString() + "." + Format; var fullPath = Path.Combine(folder, fileName); using(var file = File.OpenWrite(fullPath)) { file.Write(Bytes, 0, Bytes.Length); } return fileName; } private static readonly Regex _regex = new Regex( @"data:(?<mimeType>[\w]+)/(?<mimeSubType>[\w]+);\w+,(?<data>.*)", RegexOptions.Compiled ); }
The ImageDataUrl class can also save the decoded bytes to disk, so all we need to do inside of a controller action is use the class, and return a URL to the newly saved image.
[HttpPost] public string Upload(string dataUrl) { var image = new ImageDataUrl(dataUrl); var fileName = image.SaveTo(Server.MapPath("~/uploads")); var url = Url.Content("~/uploads/" + fileName); return url; }
That's one approach to uploading the image.
A quick example to showing how to capture a still image from a video.
Assume you have the following HTML setup:
<video id="video" controls="controls"> <source src=".mp4" /> </video> <button id="capture">Capture</button> <div id="output"></div>
Then when the user clicks the capture button, we'll write the current video contents into a canvas, and use the canvas to generate a data URL for an image to display.
(function() { "use strict"; var video, $output; var scale = 0.25; var initialize = function() { $output = $("#output"); video = $("#video").get(0); $("#capture").click(captureImage); }; var captureImage = function() { var canvas = document.createElement("canvas"); canvas.width = video.videoWidth * scale; canvas.height = video.videoHeight * scale; canvas.getContext('2d') .drawImage(video, 0, 0, canvas.width, canvas.height); var img = document.createElement("img"); img.src = canvas.toDataURL(); $output.prepend(img); }; $(initialize); }());