I am trying to use Unity with my WCF Data Service (OData). I have code that looks like this:
public class PatientService : DataService<IPatientRepository>
I want unity to inject the correct object for IPatientRepository at run time (either the real PatientRepository or a faked one that I use for testing.)
I have done the:
IUnityContainer container = new UnityContainer();
container.RegisterType<IPatientRepository, MyEntities>();
But when I run I get:
The server encountered an error processing the request. The exception message is 'Unable to create data provider. Type 'RepositoryInterfaces.IPatientRepository' for data source in 'Patien开发者_开发技巧tService.PatientService' is abstract.'
Is there a way to inject this dependancy? Or do I have to put the real class in that spot?
The ServiceLocator class and the ServiceLocator (anti)pattern should not be used here. The code below looks like it is the Service Locator (anti)pattern but it isn't quite.
The CreateDataSource method is the earliest point in the request lifecycle that I have found to compose your object graph. Here, it is used as the Composition Root. Bootstrapper is a helper class that invokes the Unity configuration, whether it is loading it from XML or in code.
public class PatientService : DataService<IPatientRepository>
{
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service
operations are visible, updatable, etc.
...
}
[WebGet]
public IQueryable<Patient> Patients()
{
return from p in CurrentDataSource.Patients select p;
}
protected override IPatientRepository CreateDataSource()
{
IUnityContainer container = new UnityContainer();
Bootstrapper.Initialise(container);
return container.Resolve<IPatientRepository>();
}
}
So @Roy was correct to point you to the CreateDataSource() method. However the use of ServiceLocator, as a class or as a pattern should be avoided. Unfortunately, Microsoft have almost forced everyone down the ServiceLocator route with classes such as ServiceLocator and DependencyResolver.
WCF Data Services doesn't know about your Container and hence cannot call it to find out the implementation of the interface you pass.
Likewise, your Container can do constructor injection but cannot dynamically specify the T in DataService<T>.
So as far as I can tell, there is no way to use DataService with an Interface and then inject an implementation.
EDIT: What should work, as Vitek pointed out in the comments, is to just declare your class a DataSource<T> with an interface and then override the CreateDataSource() method. In that method, you could then do a ServiceLocator call to the implementation of IYourInterface:
var myService = ServiceLocator.Get<IYourInterface>();
This of course requires that you configure your container for service location.
The Patterns & Practices group has apparently implemented a Unity adapter for the Service Locator pattern, see http://commonservicelocator.codeplex.com/wikipage?title=Unity%20Adapter&referringTitle=Home&ProjectName=commonservicelocator.
Fore more on the Service Locator pattern, see http://msdn.microsoft.com/en-us/library/ff648968.aspx.
精彩评论