Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Extensibility/Instancing/Lifetime/Client/Client.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<Using Include="System.ServiceModel" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.ServiceModel.Http" Version="4.*" />
<PackageReference Include="System.ServiceModel.NetTcp" Version="4.*" />
</ItemGroup>

</Project>
67 changes: 67 additions & 0 deletions Extensibility/Instancing/Lifetime/Client/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ServiceModel.Channels;

NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
var endpointAddress = new EndpointAddress("net.tcp://localhost:8089/EchoService/netTcp");

Console.WriteLine("Press <enter> to open a channel and send a request.");

Console.ReadLine();

MessageHeader shareableInstanceContextHeader = MessageHeader.CreateHeader(
CustomHeader.HeaderName,
CustomHeader.HeaderNamespace,
Guid.NewGuid().ToString());

ChannelFactory<IEchoService> channelFactory = new ChannelFactory<IEchoService>(binding, endpointAddress);
IEchoService proxy = channelFactory.CreateChannel();

using (new OperationContextScope((IClientChannel)proxy))
{
OperationContext.Current.OutgoingMessageHeaders.Add(shareableInstanceContextHeader);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Service returned: " + proxy.Echo("Apple"));
Console.ForegroundColor = ConsoleColor.Gray;
}

((IChannel)proxy).Close();

Console.WriteLine("Channel No 1 closed.");

Console.WriteLine(
"Press <ENTER> to send another request from a different channel " +
"to the same instance. ");

Console.ReadLine();

proxy = channelFactory.CreateChannel();

using (new OperationContextScope((IClientChannel)proxy))
{
OperationContext.Current.OutgoingMessageHeaders.Add(shareableInstanceContextHeader);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Service returned: " + proxy.Echo("Apple"));
Console.ForegroundColor = ConsoleColor.Gray;
}

((IChannel)proxy).Close();

Console.WriteLine("Channel No 2 closed.");
Console.WriteLine("Press <ENTER> to complete test.");
Console.ReadLine();


[ServiceContract(SessionMode = SessionMode.Required)]
interface IEchoService
{
[OperationContract]
string Echo(string value);
}

public static class CustomHeader
{
public static readonly string HeaderName = "InstanceId";
public static readonly string HeaderNamespace = "http://CoreWcf.Samples.LifeTime/Lifetime";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32422.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Service", "Service\Service.csproj", "{BF126326-3393-407C-B24A-8FCCC388BE27}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{B533CADA-93BB-40E1-8FBA-FE37100062C3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Extensions", "Extensions\Extensions.csproj", "{286B7623-BDB9-409A-8489-A3D3FCEFEED4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BF126326-3393-407C-B24A-8FCCC388BE27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF126326-3393-407C-B24A-8FCCC388BE27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF126326-3393-407C-B24A-8FCCC388BE27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF126326-3393-407C-B24A-8FCCC388BE27}.Release|Any CPU.Build.0 = Release|Any CPU
{B533CADA-93BB-40E1-8FBA-FE37100062C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B533CADA-93BB-40E1-8FBA-FE37100062C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B533CADA-93BB-40E1-8FBA-FE37100062C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B533CADA-93BB-40E1-8FBA-FE37100062C3}.Release|Any CPU.Build.0 = Release|Any CPU
{286B7623-BDB9-409A-8489-A3D3FCEFEED4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{286B7623-BDB9-409A-8489-A3D3FCEFEED4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{286B7623-BDB9-409A-8489-A3D3FCEFEED4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{286B7623-BDB9-409A-8489-A3D3FCEFEED4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AD996EFD-70DC-4431-B411-5A2771DD02D3}
EndGlobalSection
EndGlobal
173 changes: 173 additions & 0 deletions Extensibility/Instancing/Lifetime/Extensions/CustomLeaseExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Timers;
using Timer = System.Timers.Timer;

namespace CoreWcf.Samples.LifeTime
{
interface ICustomLease
{
bool IsIdle { get; }
Action<InstanceContext> Callback { get; set; }
}

/// <summary>
/// This class contains the implementation of an extension to InstanceContext.
/// This enables extended lifetime for the InstanceContext.
/// </summary>
class CustomLeaseExtension : IExtension<InstanceContext>, ICustomLease
{
#region Private Fields

// Reference to the InstanceContext instance owns this
// extension instance.
private InstanceContext _owner;

private bool _isIdle;
private object _thisLock;
private Timer _idleTimer;
private double _idleTimeout;
private Action<InstanceContext> _callback;

#endregion

public string InstanceId { get; }

#region Constructor

public CustomLeaseExtension(double idleTimeout, string instanceId)
{
_owner = null;
_isIdle = false;
_thisLock = new object();
_idleTimer = new Timer();
_idleTimeout = idleTimeout;
InstanceId = instanceId;
}

#endregion

#region IExtension<InstanceContext> Members

/// <summary>
/// Attaches this extension to current instance of
/// InstanceContext.
/// </summary>
/// <remarks>
/// This method is called by WCF at the time it attaches this
/// extension.
/// </remarks>
public void Attach(InstanceContext owner)
{
_owner = owner;
}

public void Detach(InstanceContext owner)
{
}

#endregion

#region ICustomLease Members

/// <summary>
/// Gets or sets a value indicating whether this
/// InstanceContext is idle or not.
/// </summary>
public bool IsIdle
{
get
{
lock (_thisLock)
{
if (_isIdle)
{
return true;
}
else
{
StartTimer();
return false;
}
}
}
}

/// <summary>
/// Gets or sets the InstanceContextIdleCallback.
/// </summary>
public Action<InstanceContext> Callback
{
get
{
lock (_thisLock)
{
return _callback;
}
}
set
{
// Immutable state.
if (_idleTimer.Enabled)
{
throw new InvalidOperationException("Callback could not be changed when the timer is running.");
}

lock (_thisLock)
{
_callback = value;
}
}
}

#endregion

#region Helper members

/// <summary>
/// Starts the timer.
/// </summary>
void StartTimer()
{
lock (_thisLock)
{
_idleTimer.Interval = _idleTimeout;
_idleTimer.Elapsed += new ElapsedEventHandler(idleTimer_Elapsed);

if (!_idleTimer.Enabled)
{
_idleTimer.Start();
}
}
}

public void StopTimer()
{
lock (_thisLock)
{
if (_idleTimer.Enabled)
{
_idleTimer.Stop();
}
}
}

/// <summary>
/// Timer elapsed event handler.
/// </summary>
void idleTimer_Elapsed(object sender, ElapsedEventArgs args)
{
lock (_thisLock)
{
StopTimer();
_isIdle = true;
Utility.WriteMessageToConsole("Custom lease timeout expired. Notifying WCF.");
_callback(_owner);
}
}

#endregion

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.ObjectModel;
using CoreWCF.Dispatcher;

namespace CoreWcf.Samples.LifeTime
{
/// <summary>
/// This class contains the implementation for the attribute
/// used to add custom lease time to the service instance.
/// </summary>
public sealed class CustomLeaseTimeAttribute : Attribute, IServiceBehavior
{
#region Private Fields

#endregion

#region Properties

/// <summary>
/// Gets or sets the custom lease time.
/// </summary>
public double Timeout { get; set; }

#endregion

#region IServiceBehavior Members

public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
{

}

/// <summary>
/// Applies the custom lease time behavior.
/// </summary>
/// <remarks>
/// This method is invoked by WCF runtime.
/// </remarks>
public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
{
CustomLifetimeLease customLease = new CustomLifetimeLease(Timeout);

foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;

if (cd != null)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.InstanceContextProvider = customLease;
}
}
}
}

public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
{

}

#endregion
}
}
Loading