mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
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:
@@ -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" />
|
||||
|
@@ -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();
|
||||
|
@@ -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.
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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" />
|
||||
|
71
src/Orchard/Wcf/OrchardDependencyInjectionServiceBehavior.cs
Normal file
71
src/Orchard/Wcf/OrchardDependencyInjectionServiceBehavior.cs
Normal 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) {
|
||||
}
|
||||
}
|
||||
}
|
31
src/Orchard/Wcf/OrchardInstanceContext.cs
Normal file
31
src/Orchard/Wcf/OrchardInstanceContext.cs
Normal 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>());
|
||||
}
|
||||
}
|
||||
}
|
35
src/Orchard/Wcf/OrchardInstanceProvider.cs
Normal file
35
src/Orchard/Wcf/OrchardInstanceProvider.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
73
src/Orchard/Wcf/OrchardServiceHostFactory.cs
Normal file
73
src/Orchard/Wcf/OrchardServiceHostFactory.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user