Andrei Rinea

.NET Framework & SQL Server

A useful Custom Configuration Section for inline unconstrained XML

clock September 21, 2009 00:05 by author Andrei Rinea

As I was writing a small TCP server for serving Silverlight local TCP policy I came across a certain need. Inspired by Dan Wahlin's server implementation I chose to write a simplified version for myself. I needed to keep some XML in App.config without constraining it with a schema.

The normal solution in this case is a custom section, sibling to appSettings if you wish. So my App.Config looked at first like this :

<configuration>

  <
appSettings
>
    <
add key="ipAddress" value="127.0.0.1"
/>
  </
appSettings
>

  <
access-policy
>
    <
cross-domain-access
>
      <
policy
>
        <
allow-from
>
          <
domain uri="*"
/>
        </
allow-from
>
        <
grant-to
>
          <
socket-resource port="4502" protocol="tcp"
/>
        </
grant-to
>
      </
policy
>
    </
cross-domain-access
>
  </
access-policy
>

</
configuration>

Upon running the program even addressing the "ipAddress" key in the appSettings section throws an exception like:

System.Configuration.ConfigurationErrorsException was unhandled
  Message="Configuration system failed to initialize"
  Source="System.Configuration"
  BareMessage="Configuration system failed to initialize"
  Line=0
  StackTrace:
       at System.Configuration.ConfigurationManager.PrepareConfigSystem()
       at System.Configuration.ConfigurationManager.GetSection(String sectionName)
       at System.Configuration.ConfigurationManager.get_AppSettings()
       at ConsoleApplication1.Program.Main(String[] args) in C:\Users\Andrei\Documents\Visual Studio 2008\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs:line 21
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.Configuration.ConfigurationErrorsException
       Message="Unrecognized configuration section access-policy. (C:\\Users\\Andrei\\Documents\\Visual Studio 2008\\Projects\\ConsoleApplication1\\ConsoleApplication1\\bin\\Debug\\ConsoleApplication1.vshost.exe.config line 8)"
       Source="System.Configuration"
       BareMessage="Unrecognized configuration section access-policy."
       Filename="C:\\Users\\Andrei\\Documents\\Visual Studio 2008\\Projects\\ConsoleApplication1\\ConsoleApplication1\\bin\\Debug\\ConsoleApplication1.vshost.exe.config"
       Line=8
       StackTrace:
            at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignoreLocal)
            at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors schemaErrors)
            at System.Configuration.BaseConfigurationRecord.ThrowIfInitErrors()
            at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)
       InnerException:

So something is wrong. We need to tell the runtime that the "access-policy" section is allowed.

<configuration>
  <
configSections
>
    <
section name="access-policy" type="CustomSections.InlineXmlSection, CustomSections"
/>
  </
configSections
>
...

At first I haven't placed the type attribute in the "section" element but it turned out it had to specified and be not empty. Moreover it must containt the fully-qualified class name and the assembly which contains it. The class must inherit from System.Configuration.ConfigurationSection.

So I created an assembly called CustomSections, added references to the System.Configuration assembly and the System.Xml assembly.

All you need to do is override the DeserializeSection method and load the XML document in there :

using System.Configuration;
using
System.Xml;

namespace
CustomSections
{
  public class InlineXmlSection :
ConfigurationSection
  {
    public XmlDocument Content { get; private set
; }

    protected override void DeserializeSection(XmlReader
reader)
    {
      (
this.Content = new XmlDocument
()).Load(reader);
    }
  }
}

The code is pretty self-explanatory : we instantiate a new XmlDocument and load it from the XmlReader provided to us by the configuration infrastructure. If anything goes bad the exception handling will be the responsability of the caller. In this case the first call to ConfigurationManager.

Now let's put the code to use :

private static void Main(string[] args)
{
  expectedRequestBytes =
Encoding.UTF8.GetBytes("<policy-file-request/>"
);
  listener =
new TcpListener(IPAddress.Parse(ConfigurationManager.AppSettings["ipAddress"
]), 943);
  var policySection = (InlineXmlSection)ConfigurationManager.GetSection("access-policy"
);
  policyBytes =
Encoding
.UTF8.GetBytes(policySection.Content.OuterXml);
  ...

The underlined code is the relevant portion (the rest is provided for context). We get the section via ConfigurationManager.GetSection and we have to cast the result to the desired section type. The we use the section as we see fit.

I will use this code sample in a future blog post regarding writing a very small TCP server for serving Silverlight 943 TCP Port policy XML content. Hope you find this useful.

Currently rated 1.0 by 1 people

  • Currently 1/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Using ADO.NET Data Servics in Silverlight 3 and eager loading parent entities

clock August 19, 2009 09:57 by author Andrei Rinea

We decided that in our Silverlight app that we develop we should not waste time writing WCF services manually to interact with data. So we turned to ADO.NET Data Services.  

I created a small Web App to host the ADO.NET Data Service which exposed the Entity Framework Model. All fine and dandy, being a bit pedant I created a very small console application just to add a service reference and test the data retrieval. All went well. Then I put the querying logic in the Silverlight app.

Something like

var employees = (from e in GetFreshContext().Employees select e).ToArray();

But upon running in Silverlight (in the console app it ran great) I get thrown with this exception : 

System.NotSupportedException: Specified method is not supported.
at System.Data.Services.Client.DataServiceQuery`1.System.Collections.Generic.IEnumerable<TElement>.GetEnumerator()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at MyApp.MainPage..ctor()
at MyApp.App.Application_Startup(Object sender, StartupEventArgs e)
at System.Windows.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, String eventName)

WTF?! The very same code doesn't work in Silverlight no matter how I try. Searching on the web desperately, led me in the end to this nice post on the blog called (how ironically?) theproblemsolver : Consuming an ADO.NET Data Service from Silverlight written by Maurice De Beijer

It turns out you can't query synchronously in Silverlight although the exception did **NOT** contain any clue whatsoever regarding this although it should. The correct way :

var query = from t in GetFreshContext().Employee select t;
var dsQuery = (DataServiceQuery<Employee>)query;
dsQuery.BeginExecute(result =>
{
    ComboEmployees.ItemsSource = dsQuery.EndExecute(result).ToArray();
}, null);
ComboEmployees.DisplayMemberPath = "FullName";
 

Then I ran across another problem and it puzzled me for a while too until I found the answer. Specifically I needed to load the Department along with Employee (the entities are different in the real app). Retrieving the list of employees brought the Department property null.

I (might) retrieve a long list of employees so re-querying for each employee entity for the department would be a very costful operation (too many HTTP requests). Looking for solutions I came across Typed Eager Loading Using Entity Framework (& What is Eager Loading vs Deferred Loading) which solves the magic string problem of eager loading but I didn't really care about the string.

I needed the entities eager-loaded. However on Silverlight/ADO.NET Data Services I don't have the option of

DbDataContext.Categories.Include(“Products”)

as presented in the blog post.

Finally it turns out that, as John Papa describes in the MSDN Magazine (Using Silverlight 2 With ADO.NET Data Services), you have an Expand method :

var query = from t in GetFreshContext().Employee.Expand("Department") select t;
var dsQuery = (DataServiceQuery<Employee>)query;
dsQuery.BeginExecute(result =>
{
    ComboEmployees.ItemsSource = dsQuery.EndExecute(result).ToArray();
}, null);
ComboEmployees.DisplayMemberPath = "FullName";

Hope this helps

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


About me

A passionated .NET Developer working closely with Microsoft technologies. View my public site.

Page List

Sign in