Updated IPBlog

Saturday, November 27, 2004 12:00:00 AM (Central Standard Time, UTC-06:00)
Updated the InfoPath form to pull the categories for the post. Here is what you will need to do:
 
  1. Open IPBlogV2.xsn in design view.
  2. Select Tools -> Data Connections
  3. Select GetCategories, Click Modify.
  4. Enter the url to the InfoPathService.asmx file on your web dasBlog website, click next.
  5. Select "GetCategores", click next.
  6. Complete the remaining dialogs using the defaults.
  7. You should be ready to open the IPBlogV2.xsn and complete your first post.
 
You can find the new download for IPBlogV2.xsn below.  If you need the entire code base you can get it here.

IPBlogv2.zip

InfoPath Blog (IPBlog) Editor for dasBlog

Thursday, November 25, 2004 12:00:00 AM (Central Standard Time, UTC-06:00)
This version of IPBlog editor is a little more extensive then the original version I wrote back in November 2003.  I have to admit I am impressed with the changes they made to in Office 2003 Service Pack 1 for InfoPath. Some of those changes included the ability to handle file attachments, defaulting date values without using javascript and better integration with managed code.
 
This release of the IPBlog editor for dasBlog took advantage of updates in SP1 and added some additional functionality that wasn't there in the first version.
 
The improvements include:
  • New Web Service to support entries hosted in dasBlog.
  • Ability to attach files to the post.
  • Ability to include graphics in-line with text and have them published as part of the post.
  • Post to a specific category.  Unfortunately right now you have to know the categories as it is textbox for posting, but I will follow it up with the ability to select the categories you want to post to through a list box or a grouping of check boxes.
 
You can download the zip of the project at the bottom of the post.  I included binaries and source for the IPBlog service.  It was compiled against version 1.6.4121.1 of dasBlog.
 
Quick Start
  1. Copy the InfoPathService.asmx to the root of your dasBlog site.
  2. Copy Sysknowlogy.dasBlog.dll and newtelligence.DasBlog.Web.dll to your bin directory.
  3. Configure the IPBlog.xsn to post to the url of the InfoPathService.asmx:
    1. Open IPBlog.xsn in design view.
    2. Select Tools -> Data Connections
    3. Select Submit, Click Modify.
    4. Enter the url to the InfoPathService.asmx file on your web dasBlog website, click next.
    5. Select "Create Entry", click next.
    1. Make sure the Field or group option is selected, and enter the root node /my:InfoPathEntry as the selected parameter, click next.
    2. Complete the remaining dialogs using the defaults.
    3. You should be ready to open the IPBlog.xsn and complete your first post.

IPBlog.zip

Contract First Web Service Development

Thursday, November 18, 2004 12:00:00 AM (Central Standard Time, UTC-06:00)
I have a heard a lot of buzz about contract first development as of late.  I first heard about it from Ed Ferron and Matt Milner after they returned from their PluralSight training in the beginning of November.
 
Aaron Skonnard and Don Box have brought it up in their blogs.
 
I Googled it and found a reference to it on MSDN that was published late October.  It that was co-authored by James Duff, Eric Cherng both of Vertigo Software (the folks that brought us PetShop) and Dino Chiesa of Microsoft.
 
The concept of Contract First development comes down to taking more control over how the .NET Framework handles the creation of your web service contract (WSDL) that clients consume.  If you don't need the control, then you don't need to take on the additional complexity of hand modifying your WSDL.  As many have mentioned, the tool sets for creating WSDL are not there yet.
 
So when do you need that control?  Interop with other platforms seems to be the most popular instance, as the fidelity of data types my not translate well into other platforms.  By taking control of the contract, you can describe in more detail how to represent a type that may not have a direct equivalent in another platform. 
 
Another instance is working in BizTalk, which requires the schema of messages to be defined first.  I just finished a SOA project that included BizTalk as a component of the implementation.  We did a type of Contract First development, but not exactly the way it is described in the MSDN article.  We designed the way we wanted our messages to look by laying them out in xml.  Then converted them to a type, and from the type created our schemas which then was consumed by BizTalk and our web services.  The MSDN article suggests having the Xml Web Services framework  generate the wsdl for you, then modify the wsdl to meet the needs of interop and generate the types from that.
 
One of the things we really struggled with was getting the xsd.exe to produce the class structures we wanted.  We ended up abandoning the tool pretty early, looked at alternatives (Dingo, XsdTidy, SchemaTron, and modifying the xsd.exe source), but ended up writing an implementation that would take an xml document and create the class structure, gets/sets for properties and strongly typed collections we were looking for.
 
The folks at thinktecure have created an IDE add-in (WsContractFirst) that takes a wsdl and creates the proxy and server side classes based on your modified wsdl contract.

Basic Assembly Configuration

Sunday, November 14, 2004 12:00:00 AM (Central Standard Time, UTC-06:00)
Here is simple implementation that supports a configuration file for an assembly.  I say simple because it only takes in account the configuration for the dll, it does not include the app, machine or other configs that make up the configuration of an application.
 
The AssemblyConfiguration class by default requires the dll that contains the AssemblyConfiguration and the dll that you want to support configuration are in the same directory.  You can override the behavior by using the constructor that takes the path to the assembly and a reference to the assembly. 
 
    1 using System;
    2 using System.Configuration;
    3 using System.Reflection;
    4 using System.Xml;
    5 using System.Windows.Forms;
    6  
    7  
    8 using TidByte.Activation;
    9  
   10  
   11 namespace TidByte.Configuration
   12 {
   13     /// <summary>
   14     /// Supports the loading of a configuration file for a .dll
   15     /// </summary>
   16     public class AssemblyConfiguration
   17     {
   18         string        _cfgFile = string.Empty;
   19         XmlDocument    _doc = null;
   20         string        _appPath = string.Empty;
   21  
   22         /// <summary>
   23         /// Default constructor that assumes that the the TidByte.Configuration dll is located in the same directory as the
   24         /// .dll that requires the AssemblyConfiguration implementation.  If you need to override this behavior, you will need to
   25         /// use the constructor that supports the identification of a path of where the dll that required configuration is located.
   26         /// </summary>
   27         public AssemblyConfiguration() : this (AppDomain.CurrentDomain.BaseDirectory, Assembly.GetCallingAssembly()) {    }
   28  
   29         /// <summary>
   30         /// Supports identifying the path of the assembly that requires configuration.  Defaults to the calling assembly as the assembly
   31         /// that requires configuration.
   32         /// </summary>
   33         /// <param name="appPath">Path to assembly to requires identification</param>
   34         public AssemblyConfiguration(string appPath) : this (appPath, Assembly.GetCallingAssembly()) {    }
   35  
   36         /// <summary>
   37         /// Supply the path, and assembly that requires configuration.
   38         /// </summary>
   39         /// <param name="appPath"></param>
   40         /// <param name="asm"></param>
   41         public AssemblyConfiguration(string appPath, Assembly asm)
   42         {
   43             //set the dll config file name
   44             _cfgFile = asm.CodeBase + ".config";
   45  
   46             //load it into the DOM
   47             _doc = new XmlDocument();
   48             _doc.Load(new XmlTextReader(_cfgFile));
   49  
   50             _appPath = appPath;
   51  
   52         }
   53  
   54  
   55         /// <summary>
   56         /// Returns the configuration according to the configSection defined in the config file
   57         /// </summary>
   58         /// <param name="section">Section of the config file that supports the configuration settings.</param>
   59         /// <returns></returns>
   60         public object GetConfig(string section)
   61         {
   62             //gets the config section that is requested
   63             XmlNode sectionNode = _doc["configuration"]["configSections"].SelectSingleNode("./section[@name='" + section + "']");
   64  
   65             if (sectionNode != null)
   66             {
   67                 //get the type of the object to create
   68                 string typeDef = sectionNode.Attributes["type"].Value;
   69                 IConfigurationSectionHandler cfgHandler = (IConfigurationSectionHandler)ActivationHelper.ActivateFromPath(typeDef, _appPath);
   70  
   71                 XmlNode sectionXml = _doc["configuration"].SelectSingleNode("./" + section);
   72  
   73                 //Call the interface
   74                 return cfgHandler.Create(sectionNode.ParentNode,null,sectionXml);
   75  
   76             }
   77  
   78             return null;
   79         }
   80  
   81     }
   82 }
 
The next code snippet shows the implementation for how the ActivationHelper works:
    1 using System;
    2 using System.Reflection;
    3 using System.Windows.Forms;
    4  
    5 namespace TidByte.Activation
    6 {
    7     /// <summary>
    8     /// Summary description for ActivationHelper.
    9     /// </summary>
   10     public class ActivationHelper
   11     {
   12         const int AssemblyName    = 1;
   13         const int ClassName        = 0;
   14  
   15         //default constructor
   16         public ActivationHelper() {}
   17  
   18         /// <summary>
   19         /// Private helper function to assist in run-time activations. Returns
   20         /// an object from the specified assembly and type.
   21         /// </summary>
   22         /// <param name="assembly">Name of the assembly file (w/out extension)</param>
   23         /// <param name="typeName">Name of the type to create (namespace must be included)</param>
   24         /// <returns>Instance of the type specified in the input parameters.</returns>
   25         public static object Activate(string assembly, string typeName)
   26         {
   27             try
   28             {
   29            
   30                 return AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assembly, typeName);
   31             }
   32             catch( Exception ex)
   33             {
   34                 throw ex;
   35             }
   36         }
   37  
   38         /// <summary>
   39         /// Private helper function to assist in run-time activations. Returns
   40         /// an object from the specified assembly and type, as defined in a standard config
   41         /// </summary>
   42         /// <param name="arArgs"> namespace.class (comma seperated),assembly filename</param>
   43         /// <returns>Instance of the type specified in the input parameters.</returns>
   44         public static object Activate(string assm)
   45         {
   46            
   47             string[] arArgs = assm.Split(new char[]{','});
   48             string assmname = arArgs[AssemblyName].Trim();
   49             string clsname = arArgs[ClassName].Trim();
   50                    
   51  
   52             //Dynamically load the deployment handler from the config file
   53             return Activate(assmname, clsname);
   54  
   55         }
   56  
   57         /// <summary>
   58         /// Activate a specific assembly from a specified path
   59         /// </summary>
   60         /// <param name="assm"></param>
   61         /// <param name="path"></param>
   62         /// <returns></returns>
   63         public static object ActivateFromPath(string assm, string path)
   64         {
   65  
   66            
   67             string[] arArgs = assm.Split(new char[]{','});
   68             string assmname = arArgs[AssemblyName].Trim();
   69             string clsname = arArgs[ClassName].Trim();
   70  
   71             Assembly lib = Assembly.LoadFrom(path + assmname + ".dll");
   72  
   73             return lib.CreateInstance(clsname);
   74         }
   75     }
   76 }
 
And last I am using a modified version of Craig Andreas "The last configuration handler I'll ever need". 
 
    1 using System;
    2 using System.Reflection;
    3 using System.IO;
    4 using System.Configuration;
    5 using System.Xml;
    6 using System.Xml.Serialization;
    7 using System.Xml.XPath;
    8 using System.Windows.Forms;
    9  
   10  
   11 using TidByte.Activation;
   12  
   13 namespace TidByte.Configuration
   14 {
   15  
   16     /*
   17     * When you map a section of your configuration file to this handler, using an entry in your config file that looks like this:
   18  
   19         <configuration>
   20             <configSections>
   21                 <section name="MyStuff" type="<Namespace>.XmlSerializerSectionHandler, Exe/DllName"/>
   22             </configSections>
   23         </configuration>
   24        
   25         What happens is that any time you ask for the MyStuff section of the config file with code that looks like this:
   26         AppConfig.GetTypeSafeConfig("MyStuff");
   27  
   28         It will actually go look in the config file to figure out who knows how to deal with the “MyStuff” section.
   29         When it sees that it’s the XmlSerializerSectionHandler, it’ll create an instance of this object and call Create,
   30         passing it (via the section parameter) a reference to the relevant portion of the config file. In our case, it might look something like this:
   31             <configuration>
   32                 <!-- configSections element goes here -->
   33                 <MyStuff type="SomeNamespace.MyStuff, CraigsConfig">
   34                     <Foo>1.234</Foo>
   35                     <Bar>A bunch of information</Bar>
   36                 </MyStuff>
   37             </configuration>
   38  
   39         What my handler does is to look for the “type” attribute on this bit of XML, in the form “classname, assemblyname”.
   40         In this case, it’s a class called MyStuff in a namespace SomeNamespace. It then – and here’s the good bit –
   41         uses the XmlSerializer to initialize an instance of this type from the XML in the configuration file.
   42         The XmlSerializer is a very cool piece of the .NET libraries, and you should check it out if you haven’t already.
   43         Basically, you write a type like this:
   44  
   45             public class MyStuff
   46             {
   47                 private float foo;
   48                 private string bar;
   49  
   50                 public float Foo
   51                 {
   52                     get { return foo; }
   53                     set { foo = value; }
   54                 }
   55  
   56                 public string Bar
   57                 {
   58                     get { return bar; }
   59                     set { bar = value;
   60                 }
   61             }
   62  
   63         And the XmlSerializer takes care of turning it into the XML above and vice versa. There are even a bunch of
   64         attributes you can use to control the process.
   65        
   66         [XmlRoot("RootElemenet")]                - allows the naming of a root element
   67         [XmlElement("FileName")]                - overrides a property name
   68         [XmlAttribute("FileName")]                - stores a property as an attribute
   69         [XmlArray("CollectionName")]            - assigns a collection a name
   70         [XmlArrayItem("CollectionChildName")]    - assigns the children of the collection a name
   71  
   72         Calling:
   73  
   74         MyStuff ms = (MyStuff) AppConfigEx.GetTypeSafeConfig("MyStuff");
   75     */
   76  
   77     public class XmlSerializerSectionHandler :    IConfigurationSectionHandler
   78     {
   79         public object Create(
   80             object parent,
   81             object configContext,
   82             System.Xml.XmlNode section)
   83         {
   84             try
   85             {
   86                 //get the type that we need to create to support the configuration
   87                 XPathNavigator nav = section.CreateNavigator();
   88                 string typename = (string) nav.Evaluate("string(@type)");
   89  
   90                 //Get the location of this dll. We assume that all dll's loaded through the config are installed to a private
   91                 FileInfo fi = new FileInfo(Assembly.GetExecutingAssembly().Location);
   92                 Type t = ActivationHelper.ActivateFromPath(typename, fi.DirectoryName + @"\").GetType();
   93                 XmlSerializer ser = new XmlSerializer(t);
   94  
   95  
   96                 //xpath will select all nodes below the parent and use those to create the type;
   97                 return ser.Deserialize(new XmlNodeReader(section.SelectSingleNode("*")));
   98                
   99             }
  100             catch (Exception ex)
  101             {
  102                 Console.WriteLine(ex.ToString());
  103                 throw ex;
  104             }
  105         }
  106  
  107     }
  108  
  109 }