4 stories
·
0 followers

WebAPI Tip #6: Is This Stuff Only Good For CRUD?

2 Shares

It doesn't take long to realize that the HTTP methods POST, GET, PUT, and DELETE can map directly to the database operations we call CRUD (create, read, update, and delete).

It also doesn't take much effort to find samples that demonstrate CRUD applications with the WebAPI. In fact, the built-in scaffolding can give you code where the only software between an incoming HTTP message and the database is the EntityFramework.

Is CRUD all the WebAPI is good for? That's a question I've heard asked a few times.

Stepping Back

I think one of the reasons we see CRUD with the WebAPI is because CRUD is simple. CRUD is the easiest approach to building a running application. CRUD is also the easiest approach to building a demo, and for explaining how a new technology works. CRUD isn't specific to the WebAPI, you can build CRUD applications on any framework that sits on the top or the outer layer of an application.

CRUD is Everywhere

All the above applications would have these characteristics:

- Minimal business logic

- Database structure mimicked in the output (on the screen, or in request and response messages).

There is nothing inherently wrong with CRUD, and for some applications it's all that is needed.

But Can It Do More?

Let's not talk about WebAPI as yet, let's  talk about these 2 WPF scenarios:

1) When the user clicks the Save button, take the information in the "New Customer" form, check for required fields, and save the data in the Customers table.

versus

2) When the user clicks the Save button, take the information from the "New Customer" form. Send the data to the Customer service for validation, identification, and eventual storage. If the first stage validation succeeds, send a message to the legacy Sales service  so it has the chance to build alerts based on the customer profile. Finally, send a message to the Tenant Provisioning service to start reserving hardware resources for the customer and retrieve a token for future progress checks on the provisioning of the service.

#1 is simple CRUD and relatively trivial to build with most frameworks. In fact, scaffolding and code generation might get you 90% of the way there.

#2 presents a few more challenges, but it's no more challenging with WPF than it would be with the WebAPI (in fact, I think it might be a bit simpler in a stateless environment like a web service). The framework presents no inherent obstacles to building a feature rich application in a complex domain.

Of course, you should think about the problem differently with the WebAPI (see How To GET A Cup Of Coffee, for example), but most of the hard work, as always, is building a domain and architecture with just the right amount of flexibility to solve the business problem for today and tomorrow. That's something no reusable framework gives you out of the box.

Read the whole story
Flytzen
4040 days ago
reply
Chinnor, UK
Share this story
Delete

ASP.NET WebAPI Tip #3: camelCasing JSON

1 Share

Let's say you have the following type definition in C#:

public class Thing
{
    public int Id { get; set; }
    public string FirstName { get; set; }    
    public string ISBN { get; set; }
    public DateTime ReleaseDate { get; set; }
}

The default JSON serialization of a thing will look like this:

{"Id":1,"FirstName":"Scott","ISBN":"123","ReleaseDate":"2013-03-24T16:26:33.7719981Z"}

It feels awkward to work with JavaScript objects where the first letter of a property name is a capital letter. But, it feels awkward to work with C# objects where the first letter of a property name is not capitalized.

Fortunately, the default serializer (Json.NET) will let you have the best of both worlds. All you need is a bit of configuration during application startup:

var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

The CamelCasePropertyNamesContractResolver will produce the following JSON instead:

{
  "id": 1,
  "firstName": "Scott",
  "isbn": "123",
  "releaseDate": "2013-03-24T16:39:28.4516517Z"
}

We also tweaked the formatting settings to make the JSON easier for humans to read.

Read the whole story
Flytzen
4047 days ago
reply
Chinnor, UK
Share this story
Delete

Hacking Up A Glimpse Plugin

1 Share

Glimpse is highly extensible. If there is something you want to know about on the server, it's relatively easy to write a plugin that will feed data to the Glimpse dashboard. There is some documentation in the Glimpse GitHub wiki on writing an extension. This post provides a slightly more complex example to show how a Glimpse dashboard tab can interact with data collectors using a message broker.

The Scenario

Let's say you are adding additional IDisplayMode objects into the global ASP.NET MVC DisplayModeProvider. These display modes will select device specific views (an iPhone view, a Kindle Fire view, etc). Now, you want to look in the Glimpse dashboard to easily see what providers are registered, the order of evaluation, and which of the providers the runtime selected for a particular request.

The Filter

There are various extension points in ASP.NET MVC that will let you tap into the processing pipeline. Quite a bit of the core Glimpse.Mvc3 package relies on proxy objects that wrap runtime components (like the view engines) and feed data to Glimpse when interesting things happen (how a view is selected, for example). Once you find a way to tap into the runtime, feeding data to Glimpse is the easy part.

One way to tap into the runtime is to use a global filter (perhaps not the best approach, but it is simple for this demonstration). Here is a result filter that will find the current display mode being used and send the mode to Glimpse as part of a message.

public class GlimpseDisplayModeDump : IResultFilter
{
    private readonly IMessageBroker _broker;

    public GlimpseDisplayModeDump(IMessageBroker broker)
    {
        _broker = broker;
    }

    public void OnResultExecuting(ResultExecutingContext filterContext)
    {

    }

    public void OnResultExecuted(ResultExecutedContext filterContext)
    {
        var mode = filterContext.DisplayMode;
        if (_broker != null)
        {
            _broker.Publish(new DisplayModeMessage(mode));
        }
    }
}

The key to the Glimpse <-> IResultFilter interaction is the Glimpse message broker. The message broker allows us to publish messages of any type, and an interested party can subscribe to these messages and aggregate or summarize information from the messages. When the filter executes, it will look at the display mode for the request (passed by MVC as part of the filter context), and pass the mode as part of a message via the message broker.

The Message

The message itself is a simple object that encapsulates the display mode and provides a simple property to retrieve the name (ModeId) of the display mode.

public class DisplayModeMessage
{
    public DisplayModeMessage(IDisplayMode mode)
    {
        Mode = mode;
    }

    public IDisplayMode Mode { get; set; }

    public string ModeId
    {
        get { return Mode.GetName(); }
    }
}

In the above code, GetName is an extension method to compute the name of a display mode. In MVC, the IDisplayMode interface doesn't provide a lot of information, so we'll check to see if the object is actually a DefaultDisplayMode object.

public static class DisplayModeExtensions
{
    public static string GetName(this IDisplayMode mode)
    {
        var asDefault = mode as DefaultDisplayMode;
        if (asDefault != null)
        {
            if (!String.IsNullOrEmpty(asDefault.DisplayModeId))
            {
                return asDefault.DisplayModeId;
            }
            return "Default DefaultDisplayMode";
        }
        if(mode != null)
        {
            return mode.GetType().Name;    
        }
        return "None";
    }
}

The Tab

An object implementing the Glimpse ITab interface has a 1:1 correlation with tabs that appear in the client-side dashboard. It is the job of the tab to provide a name that appears in the dashboard, and to provide data to display in the tab when Glimpse is ready. Here's a tab to show the display mode data.

public class DisplayModeTab : TabBase, ITabSetup
{
    public void Setup(ITabSetupContext context)
    {
        GlobalFilters.Filters.Add(new GlimpseDisplayModeDump(context.MessageBroker));
        context.PersistMessages<DisplayModeMessage>();
    }

    public override object GetData(ITabContext context)
    {
        var result = new List<object[]>();
        var message = context.GetMessages<DisplayModeMessage>().FirstOrDefault();
        var id = message != null ? message.ModeId : "<none>";

        result.Add(new object[] { "Key", "Value" });
        result.Add(new object[] { "Selected Display Mode", id });
        result.Add(new object[] { "All Display Modes",                                 
                          DisplayModeProvider.Instance
                                             .Modes
                                             .Select(mode => mode.GetName()).ToArray()
                                });
        return result;
    }

    public override string Name
    {
        get { return "DisplayMode"; }
    }
}

The GetData method is the key to producing data for a request. In this sample the code will find the DisplayModeMessage for the request, as well as look at all of the registered display modes, and produce a loose collection of what is essentially key/value pairs of data for display. 

The Result

All of the above code can go directly into your MVC project, or into a separate assembly with a reference to Glimpe.Core (the preferred approach). Once the assembly is in the web app's bin directory, Glimpse will pick it up and start interacting with the tab to show data in the browser dashboard. More advanced formatting is possible, too.

image

Read the whole story
Flytzen
4056 days ago
reply
Chinnor, UK
Share this story
Delete

Animating lists with CSS 3 transitions

1 Comment

Ever wanted to implement animated lists or grids, like in the following 12-second video?

This may look like a native iOS app, but this UI is all implemented with HTML, CSS, and JavaScript (see the previous post for details about my new iPhone app, Touralot, built with PhoneGap). So, how does all this slidey stuff work?

Using “transform” and “transition” in lists

The basic principles here are:

  • For animations to be smooth and hardware-accelerated, they have to be done with transform: translate3d
  • Even so, element positions should still be determined by the DOM structure (minimizing use of JavaScript)

So, consider some markup like the following:

<ul class="items"> <li>Monday</li> <li>Tuesday</li> <li>Wednesday</li> ... </ul>

The element positions are determined by the DOM structure, but not using translate3d. Now consider the following CSS rules:

.items { position: relative; } .items li { position: absolute; top: 0; left: 0; transition: all 0.2s ease-out; } .items li:nth-child(1) { transform: translate3d(0, 0%, 0); } .items li:nth-child(2) { transform: translate3d(0, 100%, 0); } .items li:nth-child(3) { transform: translate3d(0, 200%, 0); } ...

As you can see, the <li> elements will now be positioned absolutely against the parent <ul>, and we use translate3d to recover the usual vertical offset based on each element’s position in the DOM. What’s more, there’s a transition rule so that, whenever translate3d changes, the browser smoothly animates the element to its new position.

[Aside: For Webkit, you’d need prefixed rules as well (-webkit-transform and -webkit-transition). Current versions of IE and Firefox don’t require the prefixes.]

What’s the result? Well, now whenever you change the set of <li> elements inside the <ul>, all the other <li> elements will smoothly animate into their new positions, without you having to write any code to tell them to do so. This works wonderfully if you’re generating your DOM through any kind of templates/binding library such as with Knockout’s foreach binding, but also works nicely just with plain old DOM operations. Try this:

The add and remove functionality doesn’t have to tell the elements to animate. They just do that naturally. For example, the code for add is just:

$(".append").click(function () { $("<li>New item</li>").insertAfter($(".items").children()[2]); });

Browser quirks

Webkit (or at least Chrome) has annoying bug whereby it doesn’t account for in-flight CSS transitions when computing the scroll extents of a container. So you’ll need to do something like the following to force it to recompute the scroll container bounds at the end of the transition:

// Workaround for Webkit bug: force scroll height to be recomputed after the transition ends, not only when it starts $(".items").on("webkitTransitionEnd", function () { $(this).hide().offset(); $(this).show(); });

Also, since IE<10 doesn’t support transform or transition, you might also want to include some conditional CSS like the following to get basic non-animated behaviour on older browsers:

<!--[if lte IE 9]><style type="text/css"> /* Old IE doesn't support CSS transform or transitions */ .list-example .items li { position: relative; display: inline-block; } </style><![endif]-->

It works for grids, too

With this technique, there’s nothing special about one-dimensional vertical lists. It works exactly as well for two-dimensional grids, without any changes.

Well actually, this raises the question of where all those .items li:nth-child(x) rules are coming from. So far I assumed you were writing them by hand. But how many such rules should you write? Couldn’t we generate them programmatically? Why yes, of course. Try this utility function:

function createListStyles(rulePattern, rows, cols) { var rules = [], index = 0; for (var rowIndex = 0; rowIndex < rows; rowIndex++) { for (var colIndex = 0; colIndex < cols; colIndex++) { var x = (colIndex * 100) + "%", y = (rowIndex * 100) + "%", transforms = "{ -webkit-transform: translate3d(" + x + ", " + y + ", 0); transform: translate3d(" + x + ", " + y + ", 0); }"; rules.push(rulePattern.replace("{0}", ++index) + transforms); } } var headElem = document.getElementsByTagName("head")[0], styleElem = $("<style>").attr("type", "text/css").appendTo(headElem)[0]; if (styleElem.styleSheet) { styleElem.styleSheet.cssText = rules.join("\n"); } else { styleElem.textContent = rules.join("\n"); } }

You can specify a maximum number of elements to account for, and the number of columns desired in your grid (or pass 1 for a single-column vertical list). Of course, it would be nicer still if we could write just one rule that specified the translate3d values as a function of the element index, but I’m not aware of any way of doing that in CSS 3. Let me know if you can think of one!

Here’s the result, as a three-column grid:

Supporting arbitrary reorderings

The technique so far is great for animating all elements other than the one you’re inserting or reordering. But if you remove and insert an element in a new position, it will appear there instantly, without a transition, because it is a brand new element as far as the CSS transition logic is concerned.

So, how would it be possible to achieve something like the following, where the “reorder” button smoothly moves elements to new positions? Try it: click the random order button:

One possible technique is to override the translate3d values for each element with a snapshot of their current values, so that the elements retain their coordinates independently of their DOM order. Then, after mutating the DOM, remove your snapshot values, and then the CSS transition will kick in to move the element smoothly to its final location.

Here’s are a couple of handle jQuery utility functions:

(function () { var stylesToSnapshot = ["transform", "-webkit-transform"]; $.fn.snapshotStyles = function () { if (window.getComputedStyle) { $(this).each(function () { for (var i = 0; i < stylesToSnapshot.length; i++) this.style[stylesToSnapshot[i]] = getComputedStyle(this)[stylesToSnapshot[i]]; }); } return this; }; $.fn.releaseSnapshot = function () { $(this).each(function () { this.offsetHeight; // Force position to be recomputed before transition starts for (var i = 0; i < stylesToSnapshot.length; i++) this.style[stylesToSnapshot[i]] = ""; }); }; })();

Now you can achieve the random reordering thing as follows:

$(".reorder").click(function () { $(".items li") .snapshotStyles() .tsort({ order: "rand" }) .releaseSnapshot(); });

This works just the same with two-dimensional grids as with vertical lists.

For convenience, I used the tinysort library here (I only just learned about it this morning – it’s very neat), which can also sort the elements in a meaningful way, not only randomly. But it would work exactly the same if you write manual code to reorder the elements.

Supporting drag-and-drop reordering

Getting to this point may have seemed complicated, but it has some great benefits. Since the animation and positioning is controlled entirely by CSS, it composes beautifully with many other techniques for modifying the DOM. For example, if a drag-drop library shuffles the DOM elements, then they will now animate.

As an example, we can throw in jQuery UI’s sortable mechanism to enable drag-drop reordering. But let’s make it slick, and also animate the “dropping” phase of the operation, where the element you dragged moves from wherever you’re holding it into its final position.

Here’s how you can do that:

$("ul.items").sortable({ start: function (event, ui) { // Temporarily move the dragged item to the end of the list so that it doesn't offset the items // below it (jQuery UI adds a 'placeholder' element which creates the desired offset during dragging) $(ui.item).appendTo(this).addClass("dragging"); }, stop: function (event, ui) { // jQuery UI instantly moves the element to its final position, but we want it to transition there. // So, first convert the final top/left position into a translate3d style override var newTranslation = "translate3d(" + ui.position.left + "px, " + ui.position.top + "px, 0)"; $(ui.item).css("-webkit-transform", newTranslation) .css("transform", newTranslation); // ... then remove that override within a snapshot so that it transitions. $(ui.item).snapshotStyles().removeClass("dragging").releaseSnapshot(); } });

Here’s the result. Be sure to try this in a desktop browser, not a phone/tablet, because jQuery UI sortable doesn’t handle touch events by default. Also if you’re on IE, be sure to use IE10+ or you won’t see animations.

Weird flicker in Chrome? It only happens when the example is in this iframe. Try the “Edit in JSFiddle” link to see it without.

… and here’s a two-dimensional grid, with the same drag-drop code:

If you want better support for phones and tables, there are various ways of upgrading jQuery UI “sortable” to respond to touch events. Or write your own.


Read the whole story
Flytzen
4057 days ago
reply
Cool
Chinnor, UK
Share this story
Delete