Why is <clear></clear> not the same as <clear /> in app.config? - c#

Can someone please give me the technical reason why <clear></clear> is invalid in app.config vs <clear />
It's typically used like this :
<connectionStrings>
<clear/>
<add etc..... />
</connectionStrings>
Problem is I'm using an installer product (InstallShield) with does xml transformation to app.config files, and it's changing <clear /> to <clear></clear>
This breaks the application (service won't even start)
For now I'm just looking for the technical explanation, but if you have any workaround that would be nice too.

It seems that using <clear></clear> breaks the parsing of the connectionStrings section (and probably others too, if used there). See the comment of Hans Passant for a possible explanation.
If <clear></clear> is present, the ConfigurationManager.ConnectionStrings is empty. So the reason for you service crashing may be, that you don't check if this collection contains any elements or try to access them via ConfigurationManager.ConnectionStrings["nameoftheconnection"] which throws an exception if there is no element with that key.
Possible workarounds (which I admin are both rather clumsy and hacky)
You remove the <clear />. This may lead to some additional connect strings created by some referenced assemblies. But as your own connectionstring should be at the end of this collection, you may be able to remove the unwanted entries.
You add a custom task to your installation routine, which processes the app.config file in one of the later steps and replaces <clear></clear> with <clear />

Related

Where to find the location of IIS manager connection strings

I was getting an error saying that one of my connection string in my application's web.config file was already defined.
I checked in the IIS settings and when I checked the connection string property it was there already with Entry Type : Inherited.
So I went up the chain and went all the way up to the root of the localhost and checked the connection strings there.
I found a bunch of connection strings there as well.. but they're also all with Entry Type Inherited..
I checked the web.config file inside the wwwroot folder but didn't find any connection strings defined in there..
Where could these connection strings be coming from?...
Configuration files in .NET are inherited in the following order:
systemroot\Microsoft .NET\Framework\versionNumber\CONFIG\Machine.config
systemroot\Microsoft .NET\Framework\versionNumber\CONFIG\Web.config (ASP.NET only)
(application directory)\Web.config
So the connection strings that show up as "inherited" are specified in either of the upper two files.
Reference: MSDN: ASP.NET Configuration File Hierarchy and Inheritance
If you don't want to alter the machine-wide configuration, you can <clear /> them from being inherited in your application's configuration as explained in What does <clear /> signify when specifying a connectionstring?:
<connectionStrings>
<clear />
<add name="LocalSqlServer" connectionString="..." />
</connectionStrings>

Find out which web.config(s) have been loaded

I'm encountering an error indicating that the web.config being loaded by this particular sub-project of my solution has a connectionstring that conflicts with an existing entry from an already-loaded web.config
(Exception message is: Additional information: The entry 'connStr' has already been added.)
Is there a way to easily find out the list of all web.configs loaded/being loaded, so that I can ascertain where to conflict is arising
There is only one web.config that will be loaded, however, it will inherit from your machine configuration. For IIS this is here:
%windir%\Microsoft.NET\Framework\framework_version\CONFIG\machine.config
And for IIS Express in one of these places:
%userprofile%\documents\iisexpress\config\applicationhost.config
%userprofile%\my documents\iisexpress\config\applicationhost.config
$(solutionDir)\.vs\config\applicationhost.config (only for Visual Studio 2015 and above)
So you can remove the duplicate from there, or add a remove entry in your web.config, for example:
<connectionStrings>
<remove name="MyConnection" />
<add name="MyConnection" connectionString="..." providerName="System.Data.SqlClient" />
</connectionStrings>
I've had this problem before, I added inheritInChildApplications="false" in my main web.config. This way I know that my sub web.config will not have any conflict.

ConnectionString for assemblies

I have a website with a connection string listed in its web.config. The connection string is altered by the Publish feature so that it can reference a development database until it is released, when it references a separate release database.
The website accesses the databases through some assemblies, though. They are Class Libraries so they can't be Published, at least as far as I can tell. I read that the web.config would override the app.config connectionstrings, but that doesn't seem to be happening.
Whenever I Publish the release site references the development database, unless I alter the assemblies app.config files to reference the release database.
I don't want to have to remember to do that every time. How do I handle this?
You've got two issues here:
1. How to remember to publish the correct settings each time you publish:
One way to deploy such settings is by using web.config transformations in Visual Studio. This is pretty easy to set up and means that you do not have to remember to update the settings each time you publish.
As well as debug and release environments, you can also create transforms for "UAT", "Staging", "Beta" or whatever other configs you might need.
You might find these articles useful: here, here and here.
For example, here is a transform for a Release environment:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
</system.web>
</configuration>
Above, you will see that the transform for Release mode sets the attributes of the MyDB connection string (xdt:Transform="SetAttributes"), removes the debug attribute from the compilation section and replaces the customErrors section with a new version.
It's a simple, yet very powerful technique.
2. How to get your assemblies to pick up the settings in the web.config
If your libraries have been written in the usual way, they should be retrieving their connection strings by simply accessing the [Web]ConfigurationManager.ConnectionStrings property. Like #Bob Horn says, they should then pick up the settings from the host process's config file (in this case the web.config of your web app).
However, sometimes you might find that a library is getting its settings from a .Settings file in the project, in which case things get a little more complicated. You will need to copy the settings section of the app.config in to the web.config. (You can also do this using the transforms technology described above.)
If you have access to the source code of the other assemblies, find the part of the code that retrieves connection strings. If it's not accessing the ConfigurationManager class, then that might explain why it's not picking up the web.config file.

Connect client application services to a custom DB (not the default CE DB)

I have an existing C# ASP.NET web application which uses the membership and role providers. The tables for these are hosted in the same DB which holds all of the application tables (hosted in Azure for production, local SQLExpress for dev).
I would like to write a console application which uses the same user and role information. To this end I have enable client application services (on the console app) and added a new web service which exposes these to the console app.
I can get this working in a test setup (both as console and winforms), i.e. with the web service creating its own blank set of users/roles which from what I've read are stored in a local file as a SQL CE database.
How can I get the web service to be reading from my application's DB?
Relevent web.config for original web application:
<profile defaultProvider="DefaultProfileProvider">
<providers>
<add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="SecondBiteDBContext" applicationName="/" />
</providers>
</profile>
<membership defaultProvider="DefaultMembershipProvider">
<providers>
<add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="SecondBiteDBContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="10" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
<roleManager defaultProvider="DefaultRoleProvider" enabled="true">
<providers>
<add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="SecondBiteDBContext" applicationName="/" />
</providers>
</roleManager>
Web.config for the web service:
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true" requireSSL="false" />
<profileService enabled="true" readAccessProperties="WebSettingsTestText" writeAccessProperties="WebSettingsTestText" />
<roleService enabled="true"/>
</webServices>
</scripting>
</system.web.extensions>
....
<system.web>
<profile enabled="true" >
<properties>
<add name="WebSettingsTestText" type="string"
readOnly="false" defaultValue="DefaultText"
serializeAs="String" allowAnonymous="false" />
</properties>
</profile>
</system.web>
App.config for console app:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="ClientSettingsProvider.ServiceUri" value="http://localhost:31337/SecondBiteAppServices/Profile_JSON_AppService.axd" />
<add key="ClientSettingsProvider.ConnectionStringName" value="DefaultConnection" />
</appSettings>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=.\SQLExpress;Initial Catalog=SBAuto;MultipleActiveResultSets=True;Integrated Security=SSPI" />
</connectionStrings>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
<providers>
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="http://localhost:31337/SecondBiteAppServices/Authentication_JSON_AppService.axd" connectionStringName="DefaultConnection" savePasswordHashLocally="False" />
</providers>
</membership>
<roleManager defaultProvider="ClientRoleProvider" enabled="true">
<providers>
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="http://localhost:31337/SecondBiteAppServices/Role_JSON_AppService.axd" cacheTimeout="86400" connectionStringName="DefaultConnection" />
</providers>
</roleManager>
</system.web>
</configuration>
I haven't specified the optional credentials provider, because I'm not using a form - right now I can't get a hard coded call to validateuser() to succeed.
Using project properties -> services tab -> advanced button, I've specified a custom connection string pointing to the required DB. I know it is connecting to my DB, because for a while I was getting exceptions about "invalid object ApplicationProperties". Creating a table in my DB with columns PropertyName and PropertyValue fixed this. Note that I had already run aspnet_regsql on my DB which I would expect should have created the required tables.
However it is not passing validation checks on the users residing in that DB - it runs cleanly (no exceptions) but fails the login. Based on the structure of app.config above, I speculate that the custom connection string is only applying to the profile service, not the membership or role services? (Only the profile service [client settings provider] is taking the connection string as a param.) EDIT: Looking back at some docs, http://msdn.microsoft.com/en-us/library/bb384312 seems to indicate this custom connection string is only for storing the offline local cache stuff.
Using project -> asp.net configuration (with the web service project selected), the web site admin tool doesn't let me do anything meaningful to configure the providers or add new ones.
I haven't been able to track down anything that will let me actually use the users and roles in that DB. Any ideas? (I am fairly new to .net, so it is quite possible I'm missing something, but I've been having a lot of trouble with the documentation and getting any decent results out of google.)
Once this is working, I want to share business logic between the various projects. Currently the logic is located in the main web app controller methods - obviously I will need to refactor that out to a shared layer. Will that be possible given the objects involved are based on entity framework?
I did a trial refactor before I started with all of this client services stuff. I was able to get everything referenced and compiling but the code was failing silently very early in execution, my best guess was that all of the various framework related stuff was not initialized properly - hence entering into client app services. However I'm worried that even if I get CAS going, entity framework is going to still cause issues.
Last one: how can I share config elements (connection strings mostly) between config files in different projects? Would like to be able to swap between dev and production without having to edit multiple files.
EDIT: How much of a hack is doing something like this? http://devpinoy.org/blogs/comgen/archive/2007/08/15/use-membership-api-in-winforms.aspx
That's the only actually useful thing I've been able to find, even if not directly related to CAS. It seems like I could just copy the appropriate lines form my main web app web.config (which include a link to my DB's connection string).
Thanks!
Update 25/1/13: Tried the alternative suggested on the edited in link just above, substiting in the web.config elements listed above (although I also had to copy the system.web.providers.dll manually to the bin/debug dir). I can cleanly call validateuser(), but it still won't allow the login. I know I'm hitting my DB because activity is occurring in SQL profiler, and the last activity timestamp on the user table is being updated. This doesn't occur when doing it the CAS way.
Update 25/1/13 #2 - Just spent the past 4 hours trying to debug why it is failing, and its driving me insane fast. By reading the code (not debugging) all I can tell is that it is failing on comparing the provided password hash with the stored one. I'm 100% sure I'm providing the correct user and password.
Microsoft hasn't published the code for system.web.providers.dll, so debugging wise I can't step into anything beyond the membership.validateuser call since that calls DefaultMembershipProvider.ValidateUser.
Resharper will show me the soure code of DefaultMembershipProvider (by decompiling it) but I can't get it to debug into it. I've read elsewhere that you can decompile the whole dll to a project, remove the reference to the dll and then add the project.
Attemping to do so, I've had the following problems:
Dis# allows me to save the lot as project, but it produces seemingly managled source full of a lot of errors. They seem to be mostly syntax errors around where it hasn't got the variable names right. When importing the project VS warns about changing the target .net version, but this doesn't seem to do anything
Telerik JustDecompile lets me save the project, but it didn't include the .cs file that compliments system.web.providers.resources.providerresources.resx. I imported the .cs from Dis# which works. However it is still full of errors, but different ones (still a few syntax related though) and not so many. A fair number of them have something to do with classes in other system.x namespaces. Blanket adding the lot as references didn't help anything.
ILSpy - when opening the dll, it lists the portions of the other namespaces that the JustDecompile project seems to be referencing. But it only lets me save the files one by one and I'm not really interested in trying to rebuild the structure of several dozen dll files by hand...
This is my first attempt at decompiling anything, but everything I can find seems to be indicating what I'm doing should work (but they certainly didn't mention any of the problems I've been having). Any ideas of what to do next?
Side note relating to my attempted web service in the OP: I noticed that aspnet_regsql.exe created a duplicate set of membership and role tables prefixed by "aspnet_". E.g. aspnet_membership whilst my existing app/code uses just plain membership. That clears up why the web service wouldn't read my data, as it was checking different tables.
I found a blog (can't find the link again right now) about someone who wrote some code to migrate their data between the two schemas which indicated that the different sets of tables are related to different versions of the membership (etc) providers. So I'm assuming that the providers as seen in the "universal providers (system.web.providers) are different (and imcompatible) with the providers used in client application services and exposed by the web service I created.
Providing an answer to hopefully spare some others a lot of pain. I don't have the answers to all of the questions I asked above, but there is useful information here.
To make the universal providers (system.web.providers.dll) connect to any DB, simply use the relevant config lines from my first web.config snippet above. This works in app.config (etc) for any type of .NET project (as far as the ones I've tried). Make sure you add a reference to the dll, and that the connection string is included in the config. I refactored the connection strings to a separate config which I linked to each project, to avoid duplication of details.
The old style providers are incompatible with the new universal providers, because their SQL schema is different. It is possible to convert from old to new ones by writing some scripts to transform between schema.
BUT there are issues with the hash algorithm used to validate logins when switching between them like this. You need to force SHA1 on e.g. <membership defaultProvider="DefaultMembershipProvider" hashAlgorithmType="SHA1"> when trying to use these providers outside of a web application.
This is why my ValidateUser() calls that I was asking about were failing. This bug on Connect is relevant: http://connect.microsoft.com/VisualStudio/feedback/details/734341/system-web-providers-defaultmembershipprovider-behavior-differs-from-sqlmembershipprovider-when-dealing-with-password-compatibility . Because of this bug, my web app (using universal providers) has been running in SHA1 mode since the start - it should have been HMACSHA256. The default HMACSHA256 was correctly applying when using the console app hence the mismatch!
Someone else who had issues with hash algorithm configuration: http://chriskinsmanblog.azurewebsites.net/2012/03/30/SystemWebProvidersDefaultMembershipProviderBehaviorChange.aspx
However after all of the above, I discovered that you don't necessarily need to be using these providers. It is possible to get the entity framework to execute correctly without being logged in or having any reference to the providers. (I wish I knew why I couldn't get it work before I started all this mess. I know I had the relevant dlls referenced.)
I still have no idea why I couldn't satisfactorily recompile web.providers.dll.

There is no build provider registered for the extension '.rss'

I tried to make a .rss file in my ASP.NET application work like a .ashx and although I did everything I was supposed to, I am still getting this error:
There is no build provider registered for the extension '.rss'. You can register one in the section in machine.config or web.config. Make sure is has a BuildProviderAppliesToAttribute attribute which includes the value 'Web' or 'All'.
There IS a build provider registered!
<buildProviders>
<add extension="*.rss" type="System.Web.Compilation.WebHandlerBuildProvider"/>
</buildProviders>
<httpHandlers>
<remove verb="*" path="*.rss"/>
<add verb="*" path="*.rss" type="System.Web.UI.SimpleHandlerFactory"/>
...
I also added .rss in the IIS config. What is left to do?! Using ASP.NET 3.5
In the extension attribute, remove the asterisk:
<add extension=".rss" type="System.Web.Compilation.WebHandlerBuildProvider"/>
Build providers are used to generate source code at runtime. Are you sure you mean to generate source code for rss files? One thing I can say with a decent amount of certainty is there appears to be no WebHandlerBuildProvider.
Also, have you seen the RSS Toolkit?

Categories

Resources