Edit: Please be sure to check out the comments! Eilon Lipton the author of ObjectDataSource was so nice and did talk to me about my problem. Awesome! He even went as far as creating a blog post Using ObjectDataSource to do the dirty work for your custom data source over at his blog about it. But first enjoy the original story posted on Sept. 9th 2006:
The ObjectDataSource is a great new tool in ASP.NET 2.0. But unfortunatelly its primary intended way of using it, is by using static methods or methods of objects that get created using the default constructor. But this is very limiting when building complex websites. Especially complex websites that should be maintainable.
That means it is not easy using the ODS when employing software cells, a Model View Presenter approach, capsulation of logic, etc. Especially MVP suffers from a considerable amount of work-around-uglyness, when using the standard ObjectDataSource. Sure, it is possible to override the default object creation process by attaching to the ObjectCreating event.
XML:<body>
<form id="form1" runat="server">
<div>
<asp:ObjectDataSource ID="ODS1"
runat="server"
OnObjectCreating="ODS1_ObjectCreating" />
</div>
</form>
</body>
and in the code behind:
C#:protected void ODS1_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
e.ObjectInstance = presenter.getAdapter();
}
Sure, that could be a solution - but I'd rather do something like this:
XML:<body>
<form id="form1" runat="server">
<div>
<myDS:AdapterDataSource ID="ADS1"
runat="server"
AdapterProvider="presenter"
AdapterProviderMethod="getAdapter"
AdapterSelectMethod="Select"
AdapterTypeName="TestAdapter" />
</div>
</form>
</body>
Ha, EAAAAAAASY to do, right? Just override the method onObjectCreating of the base class ObjectDataSource in the new class AdapterDataSource. Well, if you look at the specs you will realize that the Event is not actually raised in ObjectDataSource - just made public there. The actual event is raised inside ObjectDataSourceView. But still no problemo, right:
C#:public class AdapterDataSourceView : ObjectDataSourceView
{
private AdapterDataSource m_owner;
public AdapterDataSourceView(AdapterDataSource owner, string name, HttpContext context)
: base(owner, name, context)
{
m_owner = owner;
}
protected override void OnObjectCreating(ObjectDataSourceEventArgs e)
{
// Let the ADS decide if we have to do some magic here.
if (m_owner.HasCustomDataBinding)
{
e.ObjectInstance = getCustomBinding();
}
base.OnObjectCreating(e);
}
private object getCustomBinding()
{
throw new System.
Exception("The method or operation is not implemented.");
// e.g. return m_owner.CustomDataBinding;
}
}
So now, all we have to do is override the one method of ObjectDataSource in the AdapterDataSource that generates those ObjectDataSourceView instances, right... WRONG. No method seems to be responsible for creating the view.
Using the reflector I found out what was really happening behind the scenes.
C#:private ObjectDataSourceView GetView()
{
if (this._view == null)
{
this._view =
new ObjectDataSourceView
(this,
"DefaultView",
this.
Context);
if (base.IsTrackingViewState)
{
((IStateManager) this._view).TrackViewState();
}
}
return this._view;
}
The method used is called getView() inside the .NET Framework provided by Microsoft - and it is private! Yeah, baby.
All those protected methods inside the ObjectDataSource class are just for show - because the main step in the process of creating the actual view can not be overridden.
But I wasn't going to give up that easily. How about overriding all methods that depend on GetView(). That way I could retire the private GetView() and great my own view creation algorithm. So full of hope I fired up the Analyser. But when I saw the following I started sobbing quietly:

Well, to make a long story short - I did try to do the overriding and stuff - but unfortunatelly those methods sometimes use Attributes that are internal and all kind of crazy stuff that makes you want to beat the programmer that did put that little innocent "private" in front of GetView(). 
Because it is 3 in the morning and I am really tired I did use this shortcut:
C#:public AdapterDataSource()
: base()
{
Type baseType =
typeof(ObjectDataSource
);
FieldInfo fi = baseType.GetField("_view", BindingFlags.Instance | BindingFlags.NonPublic);
AdapterDataSourceView sourceView =
new AdapterDataSourceView
(this,
"DefaultView",
this.
Context);
fi.SetValue(this, sourceView);
if (base.IsTrackingViewState)
{
((IStateManager)sourceView).TrackViewState();
}
}
UUUUUUUUUUUUUUUUUGLY! And it breaks when using Mono - because there it's a private property called DefaultView. And the best part about this: There actually is a PROTECTED method called GetView(string viewName). But that does not get used, probably because it returns simply a DataSourceView instead of a ObjectDataSourceView...
C#:protected override DataSourceView GetView(string viewName)
{
if ((viewName == null) || ((viewName.Length != 0) && !string.Equals(viewName, "DefaultView", StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException
(SR.
GetString("DataSource_InvalidViewName",
new object[] { this.
ID,
"DefaultView" }),
"viewName");
}
return this.GetView();
}
I just wonder why nobody considered using:
C#:protected readonly string DEFAULT_VIEW = "DefaultView";
protected override DataSourceView GetView(string viewName)
{
if ((viewName == null) || ((viewName.Length != 0) && !string.Equals(viewName, DEFAULT_VIEW, StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException
(SR.
GetString("DataSource_InvalidViewName",
new object[] { this.
ID, DEFAULT_VIEW
}),
"viewName");
}
if (this._view == null)
{
this._view =
new ObjectDataSourceView
(this, DEFAULT_VIEW,
this.
Context);
if (base.IsTrackingViewState)
{
((IStateManager) this._view).TrackViewState();
}
}
return this._view;
}
private ObjectDataSourceView GetView()
{
if (this._view == null)
{
return GetView(DEFAULT_VIEW) as ObjectDataSourceView;
}
return this._view;
}
private ObjectDataSourceView _view;
*SOB*
Update:
Marc Brooks pointed out that there is a bugreport on this issue. Check the comments to find out how that "worked out".
Tweet this