ASP.NET MVC Scorecard Web Application - Part 3

In this entry I want to cover a helper I wrote and some other bits to simplify creating charts for the scorecard application.

One of the things I wanted to do was get rid of the excessive amount of code needed in the view to generate various charts.  Since at some point I wanted to be able to dynamically create charts based on user input, I figured what better time than now to start chiseling out a helper class for displaying the charts.

Take the pie chart I created in the last entry.  The code in the view looked like this.

using (Chart chartPie = new Chart())
{
    double[] yValues = (double[])ViewData["TopCountryCounts"];
    string[] xValues = (string[])ViewData["TopCountries"];
 
    Title t = new Title("Pie Chart Representation",
        Docking.Top,
        new System.Drawing.Font("Verdana, Helvetica, Sans-Serif", 14, System.Drawing.FontStyle.Bold),
        System.Drawing.Color.FromArgb(26, 59, 105));
    chartPie.Titles.Add(t);
    chartPie.ChartAreas.Add("Default");
 
    // create a couple of series
    chartPie.Series.Add("Default");
    chartPie.Series["Default"].Points.DataBindXY(xValues, yValues);
 
    // Set Doughnut chart type
    chartPie.Series["Default"].ChartType = SeriesChartType.Pie;
 
    // Set labels style
    chartPie.Series["Default"]["PieLabelStyle"] = "Inside";
    // Set Doughnut radius percentage
    chartPie.Series["Default"]["DoughnutRadius"] = "40";
    // Explode data point with label "USA"
    chartPie.Series["Default"].Points[3]["Exploded"] = "true";
 
    chartPie.Width = 400;
    chartPie.Height = 300;
    chartPie.Page = this;
    HtmlTextWriter writer = new HtmlTextWriter(Page.Response.Output);
    chartPie.RenderControl(writer);
}

At 31 lines of code, I was not really stoked about this.  A lot of this, such as creating the title, the chart area, and having a series was something that would be needed by most charts.  With that I went to work writing a set of tests to test the helper class.

public const string title = "Chart Title";
public double[] YValues = {3};
public string[] XValues = {"X Value"};
 
[TestMethod]
public void InstantiateChartHelper()
{
    ChartHelper chartHelper = new ChartHelper("title", YValues, XValues, SeriesChartType.Pie);
    Assert.IsNotNull(chartHelper);
}

This first test and default values, that I assumed I would use for the other tests, got me a nice skeleton class & constructor.  I used ReSharper to flesh it out a little and then went to writing the other tests.  Each contributing a bit more functionality to the overall class.  I have excluded the remaining tests from this blog entry, but they will be available when I provide the solution for download (that means keep reading and stay tuned).  The class however, that ended up with is below.

public class ChartHelper
{
    public ChartHelper(string chartTitle, IEnumerable<double> seriesValues, IEnumerable<string> seriesKeys, SeriesChartType chartType)
    {
        // Setup defaults.
        System.Drawing.Font font = new System.Drawing.Font("Verdana, Helvetica, Sans-Serif", 14, System.Drawing.FontStyle.Bold);
        System.Drawing.Color color = System.Drawing.Color.FromArgb(26, 59, 105);
 
        // Title
        Title title = new Title(chartTitle, Docking.Top, font, color);
       
        // Chart Area
        ChartArea chartArea = new ChartArea("DefaultChartArea");
        chartArea.Area3DStyle.Enable3D = true;
        
        // Series
        Series series = new Series("DefaultSeries");
        series.Points.DataBindXY(seriesKeys, seriesValues);
        series.ChartType = chartType;
 
        ResultingChart = new Chart();
        ResultingChart.Titles.Add(title);
        ResultingChart.ChartAreas.Add(chartArea);
        ResultingChart.Series.Add(series);
        
    }
 
    public Chart ResultingChart { get; set; }
}

As you can see, a nice simple class.  With this class I was then able to use to reduce my lines of code to 9 lines (including the multi-line instantiation, which I suppose could be one line, leaving me with 6).

Scorecard.Views.ChartHelper chartHelper = new Scorecard.Views.ChartHelper("Pie Chart Representation",
   (double[])ViewData["TopCountryCounts"],
   (string[])ViewData["TopCountries"],
   SeriesChartType.Pie);
Chart chartPieTwo = chartHelper.ResultingChart;
 
chartPieTwo.Page = this;
HtmlTextWriter writer1 = new HtmlTextWriter(Page.Response.Output);
chartPieTwo.RenderControl(writer1);

This now generates the following pie chart.

There are a few more defaults I want to set though, so I went ahead and added a logic section for pie charts as shown below, with the switch view to provide a bit of factory style magic.

ResultingChart = new Chart();
 
// Setup defaults.
System.Drawing.Font font = new System.Drawing.Font("Verdana, Helvetica, Sans-Serif", 14, System.Drawing.FontStyle.Bold);
System.Drawing.Color color = System.Drawing.Color.FromArgb(26, 59, 105);
 
// Title
Title title = new Title(chartTitle, Docking.Top, font, color);
ResultingChart.Titles.Add(title);
 
// Chart Area
ChartArea chartArea = new ChartArea("DefaultChartArea") {Area3DStyle = {Enable3D = true}};
ResultingChart.ChartAreas.Add(chartArea);
 
// Series
Series series = new Series("DefaultSeries");
series.Points.DataBindXY(seriesKeys, seriesValues);
series.ChartType = chartType;
ResultingChart.Series.Add(series);
 
// Legend
Legend legend = new Legend("DefaultLegend");
ResultingChart.Legends.Add(legend);
 
switch (chartType)
{
    case SeriesChartType.Bar:
        break;
    case SeriesChartType.Column:
        break;
    case SeriesChartType.Pie:
        series["PieLabelStyle"] = "Inside";
        ResultingChart.Legends[0].Docking = Docking.Bottom;
        ResultingChart.Legends[0].Enabled = true;
        break;
    case SeriesChartType.Funnel:
        break;
    case SeriesChartType.Line:
        break;
    default:
        throw new ArgumentOutOfRangeException("chartType");
}
 
ResultingChart.Width = 400;
ResultingChart.Height = 300;

Notice I also reorganized where some things where instantiated, such as the Chart Object, and organized the order according to each thing I needed to have for the chart.  Once I did this I ran and rendered the chart, which I was happy with for now.

At this point I went back in and added some more charts to my scorecard view.  While I did this I noticed one last thing I ought to refactor.

<table>
<tr>
<td>
    <%
        Scorecard.Views.ChartHelper chartHelper = new Scorecard.Views.ChartHelper("Top Countries",
           (double[])ViewData["TopCountryCounts"],
           (string[])ViewData["TopCountries"],
           SeriesChartType.Pie);
        Chart chartPieTwo = chartHelper.ResultingChart;
 
        // Explode data point with label "USA"
        chartPieTwo.Series["DefaultSeries"].Points[3]["Exploded"] = "true";
 
        chartPieTwo.Page = this;
        HtmlTextWriter writer = new HtmlTextWriter(Page.Response.Output);
        chartPieTwo.RenderControl(writer);
    %>
</td>
<td>
    <%
        chartHelper = new Scorecard.Views.ChartHelper("View Cart Trend",
           (double[])ViewData["LineValues"],
           (string[])ViewData["TopEngines"],
           SeriesChartType.Line);
 
        Chart lineChart = chartHelper.ResultingChart;
 
        lineChart.Page = this;
        lineChart.RenderControl(writer);
    %>
</td>
</tr>
<tr>
<td>
    <%
        chartHelper = new Scorecard.Views.ChartHelper("Yesterday's Page Views",
         (double[])ViewData["ColumnStats"],
         (string[])ViewData["ColumnStatHeaders"],
         SeriesChartType.Column);
 
        Chart columnChart = chartHelper.ResultingChart;
 
        columnChart.Page = this;
        columnChart.RenderControl(writer);
    %>
</td>
<td>
    <%
        double[] theValues = (double[]) ViewData["ColumnStats"];
        double[] newValues = new double[]{0,0,0,0};
        int count = 0;
        foreach(double d in theValues)
        {
            newValues[count] += d*DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month) +
                                DateTime.Now.Month + DateTime.Now.Millisecond;
            
            count++;
        }
 
        chartHelper = new Scorecard.Views.ChartHelper("Current Month Page Views",
    newValues,
    (string[])ViewData["ColumnStatHeaders"],
    SeriesChartType.Bar);
 
        Chart barChart = chartHelper.ResultingChart;
 
        barChart.Page = this;
        barChart.RenderControl(writer);
    %>
</td>
</tr>
</table>

I was assigning the page and rendering the control at every single section within my table.  I didn't need to do that, so I went back and added a render method to the ChartHelper Class.

public void RenderChart(Page page)
{
    ResultingChart.Page = page;
    HtmlTextWriter writer = new HtmlTextWriter(page.Response.Output);
    ResultingChart.RenderControl(writer);
}

With a small change to the view I can now render each chart with one line of code.

chartHelper.RenderChart(this);

Now that puts everything in a better situation.  Until the next part.  Happy coding.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 1/6/2010 at 5:02 AM
Tags: , , , , ,
Categories: How-To, Samples, and Such
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (3) | Post RSSRSS comment feed

ASP.NET MVC Scorecard Web Application - Part 2

Alright, time to add some actual functionality to this thing.  First I want a report showing up on the scorecard page that has already been created.  I don't really care what it displays, just want to get it working and displaying.  I will get one report working and then pull up others and connect them with actual data from the Model.

First things first I grabbed the MS Charting controls, which you will need to follow along with this section of code.  I assume for the rest of this entry that the charting controls are installed.

First off I created some nice fake data in a DataTable.  The object I created is below.  This is located in the Models path for now.  Just to get this mocked up.

public class ReportSampleData
{
    public ReportSampleData()
    {
        SampleData = new DataTable("Adron's Sample Data");
 
        SampleData.Columns.Add(new DataColumn("Col1"));
        SampleData.Columns.Add(new DataColumn("Col2"));
        SampleData.Columns.Add(new DataColumn("Col3"));
        SampleData.Columns.Add(new DataColumn("Col4"));
 
        DataRow dr1 = SampleData.NewRow();
        dr1[0] = "Sample Set 1";
        dr1[1] = 14;
        dr1[2] = 13;
        dr1[3] = 10;
        DataRow dr2 = SampleData.NewRow();
        dr2[0] = "Sample Set 2";
        dr2[1] = 15;
        dr2[2] = 13;
        dr2[3] = 12;
        DataRow dr3 = SampleData.NewRow();
        dr3[0] = "Sample Set 2";
        dr3[1] = 17;
        dr3[2] = 11;
        dr3[3] = 9;
 
        SampleData.Rows.Add(dr1);
        SampleData.Rows.Add(dr2);
        SampleData.Rows.Add(dr3);
    }
 
    public DataTable SampleData { get; set; }
}

Once I created the fake data, I dropped in the chart control into the Display.aspx view under the Scorecard Directory of the views.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
 
<%@ Register Assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    Namespace="System.Web.UI.DataVisualization.Charting" TagPrefix="asp" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Scorecard
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <form id="form1" runat="server">
    <h2>
        Scorecard
    </h2>
    <%
        using (Chart chartColumns = new Chart())
        {
            chartColumns.Width = 412;
            chartColumns.Height = 296;
            chartColumns.RenderType = RenderType.ImageTag;
           
            chartColumns.Palette = ChartColorPalette.None;
            Title t = new Title("Column Bar Chart",
                Docking.Top,
                new System.Drawing.Font("Verdana, Helvetica, Sans-Serif", 14, System.Drawing.FontStyle.Bold),
                System.Drawing.Color.FromArgb(26, 59, 105));
            chartColumns.Titles.Add(t);
            chartColumns.ChartAreas.Add("Series 1");
 
            // create a couple of series  
            chartColumns.Series.Add("Series 1");
            chartColumns.Series.Add("Series 2");
 
            // add points to series 1  
            foreach (int value in (List<int>)ViewData["Chart"])
            {
                chartColumns.Series["Series 1"].Points.AddY(value + DateTime.Now.Second);
            }
 
            // add points to series 2  
            foreach (int value in (List<int>)ViewData["Chart"])
            {
                chartColumns.Series["Series 2"].Points.AddY(value + DateTime.Now.Minute);
            }
           
            chartColumns.Legends.Add("Legend1");
            chartColumns.BorderSkin.SkinStyle = BorderSkinStyle.None;
            
            // Render chart control  
            chartColumns.Page = this;
            HtmlTextWriter writer = new HtmlTextWriter(Page.Response.Output);
            chartColumns.RenderControl(writer);
        }
    %>
    </form>
</asp:Content>

Once that was finished the final step is to toss in the controller the view data.

public ActionResult Display()
{
    ViewData["Chart"] = new List<int>() {4, 6, 12, 3, 11};
    return View("Display");
}

Now run the app and check out the page.  You should see a chart like that shown below.  (Click for larger image)

That covers the second part of this series.  I will have another addition up soon, tying even more bits together.

Shout it kick it on DotNetKicks.com
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 12/31/2009 at 5:06 AM
Tags: , , , , ,
Categories: How-To, Samples, and Such
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (12) | Post RSSRSS comment feed

ASP.NET MVC Scorecard Web Application - Part 1

There have been a lot of requests for MVC based scorecards, so I am going to kick off a new series of wiring up an MVC scorecard site.  This first part will simply cover setting up the basic site and skeleton framework using the default ASP.NET MVC Project.

Start off by starting a new ASP.NET MVC Project.  Since I will be creating tests for this walk through, be sure to add a unit test project also.  I am just using the default MS-test libraries for now, but feel free to apply whatever test framework you would like.

To create additional views and controllers we'll add a unit test for a new controller.  I will name this new controller ScorecardController, so I have added a test file called ScorecardControllerTest.cs.  The first test is just the standard action for the appropriate method actions and returning the view, as follows.  I added a similar test for the Index method also.

[TestClass]
public class ScorecardControllerTest
{
    [TestMethod]
    public void Scorecard()
    {
        ScorecardController scorecardController = new ScorecardController();
        var result = scorecardController.Scorecard() as ViewResult;
        Assert.IsNotNull(result);
    }
 
    [TestMethod]
    public void Index()
    {
        ScorecardController scorecardController = new ScorecardController();
        var result = scorecardController.Index() as ViewResult;
        Assert.IsNotNull(result);
    }
}

Once the skeleton implementation is made to get green lights on these tests, a controller will be created with the following code.

public class ScorecardController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
 
    public ActionResult Scorecard()
    {
        return View();
    }
}

At this point I need to create some tests for what is expected in the view, but I will get to that once a bit more of the skeleton of the site is done.  As soon as I wrote these tests, based on where they are located in my folder structure I decided that I need to do a quick refactor of the name.  Having a Scorecard/Scorecard path just seemed stupid, so I renamed the Scorecard.aspx to Display.aspx and changed the method name appropriately.  If you are following along, the subsequent code will be using the renamed page/method, etc.

The next thing I wanted to do was to get the view coming up appropriately, so first things first, new tests.

[TestMethod]
public void ScorecardViewExists()
{
    ScorecardController scorecardController = new ScorecardController();
    var result = scorecardController.Display() as ViewResult;
    Assert.AreEqual("Display", result.ViewName);
}

First of course it fails, but with the appropriate change shown, all runs green again.

public ActionResult Display()
{
    return View("Display");
}

So after this I added the following tests, controller actions, and views.

[TestMethod]
public void Select()
{
    ScorecardController scorecardController = new ScorecardController();
    var result = scorecardController.Select() as ViewResult;
    Assert.IsNotNull(result);
}
 
[TestMethod]
public void SelectViewNamed()
{
    ScorecardController scorecardController = new ScorecardController();
    var result = scorecardController.Select() as ViewResult;
    Assert.AreEqual("Select", result.ViewName);
}
 
[TestMethod]
public void IndexViewNamed()
{
    ScorecardController scorecardController = new ScorecardController();
    var result = scorecardController.Index() as ViewResult;
    Assert.AreEqual("Index", result.ViewName);
}

After that I edited the CSS so I could get a better feel to the site relative to what I am working toward.  I will leave you to decide what you want to do with the CSS & such yourself.  One of these days I will be graphic artists worthy, for now I am just happy with a decent looking layout and reasonable colors. ;)

When I was done my Solution Explorer looked like this.

Last I added the following to the Site.Master page for appropriate linkages.  This spot is located in the menucontainer section of the page.

<div id="menucontainer">
    <ul id="menu">
        <li>
            <%= Html.ActionLink("Home", "Index", "Home")%></li>
        <li>
            <%= Html.ActionLink("About", "About", "Home")%></li>
        <li>
            <%= Html.ActionLink("Scorecard", "Display", "Scorecard") %></li>
    </ul>
</div>

When I run the app I now have a basic skeleton and the initial pages I am going to work with.  Next steps coming soon.

kick it on DotNetKicks.com Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 12/29/2009 at 5:05 AM
Tags: , , , , , ,
Categories: How-To, Samples, and Such | Unit Testing
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (6) | Post RSSRSS comment feed

Logging ADO.NET Data Services Research - Part 1

I started digging through ADO.NET Data Services for work related items and this is my research so far. So far setting up a ADO.NET Data Services Service (redundant?) is super easy. There are several "Getting Started with ADO.NET Data Services" write ups out there; "Introduction to ADO.NET Data Services", "ADO.NET Data Services with ASP.NET AJAX Support", and others. One that has given me gruff so far is "Using ADO.NET Data Services" in the MSDN Documentation. It appears that parts of the code are misplaced and commented, in addition it doesn't work. I've tried it on several boxes just as the tutorial states and it just doesn't provide the feed. The error generally seems to be,

Server Error in '/' Application.

The type 'CustomDataService.ContactsListing', provided as the Service attribute value in the ServiceHost directive could not be found.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The type 'CustomDataService.ContactsListing', provided as the Service attribute value in the ServiceHost directive could not be found.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.


Stack Trace:

    

[InvalidOperationException: The type 'CustomDataService.ContactsListing', provided as the Service attribute value in the ServiceHost directive could not be found.]

System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses) +4072062

System.ServiceModel.HostingManager.CreateService(String normalizedVirtualPath) +11656092

System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +42

System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +479

    

[ServiceActivationException: The service '/ContactsListing.svc' cannot be activated due to an exception during compilation. The exception message is: The type 'CustomDataService.ContactsListing', provided as the Service attribute value in the ServiceHost directive could not be found..]

System.ServiceModel.AsyncResult.End(IAsyncResult result) +11527290

System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +194

System.ServiceModel.Activation.HostedHttpRequestAsyncResult.ExecuteSynchronous(HttpApplication context, Boolean flowContext) +176

System.ServiceModel.Activation.HttpHandler.ProcessRequest(HttpContext context) +23

System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181

System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

    

Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053

The Astoria Team Blog article "ADO.NET Data Services Concepts", which is generally pretty good so take a read, also has a link to this MSDN and other information. They also have an entry on the upcoming "Astoria Offline" that is coming soon - this should be interesting.

A Tutorial on ADO.NET Data Access Services

Project FilesWithout a working test I went out on my own and did the following. First I created a Visual Studio Solution and added several project types to it;  An ASP.NET MVC Web Application & respective Unit Test Project, a Database Project, and finally a Silverlight 2 Project that I selected the ASP.NET MVC as the host for the Silverlight 2 Page.  Overall the solution looked something like the image to the left.  Click on the image to see a full size and for clarity.

Inside the ReporterMvc Project I created a new folder called Services.  This is the folder I'll actually place the ADO.NET Data Services in to keep the overall project orderly.

After I created the projects I setup the database for use.  I created the database previously so I already had a generation script.  So I went ahead and created the database via the Service Explorer Wizard in Visual Studio and then ran the script I have.  The script is listed separately on the code page.

Next I created an ADO.NET Entity Data Model & associated entity objects.  Create these objects inside the Models directory.  During the course of the wizard be sure to select all of the tables and views.

To update or add tables I just right click on the empty white space around the entities and select the "Update Model from Database..." option. Follow the instructions on the dialog that appears, it will be the same as the wizard shown above.  What I ended up with is as shown.

Next I added the ADO.NET Web Service to the project. With both of those added I now had the following in my project;  FeedCollector.edmx in the models directory and ReporterServices.svc in the Services directory.

I opened up the FeedCollector.edmx.cs file to verify that the class was actually named FeedCollectorEntities.  When you open up the designer code file it will look like the code listed below (I've just cut the first 41 lines of generated code.  I bolded the class name just for familiarity.  If ever in doubt about what type you'll pass in the data services, this is how one can easily find it.

   1:  //------------------------------------------------------------------------------
   2:  // <auto-generated>
   3:  //     This code was generated by a tool.
   4:  //     Runtime Version:2.0.50727.3053
   5:  //
   6:  //     Changes to this file may cause incorrect behavior and will be lost if
   7:  //     the code is regenerated.
   8:  // </auto-generated>
   9:  //------------------------------------------------------------------------------
  10:   
  11:  [assembly: global::System.Data.Objects.DataClasses.EdmSchemaAttribute()]
  12:  [assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("FeedCollectorModel", "FK_RssFeedEntries_RssFeeds", "RssFeeds", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(ReporterMvc.Models.RssFeeds), "RssFeedEntries", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(ReporterMvc.Models.RssFeedEntries))]
  13:  [assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("FeedCollectorModel", "FK_RssFeedEntryCategories_RssFeedEntries", "RssFeedEntries", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(ReporterMvc.Models.RssFeedEntries), "RssFeedEntryCategories", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(ReporterMvc.Models.RssFeedEntryCategories))]
  14:  [assembly: global::System.Data.Objects.DataClasses.EdmRelationshipAttribute("FeedCollectorModel", "FK_RssFeedEntryTags_RssFeedEntries", "RssFeedEntries", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(ReporterMvc.Models.RssFeedEntries), "RssFeedEntryTags", global::System.Data.Metadata.Edm.RelationshipMultiplicity.Many, typeof(ReporterMvc.Models.RssFeedEntryTags))]
  15:   
  16:  // Original file name:
  17:  // Generation date: 11/22/2008 11:27:18 AM
  18:  namespace ReporterMvc.Models
  19:  {
  20:      
  21:      /// <summary>
  22:      /// There are no comments for FeedCollectorEntities in the schema.
  23:      /// </summary>
  24:      public partial class FeedCollectorEntities : global::System.Data.Objects.ObjectContext
  25:      {
  26:          /// <summary>
  27:          /// Initializes a new FeedCollectorEntities object using the connection string found in the 'FeedCollectorEntities' section of the application configuration file.
  28:          /// </summary>
  29:          public FeedCollectorEntities() : 
  30:                  base("name=FeedCollectorEntities", "FeedCollectorEntities")
  31:          {
  32:              this.OnContextCreated();
  33:          }
  34:          /// <summary>
  35:          /// Initialize a new FeedCollectorEntities object.
  36:          /// </summary>
  37:          public FeedCollectorEntities(string connectionString) : 
  38:                  base(connectionString, "FeedCollectorEntities")
  39:          {
  40:              this.OnContextCreated();
  41:          }

After that I opened up the code behind and stuck in a few key elements of code.  This allows the service to be opened up to an requestor of the service.

   1:  using System.Data.Services;
   2:  using ReporterMvc.Models;
   3:   
   4:  namespace ReporterMvc.Services
   5:  {
   6:      public class ReporterServices : DataService<FeedCollectorEntities>
   7:      {
   8:          public static void InitializeService(IDataServiceConfiguration config)
   9:          {
  10:              config.SetEntitySetAccessRule("*", EntitySetRights.All);
  11:          }
  12:      }
  13:  }

The next thing I've tried is the ways to query via REST. I like the "Introduction to ADO.NET Data Services Part 2" entry that Greg Galipeau has written on his blog. For my test I went against some of my work related data. One of the things that bugs me though is the http://somedomain/stuff.svc/ being used for the REST address. I want it to just be http://somedomain/stuff/.

With just these simple actions I then checked the service to assure I was getting back accurate results.  I right clicked on the file and selected Browse.  The following were the results.

<service xml:base="http://localhost:50681/Services/ReporterServices.svc/">
<workspace>
<atom:title>Default</atom:title>
<collection href="RssFeedEntries">
<atom:title>RssFeedEntries</atom:title>
</collection>
<collection href="RssFeedEntryCategories">
<atom:title>RssFeedEntryCategories</atom:title>
</collection>
<collection href="RssFeedEntryTags">
<atom:title>RssFeedEntryTags</atom:title>
</collection>
<collection href="RssFeeds">
<atom:title>RssFeeds</atom:title>
</collection>
<collection href="RssEntriesCategoriesTags">
<atom:title>RssEntriesCategoriesTags</atom:title>
</collection>
<collection href="RssFeedsEntries">
<atom:title>RssFeedsEntries</atom:title>
</collection>
<collection href="RssFeedsEntriesTagsCategories">
<atom:title>RssFeedsEntriesTagsCategories</atom:title>
</collection>
</workspace>
</service>

This was perfect, exactly what I expected.  I did a few further tests.  The URI that I started with was http://localhost:6your6port6here/ResporterServices.svc/ which is what gave me the results above.  If you take any of the <atom:title/> attributes and pass them into the URI you'll get the respective results.  For example I tested out the RssFeeds (http://localhost:6your6port6here/Services/ReporterServices.svc/RssFeeds/) and received the appropriate results.  When checking the results in IE make sure to turn off the feed options.  In Opera you get the straight feed, which is handy.

If you have to pick a browser to test this with, I prefer Opera.  The results are uber clean compared to the other browsers and you don't have to go clicking options or selecting to not feed the atom results.  An example of the results.

 

In part 2 I'll show how to wire up a Silverlight 2 Client to these data services.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList