Here’s a little oddball issue I ran into today that hosed – during a demo of course – all the existing ASMX Web Services text pages in one of my applications. The error that occurred resulted in a yellow screen of death when accessing the ASMX service directly (http://localhost/wwstore/services/WebStoreConsumerService.asmx):
CS0104: 'DataBinder' is an ambiguous reference between 'Westwind.Web.Controls.DataBinder' and 'System.Web.UI.DataBinder'
Multiple DataBinder Objects and DataBinder.Eval()
The issue here is caused by the fact that I have a component in Westwind.Web.Controls.DataBinder that apparently conflicts with the System.Web.UI.DataBinder
. You would think that the separate namespaces should isolate me from problems like this, but unfortunately here the overlapping names ram heads due to the use of a static method call of DataBinder.Eval()
.
The problem is that the DataBinder.Eval()
is a static method call so there’s never an instance created to qualify exactly which type is to be used. Both System.Web.UI
and Westwind.Web.Controls
are in scope, the former because it’s automatically included as a namespace, the latter because it’s added explicitly in the <pages><namespaces> section of Web.Config:
<pages>
<namespaces>
<add namespace="Westwind.Web" />
<add namespace="Westwind.Web.Controls" />
<add namespace="Westwind.Utilities" />
<add namespace="Westwind.WebStore" />
</namespaces>
<controls>
<add assembly="Westwind.Web" namespace="Westwind.Web.Controls" tagPrefix="ww" />
</controls>
</pages>
which automatically includes the namespace into the page.
The result is that that the DataBinder.Eval()
can’t be resolved properly by the compiler – it doesn’t know which DataBinder should be used. Actually it’d be nice if the compiler was smart enough to check for the actual method Eval before throwing the error. Since my component doesn’t have a static Eval method (or any static members for that matter) it seems that the compiler should be able to prioritize the call.
Ironically this error would not be an issue if this was anything but a framework provided page which is:
C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\DefaultWsdlHelpGenerator.aspx
Hardcoding Bindings to DataBinder
To fix the problem is easy enough by changing all the .NET 1.x DataBinder.Eval()
calls with:
<%# System.Web.UI.DataBinder.Eval(Container.DataItem, "Value.Documentation") %>
or
<%# Eval("Value.Documentation") %>
Replacing all DataBinder.Eval()
calls with either code fixes the problem, but of course it only does so on my machine(s) – still a problem for anybody else.
Removing the non-Microsoft Namespace Reference in web.config
In the end there are few solutions that can be used to work around this problem – none really satisfying. The easiest and the one I actually ended up with is by removing the Westwind.Web.Controls namespace from the global ASP.NET namespace list:
<namespaces>
<add namespace="Westwind.Web" />
<!--<add namespace="Westwind.Web.Controls" />-->
<add namespace="Westwind.Utilities" />
<add namespace="Westwind.WebStore" />
</namespaces>
It turns out that this works just fine in my case because the Westwind.Web.Controls namespace isn’t used much in Web page code. A while back I thankfully refactored all the utility and control code into separate namespaces, so the need for the Controls namespace is not used much if at all. Unfortunately that change won't show a problem until pages are fired at runtime 🤷
The other option I was at first considering to get around this was to put the control into a separate namespace (ie. Westwind.Web.Controls.DataBinding) which certainly would have worked but this causes a number of problems when adding page register commands into the page. The following wouldn’t work:
<%@ Register Assembly="Westwind.Web"
Namespace="Westwind.Web.Controls" TagPrefix="ww" %>
unless I also add:
<%@ Register Assembly="Westwind.Web" Namespace="Westwind.Web.Controls.DataBinding" TagPrefix="ww" %>
IOW, changing a lot of pages potentially.
Best option: Add a LOCAL web.config
Finally another solution is to add a local web.config
file into the folder with the Web Service(s) lives, and explicitly exclude the offending namespace(s):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<pages>
<namespaces>
<remove namespace="Westwind.Web.Controls"/>
</namespaces>
</pages>
</system.web>
</configuration>
This assumes you isolate the Web Service(s) into a separate folder where the removal won't affect you.
Summary
This is obviously a very isolated incident and situation, but it’s easy to get tripped up by this. Ideally I think that the generic .NET code in DefaultWsdlHelpGenerator.aspx
was namespace safe by explicitly prefixing namespaces in static method calls.
There goes another couple of hours of sleuthing to find a solution. <shrug>
Other Posts you might also like