<feed xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US">
    <title>Bill Osuch - Random geek notes</title>
    <link rel="self" type="application/xml" href="http://geekswithblogs.net/bosuch/Atom.aspx" />
    <subtitle type="html"> </subtitle>
    <id>http://geekswithblogs.net/bosuch/Default.aspx</id>
    <author>
        <name>Bill Osuch</name>
        <uri>http://geekswithblogs.net/bosuch/Default.aspx</uri>
    </author>
    <generator uri="http://subtextproject.com" version="Subtext Version 0.0.0.0">Subtext</generator>
    <updated>2013-05-13T13:14:16Z</updated>
    <entry>
        <title>How to preserve state across pages in a Windows 8 app</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2013/01/04/how-to-preserve-state-across-pages-in-a-windows-8.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2013/01/04/how-to-preserve-state-across-pages-in-a-windows-8.aspx</id>
        <published>2013-01-04T11:58:19-06:00:00</published>
        <updated>2013-01-04T11:58:19Z</updated>
        <content type="html">&lt;p&gt;When designing a Windows 8 app, you need a way to preserve the state of various items as you navigate from page to page. Windows allows this using the pageState dictionary - a dictionary that can contain any serializable object. If you're a web programmer, you can think of this as similar to using a session variable. Today I'll add this to the cascading ListBoxes shown earlier. You can download the code for that project at &lt;a href="http://dl.dropbox.com/u/22528394/ListBoxDrillDown.zip" target="_blank"&gt;ListBoxDrillDown.zip&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;First, we'll add a navigation button to the page. Put the pnlMain StackPanel and the new button inside another StackPanel, like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;StackPanel x:Name="pnlContainer" Grid.Row="2" Orientation="Vertical"&amp;gt;     &lt;br /&gt;    &amp;lt;Button x:Name="btnSearch" Content="Show" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="40,0,0,0" Click="btnSearch_Click"/&amp;gt;      &lt;br /&gt;    &amp;lt;StackPanel x:Name="pnlMain" HorizontalAlignment="Left" Margin="20,10" VerticalAlignment="Top" Orientation="Horizontal"/&amp;gt;      &lt;br /&gt;&amp;lt;/StackPanel&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Then add the Click method:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private void btnSearch_Click(object sender, RoutedEventArgs e)     &lt;br /&gt;{      &lt;br /&gt;    if (_categoryID &amp;gt; 0)      &lt;br /&gt;    {      &lt;br /&gt;        this.Frame.Navigate(typeof(LandingPage));      &lt;br /&gt;    }      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;LandingPage isn't actually part of the project yet, so go ahead and add it. Just add a Basic Page called LandingPage.xaml to the project. It won't be used for anything other than the back button control.&lt;/p&gt;  &lt;p&gt;Now, if you run the app, after you select at least one item in the first ListBox you'll be able to click the button to navigate to the second page. When you click the back button, however, you return with only the first ListBox showing and nothing selected; anything that you had drilled down into will have to be reselected. Let's fix that.&lt;/p&gt;  &lt;p&gt;Locate the SaveState method and add the following code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;List&amp;lt;int&amp;gt; list = new List&amp;lt;int&amp;gt;();&lt;/p&gt;    &lt;p&gt;for (int x = 1; x &amp;lt;= _listBoxCount; x++)     &lt;br /&gt;{      &lt;br /&gt;    ListBox lb = (ListBox)pnlMain.Children[x - 1];      &lt;br /&gt;    if (lb.SelectedValue != null)      &lt;br /&gt;    {      &lt;br /&gt;        list.Add(lb.SelectedIndex);      &lt;br /&gt;    }      &lt;br /&gt;}&lt;/p&gt;    &lt;p&gt;pageState["listBoxSettings"] = list;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Here I'm simply adding all the SelectedIndex values to a List and saving it to pageState.&lt;/p&gt;  &lt;p&gt;Now, to retrieve this List once we've navigated away and back to the page. Add a variable to the class:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private List&amp;lt;int&amp;gt; _selectionList = null;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Then add the following code to the LoadState method:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;if (pageState != null &amp;amp;&amp;amp; pageState.ContainsKey("listBoxSettings"))     &lt;br /&gt;{      &lt;br /&gt;    _selectionList = (List&amp;lt;int&amp;gt;)pageState["listBoxSettings"];      &lt;br /&gt;}&lt;/p&gt;    &lt;p&gt;CallGetCategoryInfo(_categoryID);&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Here I check to see if the "listBoxSettings" key is populated (since this same method will be called the first time the page is loaded, it could be empty...), and then assign it to the variable. Notice that the CallGetCategoryInfo(_categoryID) statement has moved from the ChooseCategory() method; I want to make sure it's called after pageState has been retrieved.&lt;/p&gt;  &lt;p&gt;Next, add this code to the AddListBox() method, right before the ListBox is added to the Panel:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;if (_selectionList != null &amp;amp;&amp;amp; _selectionList.Count &amp;gt;= _listBoxCount)     &lt;br /&gt;{      &lt;br /&gt;    listBox1.SelectedIndex = _selectionList[_listBoxCount - 1];      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;When a new ListBox is created, I'm checking to see if the ListBox in that position has a selection in the List variable. If so, set the SelectedIndex. The SelectionChanged event will fire again, and the code will check again to see if another selection has already been made.&lt;/p&gt;  &lt;p&gt;At this point you should be able to test the app and verify that everything works. Fire it up, drill all the way down in the ListBoxes, go to the next page, and return. You should see all your selections preserved. There's one last thing that we have to do, though. Try this: Drill down as far as you can go into a category, go to the next page and return. Now, at the top level, select a different category. You'll see the app automatically drill down again! This is because the List is still held in the _selectionList variable, and the app doesn't know the difference between a human clicking and the automatic process that happens when we return to the page. The easy way to fix this is to simply clear the List when clicking in a ListBox to the left of another ListBox (i.e. a higher level). Add this code to the ComboBox_SelectionChanged event handler:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;_selectionList.Clear();&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;...inside the for() loop.&lt;/p&gt;  &lt;p&gt;Keep in mind, these settings are only going to be preserved while you're using the app - if it's suspended or terminated, they're not available. If you need to preserve them after the app is terminated, you can use the SuspensionManager.&lt;/p&gt;  &lt;p&gt;When you hit the back button, you'll probably notice a delay as each new ListBox appears. This is because it's fetching the contents from the eBay API, just as it did the first time you selected it. If you don't like this, then you could simply store the contents of each ListBox in pageState and repopulate.&lt;/p&gt;  &lt;p&gt;You can download the code for this at &lt;a href="http://dl.dropbox.com/u/22528394/SaveStateDemo.zip" target="_blank"&gt;SaveStateDemo.zip&lt;/a&gt;.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:bcc46c76-8d2a-4737-a62c-343405fa97f4" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/eBay" rel="tag"&gt;eBay&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Windows+8" rel="tag"&gt;Windows 8&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Csharp" rel="tag"&gt;Csharp&lt;/a&gt;&lt;/div&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/151739.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/151739.aspx</wfw:comment>
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/151739.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/151739.aspx</trackback:ping>
    </entry>
    <entry>
        <title>Using cascading ListBoxes to display hierarchical data in Windows 8</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/12/20/using-cascading-listboxes-to-display-hierarchical-data-in-windows-8.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/12/20/using-cascading-listboxes-to-display-hierarchical-data-in-windows-8.aspx</id>
        <published>2012-12-20T14:28:30-06:00:00</published>
        <updated>2012-12-20T14:28:30Z</updated>
        <content type="html">&lt;p&gt;When you're dealing with hierarchical data (a tree-like data format such as folders that have sub-folders that have subfolders, etc.) you have to come up with an organized way of displaying it. You could create a tree view, similar to how Windows Explorer displays folders, but I wanted to try something different in Windows 8 - cascading ListBoxes. The user selects an items in a ListBox, and then a new ListBox appears to the right showing the sub-categories. This continues as long as there's data left to drill into.&lt;/p&gt;  &lt;p&gt;For a data source, I'll use the eBay category list API that I blogged about previously.&lt;/p&gt;  &lt;p&gt;Begin by creating a Windows Store project - a Blank App. Add a Basic Page called ChooseCategory.xaml, and delete the MainPage.xaml file that was created with the app. (For this demo you could get away with the blank page, but it's good to have the Grid and the VisualStateGroup automatically added) Open up App.xaml.cs and change this line:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;to call ChooseCategory instead of MainPage. Finally, in App.xaml change the Theme to Light by adding RequestedTheme="Light" to the Application tag. You could leave it dark by default, but then your ListBoxes will look a bit out of place unless you modify their style.&lt;/p&gt;  &lt;p&gt;Next I'll add a class file to the project to hold a List that can be bound to each ListBox, as well as hold the method to make the call to the eBay API. This is almost identical to the previous post, with a few minor tweaks.&lt;/p&gt;  &lt;p&gt;Here are the two classes to hold the List:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public class Categories      &lt;br /&gt;{       &lt;br /&gt;    private List&amp;lt;CategoryDetails&amp;gt; _Items = new List&amp;lt;CategoryDetails&amp;gt;();       &lt;br /&gt;    public List&amp;lt;CategoryDetails&amp;gt; Items       &lt;br /&gt;    {       &lt;br /&gt;        get       &lt;br /&gt;        {       &lt;br /&gt;            return this._Items;       &lt;br /&gt;        }       &lt;br /&gt;        set       &lt;br /&gt;        {       &lt;br /&gt;            this._Items = value;       &lt;br /&gt;        }       &lt;br /&gt;    }       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;public class CategoryDetails      &lt;br /&gt;{       &lt;br /&gt;    public string categoryName { get; set; }       &lt;br /&gt;    public int categoryId { get; set; }       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;You could have more data in these if you wanted, but since this is a ListBox demo I just wanted some simple name/value pairs.&lt;/p&gt;  &lt;p&gt;And here is the method that makes the call to the eBay API:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public async Task&amp;lt;Categories&amp;gt; CallGetCategoryInfo(int CategoryID)      &lt;br /&gt;{       &lt;br /&gt;    HttpClient httpClient = new HttpClient();       &lt;br /&gt;    string api_key = "MyKey";       &lt;br /&gt;    string searchUrl = "&lt;a href="http://open.api.ebay.com/Shopping?callname=GetCategoryInfo&amp;quot;;"&gt;http://open.api.ebay.com/Shopping?callname=GetCategoryInfo";&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;    string requestUrl = searchUrl + "&amp;amp;appid=" + api_key + "&amp;amp;version=679&amp;amp;siteid=0&amp;amp;CategoryID=" + CategoryID.ToString() + "&amp;amp;IncludeSelector=ChildCategories";&lt;/p&gt;    &lt;p&gt;    HttpResponseMessage response = await httpClient.GetAsync(requestUrl);      &lt;br /&gt;    System.Xml.Linq.XDocument doc = System.Xml.Linq.XDocument.Load(await response.Content.ReadAsStreamAsync());&lt;/p&gt;    &lt;p&gt;    XNamespace ns = "urn:ebay:apis:eBLBaseComponents";&lt;/p&gt;    &lt;p&gt;    var query = from categories in doc.Descendants(ns + "Category")      &lt;br /&gt;        select new       &lt;br /&gt;        {       &lt;br /&gt;            CategoryID = categories.Element(ns + "CategoryID").Value,       &lt;br /&gt;            CategoryParentID = categories.Element(ns + "CategoryParentID").Value,       &lt;br /&gt;            CategoryName = categories.Element(ns + "CategoryName").Value,       &lt;br /&gt;            LeafCategory = categories.Element(ns + "LeafCategory").Value,       &lt;br /&gt;        };&lt;/p&gt;    &lt;p&gt;    List&amp;lt;CategoryDetails&amp;gt; catList = new List&amp;lt;CategoryDetails&amp;gt;();&lt;/p&gt;    &lt;p&gt;    Categories c = new Categories();&lt;/p&gt;    &lt;p&gt;    foreach (var element in query)      &lt;br /&gt;    {       &lt;br /&gt;        //The first category returned in the xml will always be either root, or the parent level category       &lt;br /&gt;        //I don't want it in the list       &lt;br /&gt;        if (element.CategoryID != "-1" &amp;amp;&amp;amp; element.CategoryID != CategoryID.ToString())       &lt;br /&gt;        {       &lt;br /&gt;            CategoryDetails cd = new CategoryDetails();       &lt;br /&gt;            cd.categoryId = Convert.ToInt32(element.CategoryID);       &lt;br /&gt;            cd.categoryName = (Convert.ToBoolean(element.LeafCategory) ? element.CategoryName : element.CategoryName + " -&amp;gt;");&lt;/p&gt;    &lt;p&gt;            catList.Add(cd);      &lt;br /&gt;        }       &lt;br /&gt;    }&lt;/p&gt;    &lt;p&gt;    c.Items = catList;&lt;/p&gt;    &lt;p&gt;    return c;      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now let's modify ChooseCategory.xaml. Change the AppName:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;x:String x:Key="AppName"&amp;gt;Choose Category&amp;lt;/x:String&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And add a StackPanel right below the grid that hold the pageTitle TextBlock:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;StackPanel x:Name="pnlMain" HorizontalAlignment="Left" Margin="20,10" Grid.Row="2" VerticalAlignment="Top" Orientation="Horizontal"/&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This is the panel that we'll add the ListBoxes to.&lt;/p&gt;  &lt;p&gt;Now for the code-behind in ChooseCategory.xaml.cs. Declare a few variables in the class:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private int _categoryID = -1;      &lt;br /&gt;private string _categoryName = "";       &lt;br /&gt;private List&amp;lt;CategoryDetails&amp;gt; _cbp = null;       &lt;br /&gt;private int _listBoxCount = 0;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Add a method to retrieve the data from eBay and call the method that adds a new ListBox:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private async void CallGetCategoryInfo(int CategoryID)      &lt;br /&gt;{       &lt;br /&gt;    CategoriesDataSource cds = new CategoriesDataSource();       &lt;br /&gt;    Categories c = await cds.CallGetCategoryInfo(CategoryID);       &lt;br /&gt;    _cbp = c.Items;&lt;/p&gt;    &lt;p&gt;    AddListBox();      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now we add a new ListBox if we had some data returned from eBay. We set the DisplayMemberPath and SelectedValuePath to the public properties of the CategoryDetails object, give the ListBox a distinct name (we'll need it later), wire up an event handler, and add the ListBox to the StackPanel:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private void AddListBox()      &lt;br /&gt;{       &lt;br /&gt;    //If the List count is 0, that means we have drilled all the way down       &lt;br /&gt;    if (_cbp.Count &amp;gt; 0)       &lt;br /&gt;    {       &lt;br /&gt;        _listBoxCount += 1;&lt;/p&gt;    &lt;p&gt;        ListBox listBox1 = new ListBox();      &lt;br /&gt;        listBox1.DisplayMemberPath = "categoryName";       &lt;br /&gt;        listBox1.SelectedValuePath = "categoryId";       &lt;br /&gt;        listBox1.ItemsSource = _cbp;       &lt;br /&gt;        listBox1.Width = 250;       &lt;br /&gt;        listBox1.Name = "CategoryLevel" + _listBoxCount.ToString();       &lt;br /&gt;        listBox1.SelectionChanged += ComboBox_SelectionChanged;       &lt;br /&gt;        pnlMain.Children.Add(listBox1);       &lt;br /&gt;    }       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Finally we're going to handle selecting an item in the ListBox:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)      &lt;br /&gt;{       &lt;br /&gt;    Selector list = sender as Selector;&lt;/p&gt;    &lt;p&gt;    // Delete listboxes to the right if we click back a level      &lt;br /&gt;    int clickedCategoryLevel = Convert.ToInt32(list.Name.Replace("CategoryLevel", ""));       &lt;br /&gt;    for (int x = _listBoxCount; x &amp;gt; clickedCategoryLevel; x--)       &lt;br /&gt;    {       &lt;br /&gt;        pnlMain.Children.RemoveAt(x - 1);       &lt;br /&gt;    }&lt;/p&gt;    &lt;p&gt;    _listBoxCount = clickedCategoryLevel;      &lt;br /&gt;    _categoryID = Convert.ToInt32(list.SelectedValue);&lt;/p&gt;    &lt;p&gt;    CallGetCategoryInfo(_categoryID);      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If the user backs up a level (i.e. they have drilled down a few levels, but now want to click something at a higher level and start over instead of drilling down further), then we need to delete any ListBoxes to the right of the one that was just clicked. Then we call CallGetCategoryInfo again to retrieve the data and add a new ListBox.&lt;/p&gt;  &lt;p&gt;Finally, add a call to CallGetCategoryInfo in the constructor to start the whole process off:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public ChooseCategory()      &lt;br /&gt;{       &lt;br /&gt;    this.InitializeComponent();&lt;/p&gt;    &lt;p&gt;    CallGetCategoryInfo(_categoryID);      &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Fire up the app and try drilling down and back up. If everything works correctly, you should get results looking similar to this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/34c4e497c42b_C38D/CategoryChooser_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="CategoryChooser" border="0" alt="CategoryChooser" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/34c4e497c42b_C38D/CategoryChooser_thumb.png" width="244" height="136" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Notice that some of the lines end with "-&amp;gt;". In the CallGetCategoryInfo I check to see whether the category being added to the List is a "Leaf" category - the lowest level of category (you can't drill down any further). If it is, I add that text to give a visual indication that there are sub-categories.&lt;/p&gt;  &lt;p&gt;Notice that I didn't do anything with the various VisualStates, so this will really only look good in FullScreenPortrait mode. I haven't really thought about how other modes would work (especially snapped!); this was more of a proof-of-concept.&lt;/p&gt;  &lt;p&gt;You can download the entire source code at: &lt;a title="http://dl.dropbox.com/u/22528394/ListBoxDrillDown.zip" href="http://dl.dropbox.com/u/22528394/ListBoxDrillDown.zip"&gt;http://dl.dropbox.com/u/22528394/ListBoxDrillDown.zip&lt;/a&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:56bcacae-dd89-4912-84ea-93125fa66d67" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/eBay" rel="tag"&gt;eBay&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Windows+8" rel="tag"&gt;Windows 8&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Csharp" rel="tag"&gt;Csharp&lt;/a&gt;&lt;/div&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/151619.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/151619.aspx</wfw:comment>
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/151619.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/151619.aspx</trackback:ping>
    </entry>
    <entry>
        <title>Retrieving a list of eBay categories in a .Net 4.5 Windows Store App</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/12/19/retrieving-a-list-of-ebay-categories-in-a-.net-4.5.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/12/19/retrieving-a-list-of-ebay-categories-in-a-.net-4.5.aspx</id>
        <published>2012-12-19T11:18:34-06:00:00</published>
        <updated>2012-12-19T11:18:34Z</updated>
        <content type="html">&lt;p&gt;&lt;a href="http://geekswithblogs.net/bosuch/archive/2012/06/25/retrieving-a-list-of-ebay-categories-using-the-.net-sdk.aspx" target="_blank"&gt;Previously I wrote a post&lt;/a&gt; on how to get the eBay category list using their .Net SDK. I wanted to try doing the same thing in a Windows Store App for Windows 8 using Visual Studio 2012, but quickly ran into compatibility problems since the DLLs are compiled for .Net 2.0. I could have either changed the targetted framework, or attempted to re-write the DLLs, but neither sounded particularly exciting, so I simply decided to fall back to using a simple URL request and parsing it via Linq to XML.&lt;/p&gt;  &lt;p&gt;As mentioned in the previous post, the first step is to join the eBay Developer Program. Once you've joined and gotten your app ID, you can try a simple request with this URL:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://open.api.ebay.com/Shopping?callname=GetCategoryInfo&amp;amp;appid=yourappid8&amp;amp;version=679&amp;amp;siteid=0&amp;amp;CategoryID=-1&amp;amp;IncludeSelector=ChildCategories"&gt;http://open.api.ebay.com/Shopping?callname=GetCategoryInfo&amp;amp;appid=yourappid8&amp;amp;version=679&amp;amp;siteid=0&amp;amp;CategoryID=-1&amp;amp;IncludeSelector=ChildCategories&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Passing CategoryID=-1 returns the top-level categories, like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;GetCategoryInfoResponse xmlns="urn:ebay:apis:eBLBaseComponents"&amp;gt;      &lt;br /&gt;   &amp;lt;Timestamp&amp;gt;2012-12-19T16:03:33.893Z&amp;lt;/Timestamp&amp;gt;       &lt;br /&gt;   &amp;lt;Ack&amp;gt;Success&amp;lt;/Ack&amp;gt;       &lt;br /&gt;   &amp;lt;Build&amp;gt;E803_CORE_BUNDLED_15627359_R1&amp;lt;/Build&amp;gt;       &lt;br /&gt;   &amp;lt;Version&amp;gt;803&amp;lt;/Version&amp;gt;       &lt;br /&gt;   &amp;lt;CategoryArray&amp;gt;       &lt;br /&gt;      &amp;lt;Category&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryID&amp;gt;-1&amp;lt;/CategoryID&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryLevel&amp;gt;0&amp;lt;/CategoryLevel&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryName&amp;gt;Root&amp;lt;/CategoryName&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryParentID&amp;gt;0&amp;lt;/CategoryParentID&amp;gt;       &lt;br /&gt;         &amp;lt;LeafCategory&amp;gt;false&amp;lt;/LeafCategory&amp;gt;       &lt;br /&gt;      &amp;lt;/Category&amp;gt;       &lt;br /&gt;      &amp;lt;Category&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryID&amp;gt;20081&amp;lt;/CategoryID&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryLevel&amp;gt;1&amp;lt;/CategoryLevel&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryName&amp;gt;Antiques&amp;lt;/CategoryName&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryParentID&amp;gt;-1&amp;lt;/CategoryParentID&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryNamePath&amp;gt;Antiques&amp;lt;/CategoryNamePath&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryIDPath&amp;gt;20081&amp;lt;/CategoryIDPath&amp;gt;       &lt;br /&gt;         &amp;lt;LeafCategory&amp;gt;false&amp;lt;/LeafCategory&amp;gt;       &lt;br /&gt;      &amp;lt;/Category&amp;gt;       &lt;br /&gt;(etc.)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;You can continue to walk down the category tree by passing the sub-category IDs.&lt;/p&gt;  &lt;p&gt;The first step will be to fire up an HttpClient and send an asynchronous GET request to the URL:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private async Task&amp;lt;string&amp;gt; CallGetCategoryInfo(int CategoryID)      &lt;br /&gt;{       &lt;br /&gt;    httpClient = new HttpClient();       &lt;br /&gt;    string searchUrl = "&lt;a href="http://open.api.ebay.com/Shopping?callname=GetCategoryInfo&amp;quot;;"&gt;http://open.api.ebay.com/Shopping?callname=GetCategoryInfo";&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;    string requestUrl = searchUrl + "&amp;amp;appid=" + api_key + "&amp;amp;version=679&amp;amp;siteid=0&amp;amp;CategoryID=" + CategoryID.ToString() + "&amp;amp;IncludeSelector=ChildCategories";&lt;/p&gt;    &lt;p&gt;    HttpResponseMessage response = await httpClient.GetAsync(requestUrl);&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Next we'll load the response stream into an XDocument and create a Ling query:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;    System.Xml.Linq.XDocument doc = System.Xml.Linq.XDocument.Load(await response.Content.ReadAsStreamAsync());&lt;/p&gt;    &lt;p&gt;    XNamespace ns = "urn:ebay:apis:eBLBaseComponents";&lt;/p&gt;    &lt;p&gt;    var query = from categories in doc.Descendants(ns + "Category")      &lt;br /&gt;        select new       &lt;br /&gt;        {       &lt;br /&gt;            CategoryID = categories.Element(ns + "CategoryID").Value,       &lt;br /&gt;            CategoryParentID = categories.Element(ns + "CategoryParentID").Value,       &lt;br /&gt;            CategoryName = categories.Element(ns + "CategoryName").Value,       &lt;br /&gt;            LeafCategory = categories.Element(ns + "LeafCategory").Value,       &lt;br /&gt;        };&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We'll add the results of the query to a List of objects. I only needed the category name and ID, so that's all my object has:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public class ComboBoxPairs      &lt;br /&gt;{       &lt;br /&gt;    public string categoryName { get; set; }       &lt;br /&gt;    public int categoryId { get; set; }&lt;/p&gt;    &lt;p&gt;    public ComboBoxPairs(string CategoryName, int CategoryId)      &lt;br /&gt;    {       &lt;br /&gt;        categoryName = CategoryName;       &lt;br /&gt;        categoryId = CategoryId;       &lt;br /&gt;    }       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And here I add the objects to the List:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;    List&amp;lt;ComboBoxPairs&amp;gt; cbp = new List&amp;lt;ComboBoxPairs&amp;gt;();&lt;/p&gt;    &lt;p&gt;    foreach (var element in query)      &lt;br /&gt;    {       &lt;br /&gt;        //The first category returned in the xml will always be either root, or the parent level category.       &lt;br /&gt;        // I don't want it in the list       &lt;br /&gt;        if (element.CategoryID != "-1" &amp;amp;&amp;amp; element.CategoryID != _categoryID.ToString())       &lt;br /&gt;        {       &lt;br /&gt;            cbp.Add(new ComboBoxPairs(element.CategoryName, Convert.ToInt32(element.CategoryID)));       &lt;br /&gt;        }       &lt;br /&gt;    }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Finally I assign the List to a global variable and exit:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;    _cbp = cbp;      &lt;br /&gt;    return "Finished";&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The big difference between this method and using the SDK is that you can only return one level at a time. This is probably a good thing; the web service is responsive enough that there's no noticeable wait to the call, versus a distinct wait (and massive size) for retrieving the entire list. If you did want the entire list for some reason, you can simply drill down - use a category ID of -1 (the root category ID) on the first call to get all the level 1 categories, then use a level 1 category ID on the second call to get all the level 2 children of the specified category ID, and so forth. When you get to LeafCategory = true, you can stop.&lt;/p&gt;  &lt;p&gt;If you omit the &amp;amp;IncludeSelector=ChildCategories flag then you'll just get info for the selected category, but you'll also get the version and last update time, like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;GetCategoryInfoResponse xmlns="urn:ebay:apis:eBLBaseComponents"&amp;gt;      &lt;br /&gt;   &amp;lt;Timestamp&amp;gt;2012-12-19T16:37:46.516Z&amp;lt;/Timestamp&amp;gt;       &lt;br /&gt;   &amp;lt;Ack&amp;gt;Success&amp;lt;/Ack&amp;gt;       &lt;br /&gt;   &amp;lt;Build&amp;gt;E803_CORE_BUNDLED_15627359_R1&amp;lt;/Build&amp;gt;       &lt;br /&gt;   &amp;lt;Version&amp;gt;803&amp;lt;/Version&amp;gt;       &lt;br /&gt;   &amp;lt;CategoryArray&amp;gt;       &lt;br /&gt;      &amp;lt;Category&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryID&amp;gt;-1&amp;lt;/CategoryID&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryLevel&amp;gt;0&amp;lt;/CategoryLevel&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryName&amp;gt;Root&amp;lt;/CategoryName&amp;gt;       &lt;br /&gt;         &amp;lt;CategoryParentID&amp;gt;0&amp;lt;/CategoryParentID&amp;gt;       &lt;br /&gt;         &amp;lt;LeafCategory&amp;gt;false&amp;lt;/LeafCategory&amp;gt;       &lt;br /&gt;      &amp;lt;/Category&amp;gt;       &lt;br /&gt;   &amp;lt;/CategoryArray&amp;gt;       &lt;br /&gt;   &amp;lt;CategoryCount&amp;gt;1&amp;lt;/CategoryCount&amp;gt;       &lt;br /&gt;   &amp;lt;UpdateTime&amp;gt;2012-09-11T02:42:04.000Z&amp;lt;/UpdateTime&amp;gt;       &lt;br /&gt;   &amp;lt;CategoryVersion&amp;gt;102&amp;lt;/CategoryVersion&amp;gt;       &lt;br /&gt;&amp;lt;/GetCategoryInfoResponse&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;If you're storing the information locally you can then compare to determine whether the category has changed; if it hasn't, skip the full query and move on to the next.&lt;/p&gt;  &lt;p&gt;Here's the full code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private async Task&amp;lt;string&amp;gt; CallGetCategoryInfo(int CategoryID)      &lt;br /&gt;{       &lt;br /&gt;    // &lt;a href="http://open.api.ebay.com/Shopping?callname=GetCategoryInfo&amp;amp;appid=appID&amp;amp;version=679&amp;amp;siteid=0&amp;amp;CategoryID=-1&amp;amp;IncludeSelector=ChildCategories"&gt;http://open.api.ebay.com/Shopping?callname=GetCategoryInfo&amp;amp;appid=appID&amp;amp;version=679&amp;amp;siteid=0&amp;amp;CategoryID=-1&amp;amp;IncludeSelector=ChildCategories&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;    httpClient = new HttpClient();      &lt;br /&gt;    string searchUrl = "&lt;a href="http://open.api.ebay.com/Shopping?callname=GetCategoryInfo&amp;quot;;"&gt;http://open.api.ebay.com/Shopping?callname=GetCategoryInfo";&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;    string requestUrl = searchUrl + "&amp;amp;appid=" + api_key + "&amp;amp;version=679&amp;amp;siteid=0&amp;amp;CategoryID=" + CategoryID.ToString() + "&amp;amp;IncludeSelector=ChildCategories";&lt;/p&gt;    &lt;p&gt;    HttpResponseMessage response = await httpClient.GetAsync(requestUrl);      &lt;br /&gt;    System.Xml.Linq.XDocument doc = System.Xml.Linq.XDocument.Load(await response.Content.ReadAsStreamAsync());&lt;/p&gt;    &lt;p&gt;    XNamespace ns = "urn:ebay:apis:eBLBaseComponents";&lt;/p&gt;    &lt;p&gt;    var query = from categories in doc.Descendants(ns + "Category")      &lt;br /&gt;        select new       &lt;br /&gt;        {       &lt;br /&gt;            CategoryID = categories.Element(ns + "CategoryID").Value,       &lt;br /&gt;            CategoryParentID = categories.Element(ns + "CategoryParentID").Value,       &lt;br /&gt;            CategoryName = categories.Element(ns + "CategoryName").Value,       &lt;br /&gt;            LeafCategory = categories.Element(ns + "LeafCategory").Value,       &lt;br /&gt;        };&lt;/p&gt;    &lt;p&gt;    List&amp;lt;ComboBoxPairs&amp;gt; cbp = new List&amp;lt;ComboBoxPairs&amp;gt;();&lt;/p&gt;    &lt;p&gt;    foreach (var element in query)      &lt;br /&gt;    {       &lt;br /&gt;        //The first category returned in the xml will always be either root, or the parent level category       &lt;br /&gt;        //I don't want it in the list       &lt;br /&gt;        if (element.CategoryID != "-1" &amp;amp;&amp;amp; element.CategoryID != _categoryID.ToString())       &lt;br /&gt;        {       &lt;br /&gt;            cbp.Add(new ComboBoxPairs(element.CategoryName, Convert.ToInt32(element.CategoryID)));       &lt;br /&gt;        }       &lt;br /&gt;    }&lt;/p&gt;    &lt;p&gt;    _cbp = cbp;      &lt;br /&gt;    return "Finished";       &lt;br /&gt;}&lt;/p&gt;    &lt;p&gt;public class ComboBoxPairs      &lt;br /&gt;{       &lt;br /&gt;    public string categoryName { get; set; }       &lt;br /&gt;    public int categoryId { get; set; }&lt;/p&gt;    &lt;p&gt;    public ComboBoxPairs(string CategoryName, int CategoryId)      &lt;br /&gt;    {       &lt;br /&gt;        categoryName = CategoryName;       &lt;br /&gt;        categoryId = CategoryId;       &lt;br /&gt;    }       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;    &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0a0c2522-08f0-438b-b6e1-a1afc8969e9a" class="wlWriterEditableSmartContent"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/eBay" rel="tag"&gt;eBay&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Csharp" rel="tag"&gt;Csharp&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Windows+8" rel="tag"&gt;Windows 8&lt;/a&gt;&lt;/div&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/151599.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/151599.aspx</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/151599.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/151599.aspx</trackback:ping>
    </entry>
    <entry>
        <title>Android&amp;ndash;Finding your SDK debug certificate MD5 fingerprint using Keytool</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/10/18/androidndashfinding-your-sdk-debug-certificate-md5-fingerprint-using-keytool.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/10/18/androidndashfinding-your-sdk-debug-certificate-md5-fingerprint-using-keytool.aspx</id>
        <published>2012-10-18T09:18:19-06:00:00</published>
        <updated>2012-12-19T09:35:10Z</updated>
        <content type="html">&lt;p&gt;I recently upgraded to a new development machine, which means the certificate used to sign my applications during debug changed. Under most circumstances you’ll never notice a difference, but if you’re developing apps using Google’s Maps API you’ll find that your old API key no longer works with the new certificate fingerprint. &lt;/p&gt;  &lt;p&gt;Google's &lt;a href="https://developers.google.com/maps/documentation/android/mapkey#getdebugfingerprint" target="_blank"&gt;instructions&lt;/a&gt; walk you through retrieving the MD5 fingerprint of your SDK debug certificate - the certificate that you’re probably signing your apps with before publishing, but it doesn't talk much about the Keytool command.&lt;/p&gt;  &lt;p&gt;The thing to remember is that Keytool is part of Java, not the Android SDK, so you'll never find it searching through your Android and Eclipse directories. Mine is located in C:\Program Files\Java\jdk1.7.0_02\bin so you should find yours somewhere similar.&lt;/p&gt;  &lt;p&gt;From a command prompt, navigate to this directory and type:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;keytool -v -list -keystore "C:/Documents and Settings/&amp;lt;user name&amp;gt;/.android/debug.keystore"&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;That’s assuming the path to your debug certificate is in the typical location. If this doesn’t work, you can find out where it’s located in Eclipse by clicking Window –&amp;gt; Preferences –&amp;gt; Android –&amp;gt; Build.&lt;/p&gt;  &lt;p&gt;There's no need to use the additional commands shown on Google's page. You'll be prompted for a password, just hit enter. The last line shown, Certificate fingerprint, is the key you'll give Google to generate your new Maps API key.&lt;/p&gt;  &lt;p&gt;Technorati Tags: &lt;a href="http://technorati.com/tag/Android" rel="tag"&gt;Android&lt;/a&gt; &lt;a href="http://technorati.com/tag/Mapping" rel="tag"&gt;Mapping&lt;/a&gt;&lt;/p&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/151020.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/151020.aspx</wfw:comment>
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/151020.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/151020.aspx</trackback:ping>
    </entry>
    <entry>
        <title>Packt Publishing Thousand Titles Campaign&amp;ndash;free eBook!</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/09/28/packt-publishing-thousand-titles-campaignndashfree-ebook.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/09/28/packt-publishing-thousand-titles-campaignndashfree-ebook.aspx</id>
        <published>2012-09-28T12:10:42-06:00:00</published>
        <updated>2012-12-19T09:36:13Z</updated>
        <content type="html">&lt;p&gt;Packt Publishing is celebrating the release of its 1000th title by offering web site members their choice of free eBook. They are also opening their online library for a week for free to members, to allow you to research your choice. &lt;/p&gt;  &lt;p&gt;If you’re not already a member, signing up is free, but you have to do so by September 30th to get the free eBook.&lt;/p&gt;  &lt;p&gt;To sign up, just go to &lt;a href="http://www.packtpub.com/login"&gt;www.packtpub.com/login&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/150834.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/150834.aspx</wfw:comment>
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/150834.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/150834.aspx</trackback:ping>
    </entry>
    <entry>
        <title>BizTalk&amp;ndash;Looping through repeating message nodes in orchestrations</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/08/15/biztalkndashlooping-through-repeating-message-nodes-in-orchestrations.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/08/15/biztalkndashlooping-through-repeating-message-nodes-in-orchestrations.aspx</id>
        <published>2012-08-15T15:10:30-06:00:00</published>
        <updated>2012-08-15T15:10:30Z</updated>
        <content type="html">&lt;p&gt;Say that you have an incoming BizTalk message with many repeating nodes, and you want to process each one the same. The easiest thing to do would be to use the envelope to split the single message into multiple messages, then have multiple instances of your orchestration handle each one (similar to how the HIPAA “multiple” message schemas work). But what if you need to do some work after every individual message has been processed? I’ll show you how to use the Loop functoid along with xpath queries to loop through the message.&lt;/p&gt;  &lt;p&gt;In my case, I’m receiving a flat file where each line is a response to a transaction we have submitted. After mapping the flat file to xml, I get something like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;Response&amp;gt;      &lt;br /&gt;   &amp;lt;Record&amp;gt;       &lt;br /&gt;      &amp;lt;RecordId&amp;gt;xxx&amp;lt;/RecordId&amp;gt;       &lt;br /&gt;      &amp;lt;SubmitterId&amp;gt;xxx&amp;lt;/SubmitterId&amp;gt;       &lt;br /&gt;      &amp;lt;Status&amp;gt;xxx&amp;lt;/Status&amp;gt;       &lt;br /&gt;   &amp;lt;/Record&amp;gt;       &lt;br /&gt;   &amp;lt;Record&amp;gt;       &lt;br /&gt;      &amp;lt;RecordId&amp;gt;xxx&amp;lt;/RecordId&amp;gt;       &lt;br /&gt;      &amp;lt;SubmitterId&amp;gt;xxx&amp;lt;/SubmitterId&amp;gt;       &lt;br /&gt;      &amp;lt;Status&amp;gt;xxx&amp;lt;/Status&amp;gt;       &lt;br /&gt;   &amp;lt;/Record&amp;gt;       &lt;br /&gt;&amp;lt;/Response&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I want to insert each Record into the database, then do some work once they’ve all been inserted.&lt;/p&gt;  &lt;p&gt;The first step is to create the single Record version of the message. It’ll be basically the same as the incoming Response message, just without the Response node at the top:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;Record&amp;gt;      &lt;br /&gt;   &amp;lt;RecordId&amp;gt;xxx&amp;lt;/RecordId&amp;gt;       &lt;br /&gt;   &amp;lt;SubmitterId&amp;gt;xxx&amp;lt;/SubmitterId&amp;gt;       &lt;br /&gt;   &amp;lt;Status&amp;gt;xxx&amp;lt;/Status&amp;gt;       &lt;br /&gt;&amp;lt;/Record&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The schema needs to be created without a Target Namespace; you’ll see why later.&lt;/p&gt;  &lt;p&gt;Next, create the orchestration, two messages:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;FullResponse (using the full flat file schema) &lt;/li&gt;    &lt;li&gt;SingleResponse (using the new single Record schema) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;…and three variables:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;counter - int &lt;/li&gt;    &lt;li&gt;counterString – string &lt;/li&gt;    &lt;li&gt;responseCount - int &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Drag various shapes onto your orchestration until you wind up with something that look like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/2a5c45cafa90_CF72/LoopingPost_2.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="LoopingPost" border="0" alt="LoopingPost" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/2a5c45cafa90_CF72/LoopingPost_thumb.jpg" width="463" height="604" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I’ll start at the top and detail how each shape should be configured.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Receive&lt;/strong&gt; – receives FullResponse message&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Expression&lt;/strong&gt; - here you’re going to use an xpath query to count how many Record nodes are in the FullResponse message:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;responseCount = xpath(InstaMedResponse, "count(/*[local-name()='Response' and namespace-uri()='&lt;a href="http://MyProject.Response_FF']/*[local-name()='Record'"&gt;http://MyProject.Response_FF']/*[local-name()='Record'&lt;/a&gt; and namespace-uri()=''])");       &lt;br /&gt;counter = 1;       &lt;br /&gt;counterString = "1";&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;(Pay attention to the namespace, yours may be different)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Loop&lt;/strong&gt; -  what’s the loop condition?&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;counter &amp;lt;= responseCount&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;strong&gt;Message Assignment&lt;/strong&gt; – here we’re grabbing a single Record node and assigning it to the SingleResponse message:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;SingleResponse = xpath(InstaMedResponse, "/*[local-name()='Response' and namespace-uri()='&lt;a href="http://AnciPay.InstaMedResponse_FF']/*[local-name()='Record'"&gt;http://AnciPay.InstaMedResponse_FF']/*[local-name()='Record'&lt;/a&gt; and namespace-uri()=''][" + counterString + "]");&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Remember how I said the new schema needs to be created without a target namespace? Your xpath query will return the Record node without a namespace. Also, we have to (unfortunately) use counterString rather than just counter.ToString(), otherwise BizTalk will complain about an xpath error.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Map&lt;/strong&gt; – this one is optional for the demo; in my case I’m mapping it to the Request Side of a generated schema. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Expression&lt;/strong&gt; – here we need to increment the counter:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;counter = counter + 1;      &lt;br /&gt;counterString = counter.ToString();&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;strong&gt;Send &amp;amp; Receive&lt;/strong&gt; -  I’m using a WCF port to save to a database (&lt;a href="http://geekswithblogs.net/bosuch/archive/2010/10/19/biztalk---simple-wcf-tutorial-for-using-a-stored-procedure.aspx" target="_blank"&gt;click here for a simple tutorial&lt;/a&gt;), but you could omit these steps if you want.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Expression&lt;/strong&gt; – this can really be anything that you want to happen after every individual Record node has been processed – run a stored procedure, send email, whatever. &lt;/p&gt;  &lt;p&gt;Compile, deploy and test. If you just drop the SingleResponse message to a send port (instead of the database), you should see your incoming message split into multiple messages.&lt;/p&gt;  &lt;p&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/BizTalk" rel="tag"&gt;BizTalk&lt;/a&gt;&lt;/p&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/150433.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/150433.aspx</wfw:comment>
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/150433.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/150433.aspx</trackback:ping>
    </entry>
    <entry>
        <title>Retrieving a list of eBay categories using the .NET SDK and GetCategoriesCall</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/06/25/retrieving-a-list-of-ebay-categories-using-the-.net-sdk.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/06/25/retrieving-a-list-of-ebay-categories-using-the-.net-sdk.aspx</id>
        <published>2012-06-25T14:06:27-06:00:00</published>
        <updated>2012-06-25T14:06:27Z</updated>
        <content type="html">&lt;p&gt;eBay offers a .Net SDK for its Trading API - this post will show you the basics of making an API call and retrieving a list of current categories. You'll need the category ID(s) for any apps that post or search eBay.&lt;/p&gt;  &lt;p&gt;To start, download the latest SDK from &lt;a href="https://www.x.com/developers/ebay/documentation-tools/sdks/dotnet"&gt;https://www.x.com/developers/ebay/documentation-tools/sdks/dotnet&lt;/a&gt; and create a new console app project.&lt;/p&gt;  &lt;p&gt;Add a reference to the eBay.Service DLL, and a few using statements:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;using eBay.Service.Call;      &lt;br /&gt;using eBay.Service.Core.Sdk;       &lt;br /&gt;using eBay.Service.Core.Soap;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I'm assuming at this point you've already joined the eBay Developer Network and gotten your app IDs and user tokens. If not:&lt;/p&gt;  &lt;p&gt;&lt;a href="https://developer.ebay.com/join/default.aspx" target="_blank"&gt;Join the developer program&lt;/a&gt;     &lt;br /&gt;&lt;a href="https://developer.ebay.com/DevZone/account/tokens/" target="_blank"&gt;Generate tokens&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Next, add an app.config file that looks like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;?xml version="1.0"?&amp;gt;      &lt;br /&gt;&amp;lt;configuration&amp;gt;       &lt;br /&gt;  &amp;lt;appSettings&amp;gt;       &lt;br /&gt;    &amp;lt;add key="Environment.ApiServerUrl" value="&lt;a href="https://api.ebay.com/wsapi&amp;quot;/"&gt;https://api.ebay.com/wsapi"/&lt;/a&gt;&amp;gt;       &lt;br /&gt;    &amp;lt;add key="UserAccount.ApiToken" value="YourBigLongToken"/&amp;gt;       &lt;br /&gt;  &amp;lt;/appSettings&amp;gt;       &lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And then add the code to get the xml list of categories:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;ApiContext apiContext = GetApiContext();&lt;/p&gt;    &lt;p&gt;GetCategoriesCall apiCall = new GetCategoriesCall(apiContext);      &lt;br /&gt;apiCall.CategorySiteID = "0";&lt;/p&gt;    &lt;p&gt;//Leave this commented out to retrieve all category levels (all the way down):      &lt;br /&gt;//apiCall.LevelLimit = 4;&lt;/p&gt;    &lt;p&gt;//Uncomment this to begin at a specific parent category:      &lt;br /&gt;//StringCollection parentCategories = new StringCollection();       &lt;br /&gt;//parentCategories.Add("63");       &lt;br /&gt;//apiCall.CategoryParent = parentCategories;&lt;/p&gt;    &lt;p&gt;apiCall.DetailLevelList.Add(DetailLevelCodeType.ReturnAll);      &lt;br /&gt;CategoryTypeCollection cats = apiCall.GetCategories();&lt;/p&gt;    &lt;p&gt;using (StreamWriter outfile = new StreamWriter(@"C:\Temp\EbayCategories.xml"))      &lt;br /&gt;{       &lt;br /&gt;   outfile.Write(apiCall.SoapResponse);       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;GetApiContext() (provided in the sample apps in the SDK) is required for any call:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;        static ApiContext GetApiContext()      &lt;br /&gt;        {       &lt;br /&gt;            //apiContext is a singleton,       &lt;br /&gt;            //to avoid duplicate configuration reading       &lt;br /&gt;            if (apiContext != null)       &lt;br /&gt;            {       &lt;br /&gt;                return apiContext;       &lt;br /&gt;            }       &lt;br /&gt;            else       &lt;br /&gt;            {       &lt;br /&gt;                apiContext = new ApiContext();&lt;/p&gt;    &lt;p&gt;                //set Api Server Url      &lt;br /&gt;                apiContext.SoapApiServerUrl = ConfigurationManager.AppSettings["Environment.ApiServerUrl"];       &lt;br /&gt;                //set Api Token to access eBay Api Server       &lt;br /&gt;                ApiCredential apiCredential = new ApiCredential();       &lt;br /&gt;                apiCredential.eBayToken = ConfigurationManager.AppSettings["UserAccount.ApiToken"];       &lt;br /&gt;                apiContext.ApiCredential = apiCredential;       &lt;br /&gt;                //set eBay Site target to US       &lt;br /&gt;                apiContext.Site = SiteCodeType.US;&lt;/p&gt;    &lt;p&gt;                return apiContext;      &lt;br /&gt;            }       &lt;br /&gt;        }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Running this will give you a large (4 or 5 megs) XML file that looks something like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;soapenv:Envelope xmlns:xsi="&lt;a href="http://www.w3.org/2001/XMLSchema-instance&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema-instance"&lt;/a&gt; xmlns:xsd="&lt;a href="http://www.w3.org/2001/XMLSchema&amp;quot;"&gt;http://www.w3.org/2001/XMLSchema"&lt;/a&gt; xmlns:soapenv="&lt;a href="http://schemas.xmlsoap.org/soap/envelope/&amp;quot;"&gt;http://schemas.xmlsoap.org/soap/envelope/"&lt;/a&gt;&amp;gt;       &lt;br /&gt;   &amp;lt;soapenv:Body&amp;gt;       &lt;br /&gt;      &amp;lt;GetCategoriesResponse xmlns="urn:ebay:apis:eBLBaseComponents"&amp;gt;       &lt;br /&gt;         &amp;lt;Timestamp&amp;gt;2012-06-06T16:03:46.158Z&amp;lt;/Timestamp&amp;gt;       &lt;br /&gt;         &amp;lt;Ack&amp;gt;Success&amp;lt;/Ack&amp;gt;       &lt;br /&gt;         &amp;lt;CorrelationID&amp;gt;d02dd9e3-295a-4268-9ea5-554eeb2e0e18&amp;lt;/CorrelationID&amp;gt;       &lt;br /&gt;         &amp;lt;Version&amp;gt;775&amp;lt;/Version&amp;gt;       &lt;br /&gt;         &amp;lt;Build&amp;gt;E775_CORE_BUNDLED_14891042_R1&amp;lt;/Build&amp;gt; -       &lt;br /&gt;         &amp;lt;CategoryArray&amp;gt;       &lt;br /&gt;            &amp;lt;Category&amp;gt;       &lt;br /&gt;               &amp;lt;BestOfferEnabled&amp;gt;true&amp;lt;/BestOfferEnabled&amp;gt;       &lt;br /&gt;               &amp;lt;AutoPayEnabled&amp;gt;true&amp;lt;/AutoPayEnabled&amp;gt;       &lt;br /&gt;               &amp;lt;CategoryID&amp;gt;20081&amp;lt;/CategoryID&amp;gt;       &lt;br /&gt;               &amp;lt;CategoryLevel&amp;gt;1&amp;lt;/CategoryLevel&amp;gt;       &lt;br /&gt;               &amp;lt;CategoryName&amp;gt;Antiques&amp;lt;/CategoryName&amp;gt;       &lt;br /&gt;               &amp;lt;CategoryParentID&amp;gt;20081&amp;lt;/CategoryParentID&amp;gt;       &lt;br /&gt;            &amp;lt;/Category&amp;gt;       &lt;br /&gt;            &amp;lt;Category&amp;gt;       &lt;br /&gt;               &amp;lt;BestOfferEnabled&amp;gt;true&amp;lt;/BestOfferEnabled&amp;gt;       &lt;br /&gt;               &amp;lt;AutoPayEnabled&amp;gt;true&amp;lt;/AutoPayEnabled&amp;gt;       &lt;br /&gt;               &amp;lt;CategoryID&amp;gt;37903&amp;lt;/CategoryID&amp;gt;       &lt;br /&gt;               &amp;lt;CategoryLevel&amp;gt;2&amp;lt;/CategoryLevel&amp;gt;       &lt;br /&gt;               &amp;lt;CategoryName&amp;gt;Antiquities&amp;lt;/CategoryName&amp;gt;       &lt;br /&gt;               &amp;lt;CategoryParentID&amp;gt;20081&amp;lt;/CategoryParentID&amp;gt;       &lt;br /&gt;            &amp;lt;/Category&amp;gt;       &lt;br /&gt;(etc.)&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;You could work with this, but I wanted a nicely nested view, like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;lt;CategoryArray&amp;gt;      &lt;br /&gt;   &amp;lt;Category Name='Antiques' ID='20081' Level='1'&amp;gt;       &lt;br /&gt;      &amp;lt;Category Name='Antiquities' ID='37903' Level='2'/&amp;gt;       &lt;br /&gt;&amp;lt;/CategoryArray&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;...so I transformed the xml:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;private void TransformXML(CategoryTypeCollection cats)      &lt;br /&gt;        {       &lt;br /&gt;            XmlElement topLevelElement = null;       &lt;br /&gt;            XmlElement childLevelElement = null;       &lt;br /&gt;            XmlNode parentNode = null;       &lt;br /&gt;            string categoryString = "";&lt;/p&gt;    &lt;p&gt;            XmlDocument returnDoc = new XmlDocument();      &lt;br /&gt;            XmlElement root = returnDoc.CreateElement("CategoryArray");       &lt;br /&gt;            returnDoc.AppendChild(root);&lt;/p&gt;    &lt;p&gt;            XmlNode rootNode = returnDoc.SelectSingleNode("/CategoryArray");&lt;/p&gt;    &lt;p&gt;            //Loop through CategoryTypeCollection      &lt;br /&gt;            foreach (CategoryType category in cats)       &lt;br /&gt;            {       &lt;br /&gt;                if (category.CategoryLevel == 1)       &lt;br /&gt;                {       &lt;br /&gt;                    //Top-level category, so we know we can just add it       &lt;br /&gt;                    topLevelElement = returnDoc.CreateElement("Category");       &lt;br /&gt;                    topLevelElement.SetAttribute("Name", category.CategoryName);       &lt;br /&gt;                    topLevelElement.SetAttribute("ID", category.CategoryID);       &lt;br /&gt;                    rootNode.AppendChild(topLevelElement);       &lt;br /&gt;                }       &lt;br /&gt;                else       &lt;br /&gt;                {       &lt;br /&gt;                    // Level number will determine how many Category nodes we are deep       &lt;br /&gt;                    categoryString = "";       &lt;br /&gt;                    for (int x = 1; x &amp;lt; category.CategoryLevel; x++)       &lt;br /&gt;                    {       &lt;br /&gt;                        categoryString += "/Category";       &lt;br /&gt;                    }       &lt;br /&gt;                    parentNode = returnDoc.SelectSingleNode("/CategoryArray" + categoryString + "[@ID='" + category.CategoryParentID[0] + "']");       &lt;br /&gt;                    childLevelElement = returnDoc.CreateElement("Category");       &lt;br /&gt;                    childLevelElement.SetAttribute("Name", category.CategoryName);       &lt;br /&gt;                    childLevelElement.SetAttribute("ID", category.CategoryID);       &lt;br /&gt;                    parentNode.AppendChild(childLevelElement);       &lt;br /&gt;                }       &lt;br /&gt;            }&lt;/p&gt;    &lt;p&gt;            returnDoc.Save(@"C:\Temp\EbayCategories-Modified.xml");      &lt;br /&gt;        }&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Yes, there are probably much cleaner ways of dealing with it, but I'm not an xml expert…&lt;/p&gt;  &lt;p&gt;Keep in mind, eBay categories do not change on a regular basis, so you should be able to cache this data (either in a file or database) for some time. The xml returns a CategoryVersion node that you can use to determine if the category list has changed.&lt;/p&gt;  &lt;p&gt;Technorati Tags: &lt;a href="http://technorati.com/tag/Csharp" rel="tag"&gt;Csharp&lt;/a&gt;, &lt;a href="http://technorati.com/tag/eBay" rel="tag"&gt;eBay&lt;/a&gt;&lt;/p&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/150049.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/150049.aspx</wfw:comment>
        <slash:comments>2</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/150049.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/150049.aspx</trackback:ping>
    </entry>
    <entry>
        <title>C#&amp;ndash;Using a delegate to raise an event from one class to another</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/06/12/cndashusing-a-delegate-to-raise-an-event-from-one-class.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/06/12/cndashusing-a-delegate-to-raise-an-event-from-one-class.aspx</id>
        <published>2012-06-12T12:32:53-06:00:00</published>
        <updated>2012-06-12T12:32:53Z</updated>
        <content type="html">&lt;p&gt;Even though this may be a relatively common task for many people, I’ve had to show it to enough new developers that I figured I’d immortalize it…&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/awbftdfh.aspx" target="_blank"&gt;MSDN&lt;/a&gt; says “Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers.” Any time you add a button to a Windows Form or Web app, you can subscribe to the OnClick event, and you can also create your own event handlers to pass events between classes. Here I’ll show you how to raise an event from a separate class to a console application (or Windows Form).&lt;/p&gt;  &lt;p&gt;First, create a console app project (you could create a Windows Form, but this is easier for this demo). Add a class file called MyEvent.cs (it doesn’t really need to be a separate file, this is just for clarity) with the following code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;public delegate void MyHandler1(object sender, MyEvent e);&lt;/p&gt;    &lt;p&gt;public class MyEvent : EventArgs      &lt;br /&gt;{       &lt;br /&gt;    public string message;       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Your event can have whatever public properties you like; here we’re just got a single string.&lt;/p&gt;  &lt;p&gt;Next, add a class file called WorkerDLL.cs; this will simulate the class that would be doing all the work in the project. Add the following code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;class WorkerDLL      &lt;br /&gt;{       &lt;br /&gt;    public event MyHandler1 Event1;&lt;/p&gt;    &lt;p&gt;    public WorkerDLL()      &lt;br /&gt;    {       &lt;br /&gt;    }&lt;/p&gt;    &lt;p&gt;    public void DoWork()      &lt;br /&gt;    {       &lt;br /&gt;        FireEvent("From Worker: Step 1");       &lt;br /&gt;        FireEvent("From Worker: Step 5");       &lt;br /&gt;        FireEvent("From Worker: Step 10");       &lt;br /&gt;    }&lt;/p&gt;    &lt;p&gt;    private void FireEvent(string message)      &lt;br /&gt;    {       &lt;br /&gt;        MyEvent e1 = new MyEvent();       &lt;br /&gt;        e1.message = message;&lt;/p&gt;    &lt;p&gt;        if (Event1 != null)      &lt;br /&gt;        {       &lt;br /&gt;            Event1(this, e1);       &lt;br /&gt;        }&lt;/p&gt;    &lt;p&gt;        e1 = null;      &lt;br /&gt;    }       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Notice that the FireEvent method creates an instance of the MyEvent class and passes it to the Event1 handler (which we’ll create in just a second).&lt;/p&gt;  &lt;p&gt;Finally, add the following code to Program.cs:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;static void Main(string[] args)      &lt;br /&gt;{       &lt;br /&gt;    Program p = new Program(args);       &lt;br /&gt;}&lt;/p&gt;    &lt;p&gt;public Program(string[] args)      &lt;br /&gt;{       &lt;br /&gt;    Console.WriteLine("From Console: Creating DLL");       &lt;br /&gt;    WorkerDLL wd = new WorkerDLL();&lt;/p&gt;    &lt;p&gt;    Console.WriteLine("From Console: Wiring up event handler");      &lt;br /&gt;    WireEventHandlers(wd);&lt;/p&gt;    &lt;p&gt;    Console.WriteLine("From Console: Doing the work");      &lt;br /&gt;    wd.DoWork();&lt;/p&gt;    &lt;p&gt;    Console.WriteLine("From Console: Done - press any key to finish.");      &lt;br /&gt;    Console.ReadLine();       &lt;br /&gt;}&lt;/p&gt;    &lt;p&gt;private void WireEventHandlers(WorkerDLL wd)      &lt;br /&gt;{       &lt;br /&gt;    MyHandler1 handler = new MyHandler1(OnHandler1);       &lt;br /&gt;    wd.Event1 += handler;       &lt;br /&gt;}&lt;/p&gt;    &lt;p&gt;public void OnHandler1(object sender, MyEvent e)      &lt;br /&gt;{       &lt;br /&gt;    Console.WriteLine(e.message);       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The OnHandler1 method is called any time the event handler “hears” an event matching the specified signature – you could have it log to a file, write to a database, etc. Run the app in debug mode and you should see output like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/6182a44067ee_9BC9/image_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/6182a44067ee_9BC9/image_thumb.png" width="400" height="114" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;You can distinctly see which lines were written by the console application itself (Program.cs) and which were written by the worker class (WorkerDLL.cs).&lt;/p&gt;  &lt;p&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Csharp" rel="tag"&gt;Csharp&lt;/a&gt;&lt;/p&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/149906.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/149906.aspx</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/149906.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/149906.aspx</trackback:ping>
    </entry>
    <entry>
        <title>Review&amp;ndash;Build Android and iOS apps in Visual Studio with Nomad</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/06/01/reviewndashbuild-android-and-ios-apps-in-visual-studio-with-nomad.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/06/01/reviewndashbuild-android-and-ios-apps-in-visual-studio-with-nomad.aspx</id>
        <published>2012-06-01T12:32:51-06:00:00</published>
        <updated>2012-06-01T12:32:51Z</updated>
        <content type="html">&lt;p&gt;Nomad is a Visual Studio extension that allows you build apps for both Android and iOS platforms in Visual Studio using HTML5. There is no need to switch between .Net, Java and Objective-C to target different platforms - write your code once in HTML5 and build for all common mobile platforms and tablets. You have access to the native hardware functions (such as camera and GPS) through the PhoneGap library, UI libraries such as jQuery mobile allow you to create an impressive UI with minimal work.&lt;/p&gt;  &lt;p&gt;Nomad is still in an early access beta stage, so the documentation is a bit sparse. In fact, the only documentation is a simple series of steps on how to install the plug-in, set up a project, build and deploy it. You're going to want to be a least a little familiar with the PhoneGap library and jQuery mobile to really tap into the power of this.&lt;/p&gt;  &lt;p&gt;The sample project included with the download shows you just how simple it is to create projects in Visual Studio. The sample solution comes with an index.html file containing the HTML5 code, the Cordova (PhoneGap) library, jQuery libraries, and a JQuery style sheet:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_thumb.png" width="350" height="243" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The html file is pretty straightforward. If you haven't experimented with JQuery mobile before, some of the attributes (such as data-role) might be new to you, but some quick Googling will fill in everything you need to know. The first part of the file builds a simple (but attractive) list with some links in it:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_4.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_thumb_1.png" width="693" height="499" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_6.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_thumb_2.png" width="484" height="413" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The second part of the file is where things get interesting and it taps into the PhoneGap library. For instance, it gets the geolocation position by calling position.coords.latitude and position.coords.longitude:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_8.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_thumb_3.png" width="859" height="106" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;...and then displays it in a simple span:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_10.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_thumb_4.png" width="484" height="682" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Building is pretty simple, at least for Android (I'm not an iOS developer so I didn't look at that feature) - just configure the display name, version number, and package ID. There's no need to specify Android version; Nomad supports 2.2 and later. Enter these bits of information, click the new "Build for Android" button (not the regular Visual Studio Build link...) and you get a dialog box saying that your code is being built by their cloud build service (so no building while away from a WiFi signal apparently). After a couple minutes you wind up with a .apk file that can be copied over to your device. Applications built with Nomad for Android currently use a temporary certificate, so you can test the app on your devices but you cannot publish them in the Google Play Store (yet). And I love the "success" dialog box:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_12.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/d5b2b50625da_BB7A/image_thumb_5.png" width="461" height="194" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Since Nomad is still in Beta, no pricing plans have been announced yet, so I'll be curious to see if this becomes a cost-effective solution to mobile app development. If it is, I may even be tempted to spring for the $99 iOS membership fee! In the meantime, I plan to work on porting some of my apps over to it and seeing how they work. My only quibble at this time is the lack of a centralized documentation location - I'd like to at least see which (if any) features of JQuery and PhoneGap are limited or not supported. Also, some notes on targeting different Android screen sizes would be nice, but it's relatively easy to find jQuery examples out on the InterWebs. Oh well, trial and error!&lt;/p&gt;  &lt;p&gt;You can download the Nomad extension for Visual Studio by going to their web site: &lt;a href="http://www.vsnomad.com" target="_blank"&gt;www.vsnomad.com&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Technorati Tags: &lt;a href="http://technorati.com/tag/Android" rel="tag"&gt;Android&lt;/a&gt;, &lt;a href="http://technorati.com/tag/Nomad" rel="tag"&gt;Nomad&lt;/a&gt;&lt;/p&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/149795.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/149795.aspx</wfw:comment>
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/149795.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/149795.aspx</trackback:ping>
    </entry>
    <entry>
        <title>BizTalk&amp;ndash;Mapping a NACHA file using the Flat File Mapping Wizard and preserving header information</title>
        <link rel="self" type="text/html" href="http://geekswithblogs.net/bosuch/archive/2012/04/20/biztalkndashmapping-a-nacha-file-using-the-flat-file-mapping-wizard.aspx" />
        <id>http://geekswithblogs.net/bosuch/archive/2012/04/20/biztalkndashmapping-a-nacha-file-using-the-flat-file-mapping-wizard.aspx</id>
        <published>2012-04-20T14:50:46-06:00:00</published>
        <updated>2012-04-20T14:50:46Z</updated>
        <content type="html">&lt;p&gt;In a previous post I demonstrated &lt;a href="http://geekswithblogs.net/bosuch/archive/2011/04/21/biztalk-using-the-flat-file-mapping-wizard-to-map-a.aspx" target="_blank"&gt;how to use the Flat File Mapping Wizard to map a NACHA financial file&lt;/a&gt;, and at the end I said I’d follow up with a post on setting up the pipeline and preserving the header information. Well, I totally forgot about that until someone asked where the post was, so here it is…&lt;/p&gt;  &lt;p&gt;Begin by creating the three schemas as shown in the previous post. Add a pipeline to the project, and drag the Flat file disassembler component from the toolbox to the Disassemble stage. Right-click on the component and display the Properties, and configure them as follows:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Document schema&lt;/strong&gt;: NACHA_Body &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Header schema&lt;/strong&gt;: NACHA_Header &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Preserve header&lt;/strong&gt;: True &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Trailer schema&lt;/strong&gt;: NACHA_Trailer &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Now, you’d think that setting Preserve header to True means you’d get the header added to each file, right? Nope! It’s merely added to the context collection of each message. You can see this for yourself by deploying the solution, creating a send a receive port (making sure your send port has the proper filter on it, since we’re not using an orchestration yet), stopping the send port, and dropping the test file in. The messages will be suspended, so you can view the FlatFileHeaderDocument context property:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/f168bf280f04_B592/image_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/f168bf280f04_B592/image_thumb.png" width="660" height="70" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;So we need to figure out a way to create a message that has the header attached. The first step will be to create a new schema. Remember, we don’t have a single schema that includes both the header and the body. Create a new schema that has all the elements in both the header and the body schemas. This is just going to be used for regular old xml, so you don’t need to worry about delimiter, positions, etc. Call it NACHA_Full.xsd; it should look something like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/f168bf280f04_B592/image_4.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/f168bf280f04_B592/image_thumb_1.png" width="256" height="497" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Next we’ll create an orchestration that receives the body message, constructs a new header message by extracting the header from the context properties, and maps both of those to our new schema. Create the schema, add the send and receive ports and shapes, then add a Construct Message shape with a Message Assignment shape inside of it, and finally add another Construct Message shape with a Transform inside of it, so you have something like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/f168bf280f04_B592/image_6.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/f168bf280f04_B592/image_thumb_2.png" width="606" height="560" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Now let’s create the messages and variables:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Message: &lt;strong&gt;Body_Input&lt;/strong&gt; – NACHA_Body message type &lt;/li&gt;    &lt;li&gt;Message: &lt;strong&gt;Full_Output&lt;/strong&gt; – NACHA_Full message type &lt;/li&gt;    &lt;li&gt;Message: &lt;strong&gt;Header_Input&lt;/strong&gt; – NACHA_Header message type &lt;/li&gt;    &lt;li&gt;Variable: &lt;strong&gt;HeaderString&lt;/strong&gt; – System.String &lt;/li&gt;    &lt;li&gt;Variable: &lt;strong&gt;HeaderXML&lt;/strong&gt; – System.Xml.XmlDocument &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Now we’ll add the code to generate the Header_Input message. Paste this into the Message Assignment shape:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;//Grab the flat file header into a string variable      &lt;br /&gt;HeaderString = Body_Input(XMLNORM.FlatFileHeaderDocument);&lt;/p&gt;    &lt;p&gt;//Load HeaderString into the XML document      &lt;br /&gt;HeaderXML = new System.Xml.XmlDocument();       &lt;br /&gt;HeaderXML.LoadXml(HeaderString);&lt;/p&gt;    &lt;p&gt;//Assign the XML to the Header message      &lt;br /&gt;Header_Input = HeaderXML;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The last step in the orchestration is to configure the map. Double click the Transform shape and create a new map. This map will have two inputs, so select both Header_Input and Body_Input as the Source, and Full_Output as the destination. Click OK, and the new map should open. Use a Mass Copy to join each record, as shown:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/f168bf280f04_B592/image_10.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://gwb.blob.core.windows.net/bosuch/Windows-Live-Writer/f168bf280f04_B592/image_thumb_4.png" width="747" height="231" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Build and Deploy, configure the Orchestration and test it. If everything works correctly, you should again have two messages, just as in the previous post, but this time they will have the header information included.&lt;/p&gt;  &lt;p&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/BizTalk" rel="tag"&gt;BizTalk&lt;/a&gt;&lt;/p&gt;&lt;img src="http://geekswithblogs.net/bosuch/aggbug/149381.aspx" width="1" height="1" /&gt;</content>
        <wfw:comment>http://geekswithblogs.net/bosuch/comments/149381.aspx</wfw:comment>
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://geekswithblogs.net/bosuch/comments/commentRss/149381.aspx</wfw:commentRss>
        <trackback:ping>http://geekswithblogs.net/bosuch/services/trackbacks/149381.aspx</trackback:ping>
    </entry>
</feed>