RIA Service in 5 minutes

 

Hi all,

 

I’ve previously blogged about how mind blowing WCF RIA Services are here

This week i found myself working with RIA Services again and this time I’ve got to show you just how easy it is (is case you didn’t take my advise and go look it up Punk

So, fire up VS2010 and create a new Silverlight Business Application

image

Two projects will be created for you, the Web project is where your DataAccess and Business logic lies, the other project is your Silverlight application.

Create an entity framework model ORM for your data (you know how to do this right?)

Next create a new Domain Service Class in the Web/Services folder

image

image

Compile.. that’s your server ready to serve up your data.

Now lets move into the Silverlight app, and add the following mark-up to your xaml

First add the domain datasource, set it to auto load and set the Query name to the name of the query that has been injected into your client app, (let intellisense help you; it will be in the Web.Services namespace context object.

        <domainControls:DomainDataSource x:Name="dataPads" LoadSize="20" AutoLoad="True" QueryName="GetPadocks">
            <domainControls:DomainDataSource.DomainContext>
                <data:FarmContext />
            </domainControls:DomainDataSource.DomainContext>
        </domainControls:DomainDataSource>

 

Add a datagrid use ElementBinding to the domainDataSource above (i’ve also put it in a telerik busyindicator to provide feedback that the data is loading)

<telerik:RadBusyIndicator IsBusy="{Binding ElementName=dataPads, Path=IsLoadingData}">
    <dataControls:DataGrid x:Name="padocksGrid" MinHeight="100"
         ItemsSource="{Binding ElementName=dataPads, Path=Data}"  />
</telerik:RadBusyIndicator>
 

 

Ok I’ve once again skimped on some of the detail but it’s a really nifty approach and i encourage you to give it a go.

(Also seeming your service is a DomainContext you can expose your data as OData a post for another day Secret telling smile )

ASP Glimpse Module

 

Now there’s a pretty sweet way of looking at what’s happening on your server, I’ve picked this tip up from watching SHanselmans MS Stack Of Love (recommended watch) @ MIX11 this year.

Here’s how, (pardon the screenshot file sizes as usual ..)

1) Create an application

image

2) Add a package

image

3) Search online for glimpse and install

image

4) Add at least one Trace to demo an additional Glimpse feature

image

5) Fire up your app and go to <appurl>/Glimpse/Config, and Turn Glimpse On

image

 

6) Click on the beady little eye on the bottom right corner of your webpage

image

7) Voilá

image

Cloud Computing (Azure) here I come

 

image

 

I’ve been playing (seriously playing) with Visual Studio LightSwitch for the last few weeks and I have to say it’s knocking my socks off, not since I programmed in MS Access (am I allowed to say that? Should I even admit where it all started for me back in 1995….), anyway,,, not since I programmed in MSAccess have I really seen a real a tool that really puts the R into RAD when it comes to small system data managment.

So now I want to publish my efforts as I’ve suckered a friend into some peer review, I could publish it to one of my webservers, manually set up a Sql Database etc (don’t have lightswitch deployment support on any of my servers just yet); but this Azure option was just too tempting.

image

 

Ok.. it didn’t take 15 minutes (more like 10) but I’ve now got access, hopefully I’ll do a follow up after I publish the final version of my app… stay tuned..

image

RESTful WCF Services

 

WCF not only provides SOAP, it’s also capable of providing RESTful services through use of the WebGet and WebInvoke attributes in the System.ServiceModel.Web assembly in conjunction with the webHttpBinding and webHttp behaviour. In fact, WebGet/WebInvoke are not really required required (however PUT is the default Http Verb and you won’t be able to specify what methods correspond to urls.

Here’s a sample;

[ServiceContract]
    public interface IPersonInfo
    {
        [OperationContract]
        [WebGet(UriTemplate = "/Details")]
        string Details();
 
        [OperationContract]
        [WebGet(UriTemplate = "/Person")]
        Person GetRandomPerson();
 
        [OperationContract]
        [WebGet(UriTemplate = "/Person?format=xml", ResponseFormat = WebMessageFormat.Xml)]
        Person GetRandomPersonXml();
 
        [OperationContract]
        [WebGet(UriTemplate = "/Person?format=json", ResponseFormat = WebMessageFormat.Json)]
        Person GetRandomPersonJson();
    }

 

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class PersonService : IPersonInfo
    {
        public string Details()
        {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
            return "Mon-Fri 9am to 5pm";
        }
 
        public Person GetRandomPerson()
        {
            return new Person { Address = "Limerick", Name = "Brian", Country = "Ireland" }; // not so random..
        }
 
        public Person GetRandomPersonXml()
        {
            return new Person { Address = "Limerick", Name = "Brian", Country = "Ireland" }; // not so random..
        }
 
        public Person GetRandomPersonJson()
        {
            return new Person { Address = "Limerick", Name = "Brian", Country = "Ireland" }; // not so random..
        }
    }

Host this service in IIS for example and you’ll be able to get the following results

image

 

As REST support only arrived in WCF 3.5 there is still a lack of support in certain areas, e.g. error handling, caching etc; what I’ve seen done in practise is people continue to use the REST Starter kit from codeplex.

ASP MVC Controller Exception handlers

 

When you crate a new MVC project a view called Error.aspx is created for you in the Views/Shared folder.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<System.Web.Mvc.HandleErrorInfo>" %>

 
<asp:Content ID="errorTitle" ContentPlaceHolderID="TitleContent" runat="server">
    Error
</asp:Content>
 
<asp:Content ID="errorContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2>
        Sorry, an error occurred while processing your request.
    </h2>
</asp:Content>

To instruct controller actions to use this Error handler you need to use the HandlErrorAttribute action filter, this is the default exception handler present in MVC.
HandleError is used to specify an exception type to handle and a View (and Master View if necessary) to display if an action method throws an unhandled exception that matches or is derived from the specified exception type.

Some points to note:

  • If no exception type is specified, then the filter handles all exception.
  • If no view is specified then the default Error view is used.
  • As mentioned earlier, exceptions are caught by base types, so it’s important to specify an order catching the most specific exception types first (much like a standard try catch code block.
  • The handler won’t get called in debug builds as it checks the HttpContext.IsCustomErrorEnabled (yellow screen of death is preferred)
  • e.g.
// Dont do this
[HandleError(Order=1, ExceptionType=typeof(Exception)]
[HandleError(Order=2, ExceptionType=typeof(ArgumentNullException, View=ArgNull)]

 

You’ll need to reverse the order, because if you want the ArgumentNullException to be handled differently, the exception shouldn’t get swallowed by the typeof(Exception) handler.

Linq

 

This is just a quick sample to show you can use Linq in 2 different yet identical ways.

The task is to show the count of people that have the same ages in our sample input data

   1:  class Program
   2:      {
   3:          class Person
   4:          {
   5:              public string Name { get; set; }
   6:              public int Age { get; set; }
   7:          }
   8:          static void Main(string[] args)
   9:          {
  10:              // some test data
  11:              var info = new List<Person> {
  12:                  new Person { Name = "Brian", Age = 34 }, new Person { Name = "Dee", Age = 29 },                
  13:                  new Person { Name = "Bob", Age = 21 }, new Person { Name = "Dave", Age = 25 },
  14:                  new Person { Name = "Tim", Age = 33 }, new Person { Name = "Jacques", Age = 43 },
  15:                  new Person { Name = "Simon", Age = 33 }, new Person { Name = "Jame", Age = 34 },
  16:                  new Person { Name = "Jason", Age = 34 }, new Person { Name = "Niamh", Age = 34 }};
  17:              
  18:              var duplicates = from p in info
  19:                               group p by p.Age into g
  20:                               where g.Count() > 1
  21:                               select g;
  22:              Print(duplicates);            
  23:   
  24:              var dups = info.GroupBy(p => p.Age).Where(p => p.Count() > 1);
  25:              Print(duplicates);
  26:          }
  27:   
  28:          static void Print(IEnumerable<IGrouping<int, Person>> obj)
  29:          {
  30:              obj.ToList().ForEach(p => Console.WriteLine(p.Key + ":" + p.Count()));
  31:          }
  32:      }

 

image

Dynamically load html into a div using jQuery

 

Mucking about more and more with jQuery now that’s it’s pretty much become the industry standard, so I needed a little project to work on. I’ve previously created my online c.v. in a Silverlight4 app (must dig that out and add it to the site); this time I decided to stay clear of any server side tech. and do everything client side.

So I decided to use jQueryUI  http://jqueryui.com/ for a few UX components; first step was to create some tabs.

Creating tabs:

 

Now if you look at jQueryUI samples for tabs you’ll see something like this.

        <div id="tabs">
            <ul>
                <li><a href="#tabs-1">First</a></li>
                <li><a href="#tabs-2">Second</a></li>
                <li><a href="#tabs-3">Third</a></li>
            </ul>
            <div id="tabs-1">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et .</div>
            <div id="tabs-2">Phasellus mattis tincidunt nibh. Cras orci urna, blandit id, pretium vel, aliquet ornare, felis. .</div>
            <div id="tabs-3">Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget.</div>
        </div>

 

Now this is all well and good, but I’ve never been one for dumping a load of html/c#/javascript etc onto my page, maybe it’s my c++ beginnings etc that causes me to look for a structured solution, but whatever it is, I decided to put the content of each tab into a separate web page.

Here’s how:

  • Create your webpages

    image

 

  • Load your content into the tab divs (I’ve just done this after the DOM is loaded with jQuery, I may lazy load other pages…)
<script type="text/javascript">
    $(function(){                        
        // Init the tab control with jQuery 
        $('#tabs').tabs();
        // Load the first page
        $('#tabs-1').load('ResumeTabs/Personal.htm');                    
    });
</script>

image

image

 

That’s it, pretty impressive ey… (that or I’m just easily impressed)

Automatically Scaling Telerik Radial Guage

 

Took a little time out tonight from the web application I’m working on as I want to create a little dashboard prototype that has to be desktop based as a result of where it will be used.

I’ve got a server JBPM (Java business process management.. pretty similar to WF4)  component that is writing log files, these log files are divided into subdirectories for each JBPM workflow that gets executed.

image

The idea is to provide a quick view for the counts of server logs at a glance with a gauge, (i'll be putting this gauge into a template for use in a listbox, but as a first step I’ve just displayed the details of the files in the first workflow folder.

Here’s what it looks like

image

The text is bound to the directory name, the yellow/orange radial bar is the count of all the log files in all subdirectories, and the needle is the count of files in the EchoLoader directory.

 

Here’s the xaml

   1:  <Window x:Class="Datagenic__Monitor.MainWindow"
   2:                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:                  xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
   5:                  Title="MainWindow" Height="350" Width="525">
   6:      <Window.Background>
   7:          <ImageBrush ImageSource="/Datagenic-%20Monitor;component/Images/background.png" />
   8:      </Window.Background>
   9:      <Grid>
  10:          <telerik:RadialGauge>
  11:              <telerik:RadialScale x:Name="radialScale" Min="0" Max="{Binding Path=MaxScale}" MajorTicks="10"
  12:                              MiddleTicks="1" MinorTicks="3">
  13:   
  14:                  <telerik:RadialScale.MajorTick>
  15:                      <telerik:MajorTickProperties />
  16:                  </telerik:RadialScale.MajorTick>
  17:                  <telerik:RadialScale.MiddleTick>
  18:                      <telerik:MiddleTickProperties Length="0.07" />
  19:                  </telerik:RadialScale.MiddleTick>
  20:                  <telerik:RadialScale.MinorTick>
  21:                      <telerik:MinorTickProperties Length="0.05" />
  22:                  </telerik:RadialScale.MinorTick>
  23:   
  24:                  <telerik:RadialScale.Label>
  25:                      <telerik:LabelProperties FontSize="10" />
  26:                  </telerik:RadialScale.Label>
  27:   
  28:                  <telerik:IndicatorList>
  29:                      <telerik:RadialBar x:Name="gauge1_radialBar" IsAnimated="True"
Value="{Binding Path=TotalLogCount}" />
  30:   
  31:                      <telerik:Needle x:Name="gauge1_needle" IsAnimated="true"
Value="{Binding Path=WFExecutions[0].LogCount}" />
  32:                  </telerik:IndicatorList>
  33:              </telerik:RadialScale>
  34:          </telerik:RadialGauge>
  35:          <Grid>
  36:              <Grid.RowDefinitions>
  37:                  <RowDefinition Height="0.60*" />
  38:                  <RowDefinition Height="0.40*" />
  39:              </Grid.RowDefinitions>
  40:   
  41:              <TextBlock Grid.Row="1" VerticalAlignment="Top" HorizontalAlignment="Center"
  42:                              Foreground="GhostWhite" FontFamily="CourierNew"
Text="{Binding Path=WFExecutions[0].FolderName}" />
  43:          </Grid>
  44:   
  45:      </Grid>
  46:  </Window>

Here’s the code

 

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Windows;
   6:  using System.Windows.Controls;
   7:  using System.Windows.Data;
   8:  using System.Windows.Documents;
   9:  using System.Windows.Input;
  10:  using System.Windows.Media;
  11:  using System.Windows.Media.Imaging;
  12:  using System.Windows.Navigation;
  13:  using System.Windows.Shapes;
  14:  using System.Collections.ObjectModel;
  15:  using System.ComponentModel;
  16:  using System.IO;
  17:   
  18:  namespace Datagenic__Monitor
  19:  {
  20:      /// <summary>
  21:      /// Interaction logic for MainWindow.xaml
  22:      /// </summary>
  23:      public partial class MainWindow : Window
  24:      {
  25:          public MainWindow()
  26:          {
  27:              InitializeComponent();
  28:   
  29:              this.DataContext = _wfExecutions;
  30:          }
  31:   
  32:          private WorkflowsExecutions _wfExecutions = new WorkflowsExecutions();
  33:      }
  34:   
  35:   
  36:      class WorkflowsExecutions :NotifyPropertyChangedBase
  37:      {
  38:          public WorkflowsExecutions()
  39:          {
  40:              this.WFExecutions = new List<WorkflowExecutions>();
  41:   
  42:              // Get the individual folders that corresponds to the logs
  43:              var executionFolders = System.IO.Directory.EnumerateDirectories(_executionFolder);
  44:              if (executionFolders != null)
  45:                  executionFolders.ToList().ForEach(f =>
  46:                      {
  47:                          var we = new WorkflowExecutions(f);                        
  48:                          we.PropertyChanged += ItemPropChanged;
  49:                          this.WFExecutions.Add(we);
  50:                      });
  51:          }
  52:   
  53:          void ItemPropChanged(object sender, PropertyChangedEventArgs e)
  54:          {
  55:              if (e.PropertyName == "LogCount")
  56:              {
  57:                  FirePropertyChanged("TotalLogCount");
  58:                  if (TotalLogCount > MaxScale)
  59:                      FirePropertyChanged("MaxScale");
  60:              }
  61:          }
  62:   
  63:          public int TotalLogCount
  64:          {
  65:              get
  66:              {
  67:                  return this.WFExecutions.Sum(we => we.LogCount);
  68:              }
  69:              set { }
  70:          }
  71:   
  72:          public int MaxScale
  73:          {
  74:              get
  75:              {
  76:                  int max = (int)(this.TotalLogCount * 1.5);
  77:                  max = max + (10 - max % 10);
  78:                  return Math.Max(100, max);
  79:              }
  80:              set { }
  81:          }
  82:   
  83:          public List<WorkflowExecutions> WFExecutions { get; set; }
  84:          
  85:   
  86:          private string _executionFolder = Properties.Settings.Default.ExecutionLogFolder;
  87:   
  88:   
  89:   
  90:          //event PropertyChangedEventHandler PropertyChanged = (s, e) => { };
  91:      }
  92:   
  93:      class WorkflowExecutions : NotifyPropertyChangedBase
  94:      {
  95:          public WorkflowExecutions(string folder)
  96:          {
  97:              this.FolderName = System.IO.Path.GetFileName(folder);
  98:              _watcher = new FileSystemWatcher(folder);
  99:              _watcher.Deleted += (s, e) => Update();
 100:              _watcher.Created += (s, e) => Update();
 101:              _watcher.EnableRaisingEvents = true;            
 102:              Update();
 103:          }
 104:          
 105:   
 106:          public string FolderName { get; set; }
 107:                    
 108:   
 109:          public int LogCount
 110:          {
 111:              get { return _logCount; }
 112:              set
 113:              {
 114:                  _logCount = value;
 115:                  base.FirePropertyChanged("LogCount");
 116:              }
 117:          }
 118:   
 119:          private void Update()
 120:          {
 121:              var files = System.IO.Directory.EnumerateFiles(_watcher.Path);
 122:              this.LogCount = files.Count();
 123:          }
 124:   
 125:          private int _logCount = 0;
 126:          private FileSystemWatcher _watcher;
 127:   
 128:      }
 129:  }

 

 

The interesting part is the auto scaling, if the TotalLogFile count passes the max scale level the view will get the property changed notification and update it bindings. (Note: I half expect telerik gauge to auto scale, if i spend a few minutes to figure out how… Shifty )

Asp MVC Entity Framework and Data annotations

 

image

 

When you create a MVC view for data entry it already has the scaffolding in place to handle client side validation (and server)
However you need to specify the data annotations you need.

You’ve two options.

1) Modify the T4 code generation templates

2) Use meta data classes (this post)

The generated EF classes are partial classes, this allows us to do the following

   1:  #region Feed
   2:   
   3:      [MetadataType(typeof(FeedMetadata))]
   4:      public partial class Feed
   5:      {
   6:      }
   7:   
   8:   
   9:      public class FeedMetadata
  10:      {
  11:          [Required(ErrorMessage="Please enter a valid name for this feed")]
  12:          public string Name { get; set; }
  13:      }
  14:   
  15:      #endregion Feeds

 

Note: while mvc3 supports these annotations they are limited to [range/required/stringlength/regularexpression]. If you wish to have a bigger offering consider the extensions offered.

Here’s how.

Go the NuGet Extension Manager (right click on references and select add Library Package Reference) and search for “DataAnnotationsExtensions.”  You should see the following two packages, choose the second (includes client side validation, first is server side only.)

Btw: If NuGet is alien to you, then don’t worry, it’s basically a packet manager to make your life a littler easier… a post for another day!