WCF SOAP and OrchardServiceHostFactory

Topics: Administration, Customizing Orchard, General
Jul 28, 2011 at 4:27 PM
Edited Jul 28, 2011 at 4:44 PM

Hello. I have created WCF SOAP service hosted in module and I am trying call that service. I developped service according to Orchard documentation. I've created svc file and added following <%@ ServiceHost Language="C#" Service="Application.Services.IMembershipManagerService" Factory="Orchard.Wcf.OrchardServiceHostFactory, Orchard.Framework" %>. But when I try test service in browser I am always get error 404 not found. Even after adding Route.cs I have same error here code

 

public class Routes : IRouteProvider   
{        
      public void GetRoutes(ICollection<RouteDescriptor> routes)       
      {            
          foreach (var routeDescriptor in GetRoutes())                                            
routes.Add(routeDescriptor);
}
 
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[]
{
new RouteDescriptor {
Priority = 5,
Route = new ServiceRoute(
"service",
new
OrchardServiceHostFactory(),
typeof(IMembershipManagerService))}
};
}
}
}
Can somebody help? How to actually use wcf services SOAP and REST in Orchard? Thanks.
Coordinator
Jul 29, 2011 at 1:16 AM

Maybe you need to allow the extension to be served, from web.config?

Jul 29, 2011 at 12:27 PM
Edited Jul 29, 2011 at 12:33 PM
bertrandleroy wrote:

Maybe you need to allow the extension to be served, from web.config?

Could you please clarify what you mean? Thanks. Here module's web.config

<?xml version="1.0"?>
<configuration>

  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <remove name="host" />
      <remove name="pages" />
      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
    </sectionGroup>
  </configSections>

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <pages pageBaseType="Orchard.Mvc.ViewEngines.Razor.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Linq"/>
        <add namespace="System.Collections.Generic"/>
        <add namespace="Orchard.Mvc.Html"/>
      </namespaces>
    </pages>
  </system.web.webPages.razor>

 
  <system.web>
    <compilation targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </assemblies>
    </compilation>
  </system.web>

  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel" switchValue="Warning,ActivityTracing"
          propagateActivity="true">
        <listeners>
          <add type="System.Diagnostics.DefaultTraceListener" name="Default">
            <filter type="" />
          </add>
          <add name="ServiceModelTraceListener">
            <filter type="" />
          </add>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add initializeData="C:\Logs\appservices_tracelog.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
          name="ServiceModelTraceListener" traceOutputOptions="LogicalOperationStack, DateTime, Timestamp, ProcessId, ThreadId, Callstack">
        <filter type="" />
      </add>
    </sharedListeners>
  </system.diagnostics>
 
  <system.serviceModel>
    <services>
      <service name="Application.Services.MembershipManagerService" behaviorConfiguration="BusinessToBusiness">
        <endpoint address="datatier" binding="wsHttpBinding" bindingConfiguration="wsHttpBindingConfig" contract="Application.Services.IMembershipManagerService"/>
      </service>
    </services>

    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpBindingConfig" transactionFlow="true">
          <security mode="Message">
            <message clientCredentialType="Certificate" />
          </security>
          <reliableSession enabled="true" />
        </binding>
      </wsHttpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior name="BusinessToBusiness">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceCredentials>
            <serviceCertificate findValue="CN=certname, OU=C2C, O=orgname, L=AT, S=GA, C=US"
                                storeLocation="LocalMachine"
                                storeName="My"
                                x509FindType="FindBySubjectDistinguishedName" />
            <clientCertificate>
              <authentication certificateValidationMode="PeerOrChainTrust"/>
            </clientCertificate>
          </serviceCredentials>

          <serviceAuthorization principalPermissionMode="None" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

when I try open svc I still have error HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.

here URL http://localhost/c2c/Modules/Application.Services/MembershipManagerService.svc

Coordinator
Jul 29, 2011 at 9:24 PM

Did you read this? http://orchard.codeplex.com/discussions/262524

Aug 2, 2011 at 4:56 PM

Following piece of code from OrchardServiceHostFactory.cs returns null when I try call my svc file

private IComponentRegistration GetRegistration(ILifetimeScope lifetimeScope, string constructorString) {
            IComponentRegistration registration;
            if (!lifetimeScope.ComponentRegistry.TryGetRegistration(new KeyedService(constructorString, typeof(object)), out registration)) {
                Type serviceType = Type.GetType(constructorString, false);
                if (serviceType != null) {
                    lifetimeScope.ComponentRegistry.TryGetRegistration(new TypedService(serviceType), out registration);
                }
            }

            return registration;
        }

I have missed something?

Aug 2, 2011 at 5:08 PM
aandriichuk wrote:

Following piece of code from OrchardServiceHostFactory.cs returns null when I try call my svc file

private IComponentRegistration GetRegistration(ILifetimeScope lifetimeScope, string constructorString) {
            IComponentRegistration registration;
            if (!lifetimeScope.ComponentRegistry.TryGetRegistration(new KeyedService(constructorString, typeof(object)), out registration)) {
                Type serviceType = Type.GetType(constructorString, false);
                if (serviceType != null) {
                    lifetimeScope.ComponentRegistry.TryGetRegistration(new TypedService(serviceType), out registration);
                }
            }

            return registration;
        }

I have missed something?

Looks like instance of my service is not present in IoC container because TryGetRegistration returns null. I use IDependency interface with contract of service. Maybe I have to add it manually into IoC container. Should I do something in root web application or enough only in module? Thanks.

Aug 3, 2011 at 5:40 PM

Problem solved. Was error in routing. Thanks for your help.

Coordinator
Aug 3, 2011 at 8:06 PM

Great. Thanks for your patience.

Dec 6, 2011 at 1:51 PM

Where you ever able to get access to the Orchard services registered in autofac?  I'm looking to get to interfaces like ILogger, IAuthorizer,  etc.  My service runs within Orchard and is created with OrchardServiveHostFactory.  A host container is injected but still no luck on resolving the objects.  Let me know if you can share a technique or code.

 

Thanks

 

    public class CNService : ICNService, Orchard.Environment.IShim

    {
        private IOrchardHostContainer hostContainer = null;
       public CNService()
        { 
            OrchardHostContainerRegistry.RegisterShim(this);
            IRunningShellTable runningShellTable = HostContainer.Resolve<IRunningShellTable>();
            HttpContextWrapper contextWrapper = new HttpContextWrapper(HttpContext.Current);
            ShellSettings shellSettings = runningShellTable.Match(contextWrapper);
            IOrchardHost orchardHost = HostContainer.Resolve<IOrchardHost>();

            ShellContext shellContext = orchardHost.GetShellContext(shellSettings);
            IWorkContextAccessor workContextAccessor = shellContext.LifetimeScope.Resolve<IWorkContextAccessor>();
            WorkContext workContext = workContextAccessor.GetContext();


            ILifetimeScope lifetimeScope = workContext.Resolve<ILifetimeScope>();
            IComponentRegistration registration;
            lifetimeScope.ComponentRegistry.TryGetRegistration(new TypedService(ILogger), out registration);



            ILogger logger = workContext.Resolve<ILogger>();

        }

Dec 6, 2011 at 2:07 PM

Generally you should inject dependencies in your constructor, e.g.:

private readonly IWorkContextAccessor _workContextAccessor;

public CNService(IWorkContextAccessor workContextAccessor) {
  _workContextAccessor = workContextAccessor;
}

There are literally thousands of examples of this in Orchard source code.

Just one caveat with ILogger - the injection works differently. You can just assign NullLogger.Instance to a public property, and it gets set for you. There are very few dependencies that work differently like this.

 

Dec 6, 2011 at 2:22 PM

Thanks for the quick response.  I'm writing a WCF service which requires a default construtor (no params).  How do I reconcile that with the constructor injection.  For instance, if I wanted INotifier and IAuthorizer in my web service how would I got those injected.

Any help would be great!

Thanks

Dec 6, 2011 at 2:42 PM

I'm not actually sure if that can work (maybe someone will correct me on that), although you could try creating a custom Autofac registration, but if the service is getting instanced somewhere you have no control over, that won't help.

Your best bet might be to have a separate service on the Orchard side that can look up a singleton of your service and then pass in any data it needs ... ?

Dec 6, 2011 at 6:22 PM

Thanks.  The OrchardHostServiceFactory seems to inject a HostContainer with a ton of instances registered.  But I can't resolve them.  We'll maybe some one has knows for sure.  Thanks again.

Mar 2, 2012 at 1:39 PM
Edited Mar 2, 2012 at 1:42 PM

SonnyPolaris,

I have had the same problem with the HostContainer and not being able to resolve instances. I posted the code on stackoverflow about a week ago, maybe it's of some use for you.

Look at the LifeTimeScope and the LifeTimeScopeExtensions

My answer to someone that wanted to use openrasta
http://stackoverflow.com/questions/9393014/orchard-cms-creating-module-for-openrasta-problems-with-dependency-injection/9395504#9395504