User: xtoff
Date: 2009/12/05 08:50 AM

Added:
 /Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/
  PerWcfSessionLifestyleTestCase.cs
 /Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/
  IOne.cs, IServiceWithSession.cs, ITwo.cs, One.cs, ServiceWithSession.cs, 
Two.cs
 /Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/
  IOperationContextProvider.cs, IWcfLifestyle.cs, 
LifestyleRegistrationExtensions.cs, OperationContextProvider.cs, 
PerChannelLifestyleExtension.cs, PerWcfSessionLifestyle.cs

Modified:
 /Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/
  Castle.Facilities.WcfIntegration.Tests-vs2008.csproj, WcfServiceFixture.cs
 /Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/
  Castle.Facilities.WcfIntegration-vs2008.csproj
 /Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Client/Proxy/
  WcfProxyGenerationHook.cs

Log:
 - added intial implementation of per-WCF-Session lifetime.

File Changes:

Directory: /Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/
======================================================================

File [modified]: Castle.Facilities.WcfIntegration-vs2008.csproj
Delta lines: +1 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Client/Proxy/WcfProxyGenerationHook.cs
    2009-12-05 08:38:19 UTC (rev 6391)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Client/Proxy/WcfProxyGenerationHook.cs
    2009-12-05 15:50:04 UTC (rev 6392)
@@ -32,6 +32,7 @@
 
                public bool ShouldInterceptMethod(Type type, MethodInfo 
methodInfo)
                {
+                       // NOTE: This is fixed now. This code can be 
uncommented and Selector does not have to have this responsibility anymore
                        // BUG: Due to... illogical behavior of DP this will 
produce illformed proxy types.
                        // We have to move this piece of logic to 
InterceptorSelector, and move it back when the bug gets fixed.

Directory: /Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/
============================================================================

File [modified]: Castle.Facilities.WcfIntegration.Tests-vs2008.csproj
Delta lines: +21 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/IOne.cs
                          (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/IOne.cs
  2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,21 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.Facilities.WcfIntegration.Tests.Components
+{
+       public interface IOne
+       {
+               void Do(string s);
+       }
+}

File [added]: PerWcfSessionLifestyleTestCase.cs
Delta lines: +1 -3
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/WcfServiceFixture.cs
        2009-12-05 08:38:19 UTC (rev 6391)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/WcfServiceFixture.cs
        2009-12-05 15:50:04 UTC (rev 6392)
@@ -17,12 +17,10 @@
        using System;
        using System.Collections.Generic;
        using System.ServiceModel;
-       using System.ServiceModel.Description;
+
        using Castle.Core;
        using Castle.Core.Interceptor;
-       using Castle.Facilities.WcfIntegration.Demo;
        using Castle.Facilities.WcfIntegration.Tests.Behaviors;
-       using Castle.MicroKernel;
        using Castle.MicroKernel.Registration;
        using Castle.Windsor;

File [modified]: WcfServiceFixture.cs
Delta lines: +0 -0
===================================================================

Directory: 
/Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/
=======================================================================================

File [added]: IOne.cs
Delta lines: +34 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/IServiceWithSession.cs
                           (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/IServiceWithSession.cs
   2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,34 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.Facilities.WcfIntegration.Tests.Components
+{
+       using System.ServiceModel;
+
+       [ServiceContract(SessionMode = SessionMode.Required)]
+       public interface IServiceWithSession
+       {
+               [OperationContract(IsInitiating = true, IsTerminating = false)]
+               void Initiating(string a);
+
+               [OperationContract(IsInitiating = false, IsTerminating = false)]
+               void Operation1(string a);
+
+               [OperationContract(IsInitiating = false, IsTerminating = false)]
+               void Operation2(string a);
+
+               [OperationContract(IsInitiating = false, IsTerminating = true)]
+               void Terminating();
+       }
+}

File [added]: IServiceWithSession.cs
Delta lines: +21 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/ITwo.cs
                          (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/ITwo.cs
  2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,21 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.Facilities.WcfIntegration.Tests.Components
+{
+       public interface ITwo
+       {
+               void Do(string s);
+       }
+}

File [added]: ITwo.cs
Delta lines: +31 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/One.cs
                           (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/One.cs
   2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,31 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.Facilities.WcfIntegration.Tests.Components
+{
+       public class One : IOne
+       {
+               private string arg;
+
+               public string Arg
+               {
+                       get { return arg; }
+               }
+
+               public void Do(string s)
+               {
+                       arg += s;
+               }
+       }
+}

File [added]: One.cs
Delta lines: +52 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/ServiceWithSession.cs
                            (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/ServiceWithSession.cs
    2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,52 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.Facilities.WcfIntegration.Tests.Components
+{
+       using System.ServiceModel;
+
+       [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
+       public class ServiceWithSession : IServiceWithSession
+       {
+               private readonly IOne one;
+               private readonly ITwo two;
+               public static int InstanceCount;
+
+               public ServiceWithSession(IOne one, ITwo two)
+               {
+                       this.one = one;
+                       this.two = two;
+                       InstanceCount++;
+               }
+
+               public void Initiating(string a)
+               {
+                       one.Do(a);
+               }
+
+               public void Operation1(string a)
+               {
+                       one.Do(a);
+               }
+
+               public void Operation2(string a)
+               {
+                       two.Do(a);
+               }
+
+               public void Terminating()
+               {
+               }
+       }
+}

File [added]: ServiceWithSession.cs
Delta lines: +31 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/Two.cs
                           (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Components/Two.cs
   2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,31 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.Facilities.WcfIntegration.Tests.Components
+{
+       public class Two : ITwo
+       {
+               private string arg;
+
+               public string Arg
+               {
+                       get { return arg; }
+               }
+
+               public void Do(string s)
+               {
+                       arg += s;
+               }
+       }
+}

File [added]: Two.cs
Delta lines: +136 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/PerWcfSessionLifestyleTestCase.cs
                           (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/PerWcfSessionLifestyleTestCase.cs
   2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,136 @@
+// Copyright 2004-2009 Castle Project - http://www.castleproject.org/
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace Castle.Facilities.WcfIntegration.Tests
+{
+       using System;
+       using System.Collections.Generic;
+       using System.Linq;
+       using System.ServiceModel;
+
+       using Castle.Core;
+       using Castle.Core.Interceptor;
+       using Castle.Facilities.WcfIntegration.Lifestyles;
+       using Castle.Facilities.WcfIntegration.Tests.Behaviors;
+       using Castle.Facilities.WcfIntegration.Tests.Components;
+       using Castle.MicroKernel.Registration;
+       using Castle.Windsor;
+
+       using NUnit.Framework;
+
+       [TestFixture]
+       public class PerWcfSessionLifestyleTestCase
+       {
+               [SetUp]
+               public void SetUp()
+               {
+                       windsorContainer = new WindsorContainer()
+                               .AddFacility<WcfFacility>(f => f.CloseTimeout = 
TimeSpan.Zero)
+                               .Register(
+                               Component.For<ServiceHostListener>(),
+                               Component.For<CollectingInterceptor>(),
+                               Component.For<UnitOfworkEndPointBehavior>(),
+                               Component.For<NetDataContractFormatBehavior>(),
+                               
Component.For<IOne>().ImplementedBy<One>().LifeStyle.PerWcfSession().Interceptors(
+                                       
InterceptorReference.ForType<CollectingInterceptor>()).Anywhere,
+                               
Component.For<ITwo>().ImplementedBy<Two>().LifeStyle.PerWcfSession().Interceptors(
+                                       
InterceptorReference.ForType<CollectingInterceptor>()).Anywhere,
+                               
Component.For<IServiceWithSession>().ImplementedBy<ServiceWithSession>().LifeStyle.Transient
+                                       .Named("Operations")
+                                       .ActAs(new 
DefaultServiceModel().AddEndpoints(
+                                               WcfEndpoint.BoundTo(new 
NetTcpBinding { PortSharingEnabled = true })
+                                                       
.At("net.tcp://localhost/Operations")
+                                               )
+                                       )
+                               );
+
+                       client = CreateClient();
+               }
+
+               [TearDown]
+               public void TearDown()
+               {
+                       windsorContainer.Dispose();
+                       ServiceWithSession.InstanceCount = 0;
+               }
+
+               private IWindsorContainer windsorContainer;
+               private IServiceWithSession client;
+
+               private IServiceWithSession CreateClient()
+               {
+                       return 
ChannelFactory<IServiceWithSession>.CreateChannel(
+                               new NetTcpBinding { PortSharingEnabled = true 
}, new EndpointAddress("net.tcp://localhost/Operations"));
+               }
+
+               [Test]
+               public void 
Services_should_be_reused_among_calls_within_session()
+               {
+                       client.Initiating("start ");
+                       client.Operation1("one ");
+                       client.Operation1("and again");
+                       client.Operation2("two ");
+                       client.Operation2("and two again");
+                       client.Terminating();
+                       IGrouping<object, IInvocation>[] invocations = 
windsorContainer.GetService<CollectingInterceptor>()
+                               .AllInvocations
+                               .GroupBy(i => i.InvocationTarget)
+                               .ToArray();
+                       Assert.AreEqual(2, invocations.Length);
+                       var one = invocations[0].Key as One;
+                       var two = invocations[1].Key as Two;
+                       Assert.AreEqual("start one and again", one.Arg);
+                       Assert.AreEqual("two and two again", two.Arg);
+               }
+
+               [Test]
+               public void Services_should_not_be_shared_between_two_sessions()
+               {
+                       client.Initiating("Client 1");
+                       client.Operation1(" Run Forrest run!");
+                       client.Terminating();
+                       client = CreateClient();
+                       client.Initiating("Client 2");
+                       client.Operation1(" welcomes you.");
+                       client.Terminating();
+                       var interceptor = 
windsorContainer.GetService<CollectingInterceptor>();
+                       IGrouping<object, IInvocation>[] invocations = 
interceptor
+                               .AllInvocations
+                               .GroupBy(i => i.InvocationTarget)
+                               .ToArray();
+
+                       Assert.AreEqual(6, ServiceWithSession.InstanceCount);
+                       Assert.AreEqual(2, invocations.Length);
+                       var one1 = invocations[0].Key as One;
+                       var one2 = invocations[1].Key as One;
+                       Assert.AreEqual("Client 1 Run Forrest run!", one1.Arg);
+                       Assert.AreEqual("Client 2 welcomes you.", one2.Arg);
+               }
+       }
+
+       public class CollectingInterceptor : StandardInterceptor
+       {
+               private readonly List<IInvocation> invocations = new 
List<IInvocation>();
+
+               public IInvocation[] AllInvocations
+               {
+                       get { return invocations.ToArray(); }
+               }
+
+               protected override void PreProceed(IInvocation invocation)
+               {
+                       invocations.Add(invocation);
+               }
+       }
+}

Directory: 
/Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/
=================================================================================

File [added]: IOperationContextProvider.cs
Delta lines: +19 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/IWcfLifestyle.cs
                               (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/IWcfLifestyle.cs
       2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,19 @@
+namespace Castle.Facilities.WcfIntegration.Lifestyles
+{
+       using System;
+
+       using Castle.MicroKernel;
+
+       /// <summary>
+       /// Contract for managing object lifestyles in the context of WCF 
runtime.
+       /// </summary>
+       public interface IWcfLifestyle:ILifestyleManager
+       {
+               /// <summary>
+               /// Id of the component associated with the lifestyle manager 
instance.
+               /// This Id does not have to have anything to do with the Id of 
the component assigned by the container.
+               /// It is used for internal tracking purposes os the facility.
+               /// </summary>
+               Guid ComponentId { get; }
+       }
+}

File [added]: IWcfLifestyle.cs
Delta lines: +13 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/LifestyleRegistrationExtensions.cs
                             (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/LifestyleRegistrationExtensions.cs
     2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,13 @@
+namespace Castle.Facilities.WcfIntegration.Lifestyles
+{
+       using Castle.MicroKernel.Registration;
+       using Castle.MicroKernel.Registration.Lifestyle;
+
+       public static class LifestyleRegistrationExtensions
+       {
+                public static ComponentRegistration<S> PerWcfSession<S>(this 
LifestyleGroup<S> @group)
+                {
+                       return group.Custom<PerWcfSessionLifestyle>();
+                }
+       }
+}

File [added]: LifestyleRegistrationExtensions.cs
Delta lines: +12 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/OperationContextProvider.cs
                            (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/OperationContextProvider.cs
    2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,12 @@
+namespace Castle.Facilities.WcfIntegration.Lifestyles
+{
+       using System.ServiceModel;
+
+       public class OperationContextProvider : IOperationContextProvider
+       {
+               public OperationContext Current
+               {
+                       get { return OperationContext.Current; }
+               }
+       }
+}

File [added]: OperationContextProvider.cs
Delta lines: +87 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/PerChannelLifestyleExtension.cs
                                (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/PerChannelLifestyleExtension.cs
        2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,87 @@
+namespace Castle.Facilities.WcfIntegration//in the default namespace so that 
it's visible out of the box
+{
+       using System;
+       using System.Collections.Generic;
+       using System.ServiceModel;
+
+       using Castle.Facilities.WcfIntegration.Lifestyles;
+
+       public class PerChannelLifestyleExtension : IExtension<IContextChannel>
+       {
+               private IContextChannel channel;
+               private readonly IDictionary<IWcfLifestyle, object> components 
= new Dictionary<IWcfLifestyle, object>(new WCFLifestyleComparer());
+               private bool used;
+
+               /// <inheritDoc />
+               public void Attach(IContextChannel owner)
+               {
+                       if(used)
+                       {
+                               throw new InvalidOperationException("This 
instance was already used!");
+                       }
+
+                       if (channel != null)
+                       {
+                               throw new InvalidOperationException("Can't 
attach twice!");
+                       }
+
+                       used = true;
+                       channel = owner;
+                       channel.Faulted += Shutdown;
+                       channel.Closed += Shutdown;
+               }
+
+               private void Shutdown(object sender, EventArgs e)
+               {
+                       channel.Extensions.Remove(this);
+                       foreach (var component in components)
+                       {
+                               component.Key.Release(component.Value);
+                       }
+                       components.Clear();
+               }
+
+               /// <inheritDoc />
+               public void Detach(IContextChannel owner)
+               {
+                       if (!used)
+                       {
+                               throw new InvalidOperationException("This 
instance was not used!");
+                       }
+                       if (channel == null)
+                       {
+                               throw new InvalidOperationException("Can't 
Detach twice or before attaching!");
+                       }
+                       channel.Faulted -= Shutdown;
+                       channel.Closed -= Shutdown;
+                       channel = null;
+               }
+
+               public object this[IWcfLifestyle manager]
+               {
+                       get
+                       {
+                               object component;
+                               components.TryGetValue(manager, out component);
+                               return component;
+                       }
+                       set
+                       {
+                               components[manager] = value;
+                       }
+               }
+
+               private class WCFLifestyleComparer : 
IEqualityComparer<IWcfLifestyle>
+               {
+                       public bool Equals(IWcfLifestyle x, IWcfLifestyle y)
+                       {
+                               return x.ComponentId.Equals(y.ComponentId);
+                       }
+
+                       public int GetHashCode(IWcfLifestyle obj)
+                       {
+                               return obj.ComponentId.GetHashCode();
+                       }
+               }
+       }
+}

File [added]: PerChannelLifestyleExtension.cs
Delta lines: +74 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/PerWcfSessionLifestyle.cs
                              (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/PerWcfSessionLifestyle.cs
      2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,74 @@
+namespace Castle.Facilities.WcfIntegration.Lifestyles
+{
+       using System;
+
+       using Castle.MicroKernel;
+       using Castle.MicroKernel.Lifestyle;
+
+       /// <summary>
+       /// Manages object instances in the context of WCF session. This means 
that when a component 
+       /// with this lifestyle is requested multiple times during WCF session, 
the same instance will be provided.
+       /// If no WCF session is available falls back to the default behavior 
of transient.
+       /// </summary>
+       public class PerWcfSessionLifestyle : AbstractLifestyleManager, 
IWcfLifestyle
+       {
+               private readonly Guid id = Guid.NewGuid();
+
+               private readonly IOperationContextProvider 
operationContextProvider;
+
+               public PerWcfSessionLifestyle()
+                       : this(new OperationContextProvider())
+               {
+               }
+
+               public PerWcfSessionLifestyle(IOperationContextProvider 
operationContextProvider)
+               {
+                       if (operationContextProvider == null)
+                       {
+                               throw new 
ArgumentNullException("operationContextProvider");
+                       }
+
+                       this.operationContextProvider = 
operationContextProvider;
+               }
+
+               public override void Dispose()
+               {
+
+               }
+
+               public override object Resolve(CreationContext context)
+               {
+                       var operation = operationContextProvider.Current;
+                       if (operation == null)
+                               return base.Resolve(context);
+
+                       if (string.IsNullOrEmpty(operation.SessionId))
+                               return base.Resolve(context);
+
+                       var channel = operation.Channel;
+
+                       // TODO: does this need locking?
+                       var lifestyle = 
channel.Extensions.Find<PerChannelLifestyleExtension>();
+
+                       if (lifestyle == null)
+                       {
+                               lifestyle = new PerChannelLifestyleExtension();
+                               channel.Extensions.Add(lifestyle);
+                       }
+
+                       var component = lifestyle[this];
+                       if (component == null)
+                       {
+                               component = base.Resolve(context);
+                               lifestyle[this] = component;
+                       }
+
+                       return component;
+               }
+
+               public Guid ComponentId
+               {
+                       get { return id; }
+               }
+       }
+}

File [added]: PerWcfSessionLifestyle.cs
Delta lines: +7 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Castle.Facilities.WcfIntegration.Tests-vs2008.csproj
        2009-12-05 08:38:19 UTC (rev 6391)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration.Tests/Castle.Facilities.WcfIntegration.Tests-vs2008.csproj
        2009-12-05 15:50:04 UTC (rev 6392)
@@ -123,8 +123,15 @@
     <Compile Include="Components\ICalculator.cs" />
     <Compile Include="Components\TraceInterceptor.cs" />
     <Compile Include="Duplex\DuplexClientFixture.cs" />
+    <Compile Include="Components\IOne.cs" />
+    <Compile Include="Components\IServiceWithSession.cs" />
+    <Compile Include="Components\ITwo.cs" />
+    <Compile Include="Components\One.cs" />
+    <Compile Include="PerWcfSessionLifestyleTestCase.cs" />
     <Compile Include="Rest\RestClientFixture.cs" />
     <Compile Include="Rest\RestServiceFixture.cs" />
+    <Compile Include="Components\ServiceWithSession.cs" />
+    <Compile Include="Components\Two.cs" />
     <Compile Include="WcfClientFixture.cs" />
     <Compile Include="Components\IOperations.cs" />

Directory: 
/Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Client/Proxy/
===================================================================================

File [modified]: WcfProxyGenerationHook.cs
Delta lines: +9 -0
===================================================================

--- 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/IOperationContextProvider.cs
                           (rev 0)
+++ 
Facilities/Wcf/trunk/src/Castle.Facilities.WcfIntegration/Lifestyles/IOperationContextProvider.cs
   2009-12-05 15:50:04 UTC (rev 6392)
@@ -0,0 +1,9 @@
+namespace Castle.Facilities.WcfIntegration.Lifestyles
+{
+       using System.ServiceModel;
+
+       public interface IOperationContextProvider
+       {
+               OperationContext Current { get; }
+       }
+}

--

You received this message because you are subscribed to the Google Groups 
"Castle Project Commits" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/castle-project-commits?hl=en.


Reply via email to