using owin middleware and dependency injection

Topics: Customizing Orchard, Troubleshooting
Jan 26, 2015 at 11:39 AM
Edited Jan 26, 2015 at 11:41 AM
I have created an owin middleware using the new stuff in 1.x to register some odata endpoints thats working ok up till now .

The registration looks like this :
   public class OwinMiddleware : IOwinMiddlewareProvider
        private readonly IWorkContextAccessor _wca; 
        private readonly Work<ISiteService> _siteServiceWork;  
        public OwinMiddleware(IWorkContextAccessor wca,Work<ISiteService> siteServiceWork)
            _wca = wca;
            _siteServiceWork = siteServiceWork;
        public IEnumerable<OwinMiddlewareRegistration> GetOwinMiddlewares()
            return new[]
                new OwinMiddlewareRegistration
                    Priority = "50",
                    // This is the delegate that sets up middlewares.
                    Configure = app => 
                            var config = new HttpConfiguration(); 
                            var builder = new ODataConventionModelBuilder();
                                routeName: "odata",
                                routePrefix: "odata",
                                model: builder.GetEdmModel());

and the Odata controller looks like this :
 public class MyContentItemController : ODataController 
        // GET: odata/MyContentItem
        public IQueryable<MyContentItem> GetMyContentItem() {

            return db.MyContentItem;
All is working well . I can access odata endpoints using a url like :
which returns back json.

But now I wish to inject some orchard services into the odata controllers to do some authorization when getting odata end points and naturally its not working . Im getting and error
An error occurred when trying to create a controller of type 'MyContentItemController'. Make sure that the controller has a parameterless public constructor.
It has no knowledge of the dependency injection mechanism.

I've looked into how its done in core with web api's where its manually registering all web api controllers in route table and using ControllerActivator and ControllerSelector to handle web api resquests.

But these odata endpoints are self host as shown in configuration above.

So my question is if anyone can think of a way to hookup the dependency injection mechanism when registering that odata endpoints in configuration so that the odatacontrollers can use the autofac dependency mechansim ?

Jan 28, 2015 at 4:08 AM
Working on the same kind of ODataController but not in Orchard, I was very interesting on this. So, I tried it, not so simple, to use app.UseWebApi(), I needed to add some binding redirections in web.config... But, I've got it working, and, as you, I had the same problem when I want to inject an orchard service in the ODataController

To work in this "owin/webapi/odata" context, maybe autofac needs special config and registrations. But it seems that I have found a workaround, not sure it works in all cases, it needs to be validated, but I share it with you. The workaround is to get an Orchard WorkContext that can be used to resolve Orchard services...

In the ODataController action (not tested in the constructor), I was able to get a WorkContext by using this
Some using I needed to add: Orchard, System.Web, System.Net.Http, System.Web.Routing...
Note: You can encapsulate this code in a method / ApiController extension...
        WorkContext wc = null;
        if (Request.GetOwinEnvironment().ContainsKey("System.Web.HttpContextBase")) {
            wc = (Request.GetOwinEnvironment()["System.Web.HttpContextBase"]
                as HttpContextBase).Request.RequestContext.GetWorkContext();
This also works
        if (Request.GetOwinEnvironment().ContainsKey("System.Web.Routing.RequestContext")) {
            wc = (Request.GetOwinEnvironment()["System.Web.Routing.RequestContext"]
                as RequestContext).GetWorkContext();
Then you can use something like that (it works in my testing environment)
        if (wc != null) {
            var siteName = wc.CurrentSite.SiteName;
            var siteService = wc.Resolve<ISiteService>();
            var superUser = siteService.GetSiteSettings().SuperUser;
Note: Maybe you will need to add other null checking, use TryResolve() in place of Resolve()...
TODO: Test other Orchard services, e.g with database access... Not sure, but I think we are still in the same web request work unit. If so, I think the NHibernate session / transaction isn't yet closed / commited... Needs to be tested