Exposing WCF Data Service (OData) in an Orchard Module

Topics: Writing modules
Jun 23, 2011 at 5:09 PM

Hi there,

I can expose a regular WCF service from an Orchard Module.
Now I need to expose a WCF Data Service from an Orchard Module and am having trouble getting it to work.
Has anyone done this?
Is there any module that does this?

Thx! 

Jun 23, 2011 at 6:19 PM

Got this to work.
In case someone else needs it, this is how I did it.
The main difficulty I was having was using OrchardServiceHostFactory. When I used DataServiceHostFactory it just worked.
Using DataServiceHostFactory did not require me to modify the svc file (nor codebehind).

To register the DataService:

        private static ServiceRoute _route2 = new ServiceRoute("Services/Test",
                                              new DataServiceHostFactory(),
                                              typeof(AcDataService));

        public IEnumerable<RouteDescriptor> GetRoutes()
        {
            return new[] {
                     new RouteDescriptor {   Priority = 20,
                                            Route = _route2

                    }
                };
        }


Jun 23, 2011 at 7:18 PM

What is the source of your data? I think the drawback of using DataServiceHostFactory directly is that your service is not integrated with Orchard’s IoC container.

Jun 23, 2011 at 7:42 PM

It's an EntityFramework 4 EntityModel.
I could not get it to work using the Orchard HostFactory. But for this particular case it is not a problem, as this module is pretty much isolated from Orchard. 

Jun 27, 2011 at 4:54 PM

santiagoIT no problem for you then, but generally both OrchardServiceHostFactory and DataServiceHostFactory extend the same base class: ServiceHostFactory.

Looks like what is needed is OrchardDataServiceHostFactory which extends DataServiceHostFactory.

Jun 28, 2011 at 1:11 AM
Edited Jun 28, 2011 at 1:13 AM

When you added your route using ServiceRoute, did IIS require you to enable ASP.NET compatibility mode? As soon as I add a ServiceRoute class I get a YSOD containing this error:

ASP.NET routing integration feature requires ASP.NET compatibility. Please see 'http://msdn.microsoft.com/en-us/library/ms731336.aspx' on how to do this.

Enabling ASP.NET compatibility requires a change to the root Web.Config of the site. Since I'm trying to add my WCF service to a module, I can't change the root Web.Config. Any thoughts?

Jun 28, 2011 at 4:45 PM

Hi there,

This is how my root web.config looks like.

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
  </system.serviceModel>

 

Jun 28, 2011 at 7:20 PM
Edited Jun 28, 2011 at 7:21 PM

@santiagoIT,

Thanks for the response. When I copied your sample XML into my root Web.config my service started working. I'll proceed like this for now. I just wish there was a way to do it that did not require modifying the root Web.Config since my web service is in a module. Apparently the module Web.config cannot enable ASP.NET compatibility mode. I guess I'll just have to include some documentation with my module telling the user how to manually modify their Web.config file.

Jun 28, 2011 at 8:10 PM
Edited Jun 28, 2011 at 8:11 PM

@moorster, In my case I needed to modify the root web.config anyway => EntityFramework will search for the Connection String in the root web.config. My module is for internal use only.
In your case, as you are building a distributable module, you should try to set that value programatically.

http://www.progtown.com/topic31653-wcf-how-program-to-set-aspnetcompatibilityenabled-true.html


Please let me know if it works. If it does I'll see if I can set the EF ConnectionString programatically as well, and leave the root web.config untouched as well.


 

Jun 28, 2011 at 8:24 PM
Edited Jun 28, 2011 at 8:25 PM

@santiagoIT,

Great suggestion about setting it programmatically. I have been looking at ways to enable Asp.Net Compatibility programmatically but no luck so far.

I was able to reduce the necessary XML snippet down to this:

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>

Then I thought, hey, maybe I can create a custom Orchard command that is run during setup, perhaps in a module recipe. I did a little research and I figured out that it is theoretically possible to modify the Web.Config file programmatically at runtime. I tried adding a command to my module to do this but I ran into the problem that my module won't even compile if the aspNetCompatibilityEnabled flag is not set. So I have a bit of a catch-22 going on. I think my next step will be to create a separate module that enables Asp.Net Compatibility, then have my module depend on that module. It's crazy enough that it just might work.


Jun 28, 2011 at 8:30 PM

@moorster,
good luck!
Let us know what the outcome is!

Jun 28, 2011 at 8:52 PM

Ok, it seems to be working. I created a little module called AspNetCompatibility containing a single command: enableaspnetcompatibility. It just contains the following code:

    public class EnableAspNetCompatibilityCommand : Orchard.Commands.DefaultOrchardCommandHandler
    {
        [CommandName("enableaspcompatibility")]
        [CommandHelp(@"Enables Asp.Net Compatibility by modifying the site's root web.config file.")]
        public void EnableAspNetCompatibility() 
        {
            Configuration config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
            ServiceModelSectionGroup serviceModelGroup = System.ServiceModel.Configuration.ServiceModelSectionGroup.GetSectionGroup(config);

            if (serviceModelGroup.ServiceHostingEnvironment.AspNetCompatibilityEnabled)
            {
                Context.Output.WriteLine("AspNetCompatibility already enabled for ServiceHostingEnvironment");
            }
            else
            {
                Context.Output.WriteLine("Enabling AspNetCompatibility for ServiceHostingEnvironment");
                serviceModelGroup.ServiceHostingEnvironment.AspNetCompatibilityEnabled = true;
            }

            if (serviceModelGroup.ServiceHostingEnvironment.MultipleSiteBindingsEnabled)
            {
                Context.Output.WriteLine("MultipleSiteBindings already enabled for ServiceHostingEnvironment");
            }
            else
            {
                Context.Output.WriteLine("Enabling MultipleSiteBindings for ServiceHostingEnvironment");
                serviceModelGroup.ServiceHostingEnvironment.MultipleSiteBindingsEnabled = true;
            }

            config.Save();
        }
    }

It seems to work. I'll have to finish my other module before I can test the dependency, but it seems to be working in isolation. I could contribute this little module if it helps anyone else.

Jul 27, 2011 at 7:50 AM

@moorster I'm very interested in your module could maybe sent my the source or and publish module? I've mailed you. Thanks!

Aug 2, 2011 at 6:12 PM
Edited Aug 2, 2011 at 6:35 PM

Hello. Could you please describe in details, step by step how to configure module for hosting WCF service? I have tried everything but still have no results. Here my discussion http://orchard.codeplex.com/discussions/266930. Many thanks.