People who are in .NET arena might encounter the plethora of xxx.config files, especially web.config. It is a required devil for placing any configuration settings for your applications. We should appreciate the effort taken by the engineers at Microsoft for introducing (at that time, Java’s configuration approach was very immature) and providing a declarative approach, centralized and optimistic way of configuring your .NET application of any size. This has fitted well for applications written for simple purpose including training codes, in-house tools, etc. In a real-world, irrespective of small, medium or large scale, both Visual Studio and developers place lots of stuff on this mess surrounded by <, >, />, ” characters.
When you see the web.config schema, it accommodates the following types of configuration for an application:
- Configuration section declaration (your custom configuration section)
- Startup settings
- Runtime settings such as impersonation, app domain manager, GC, CAS publisher policy, etc.
- Remoting settings
- Network settings like authentication modules, proxy settings, System.Net, connection related
- Tracing and debug
- Application settings
- Connection strings
- ASP.NET settings like anonymous identification, authentication and authorization, caching, compiling, custom errors, health monitoring, HTTP runtime, handlers and modules, membership
- WCF settings like service endpoint, service behavior and binding configurations
Bit sleepy? Refer http://msdn.microsoft.com/en-us/library/ms731734.aspx for WCF and http://msdn.microsoft.com/en-us/library/dayb112d.aspx for ASP.NET specific settings.
There are machine wide settings that are overridden by the site and application wide settings too. Is this really productive in the development stage and helpful in the production stage? Having experience on real world .NET applications, the main concerns with web.config are:
- Readability & Understandability. Though it has the capability of defining the whole earth even the whole universe, readability is very bad. Mentally, it outshines the content clarity.
Let us see a sample web.config for a WCF service. How easy is it for you to add some more settings related to WCF tracing?
="1.0"
<configuration>
<configSections>
<section name="WcfSaml" type="Udooz.Security.CustomTokenConfiguration,
Udooz.Security"/>
</configSections>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true">
<assemblies>
<add assembly="System.IdentityModel.Selectors, Version=3.0.0.0,
Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Security, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="Microsoft.Transactions.Bridge, Version=3.0.0.0,
Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="SMDiagnostics, Version=3.0.0.0, Culture=neutral,
PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.DirectoryServices, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Web.RegularExpressions, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Transactions, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Messaging, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.ServiceProcess, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
</assemblies></compilation>
<authentication mode="Windows"/>
</system.web>
<system.diagnostics>
<trace autoflush="true"></trace>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml" type="System.Diagnostics.XmlWriterTraceListener"/>
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging
logMalformedMessages="false"
logMessagesAtServiceLevel="false"
logEntireMessage="false"
logMessagesAtTransportLevel="false"/>
</diagnostics>
<services>
<service
behaviorConfiguration="ServiceBehavior"
name="SampleService.HelloWorldService">
<endpoint binding="wsFederationHttpBinding"
address=""
bindingConfiguration="ServiceBinding"
contract="SampleService.IHelloWorld"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<bindings>
<customBinding>
<binding name="MutalCertificateBinding">
<security authenticationMode="MutualCertificate"
requireSecurityContextCancellation ="false"
requireSignatureConfirmation="false"
messageProtectionOrder ="SignBeforeEncrypt"
requireDerivedKeys="true">
</security>
<httpTransport/>
</binding>
</customBinding>
<wsFederationHttpBinding>
<binding name="ServiceBinding">
<security mode="Message">
<message issuedTokenType=
http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1
negotiateServiceCredential="false">
<issuer address=http://localhost/SamlSecurityTokenService/SamlTokenIssuer.ashx
bindingConfiguration="UsernameBinding" binding="customBinding">
<identity>
<dns value="UdoozDotNetServerCert"/>
</identity>
</issuer>
</message>
</security>
</binding>
</wsFederationHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior" returnUnknownExceptionsAsFaults="false">
<serviceCredentials type="Udooz.Security.CustomCredentials, Udooz.Security">
<serviceCertificate findValue="CN=UdoozDotNetServerCert"
storeLocation="LocalMachine" storeName="My"
x509FindType="FindBySubjectDistinguishedName"/>
<clientCertificate>
<authentication revocationMode="NoCheck"/>
</clientCertificate>
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
The above configuration is for a federated WCF web service.
When you refer to the alternate representations of XML, you can feel the readability issue. Here is an example JSON taken from Wikipedia:
{
"firstName": "John",
"lastName": "Smith",
"age": 25,
"address":
{
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber":
[
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}
The same in XML:
<person>
<firstName>John</firstName>
<lastName>Smith</lastName>
<age>25</age>
<address>
<streetAddress>
21 2nd Street
</streetAddress>
<city>
New York
</city>
<state>
NY
</state>
<postalCode>
10021
</postalCode>
</address>
<phoneNumbers>
<phoneNumber type="home">
212 555-1234
</phoneNumber>
<phoneNumber type="fax">
646 555-4567
</phoneNumber>
</phoneNumbers>
</person>
The same in YAML which is very famous in Rails arena:
—
firstName: John
lastName: Smith
age: 25
address:
streetAddress: 21 2nd Street
city: New York
state: NY
postalCode: 10021
phoneNumbers:
– type: home
number: 212 555-1234
- type: fax
number: 646 555-4567
- Manageability – The user who might be a developer, solution architect, production administrator has to manage a lot of stuff to accomplish an intent. For example, WCF security related settings are scattered across service binding (security mode settings) and behavior (e.g. service credential settings) sections. Though technically this is the correct way, however from a user perspective, this has lesser manageability.
- Mixture Settings. Since web.config is the only best place for any configuration, the “separation of concerns” principle couldn’t be achieved in various stages of configuration. For example, some settings are more helpful during the development stage, for example, the list of claims types can be understood by a WCF service, assemblies for handling custom authentication, etc. But these configurations are in no way helpful, but making this as configuration is harmful to the application at the production stage. Just think that changing “
GivenName
” claim to “GivenName2
? in the above sample web.config might break the system.
What is Expected?
Yes, we should appreciate the level of flexibility and extensibility available in .NET. However, in this era of agile, productivity and simplicity matter. It is time to adopt and follow “convention over configuration” approach - those are main part in Rails and Android development world. If required, let the user (again developer or solution architect) override the convention.
Instead of putting everything on the messy XML tags, provide developer/solution architect/administrator friendly DSL, which would be internal DSL on C# or easy to learn external DSL. For example, in Rails, to map a web request to the appropriate REST action is being configured by Ruby syntax.
ActionController::Routing::Routes.draw do |map|
map.connect ‘products/:id’, :controller => ‘catalog’,
:action => ‘view’
#…other routings
end
In the above code, you see such mapping. These kinds of scripting will be more favourable than the awkwardness of XML.
CodeProject
<script type="text/javascript"><!-- google_ad_client = "pub-1206499418090878"; /* 234x60, created 4/28/09 */ google_ad_slot = "2185336927"; google_ad_width = 234; google_ad_height = 60; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>