I have a set of configuration items I need to persist to a "human readable" file. These items are in a hierarchy:
Device 1
Name
Channel 1
Name
Size
...
Channel N
Name
...
Device M
Name
Channel 1
Each of these item could be stored in a Dictionary with a string Key and a value. They could also be in a structure/DTO.
I don't care about the format of the file as long as it's human readable. It could be XML or it could have something more like INI format
[Header]
Key=value
Key2=value
...
Is there a way to minimize the amount of boiler plate code I would need to write to manage storing/reading configuration items?
Should I just create Data Transfer Objects (DTO)/structures and mark them serializable (Does that generate bloated XML still human readable?)
Is there other suggestions?
Edit: Not that the software has to write as well as read the config. That leaves app.config out.
YAML for .NET
I think both the XmlSerializer and NetDataContractSerializer create human readable XML. I prefer the NetDataContractSerializer because it can do things the XmlSerializer cannot, but those extra features are probably more than you need for this. If you already have classes written for your configurations, one of these two are probably your shortest path to victory.
You could also write your configurations to the local app.config file, or a sub-config file using custom ConfigSections and the Configuration class.
If you serialize your structure to JSON you get a simpler representation of your object than in XML.
Here's a sample from James Netwon-King's JSON.Net site:
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string json = JavaScriptConvert.SerializeObject(product);
//{
// "Name": "Apple",
// "Expiry": new Date(1230422400000),
// "Price": 3.99,
// "Sizes": [
// "Small",
// "Medium",
// "Large"
// ]
//}
Product deserializedProduct = JavaScriptConvert.DeserializeObject<Product>(json);
You can read his blog and download JSON.Net here.
See the FileHelpers library. It's got tons of stuff for reading from and writing to a lot of different formats - and all you have to do is mark up your objects with attributes and call Save(). Sort of like ORM for flat files.
I suspect that what you'll want to use is an app.config file which contains your settings in an XML format that .NET will be able to load in using the System.Configuration namesapce.
More info here: Link
I've generally used the registry for storing configurations (I know, bad me!), but using System.Xml to read/write a lightweight XML file isn't hard. In fact, I've done just that recently for a plugin project that uses XML documents to communicate with its host as well as store its own persistent settings.
There is also the System.Configuration namespace, but I've not really dealt with it.
I'd use a data structure that can be serialized into XML - in fact, since I'm lazy, I'd use an ADO.NET DataSet, since it has a simple serialization format that you can produce without having to think terribly hard.
As far as making it human-readable goes: if it just has to be human-readable (and not human-modifiable, which I think is what you're describing here), I'd build an XSLT transform and use it to produce an HTML version of the configuration data whenever I wrote out the XML. That gives you as fine-grained control over the visual presentation of the data as you could possibly ask for.
My preference in this situation is to create a DataSet with DataTables for the configuration data arranged in a nice relational way - then use DataSet.WriteXML() to save it to a configuration file.
Then to load it again, you just use DataSet.ReadXML() and it's back in a nice query-able object.
This is an example config file that my app allows the user to edit in a Text Editor window:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!--****************************************************************
Config File: FileToExcel_test.cfg
Author: Ron Savage
Date: 06/20/2008
Description:
File to test parsing a file into an Excel workbook.
Modification History:
Date Init Comment
06/20/2008 RS Created.
******************************************************************-->
<!--********************************************************************
Global Key Definitions
********************************************************************-->
<config key="sqlTimeout" value="1800"/>
<config key="emailSMTPServer" value="smtp-server.austin.rr.com"/>
<config key="LogFile" value="FiletoExcel_test_{yyyy}{mm}{hh}.log"/>
<config key="MaxEntries" value="1"/>
<!--********************************************************************
Delimiter Configurations
********************************************************************-->
<config key="pipe" value="|"/>
<!--********************************************************************
Source / Target Entries
********************************************************************-->
<config key="source_1" value="FILE, c:\inetpub\ftproot\filetoexcel.txt, pipe, , , , , "/>
<config key="target_1" value="XLS, REPLACE, c:\inetpub\ftproot\filetoexcel1.xls, , , , , , , ,c:\inetpub\ftproot\filetoexcel_template.xls, ,3"/>
<config key="notify_1" value="store_error, store_success"/>
</configuration>
When I load it into the DataSet, all the non-comment tags reside in a table named Config with fields Key & value. Very easy to search.
Related
I started with the solution here http://social.technet.microsoft.com/wiki/contents/articles/20547.biztalk-server-dynamic-schema-resolver-real-scenario.aspx
which matches my scenario perfectly except for the send port, but that isn't necessary. I need the receive port to choose the file and apply a schema to disassemble. From their the orchestration does the mapping, some of it custom, etc.
I've done everything in the tutorial but I keep getting the following error.
"There was a failure executing the receive pipeline... The body part is NULL"
The things I don't get from the tutorial but don't believe they should be an issue are:
I created a new solution and project to make the custompipeline component (reference figure 19) and thus the dll file. Meaning it is on it's own namespace. However, it looks like from the tutorial they created the project within the main biztalk solution (ie the one with the pipeline and the orchestration) and thus the namespace has "TechNetWiki.SchemaResolver." in it. Should I make the custompipeline component have the namespace of my main solution? I'm assuming this shouldn't matter because I should be able to use this component in other solutions as it is meant to be generic to the business rules that are associated with the biztalk application.
The other piece I don't have is Figure 15 under the "THEN Action" they have it equal the destination schema they would like to disassemble to but then they put #Src1 at the end of "http://TechNetWiki.SchemaResolver.Schemas.SRC1_FF#Src1". What is the #Src1 for?
In the sample you've linked to, the probe method of the pipeline component is pushing the first 4 characters from the filename into a typed message that is then passed into the rules engine. Its those 4 characters that match the "SRC1" in the example.
string srcFileName = pInMsg.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties This link is external to TechNet Wiki. It will open in a new window. ").ToString();
srcFileName = Path.GetFileName(srcFileName);
//Substring the first four digits to take source code to use to call BRE API
string customerCode = srcFileName.Substring(0, 4);
//create an instance of the XML object
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(string.Format(#"<ns0:Root xmlns:ns0='http://TechNetWiki.SchemaResolver.Schemas.SchemaResolverBRE This link is external to TechNet Wiki. It will open in a new window. '>
<SrcCode>{0}</SrcCode>
<MessageType></MessageType>
</ns0:Root>", customerCode));
//retreive source code in case in our cache dictionary
if (cachedSources.ContainsKey(customerCode))
{
messageType = cachedSources[customerCode];
}
else
{
TypedXmlDocument typedXmlDocument = new TypedXmlDocument("TechNetWiki.SchemaResolver.Schemas.SchemaResolverBRE", xmlDoc);
Microsoft.RuleEngine.Policy policy = new Microsoft.RuleEngine.Policy("SchemaResolverPolicy");
policy.Execute(typedXmlDocument);
So the matching rule is based on the 1st 4 characters of the filename. If one isn't matched, the probe returns a false - i.e. unrecognised.
The final part is that the message type is pushed into the returned message - this is made up of the namespace and the root schema node with a # separator - so your #src1 is the root node.
You need to implement IProbeMessage near to class
I forgot to add IProbeMessage in the code of article. It is updated now.
but it is there in sample source code
Src1 is the the root node name of schema. I mentioned that in article that message type is TargetNamespace#Root
I recommend to download the sample code
I hope this will help you
My question is related with the C# implementation of the google protocol buffers (protobuf-csharp-port, by jon skeet, great job!)
I am experiencing troubles with the extensions: let's say I wrote:
"transport_file.proto" with a "transport message" and some code to
deal with it "code_old".
and I wrote an extension of the transport message on
"Mytransport.proto" file, and new code to read it "code_new".
I'm trying to read a new message (from MyTransport.proto) with the code_old expecting to ignore the extension, but I get an exception in the merge method from TextFormat: "transport" has no field named "whatever_new_field"
Transport.Builder myAppConfigB = new Transport.Builder();
System.IO.StreamReader fich = System.IO.File.OpenText("protocolBus.App.cfg");
TextFormat.Merge(fich.ReadToEnd(),myAppConfigB);
fich.Close();
new extended file looks like:
...
Transport
{
TransportName: "K6Server_0"
DllImport: "protocolBus.Transports.CentralServer"
TransportClass: "K6Server"
K6ServerParams
{
K6Server { host: "85.51.11.23" port: 40069 }
Service: "TZinTalk"
...
}
}
...
while the old one, not extended:
...
Transport
{
TransportName: "K6Server_0"
DllImport: "Default"
TransportClass: "Multicast"
}
...
The whole idea is to use the text based protocol buffer as a config file in which I write some params, and based on one of those I load and assembly (which will read the whole message with the new extension (params to initialize the object).
Any idea? (it is a desperate question :D )
I'm using MSVC# 2008Express edition, protobuf-csharp-port version 0.9.1 (someday I'll upgrade everything).
THANKS in advance.
I'm working on a non centrilized Publish-Subscribe framework of messages (for any written message in a proto file I auto create a Publish and a Subscriber class) with different transports. By the default I use multicast, but broadcast and a "UDP star" are also included. I let the extension mechanism to let people add new transports with its owm config params that should be read by my main code_old (just to load the assembly) and let the new transport (.dll) read it again (fully).
Curious? the previous, almost functional, version is in http://protocolbus.casessite.org
Update 1
Extended types in text format are enclosed in brackets (good to know, I was not aware of it :D ) so I should have written:
[K6ServerParams]
{
K6Server { host: "85.51.11.23" port: 40069 }
Service: "TZinTalk"
...
}
Protocol buffers are designed to be backwards and forwards compatible when using their binary format, but certainly the current code doesn't expect to parse the text format with unknown fields. It could potentially be changed to do that, but I'd want to check with the Java code to try to retain parity with that.
Is there any reason you're not using the binary representation to start with? That's the normal intended usage, and the one where the vast majority of the work has gone in. (Having said which, it all seems a bit of a blur after this long away from the code...)
I am using WorkflowMarkupSerializer to save a statemachine workflow - it saves the states OK, but does not keep their positions. The code to write the workflow is here:
using (XmlWriter xmlWriter = XmlWriter.Create(fileName))
{
WorkflowMarkupSerializer markupSerializer
= new WorkflowMarkupSerializer();
markupSerializer.Serialize(xmlWriter, workflow);
}
The code to read the workflow is:
DesignerSerializationManager dsm
= new DesignerSerializationManager();
using (dsm.CreateSession())
{
using (XmlReader xmlReader
= XmlReader.Create(fileName))
{
//deserialize the workflow from the XmlReader
WorkflowMarkupSerializer markupSerializer
= new WorkflowMarkupSerializer();
workflow = markupSerializer.Deserialize(
dsm, xmlReader) as Activity;
if (dsm.Errors.Count > 0)
{
WorkflowMarkupSerializationException error
= dsm.Errors[0]
as WorkflowMarkupSerializationException;
throw error;
}
}
}
Open Control Panel -> "Regional and language options" and set list separator to ',' (comma)
and workflow serializer will use ',' (comma) as separator for X,Y coordinates for struct SizeF
then select ';' and workflow serializer will use ';' (semicolon) as separator.
This really stupid that serializer use regional setting for serialize markup.
The position of all the states is kept in a separate file. You'll need to drag it around with the markup of the workflow itself. Luckily, it's just XML as well, so you might be able to reuse most of the code you have up there. If memory serves, I believe it's simply NameOfYourWorkflow.layout.
I agree with x0n - the designer is really bad in Visual Studio.
OK, this tutorial gives good information on how to do it - although so far I am only able to save the layout, I haven't been able to correctly use the layout. The information in question is about 2/3rds down (or just do a search for .layout)
(How does one close his own question?)
Note that there is a bug in either the serialize or deserialize of the XML created (named in the example with an extension of .layout.)
It produces the following xml as the first line of the file:
<?xml version="1.0" encoding="utf-8"?><StateMachineWorkflowDesigner xmlns:ns0="clr-namespace:System.Drawing;Assembly=System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Name="New" Location="30, 30" Size="519, 587" AutoSizeMargin="16, 24" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
When reading this back in, the size attribute causes an exception. I removed Size="519, 587" from the file and the workflow is loaded back correctly. Right now, I write the file, open it and remove the size, then close it. I need to think about a more elegant solution, but at least I am now saving and restoring a state machine workflow.
Hah, even the workflow designer hosted in Visual Studio 2008 loses the positions of states randomly. This tells me it's probably not an easy task, and is information external to the Activities that comprise it. I'd dig more around the host for information; if I find something, I'll post back.
I was wondering: is there a way to create HTML files programmatically in C# as you can do with XML? Mine is a console application, so maybe some of the options are not available. Basically, I would like to do something smarter than just building a big string.
Possible scenario:
Instead of writing:
string html="<html><head>Blah</head><body>{0}</html>", myotherstring
I would like to work as in XML
XmlTextWriter w = new XmlTextWriter(xml_file_path + xml_file_name,
System.Text.Encoding.UTF8);
w.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
// construct xml
XmlElement root = xmlDoc.CreateElement("element");
...
xmlDoc.Save(w);
w.Close();
Apologies for the naive question.
Don't forget: You can generate XHTML just as easily as plain XML using the XmlTextWriter approach.
You could use NVelocity. It is a .Net port of the Java Velocity templating system. The API will not be similar to XmlWriter. Instead, you'll write a text file in a simple scripting language, put your objects into a 'context' and then merge the template and the context to generate the HTML file.
NVelocity
You could use some third party open-source libraries to generated strong typed verified (X)HTML, such as CityLizard Framework or Sharp DOM.
For example
html
[head
[title["Title of the page"]]
[meta_(
content: "text/html;charset=UTF-8",
http_equiv: "Content-Type")
]
[link_(href: "css/style.css", rel: "stylesheet", type: "text/css")]
[script_(type: "text/javascript", src: "/JavaScript/jquery-1.4.2.min.js")]
]
[body
[div
[h1["Test Form to Test"]]
[form_(action: "post", id: "Form1")
[div
[label["Parameter"]]
[input_(type: "text", value: "Enter value")]
[input_(type: "submit", value: "Submit!")]
]
]
[div
[p["Textual description of the footer"]]
[a_(href: "http://google.com/")
[span["You can find us here"]]
]
[div["Another nested container"]]
]
]
];
I realise that this question is old, however the recent release of the ASP.Net MVC 3 Razor view engine now gives you the option to use this same Razor view engine to generate HTML for any purpose.
See Hosting Razor outside of ASP.Net for a guide on how to do this.
What I did a few months back, I had an asp.net file (aspx) saved as a template in a text file, whenever the user needed a new page, I would just copy that template into the user specified folder, change the extension .txt to .aspx, and programmatically add a few options depending on the user's needs. It was a simple page though. Of course, the more complex you go, the more complex the code will be.
I’m after some C# code that will have the following methods that will return Xml as the result.
Search the Apple iTunes App store. If I pass it a name or partial name the function must return a list of possible search results or just one result if it is a perfect match.
Example shown below:
<App>
<AppId>321564880</AppId>
<Name>Doodle Clock - Clock A Doodle Do!</Name>
<ReleaseDate>Released Sep 28, 2009</ReleaseDate>
<Artist>YARG</Artist>
<Description>Description of App</Description>
<Copyright>© YARG Limited 2009</Copyright>
<Price>$0.99</Price>
<Category>Lifestyle</Category>
<MainImageUrl><!—main App icon image urlà </ImageUrl>
<ExtraImages>
<!-- these will be the extra images you see in the App store other than the main application icon -->
<ImageUrl> <!—url of extra image 1à</ImageUrl>
<ImageUrl> <!—url of extra image 2à</ImageUrl>
<ImageUrl> <!—url of extra image 3à</ImageUrl>
</ExtraImages>
<Version>Version: 1.1 (iPhone OS 3.0 Tested)</Version>
<Size>1.5 MB</Size>
</App>
Okay the best way to create xml file and parse and manipulate them is using XDocument,XElement,etc. Because they are enumerable which means you can use LINQ on them and that will help you a lot.
For example :
XElement element = new XElement("Persons",
new XElement("Person","John",
new XAttribute("Id","1")),
new XElement("Person","Aaron",
new XAttribute("Id",2))
)
returns
<Persons>
<Person Id="1">John</Person>
<Person Id="2">Aaron</Person>
</Person>
More information : System.Xml.Linq Namespace
If you are looking for speed, then you can use XMLReader and XMLWriter but you can't find the flexibility that System.Xml.Linq provides.
You should use XPath in .NET:
http://www.aspfree.com/c/a/.NET/Working-with-XPath-The-NET-Way/
I would use XmlTextReader. It's the fastest way (though read-forward-only) - if you are maybe looking for speed. If not, XPath should do.