From 33e2bff591a14177b7f4372844de4021048a2351 Mon Sep 17 00:00:00 2001 From: Abdelwahab Afifi Date: Thu, 18 May 2023 01:52:54 +0300 Subject: [PATCH] Add Instancing Lifetime Sample --- .../Instancing/Lifetime/Client/Client.csproj | 19 ++ .../Instancing/Lifetime/Client/Program.cs | 67 +++++++ .../Extensibility.Instancing.Lifetime.sln | 37 ++++ .../Extensions/CustomLeaseExtension.cs | 173 +++++++++++++++++ .../Extensions/CustomLeaseTimeAttribute.cs | 66 +++++++ .../Extensions/CustomLifetimeLease.cs | 175 ++++++++++++++++++ .../Lifetime/Extensions/Extensions.csproj | 22 +++ .../Instancing/Lifetime/Extensions/Utility.cs | 15 ++ .../Lifetime/Service/EchoService.cs | 26 +++ .../Lifetime/Service/IEchoService.cs | 13 ++ .../Instancing/Lifetime/Service/Program.cs | 66 +++++++ .../Service/Properties/launchSettings.json | 13 ++ .../Lifetime/Service/Service.csproj | 25 +++ .../Service/appsettings.Development.json | 8 + .../Lifetime/Service/appsettings.json | 9 + 15 files changed, 734 insertions(+) create mode 100644 Extensibility/Instancing/Lifetime/Client/Client.csproj create mode 100644 Extensibility/Instancing/Lifetime/Client/Program.cs create mode 100644 Extensibility/Instancing/Lifetime/Extensibility.Instancing.Lifetime.sln create mode 100644 Extensibility/Instancing/Lifetime/Extensions/CustomLeaseExtension.cs create mode 100644 Extensibility/Instancing/Lifetime/Extensions/CustomLeaseTimeAttribute.cs create mode 100644 Extensibility/Instancing/Lifetime/Extensions/CustomLifetimeLease.cs create mode 100644 Extensibility/Instancing/Lifetime/Extensions/Extensions.csproj create mode 100644 Extensibility/Instancing/Lifetime/Extensions/Utility.cs create mode 100644 Extensibility/Instancing/Lifetime/Service/EchoService.cs create mode 100644 Extensibility/Instancing/Lifetime/Service/IEchoService.cs create mode 100644 Extensibility/Instancing/Lifetime/Service/Program.cs create mode 100644 Extensibility/Instancing/Lifetime/Service/Properties/launchSettings.json create mode 100644 Extensibility/Instancing/Lifetime/Service/Service.csproj create mode 100644 Extensibility/Instancing/Lifetime/Service/appsettings.Development.json create mode 100644 Extensibility/Instancing/Lifetime/Service/appsettings.json 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": "*" +}