Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Compilation;
using System.Web.UI.WebControls;

namespace AspNetDependencyInjection.WebForms
{
/// <summary>
/// A drop-in replacement for <see cref="ObjectDataSource" /> controls that enables dependency injection
/// instantiation for data sources.
///
/// To use it, register the control namespace by adding the following element to your web.config file:
///
/// <c>
/// &lt;configuration&gt;
/// &lt;system.web&gt;
/// &lt;pages&gt;
/// &lt;controls&gt;
/// ...
/// &lt;add tagPrefix="di" namespace="AspNetDependencyInjection.WebForms" assembly="AspNetDependencyInjection" /&gt;
/// ...
/// &lt;/controls&gt;
/// &lt;/pages&gt;
/// &lt;/system.web&gt;
/// &lt;/configuration&gt;
/// </c>
///
/// Then replace the &lt;asp:ObjectDataSource&gt; tags in your code with &lt;di:DiObjectDataSource&gt; tags.
/// </summary>
/// <remarks>
/// Please make sure your <see cref="ObjectDataSource" /> methods are not marked <see langword="static" />.
/// </remarks>
public class DiObjectDataSource : ObjectDataSource
{
/// <summary>
/// Background: <see cref="ObjectDataSource" /> controls invoke a `Select` method defined
/// in the `Page` object in order to retrieve the data to bind to other controls. This select method is
/// usually a <see langword="static" /> method on the containing page, which prevents using DI,
/// but can also be an instance method, in which case it instantiates a new `Page` object and calls the method
/// on the newly created instance.
/// That's the scenario when DI should be possible.
///
/// Unfortunately it seems that Microsoft never updated the <see cref="ObjectDataSource" /> control
/// to use <see cref="HttpRuntime.WebObjectActivator" />,
/// so it's not able to instantiate DI-enabled `Page` controls.
/// However, it is possible to override its <see cref="ObjectDataSource.ObjectCreating" />
/// event to make it work the way we want.
/// </summary>
public DiObjectDataSource()
{
// We need to use `BuildManager.GetType` instead of `Type.GetType` because this method is actually
// able to look for the type in all of the application assemblies - otherwise we'd be restricted
// to the current assembly types.

this.ObjectCreating += ( sender, args ) =>
args.ObjectInstance = HttpRuntime.WebObjectActivator.GetService( BuildManager.GetType(
( (ObjectDataSourceView)sender ).TypeName, throwOnError: false, ignoreCase: true ) );
}
}
}
22 changes: 22 additions & 0 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,28 @@ Another advantage of this approach is that if you need to use a `DbContext` insi
* `WebActivatorEx`'s `PreApplicationStartMethod` (the `PreStart` method in our sample above) runs **before** OWIN's Startup method.
* See this StackOverflow post: https://stackoverflow.com/questions/21462777/webactivatorex-vs-owinstartup

### How to deal with `ObjectDataSource` controls
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to split-up the GETTING_STARTED.md file into smaller doc files under /docs/* to keep them more focused. I'll do that now and invite you to submit this as a new doc file there.

Background: `ObjectDataSource` controls invoke a `Select` method defined in the `Page` object in order to retrieve the data to bind to other controls. This select method is usually a `static` method on the containing page, which prevents using DI, but can also be an instance method, in which case it instantiates a new `Page` object and calls the method on the newly created instance. That's the scenario when DI should be possible.

Unfortunately it seems that Microsoft never updated the `ObjectDataSource` control to use `HttpRuntime.WebObjectActivator`, so it's not able to instantiate DI-enabled `Page` controls. However, it is possible to override its `ObjectCreating` event to make it work the way we want.

For your convenience, this component includes a custom `ObjectDataSource`-derived control called `DiObjectDataSource` that can be used as a drop-in replacement for basic `ObjectDataSource` controls. To use it, register the control namespace by adding the following element to your `web.config` file:
```
<configuration>
<system.web>
<pages>
<controls>
...
<add tagPrefix="di" namespace="AspNetDependencyInjection.WebForms" assembly="AspNetDependencyInjection" />
...
</controls>
</pages>
</system.web>
</configuration>
```
Then replace the `<asp:ObjectDataSource>` tags in your code with `<di:DiObjectDataSource>` tags.
*Note:* Please make sure your `ObjectDataSource` methods are not marked `static`.

## Included services

All included services are exposed as interfaces so you can replace them with your own implementation for testing purposes or for different production scenarios. They are listed below:
Expand Down