|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionA popular pattern for application design and development is to use offline files to persist configuration information so that downstream users can modify certain properties associated with an application without requiring rebuild activities like SDLC. When I was a Java Architect for Sun MicroSystems, the Properties file was the prescribed approach to do this. Although it offered some flexibility, it certainly was not ideal for many situations, especially those requiring hierarchical structures. With the advent of .NET, Microsoft opted for the much more robust and powerful extensible markup language as the underlying mechanism for storage of the offline configuration parameters. This works out great. XML is a perfect solution for such scenarios. It’s relatively simple to implement, fast, yet manages to be very powerful, extensible, and flexible. As great as XML is however, there are some shortcomings. In the case where the configuration file is a custom one defined outside the realm of the canned configuration files like app.config or web.config by Microsoft, the problem of schema validation and synchronization can be an added headache, especially since they are generally an unnecessary effort. What I mean is, these tasks have nothing to do with the actual configuration of the application but tend to be thought about a lot. In the case of the canned config files, there is a general lack of intuitive comprehension to the config file formats. One simply has to know how to configure a WCF service for instance. There is no notion of being able to intuitively configure one from scratch without knowledge of the spelling and casing of every word/character typed. I must admit that you are helped along in many regards with the intellisense engine which seems to be built atop of schema specifications, but I found that for the canned config files it was still not adequate, and for the custom ones I didn't want to have to write a schema for my configuration. BackgroundNow with the advent of .NET 3.0 comes the concept of XAML. Much more than just a presentational DSL, XAML is in fact a powerful notation for describing the runtime state of objects using XML. In some cases, it is the functional equivalent to describing this runtime behavior using, say, C# of VB or whatever language of choice you desire. Because of its very general approach to describing objects, XAML is used not just for presentational description (WPF) but also for describing workflows (WF). The last thing that gives XAML its amazing power is the fact that Microsoft introduced with it a framework for dynamically loading it on the fly! What does this mean to the average man? It means that pure XAML does not have to be compiled to work; it can be read in at runtime and still generate the appropriate object graphs. Think how JavaScript can be used to produce powerful and dynamic runtime behavior like json because of the The ProcessWithout the cloud of WPF or WF to confuse us, most people would agree that XAML by itself is a very simple mechanism for representing objects. Indeed ANY accessible class can be represented in object form as XAML. Here is the representation of a .NET <String xmlns=""clr-namespace:System;assembly=mscorlib"" >hello world</String>
Reading this value into your application involves three simple things. First, the application must reference presentationcore and presentationframework. This is a minor setback that I'm sure someone will rectify at some point. Secondly, now that we have access to string xaml = @"<string assembly=""mscorlib"" >
<String xmlns=""clr-namespace:System;assembly=mscorlib"" >
hello world</String></string >";
byte[] xaml_data = System.Text.Encoding.ASCII.GetBytes(xaml);
System.IO.MemoryStream xaml_stream = new System.IO.MemoryStream(xaml_data);
string xaml_object = (string)System.Windows.Markup.XamlReader.Load(xaml_stream);
Console.WriteLine(xaml_object);
Be sure to use the double quote notation if you are going to use a verbatim The resulting code is listed below: using (FileStream xaml_stream = File.OpenRead("config.xaml"))
{
string xaml_object = (string)System.Windows.Markup.XamlReader.Load(xaml_stream);
Console.WriteLine(xaml_object);
}
Now that we've successfully illustrated that we can indeed read types in from an external XAML file and process it within a host application, the next step is to create an actual configuration file rather than use built-in .NET types. In the old days of simple XML config files, you designed your schema (or just started slinging XML) and then built a dedicated type that knew how to read that schema and that was that. I believe it somewhat evolved to using the XML serializer to essentially represent pre-defined types in XML form. This approach is relatively similar to that, but focuses more on the XML (XAML) than on the actual classes behind them. More importantly though, XAML offers a far more flexible and robust mechanism for describing objects than the XML serializer generated XML does. namespace MindFactorial.LaunchPoint.Runtime
{
[Serializable]
public class LaunchPointConfiguration
{
public bool LaunchInDefaultContext { get; set; }
public LaunchPointApp Application { get; set; }
public PluginConfigList Plugins { get; set; }
public override string ToString()
{
string xml = XamlWriter.Save(this);
return xml;
}
}
[Serializable]
public class LaunchPointApp
{
public string Path { get; set; }
public string Name { get; set; }
public string RunnableTypeName { get; set; }
}
[Serializable]
public class PluginConfig
{
public string Name { get; set; }
public string Path { get; set; }
public string Label { get; set; }
}
[Serializable]
public class PluginConfigList : List
The <LaunchPointConfiguration
xmlns="clr-namespace:MindFactorial.LaunchPoint.Runtime;
assembly=MindFactorial.LaunchPoint.Runtime"
>
<LaunchPointConfiguration.Application>
<LaunchPointApp>
<LaunchPointApp.Name>Console</LaunchPointApp.Name>
<LaunchPointApp.Path>MindFactorial.LaunchPoint.Console.dll</LaunchPointApp.Path>
<LaunchPointApp.RunnableTypeName>MindFactorial</LaunchPointApp.RunnableTypeName>
</LaunchPointApp>
</LaunchPointConfiguration.Application>
<LaunchPointConfiguration.Plugins>
<PluginConfigList>
<PluginConfig>
<PluginConfig.Name>one</PluginConfig.Name>
<PluginConfig.Label>first plugin</PluginConfig.Label>
<PluginConfig.Path>debug\generalsettings.plugin.dll</PluginConfig.Path>
</PluginConfig>
</PluginConfigList>
</LaunchPointConfiguration.Plugins>
</LaunchPointConfiguration>
As you can see from the History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||