As a continuation of my previous blog post, I created an OData QueryFeed workflow activity sample. The sample represents an end to end data movement application utilizing a number of technologies including
By providing feedback on this blog, or sending me an email, you can help define any part of the sample. My email address is derrickv@microsoft.com.
http://msftdbprodsamples.codeplex.com/releases/view/94486.
The sample addresses the following user story:
As a developer, I want to create an OData feed activity so that an IT Analyst can consume any AdventureWorks OData feed within a business workflow.
The OData QueryFeed sample activity shows how to create a workflow activity that consumes an OData resource, and renders entity properties in a Microsoft Excel 2010 worksheet or Microsoft Word 2010 document. Using the sample QueryFeed activity, you can consume any OData resource. The sample activity uses LINQ to project OData metadata into activity designer expression items. By setting activity expressions, a fully qualified OData query string is constructed consisting of Resource, Filter, OrderBy, and Select parameters. Executing the activity returns OData entity properties.
Query string part
/CompanySales
EntitySets LINQ for Resource Items
public IEnumerable<EntitySet> EntitySets { get { //Arrange: A url to a WCF 5.0 service is given as InArgument_Url XNamespace xmlns = "http://schemas.microsoft.com/ado/2008/09/edm"; //Act: A LINQ to XML query is constructed that projects EntitySet XML to an EntitySet class IEnumerable<EntitySet> entitySets = from x in metadata .Descendants(xmlns.GetName("EntitySet")) select new EntitySet { Name = x.Attributes("Name").Single().Value, Namespace = x.Attributes("EntityType").Single().Value.Split(new char[] { '.' })[0], EntityType = x.Attributes("EntityType").Single().Value.Split(new char[] { '.' })[1] }; //Return: return entitySets; } }
$filter=OrderYear ne 2006 and Sales lt 10000
EntitySetSchema LINQ for Filter Items
public IEnumerable<EntityPropertySchema> EntitySetSchema(string resource) { IEnumerable<EntityPropertySchema> entitySchema = null; if (resource != string.Empty) { XNamespace xmlns = "http://schemas.microsoft.com/ado/2008/09/edm"; entitySchema = from p in metadata .Descendants(xmlns.GetName("EntityType")).Descendants(xmlns.GetName("Property")) where p.Parent.Attribute("Name").Value == (from e in this.EntitySets where e.Name == resource select e.EntityType).Single<string>() select new EntityPropertySchema { Parent = p.Parent, Name = p.Attribute("Name").Value, Type = p.Attribute("Type").Value, MaxLength = p.Attribute("MaxLength") == null ? "NaN" : p.Attribute("MaxLength").Value }; } return entitySchema; }
$orderby=ProductSubCategory asc,Sales desc
See Filter
$select=ProductSubCategory,Sales
The example QueryFeed workflow renders entity properties in any client that supports .NET Framework 4.0. The sample source code at http://msftdbprodsamples.codeplex.com/releases/edit/94486 shows rendering an EntityProperties TablePart in Microsoft Excel 2010 and Microsoft Word 2010. The sample source code shows how to use an extension method to extend a Microsoft Excel or Microsoft Word range.
public static void InsertEntityTable(this Range activeCell, IEnumerable<IEnumerable<EntityProperty>> entityProperties, string styleName) { int currentColumn = 0; int currentRow = 1; Range range; List<string> propertyNames = (from item in entityProperties select item).First<IEnumerable<EntityProperty>>().Select(n => n.Name).ToList<string>(); int columnCount = propertyNames.Count(); int rowCount = entityProperties.Count(); Globals.ThisAddIn.Application.ScreenUpdating = false; //Data Columns foreach (string name in propertyNames) { range = activeCell.get_Offset(1, currentColumn); range.FormulaR1C1 = name; currentColumn++; } currentColumn = 0; //Data Values foreach (IEnumerable<EntityProperty> items in entityProperties) { //row = new TableRow(); currentRow++; foreach (EntityProperty item in items) { range = activeCell.get_Offset(currentRow, currentColumn); range.FormulaR1C1 = item.Value; currentColumn++; } currentColumn = 0; } Worksheet activeSheet = Globals.ThisAddIn.Application.ActiveSheet; Range styleRange = activeCell.Range[activeSheet.Cells[2, 1], activeSheet.Cells[rowCount + 2, columnCount]]; string listObjectName = String.Format("Table{0}", activeSheet.ListObjects.Count); try { activeSheet.ListObjects.AddEx(XlListObjectSourceType.xlSrcRange, styleRange, Type.Missing, XlYesNoGuess.xlYes).Name = listObjectName; activeSheet.ListObjects[listObjectName].TableStyle = styleName; } catch { //Handle exception in a production application } styleRange.Columns.AutoFit(); Globals.ThisAddIn.Application.ScreenUpdating = true; }
My next post will show how to edit a QueryFeed workflow using a hosted Windows Workflow designer. A custom designer is included in the source code at http://msftdbprodsamples.codeplex.com/releases/view/94486.
You can read more about the QueryFeed workflow in the attached Introducing the OData QueryFeed Activity document.