diff --git a/Extensibility/Instancing/Lifetime/Client/Client.csproj b/Extensibility/Instancing/Lifetime/Client/Client.csproj
new file mode 100644
index 0000000..62b12bf
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Client/Client.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Extensibility/Instancing/Lifetime/Client/Program.cs b/Extensibility/Instancing/Lifetime/Client/Program.cs
new file mode 100644
index 0000000..b234c37
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Client/Program.cs
@@ -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 to open a channel and send a request.");
+
+Console.ReadLine();
+
+MessageHeader shareableInstanceContextHeader = MessageHeader.CreateHeader(
+ CustomHeader.HeaderName,
+ CustomHeader.HeaderNamespace,
+ Guid.NewGuid().ToString());
+
+ChannelFactory channelFactory = new ChannelFactory(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 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 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";
+}
diff --git a/Extensibility/Instancing/Lifetime/Extensibility.Instancing.Lifetime.sln b/Extensibility/Instancing/Lifetime/Extensibility.Instancing.Lifetime.sln
new file mode 100644
index 0000000..1e432a8
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Extensibility.Instancing.Lifetime.sln
@@ -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
diff --git a/Extensibility/Instancing/Lifetime/Extensions/CustomLeaseExtension.cs b/Extensibility/Instancing/Lifetime/Extensions/CustomLeaseExtension.cs
new file mode 100644
index 0000000..82c55b2
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Extensions/CustomLeaseExtension.cs
@@ -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 Callback { get; set; }
+ }
+
+ ///
+ /// This class contains the implementation of an extension to InstanceContext.
+ /// This enables extended lifetime for the InstanceContext.
+ ///
+ class CustomLeaseExtension : IExtension, 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 _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 Members
+
+ ///
+ /// Attaches this extension to current instance of
+ /// InstanceContext.
+ ///
+ ///
+ /// This method is called by WCF at the time it attaches this
+ /// extension.
+ ///
+ public void Attach(InstanceContext owner)
+ {
+ _owner = owner;
+ }
+
+ public void Detach(InstanceContext owner)
+ {
+ }
+
+ #endregion
+
+ #region ICustomLease Members
+
+ ///
+ /// Gets or sets a value indicating whether this
+ /// InstanceContext is idle or not.
+ ///
+ public bool IsIdle
+ {
+ get
+ {
+ lock (_thisLock)
+ {
+ if (_isIdle)
+ {
+ return true;
+ }
+ else
+ {
+ StartTimer();
+ return false;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the InstanceContextIdleCallback.
+ ///
+ public Action 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
+
+ ///
+ /// Starts the timer.
+ ///
+ 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();
+ }
+ }
+ }
+
+ ///
+ /// Timer elapsed event handler.
+ ///
+ void idleTimer_Elapsed(object sender, ElapsedEventArgs args)
+ {
+ lock (_thisLock)
+ {
+ StopTimer();
+ _isIdle = true;
+ Utility.WriteMessageToConsole("Custom lease timeout expired. Notifying WCF.");
+ _callback(_owner);
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/Extensibility/Instancing/Lifetime/Extensions/CustomLeaseTimeAttribute.cs b/Extensibility/Instancing/Lifetime/Extensions/CustomLeaseTimeAttribute.cs
new file mode 100644
index 0000000..50b55dc
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Extensions/CustomLeaseTimeAttribute.cs
@@ -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
+{
+ ///
+ /// This class contains the implementation for the attribute
+ /// used to add custom lease time to the service instance.
+ ///
+ public sealed class CustomLeaseTimeAttribute : Attribute, IServiceBehavior
+ {
+ #region Private Fields
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the custom lease time.
+ ///
+ public double Timeout { get; set; }
+
+ #endregion
+
+ #region IServiceBehavior Members
+
+ public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection parameters)
+ {
+
+ }
+
+ ///
+ /// Applies the custom lease time behavior.
+ ///
+ ///
+ /// This method is invoked by WCF runtime.
+ ///
+ 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
+ }
+}
diff --git a/Extensibility/Instancing/Lifetime/Extensions/CustomLifetimeLease.cs b/Extensibility/Instancing/Lifetime/Extensions/CustomLifetimeLease.cs
new file mode 100644
index 0000000..acb69c8
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Extensions/CustomLifetimeLease.cs
@@ -0,0 +1,175 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using CoreWCF.Dispatcher;
+
+namespace CoreWcf.Samples.LifeTime
+{
+ public static class CustomHeader
+ {
+ public static readonly string HeaderName = "InstanceId";
+ public static readonly string HeaderNamespace = "http://CoreWcf.Samples.LifeTime/Lifetime";
+ }
+
+ ///
+ /// This class contains the implementation for
+ /// custom lifetime lease. It implements
+ /// IShareableInstanceContextLifetime in order to be able
+ /// to attach to the service model layer.
+ ///
+ class CustomLifetimeLease : IInstanceContextProvider
+ {
+ #region Private Fields
+
+ private double _timeout;
+ private bool _isIdle;
+ private Dictionary _instanceContextCache;
+
+ // Lock must be acquired on this before
+ // accessing the isIdle member.
+ // ===============
+ // VERY IMPORTANT:
+ // ===============
+ // This is a simple approach to make it work
+ // with current API.
+ // This approach is highly not acceptable as
+ // it will result in a considerable perf hit or
+ // even cause dead locks depending on how
+ // service model handles threads.
+ private object _thisLock;
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Creates an instance of CustomLifetimeLease class.
+ ///
+ public CustomLifetimeLease(double timeout)
+ {
+ _timeout = timeout;
+ _thisLock = new object();
+ _instanceContextCache = new Dictionary();
+ }
+
+ #endregion
+
+ #region IInstanceContextProvider Members
+
+ public bool IsIdle(InstanceContext instanceContext)
+ {
+ lock (_thisLock)
+ {
+ if (_isIdle)
+ {
+ Utility.WriteMessageToConsole("WCF is checking whether the instance is Idle. Reply with 'True'");
+ }
+ else
+ {
+ Utility.WriteMessageToConsole("WCF is checking whether the instance is Idle. Reply with 'False'");
+ }
+
+ bool idleCopy = _isIdle;
+ _isIdle = false;
+ return idleCopy;
+ }
+ }
+
+ public void NotifyIdle(Action callback,
+ InstanceContext instanceContext)
+ {
+ lock (_thisLock)
+ {
+ ICustomLease customLease =
+ instanceContext.Extensions.Find();
+
+ customLease.Callback = callback;
+ _isIdle = customLease.IsIdle;
+ if (_isIdle)
+ {
+ callback(instanceContext);
+ }
+ }
+ }
+
+ ///
+ /// This implements a PerCall InstanceContextMode behavior. If a cached InstanceContext is not found
+ /// then WCF will create a new one.
+ ///
+ public InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel)
+ {
+ //Per Session behavior
+ //To implement a PerSession behavior (If underlyin binding supports it) where in all
+ //methods from one ChannelFactory will be serviced by the same InstanceContext
+
+ //Check if the incoming request has the InstanceContext id it wants to connect with.
+ if (message.Headers.FindHeader(CustomHeader.HeaderName, CustomHeader.HeaderNamespace) != -1)
+ {
+ string sharingId = message.Headers.GetHeader(CustomHeader.HeaderName, CustomHeader.HeaderNamespace);
+ if (sharingId != null && _instanceContextCache.ContainsKey(sharingId))
+ {
+ Utility.WriteMessageToConsole(string.Format("WCF is checking to see whether an InstanceContext with Id '{0}' has been cached.", sharingId));
+ //Retrieve the InstanceContext from the map
+ InstanceContext context = _instanceContextCache[sharingId];
+ if (context != null)
+ {
+ //Before returning, stop the timer on this InstanceContext
+ CustomLeaseExtension extension = context.Extensions.Find();
+ Utility.WriteMessageToConsole(string.Format("WCF is allocating InstanceContext with Id '{0}' to process new Message. Stopping the InstanceContext idle timer.", sharingId));
+ extension.StopTimer();
+
+ Utility.WriteMessageToConsole("WCF found cached InstanceContext. Returning this InstanceContext");
+ return _instanceContextCache[sharingId];
+ }
+ }
+ }
+
+ //No existing InstanceContext was found so return null and WCF will create a new one.
+ return null;
+ }
+
+ public void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel)
+ {
+ //Look if the Client has given us a unique ID to add to this InstanceContext
+ int headerIndex = message.Headers.FindHeader(CustomHeader.HeaderName, CustomHeader.HeaderNamespace);
+ string headerId = null;
+ if (headerIndex != -1)
+ {
+ headerId = message.Headers.GetHeader(headerIndex);
+ }
+
+ if (headerId == null)
+ {
+ //If no header was sent by the Client, then create a new one and assign it to this InstanceContext.
+ headerId = Guid.NewGuid().ToString();
+ Utility.WriteMessageToConsole("No header was found in the incoming message. WCF creating a new Id to associate with this InstanceContext.");
+ }
+
+ Utility.WriteMessageToConsole(string.Format("WCF created new InstanceContext with unique Id '{0}'. Adding this to cache.", headerId));
+
+ //Add this to the Cache
+ _instanceContextCache[headerId] = instanceContext;
+
+ //Register the Closing event of this InstancContext so it can be removed from the collection
+ instanceContext.Closing += RemoveInstanceContext;
+
+ IExtension customLeaseExtension =
+ new CustomLeaseExtension(_timeout, headerId);
+ instanceContext.Extensions.Add(customLeaseExtension);
+ }
+
+ public void RemoveInstanceContext(object o, EventArgs args)
+ {
+ InstanceContext context = o as InstanceContext;
+ CustomLeaseExtension extension = context.Extensions.Find();
+ string id = (extension != null) ? extension.InstanceId : null;
+ if (_instanceContextCache[id] != null)
+ {
+ Utility.WriteMessageToConsole(string.Format("WCF closed InstanceContext with Id '{0}'. Removing this from cache.", id));
+ _instanceContextCache.Remove(id);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Extensibility/Instancing/Lifetime/Extensions/Extensions.csproj b/Extensibility/Instancing/Lifetime/Extensions/Extensions.csproj
new file mode 100644
index 0000000..2ac439f
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Extensions/Extensions.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net6.0
+ enable
+ true
+ InProcess
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Extensibility/Instancing/Lifetime/Extensions/Utility.cs b/Extensibility/Instancing/Lifetime/Extensions/Utility.cs
new file mode 100644
index 0000000..c4d62fd
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Extensions/Utility.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace CoreWcf.Samples.LifeTime
+{
+ class Utility
+ {
+ public static void WriteMessageToConsole(string message)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine(message);
+ Console.ForegroundColor = ConsoleColor.Gray;
+ }
+ }
+}
diff --git a/Extensibility/Instancing/Lifetime/Service/EchoService.cs b/Extensibility/Instancing/Lifetime/Service/EchoService.cs
new file mode 100644
index 0000000..644cbf2
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Service/EchoService.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace CoreWcf.Samples.LifeTime
+{
+ // Service class which implements the service contract interface.
+ [CustomLeaseTime(Timeout = 20000)]
+ public class EchoService : IEchoService
+ {
+ public EchoService()
+ {
+ Console.ForegroundColor = ConsoleColor.Blue;
+ Console.WriteLine("Service instance created.");
+ Console.ForegroundColor = ConsoleColor.Gray;
+ }
+
+ public string Echo(string value)
+ {
+ Console.ForegroundColor = ConsoleColor.Blue;
+ Console.WriteLine("Echo method invoked with :" + value);
+ Console.ForegroundColor = ConsoleColor.Gray;
+
+ return value;
+ }
+ }
+}
diff --git a/Extensibility/Instancing/Lifetime/Service/IEchoService.cs b/Extensibility/Instancing/Lifetime/Service/IEchoService.cs
new file mode 100644
index 0000000..63eb2c5
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Service/IEchoService.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace CoreWcf.Samples.LifeTime
+{
+ // Define a service contract.
+ [ServiceContract(SessionMode = SessionMode.Required)]
+ public interface IEchoService
+ {
+ [OperationContract]
+ string Echo(string value);
+ }
+}
diff --git a/Extensibility/Instancing/Lifetime/Service/Program.cs b/Extensibility/Instancing/Lifetime/Service/Program.cs
new file mode 100644
index 0000000..2518d00
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Service/Program.cs
@@ -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.
+
+const int HttpPort = 5000;
+const int NetTcpPort = 8089;
+
+var builder = WebApplication.CreateBuilder();
+
+builder.WebHost
+.UseKestrel(options =>
+{
+ options.ListenAnyIP(HttpPort);
+})
+.UseNetTcp(NetTcpPort);
+
+//Enable CoreWCF Services, with metadata (WSDL) support
+builder.Services.AddServiceModelServices()
+ .AddServiceModelMetadata()
+ .AddSingleton()
+ .AddSingleton();
+
+var app = builder.Build();
+
+app.UseServiceModel(builder =>
+{
+ // Add the Calculator Service
+ builder.AddService(serviceOptions =>
+ {
+ serviceOptions.BaseAddresses.Clear();
+ // Set the default host name:port in generated WSDL and the base path for the address
+ serviceOptions.BaseAddresses.Add(new Uri("http://localhost/EchoService"));
+ serviceOptions.BaseAddresses.Add(new Uri($"net.tcp://localhost:{NetTcpPort}/EchoService"));
+ })
+ // Add NetTcpBinding endpoint
+ .AddServiceEndpoint(new NetTcpBinding(SecurityMode.None), "netTcp");
+
+ // Configure WSDL to be available
+ var serviceMetadataBehavior = app.Services.GetRequiredService();
+ serviceMetadataBehavior.HttpGetEnabled = true;
+});
+
+PrintLegend();
+
+Console.ForegroundColor = ConsoleColor.Green;
+Console.WriteLine("Echo service started.");
+Console.ForegroundColor = ConsoleColor.Gray;
+
+app.Run();
+
+
+static void PrintLegend()
+{
+ Console.WriteLine("=================================");
+
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine("Green: Messages from the service host.");
+
+ Console.ForegroundColor = ConsoleColor.Blue;
+ Console.WriteLine("Blue: Messages from the service instance.");
+
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine("Red: Messages from custom lease behavior.");
+ Console.ForegroundColor = ConsoleColor.Gray;
+ Console.WriteLine("=================================");
+ Console.WriteLine("");
+}
diff --git a/Extensibility/Instancing/Lifetime/Service/Properties/launchSettings.json b/Extensibility/Instancing/Lifetime/Service/Properties/launchSettings.json
new file mode 100644
index 0000000..b137378
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Service/Properties/launchSettings.json
@@ -0,0 +1,13 @@
+{
+ "profiles": {
+ "Service": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "http://localhost:5000/EchoService",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/Extensibility/Instancing/Lifetime/Service/Service.csproj b/Extensibility/Instancing/Lifetime/Service/Service.csproj
new file mode 100644
index 0000000..7ca9a5d
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Service/Service.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net6.0
+ enable
+ true
+ InProcess
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Extensibility/Instancing/Lifetime/Service/appsettings.Development.json b/Extensibility/Instancing/Lifetime/Service/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Service/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/Extensibility/Instancing/Lifetime/Service/appsettings.json b/Extensibility/Instancing/Lifetime/Service/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/Extensibility/Instancing/Lifetime/Service/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}