diff --git a/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js b/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js index d1fb8874a..edbae4a0a 100644 --- a/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js +++ b/src/Orchard.Web/Modules/Orchard.DesignerTools/Scripts/orchard-designertools-shapetracing.js @@ -1,5 +1,5 @@ -jQuery(document).ready(function ($) { - $(function () { +(function ($) { + $(document).ready(function () { // default shape window height when first opened var defaultHeight = 200; @@ -461,4 +461,4 @@ return node; } -}); +})(jQuery); diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index 5f6286d6f..b04239903 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -74,6 +74,7 @@ 3.5 + diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index 00553c25f..be112c42c 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -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(); diff --git a/src/Orchard/Environment/IOrchardHost.cs b/src/Orchard/Environment/IOrchardHost.cs index dd9018657..476f6af72 100644 --- a/src/Orchard/Environment/IOrchardHost.cs +++ b/src/Orchard/Environment/IOrchardHost.cs @@ -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 { /// void EndRequest(); + ShellContext GetShellContext(ShellSettings shellSettings); + /// /// 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. diff --git a/src/Orchard/Environment/RunningShellTable.cs b/src/Orchard/Environment/RunningShellTable.cs index 4e4db5987..e78ac9cb6 100644 --- a/src/Orchard/Environment/RunningShellTable.cs +++ b/src/Orchard/Environment/RunningShellTable.cs @@ -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; } - } } diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 6e21aa3e1..3e58275c3 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -121,6 +121,8 @@ 3.0 + + @@ -494,6 +496,10 @@ + + + + diff --git a/src/Orchard/Wcf/OrchardDependencyInjectionServiceBehavior.cs b/src/Orchard/Wcf/OrchardDependencyInjectionServiceBehavior.cs new file mode 100644 index 000000000..7c9453233 --- /dev/null +++ b/src/Orchard/Wcf/OrchardDependencyInjectionServiceBehavior.cs @@ -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 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 source = serviceDescription.Endpoints.Where(delegate(ServiceEndpoint ep) { + return ep.Contract.ContractType.IsAssignableFrom(this._implementationType); + }).Select(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(dispatcher2.ContractName)) { + dispatcher2.DispatchRuntime.InstanceProvider = provider; + } + } + continue; + } + } + } + + public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { + } + } +} diff --git a/src/Orchard/Wcf/OrchardInstanceContext.cs b/src/Orchard/Wcf/OrchardInstanceContext.cs new file mode 100644 index 000000000..19fd96800 --- /dev/null +++ b/src/Orchard/Wcf/OrchardInstanceContext.cs @@ -0,0 +1,31 @@ +using System; +using System.Linq; +using System.ServiceModel; +using Autofac; +using Autofac.Core; + +namespace Orchard.Wcf { + public class OrchardInstanceContext : IExtension, 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().Resolve(registration, Enumerable.Empty()); + } + } +} diff --git a/src/Orchard/Wcf/OrchardInstanceProvider.cs b/src/Orchard/Wcf/OrchardInstanceProvider.cs new file mode 100644 index 000000000..1d1336d80 --- /dev/null +++ b/src/Orchard/Wcf/OrchardInstanceProvider.cs @@ -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(); + if (context != null) { + context.Dispose(); + } + } + } +} diff --git a/src/Orchard/Wcf/OrchardServiceHostFactory.cs b/src/Orchard/Wcf/OrchardServiceHostFactory.cs new file mode 100644 index 000000000..52eccb3b4 --- /dev/null +++ b/src/Orchard/Wcf/OrchardServiceHostFactory.cs @@ -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(); + ShellSettings shellSettings = runningShellTable.Match(baseAddresses.First().Host, baseAddresses.First().LocalPath); + + IOrchardHost orchardHost = HostContainer.Resolve(); + ShellContext shellContext = orchardHost.GetShellContext(shellSettings); + IWorkContextAccessor workContextAccessor = shellContext.LifetimeScope.Resolve(); + + using (IWorkContextScope workContext = workContextAccessor.CreateWorkContextScope()) { + + ILifetimeScope lifetimeScope = workContext.Resolve(); + 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; + } + } +}