Where IOrchardServices gets injected?

Topics: Customizing Orchard, General
Jul 19, 2011 at 8:32 PM

I am trying to determine where IOrchardServices injects its concrete class. I notice that in Orchard.Framework/Environment/OrchardStarter.cs there are many

builder.RegisterType<XXX>().As<Ixxx>().SingleInstance();

and I am trying to determine where IOrchardServices's concrete class is injected. 

On this page, http://orchardproject.net/docs/Developer-FAQ.ashx#How_do_I_do_authorization_inside_my_module_against_current_userroles_8, under the subheading 'How do I do authorization inside my module against current user/roles?', the Orchard team mentions that in 'your' controller's constructor do the following:

public AdminController(IOrchardServices orchardServices) {
    MyServicesProperty = orchardServices;
}

and that the IOrchardServices will be injected with a concrete class. However, I'd like to know where that code does it in the Orchard source.

The reason I ask is because our team is looking at Orchard but we have a large webforms application that can only be moved over slowly and I need a way to perform property injection on a codebehind class so that when I have a property of IOrchardServices it'll get injected properly. Now, I've determined that aspx pages can be served inside the same aspnet mvc app running Orchard, just need to know how to get access to users/roles and what not.

Thanks,

Coordinator
Jul 19, 2011 at 9:10 PM

I'm asking around but I'm not sure this is possible.

Jul 19, 2011 at 9:22 PM

Can you tell me where IOrchardServices gets injected with its concrete class? In the Orchard.Web Global.asax.cs file there is a 

static void MvcSingletons(ContainerBuilder builder) {
    builder.Register(ctx => RouteTable.Routes).SingleInstance();
    builder.Register(ctx => ModelBinders.Binders).SingleInstance();
    builder.Register(ctx => ViewEngines.Engines).SingleInstance();

    // here I could add my own stuff
    builder.Register ........
}

there I could add my own stuff, just want to see what the IOrchardServices injection code looks like.

Thanks,

Coordinator
Jul 19, 2011 at 9:27 PM

Adding your stuff to the registry is not going to help as far as I understand your scenario. It seems like what you need it to get an instance of a service. That is the part that I don't know is possible without constructor injection or special code in the core. Investigating.

Jul 19, 2011 at 9:31 PM

Thanks,

I did a search on AutoFac's site, looks like property injection can be done.

Coordinator
Jul 19, 2011 at 9:50 PM

Yes, but that doesn't mean that it will work in the context of Orchard without changes to the core. If you don't want to wait for an answer and investigate it on your own, that's fine of course.

Jul 19, 2011 at 10:20 PM

I'll continue to investigate and play around with the source until I get an answer back from you. Thanks again for the help.

Jul 3, 2012 at 10:59 PM

Did anyone figure out a good way to do this?  I'm in a very peculiar situation where I need a webform to grab an Orchard dependency. 

Developer
Jul 3, 2012 at 11:44 PM
Edited Jul 3, 2012 at 11:45 PM

If you hack the core of Orchard, you may be able to implement the Service Locator pattern (using Microsoft's ServiceLocator nuget package). What you'll do is create an adapter class (a class that implements IServiceLocator) and set that one as the current service locator on ServiceLocator.SetCurrentLocator (or something similar).
You would do this in the same place where Autofac is configured: in the OrchardStarter class.

Alternatively, you could turn the local variable found there into a static property of OrchardStarter, since it implements IOrchardHostContainer which has a Resolve method which you could invoke from your web forms.

 I haven't tried this so I don't know if you'll run into any issues or if it works at all.

Jul 4, 2012 at 1:07 AM

Thought I was close, but now when I try ServiceLocator.Current.GetInstance<IWorkContextAccessor>();  It says it hasn't been registered.  I can resolve IOrchardHost, but can't get to what I need, IOrchardServices, IWorkContextAccessor, etc.  I guess these haven't been registered at this point, or maybe it's something to do with those being shell specific?  I'm still digging.

Jul 4, 2012 at 1:17 AM

Okay, this seems to work, but I'll have to look into performance implications of this...

var locator = ServiceLocator.Current;            
var host = locator.GetInstance<IOrchardHost>();
var settings = locator.GetInstance<IShellSettingsManager>().LoadSettings();
var defaultSettings = settings.FirstOrDefault(s => s.Name == "Default");
var shell = host.CreateStandaloneEnvironment(defaultSettings);
var context = shell.Resolve<IWorkContextAccessor>();

Coordinator
Jul 4, 2012 at 6:45 AM

oh wow, I just wanted to chime in and say that sounds dreadful :D Grabbing an Orchard instance from WebForms, wow. Peculiar indeed.

Developer
Jul 4, 2012 at 12:54 PM

It IS dreadful, of course. But I figured that could go without saying.

Jul 4, 2012 at 4:56 PM
Edited Jul 4, 2012 at 4:59 PM

Ya, this isn't the way I wanted to do things.  I'll give you the scenario if you're curious, and maybe you can find a way out of doing it this way.  Basically, we are using Orchard as an employee website accessible inside our network and from anywhere on the internet too.  We built an Active Directory membership provider so the authentication mechanism is handled that way when someone uses the login screen.  The problem is that our users hate logging in when they are already logged into their computers.  (We have thousands of users)  They are used to having windows authentication handle their login for them.  So, we need a mixed mode authentication mechanism that allows users on the network to authenticate with windows auth seamlessly without ever seeing a login screen, and external users should be taken to the login screen.  

Someone wrote a great blog post about how to change IIS settings on the fly to make this happen:  http://mvolo.com/iis-70-twolevel-authentication-with-forms-authentication-and-windows-authentication  

Where I got into the issue though was where this requires web.config settings under a <location> element.  As far as I can tell, these are only capable of mapping to a file or folder that's actually on disk.  So, this rules out using a route that would fire a controller action.  A webform works great for this, but then I need to grab Orchard dependencies in order to sign in the windows user.  

If there is a way to make the <location> element map to a route, or another way to have those settings changed without the location element, I wouldn't have this problem.  So far, I haven't seen a way around it.   

So, in the end, I agree that it's dreadful.  I don't want to do it this way.  If you have any ideas, I'm all ears.  Thanks guys!  You're always very helpful in these discussions.  

Jul 4, 2012 at 5:47 PM

I haven't used it yet, but as far as I know you can leverage ADFS to authenticate users against either AD or any other identity provider. Don't know what changes need to be made in Orchard and as I said I never used it, but might be worth some investigation.

Jul 5, 2012 at 12:33 AM

@JasperD I will have a look, but I think my problem pertains more to IIS windows auth than AD authentication. 

Coordinator
Jul 5, 2012 at 6:00 AM

Oh, so it's just so you can use the same authentication in the webforms app and the Orchard app? Well, authentication is pluggable in both WebForms and Orchard, so there is a better way: implement a membership provider in one, the other or both so they speak the same authentication language.

Jul 5, 2012 at 3:29 PM

Ok, this might sound crazy, but I think it's the simplest way to handle this.  I only have one webform, it's just there to allow IIS to windows authenticate.  When a user goes to the windows authenticated web form, I'm going to simply take the windows credentials, put them in a session variable, and redirect to a route where I can then use Orchard's dependencies to do all the other things I need to do.  (Authenticate, Sign In, Possibly Create a User on the fly etc.)  

This gets me out of the problem of pulling dependencies into web forms.