Adding Orchard Service Host Factory and IoC behavior for WCF support.

--HG--
branch : 1.x
extra : transplant_source : %93%05%12%2Ag8%08c%D5%7Co%DA%5B%5C%B2%C4%81%C3w%3A
This commit is contained in:
Andre Rodrigues
2011-03-28 09:29:51 -07:00
parent d1962c2615
commit 6a90e8fe2e
9 changed files with 231 additions and 5 deletions

View File

@@ -74,6 +74,7 @@
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />

View File

@@ -51,6 +51,11 @@ namespace Orchard.Environment {
get { return BuildCurrent().ToReadOnlyCollection(); }
}
public ShellContext GetShellContext(ShellSettings shellSettings) {
return Current
.Single(shellContext => shellContext.Settings.Name.Equals(shellSettings.Name));
}
void IOrchardHost.Initialize() {
Logger.Information("Initializing");
BuildCurrent();

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using Orchard.Environment.Configuration;
using Orchard.Environment.ShellBuilders;
namespace Orchard.Environment {
public interface IOrchardHost {
@@ -23,6 +25,8 @@ namespace Orchard.Environment {
/// </summary>
void EndRequest();
ShellContext GetShellContext(ShellSettings shellSettings);
/// <summary>
/// Can be used to build an temporary self-contained instance of a shell's configured code.
/// Services may be resolved from within this instance to configure and initialize it's storage.

View File

@@ -10,6 +10,7 @@ namespace Orchard.Environment {
void Remove(ShellSettings settings);
void Update(ShellSettings settings);
ShellSettings Match(HttpContextBase httpContext);
ShellSettings Match(string host, string appRelativeCurrentExecutionFilePath);
}
public class RunningShellTable : IRunningShellTable {
@@ -75,15 +76,15 @@ namespace Orchard.Environment {
}
public ShellSettings Match(HttpContextBase httpContext) {
// use Host header to prevent proxy alteration of the orignal request
var host = httpContext.Request.Headers["Host"];
return Match(httpContext.Request.Headers["Host"], httpContext.Request.AppRelativeCurrentExecutionFilePath);
}
public ShellSettings Match(string host, string appRelativePath) {
// use Host header to prevent proxy alteration of the orignal request
var hostLength = host.IndexOf(':');
if (hostLength != -1)
host = host.Substring(0, hostLength);
var appRelativePath = httpContext.Request.AppRelativeCurrentExecutionFilePath;
var mostQualifiedMatch = _shellsByHost
.Where(group => host.EndsWith(group.Key, StringComparison.OrdinalIgnoreCase))
.SelectMany(group => group
@@ -93,6 +94,5 @@ namespace Orchard.Environment {
return mostQualifiedMatch ?? _fallback;
}
}
}

View File

@@ -121,6 +121,8 @@
<Reference Include="System.Runtime.Serialization">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceModel.Activation" />
<Reference Include="System.Transactions" />
<Reference Include="System.Web" />
<Reference Include="System.Web.ApplicationServices" />
@@ -494,6 +496,10 @@
<Compile Include="Utility\Extensions\ControllerExtensions.cs" />
<Compile Include="Utility\Extensions\VirtualPathProviderExtensions.cs" />
<Compile Include="Validation\PathValidation.cs" />
<Compile Include="Wcf\OrchardDependencyInjectionServiceBehavior.cs" />
<Compile Include="Wcf\OrchardInstanceContext.cs" />
<Compile Include="Wcf\OrchardInstanceProvider.cs" />
<Compile Include="Wcf\OrchardServiceHostFactory.cs" />
<Compile Include="WorkContextExtensions.cs" />
<Compile Include="Mvc\ViewEngines\Razor\RazorCompilationEventsShim.cs" />
<Compile Include="Mvc\ViewEngines\Razor\RazorViewEngineProvider.cs" />

View File

@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Autofac;
using Autofac.Core;
namespace Orchard.Wcf {
public class OrchardDependencyInjectionServiceBehavior : IServiceBehavior {
private readonly IWorkContextAccessor _workContextAccessor;
private readonly Type _implementationType;
private readonly IComponentRegistration _componentRegistration;
public OrchardDependencyInjectionServiceBehavior(IWorkContextAccessor workContextAccessor, Type implementationType, IComponentRegistration componentRegistration) {
if (workContextAccessor == null) {
throw new ArgumentNullException("workContextAccessor");
}
if (implementationType == null) {
throw new ArgumentNullException("implementationType");
}
if (componentRegistration == null) {
throw new ArgumentNullException("componentRegistration");
}
_workContextAccessor = workContextAccessor;
_implementationType = implementationType;
_componentRegistration = componentRegistration;
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) {
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {
if (serviceDescription == null) {
throw new ArgumentNullException("serviceDescription");
}
if (serviceHostBase == null) {
throw new ArgumentNullException("serviceHostBase");
}
IEnumerable<string> source = serviceDescription.Endpoints.Where<ServiceEndpoint>(delegate(ServiceEndpoint ep) {
return ep.Contract.ContractType.IsAssignableFrom(this._implementationType);
}).Select<ServiceEndpoint, string>(delegate(ServiceEndpoint ep) {
return ep.Contract.Name;
});
OrchardInstanceProvider provider = new OrchardInstanceProvider(this._workContextAccessor, this._componentRegistration);
foreach (ChannelDispatcherBase base2 in serviceHostBase.ChannelDispatchers) {
ChannelDispatcher dispatcher = base2 as ChannelDispatcher;
if (dispatcher != null) {
foreach (EndpointDispatcher dispatcher2 in dispatcher.Endpoints) {
if (source.Contains<string>(dispatcher2.ContractName)) {
dispatcher2.DispatchRuntime.InstanceProvider = provider;
}
}
continue;
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Linq;
using System.ServiceModel;
using Autofac;
using Autofac.Core;
namespace Orchard.Wcf {
public class OrchardInstanceContext : IExtension<InstanceContext>, IDisposable {
private readonly IWorkContextScope _workContextScope;
public OrchardInstanceContext(IWorkContextAccessor workContextAccessor) {
_workContextScope = workContextAccessor.CreateWorkContextScope();
}
public void Attach(InstanceContext owner) {}
public void Detach(InstanceContext owner) {}
public void Dispose() {
_workContextScope.Dispose();
}
public object Resolve(IComponentRegistration registration) {
if (registration == null) {
throw new ArgumentNullException("registration");
}
return _workContextScope.Resolve<ILifetimeScope>().Resolve(registration, Enumerable.Empty<Parameter>());
}
}
}

View File

@@ -0,0 +1,35 @@
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using Autofac;
using Autofac.Core;
namespace Orchard.Wcf {
public class OrchardInstanceProvider : IInstanceProvider {
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IComponentRegistration _componentRegistration;
public OrchardInstanceProvider(IWorkContextAccessor workContextAccessor, IComponentRegistration componentRegistration) {
_workContextAccessor = workContextAccessor;
_componentRegistration = componentRegistration;
}
public object GetInstance(InstanceContext instanceContext, Message message) {
OrchardInstanceContext item = new OrchardInstanceContext(_workContextAccessor);
instanceContext.Extensions.Add(item);
return item.Resolve(_componentRegistration);
}
public object GetInstance(InstanceContext instanceContext) {
return GetInstance(instanceContext, null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance) {
OrchardInstanceContext context = instanceContext.Extensions.Find<OrchardInstanceContext>();
if (context != null) {
context.Dispose();
}
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using Autofac;
using Autofac.Core;
using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Environment.ShellBuilders;
namespace Orchard.Wcf {
public class OrchardServiceHostFactory : ServiceHostFactory, IShim {
public OrchardServiceHostFactory() {
OrchardHostContainerRegistry.RegisterShim(this);
}
public IOrchardHostContainer HostContainer { get; set; }
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses) {
IComponentRegistration registration;
if (constructorString == null) {
throw new ArgumentNullException("constructorString");
}
if (constructorString == string.Empty) {
throw new ArgumentOutOfRangeException("constructorString");
}
if (HostContainer == null) {
throw new InvalidOperationException();
}
// Create work context
IRunningShellTable runningShellTable = HostContainer.Resolve<IRunningShellTable>();
ShellSettings shellSettings = runningShellTable.Match(baseAddresses.First().Host, baseAddresses.First().LocalPath);
IOrchardHost orchardHost = HostContainer.Resolve<IOrchardHost>();
ShellContext shellContext = orchardHost.GetShellContext(shellSettings);
IWorkContextAccessor workContextAccessor = shellContext.LifetimeScope.Resolve<IWorkContextAccessor>();
using (IWorkContextScope workContext = workContextAccessor.CreateWorkContextScope()) {
ILifetimeScope lifetimeScope = workContext.Resolve<ILifetimeScope>();
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);
}
}
}
if (registration == null) {
throw new InvalidOperationException();
}
if (!registration.Activator.LimitType.IsClass) {
throw new InvalidOperationException();
}
return CreateServiceHost(workContextAccessor, registration, registration.Activator.LimitType, baseAddresses);
}
private ServiceHost CreateServiceHost(IWorkContextAccessor workContextAccessor, IComponentRegistration registration, Type implementationType, Uri[] baseAddresses) {
ServiceHost host = CreateServiceHost(implementationType, baseAddresses);
host.Opening += delegate {
host.Description.Behaviors.Add(new OrchardDependencyInjectionServiceBehavior(workContextAccessor, implementationType, registration));
};
return host;
}
}
}