-
Notifications
You must be signed in to change notification settings - Fork 564
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add wcfcore perf testing and deploy service with corewcf #4884
base: main
Are you sure you want to change the base?
Changes from all commits
8c06cb0
ae83d13
ddf3fa3
d5277a4
0ec7243
49ae44d
a35e57a
723e565
c7d5bf1
02a278e
1da7471
3500a2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<COMReference Include="{58fbcf7c-e7a9-467c-80b3-fc65e8fcca08}"> | ||
<WrapperTool>tlbimp</WrapperTool> | ||
<VersionMinor>0</VersionMinor> | ||
<VersionMajor>1</VersionMajor> | ||
<Guid>58fbcf7c-e7a9-467c-80b3-fc65e8fcca08</Guid> | ||
</COMReference> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="CoreWCF.Http" Version="1.*" /> | ||
<PackageReference Include="CoreWCF.NetTcp" Version="1.*" /> | ||
<PackageReference Include="CoreWCF.Primitives" Version="1.*" /> | ||
<PackageReference Include="Microsoft.AspNetCore" Version="2.*" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using NetFwTypeLib; | ||
|
||
namespace CoreWCFPerfService | ||
{ | ||
public static class FirewallRulesManager | ||
{ | ||
// This prefix is used both to name rules and to discover existing | ||
// rules created by this class, so it must be unique | ||
private static string s_RuleNamePrefix = "WCF perf test rule"; | ||
private static object s_portLock = new object(); | ||
private static bool s_registeredForProcessExit = false; | ||
private static INetFwPolicy2 s_netFwPolicy2; | ||
private static string s_remoteAddresses = "*"; | ||
|
||
private static INetFwPolicy2 NetFwPolicy2 | ||
{ | ||
get | ||
{ | ||
lock (s_portLock) | ||
{ | ||
if (s_netFwPolicy2 == null) | ||
{ | ||
Type netFwPolicy2Type = Type.GetTypeFromProgID("HNetCfg.FwPolicy2", false); | ||
s_netFwPolicy2 = (INetFwPolicy2)Activator.CreateInstance(netFwPolicy2Type); | ||
} | ||
} | ||
|
||
return s_netFwPolicy2; | ||
} | ||
} | ||
|
||
private static string RemoteAddresses | ||
{ | ||
get | ||
{ | ||
return s_remoteAddresses; | ||
} | ||
set | ||
{ | ||
s_remoteAddresses = value; | ||
} | ||
} | ||
|
||
private static string RuleNamePrefix { get; set; } | ||
|
||
private static string ApplicationName { get; set; } | ||
|
||
// We listen for ProcessExit so we can delete the firewall rules we added. | ||
private static void RegisterForProcessExit() | ||
{ | ||
lock (s_portLock) | ||
{ | ||
if (!s_registeredForProcessExit) | ||
{ | ||
AppDomain.CurrentDomain.ProcessExit += (s, e) => | ||
{ | ||
RemoveAllBridgeFirewallRules(RuleNamePrefix); | ||
}; | ||
s_registeredForProcessExit = true; | ||
} | ||
} | ||
} | ||
|
||
// Searches all existing firewall rules with the given name | ||
public static INetFwRule FindRule(string name, string port) | ||
{ | ||
lock (s_portLock) | ||
{ | ||
// Match on our special naming pattern and port | ||
HashSet<string> ruleSet = new HashSet<string>(); | ||
foreach (var r in NetFwPolicy2.Rules) | ||
{ | ||
INetFwRule rule = (INetFwRule)r; | ||
|
||
if (string.Equals(name, rule.Name, StringComparison.OrdinalIgnoreCase) && | ||
string.Equals(rule.LocalPorts, port, StringComparison.Ordinal)) | ||
{ | ||
return rule; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
|
||
private static void AddFirewallRule(string port) | ||
{ | ||
lock (s_portLock) | ||
{ | ||
// If we add any rules, register to delete them at process exit. | ||
RegisterForProcessExit(); | ||
|
||
// If we already created this rule, we don't create it again. | ||
string ruleName = string.Format("{0} {1}", RuleNamePrefix ?? s_RuleNamePrefix, port); | ||
if (FindRule(ruleName, port) != null) | ||
{ | ||
return; | ||
} | ||
|
||
INetFwRules rulesObject = NetFwPolicy2.Rules; | ||
int currentProfiles = NetFwPolicy2.CurrentProfileTypes; | ||
|
||
// Create a Rule Object. | ||
Type netFwRuleType = Type.GetTypeFromProgID("HNetCfg.FWRule", false); | ||
INetFwRule newRule = (INetFwRule)Activator.CreateInstance(netFwRuleType); | ||
|
||
try | ||
{ | ||
newRule.Name = ruleName; | ||
newRule.ApplicationName = ApplicationName; | ||
newRule.Description = string.Format("Rule added for WCF perf test use of port {0}", port); | ||
newRule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP; | ||
newRule.LocalPorts = port; | ||
newRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN; | ||
newRule.Enabled = true; | ||
newRule.Profiles = currentProfiles; | ||
newRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW; | ||
newRule.RemoteAddresses = RemoteAddresses; | ||
|
||
// Add a new rule | ||
rulesObject.Add(newRule); | ||
|
||
Trace.WriteLine(string.Format("Added firewall rule {0}", newRule.Name), | ||
typeof(FirewallRulesManager).Name); | ||
} | ||
catch (Exception ex) | ||
{ | ||
string message = string.Format("Failed to add firewall rule name:{0}, port:{1}, remoteAddresses:{2}{3}{4}", | ||
newRule.Name, port, RemoteAddresses, Environment.NewLine, ex.ToString()); | ||
Console.WriteLine(message); | ||
Trace.TraceWarning(message); | ||
} | ||
} | ||
} | ||
|
||
public static void RemoveAllBridgeFirewallRules(string preName) | ||
{ | ||
RuleNamePrefix = preName; | ||
lock (s_portLock) | ||
{ | ||
// Capture The specific rules into local list so we | ||
// don't mutate the rule list during enumeration. | ||
HashSet<string> ruleSet = new HashSet<string>(); | ||
foreach (var r in NetFwPolicy2.Rules) | ||
{ | ||
INetFwRule rule = (INetFwRule)r; | ||
string ruleName = rule.Name; | ||
if (rule.Name.StartsWith(RuleNamePrefix, StringComparison.Ordinal) && !ruleSet.Contains(rule.Name)) | ||
{ | ||
ruleSet.Add(rule.Name); | ||
} | ||
} | ||
|
||
foreach (string ruleName in ruleSet) | ||
{ | ||
try | ||
{ | ||
NetFwPolicy2.Rules.Remove(ruleName); | ||
Console.WriteLine("Removed firewall rule '{0}'", ruleName); | ||
} | ||
catch (FileNotFoundException fnfe) | ||
{ | ||
// This exception can happen when multiple processes | ||
// are cleaning up the rules, and the rule has already | ||
// been removed. | ||
Console.WriteLine("Unable to remove rule '{0}' : {1}", | ||
ruleName, fnfe.Message); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public static void OpenPortInFirewall(string preName, string appName, string port) | ||
{ | ||
RuleNamePrefix = preName; | ||
ApplicationName = appName; | ||
AddFirewallRule(port); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.Threading.Tasks; | ||
using CoreWCF; | ||
|
||
namespace WCFCorePerfService | ||
{ | ||
[ServiceContract] | ||
public interface ISayHello | ||
{ | ||
[OperationContract] | ||
Task<string> HelloAsync(string name); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using CoreWCF.IdentityModel.Selectors; | ||
|
||
namespace WCFCorePerfService | ||
{ | ||
public class MyCustomValidator : UserNamePasswordValidator | ||
{ | ||
public override ValueTask ValidateAsync(string userName, string password) | ||
{ | ||
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password)) | ||
{ | ||
return default; | ||
} | ||
ZhaodongTian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return new ValueTask(Task.FromException(new Exception("username and password cannot be empty"))); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
using System; | ||
using System.IO; | ||
using System.Net; | ||
using System.Reflection; | ||
using CoreWCF; | ||
using CoreWCF.Configuration; | ||
using CoreWCFPerfService; | ||
using Microsoft.AspNetCore; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.Hosting; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace WCFCorePerfService | ||
{ | ||
public class Program | ||
{ | ||
static void Main(string[] args) | ||
{ | ||
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "CoreWCFPerfService.exe"); | ||
Console.WriteLine(filePath); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a better option is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assembly.GetEntryAssembly().Location will return the full path of coreWCFPerfService.dll. but I need to get the full path of exe and add into firewall |
||
|
||
FirewallRulesManager.OpenPortInFirewall("CoreWCFPerfService", filePath, "8080,8443,8088"); | ||
|
||
Console.WriteLine("Application start."); | ||
|
||
using (var host = CreateWebHostBuilder(args).Build()) | ||
{ | ||
host.Start(); | ||
|
||
Console.WriteLine("Service is Ready"); | ||
Console.WriteLine("Press Any Key to Terminate..."); | ||
Console.ReadLine(); | ||
} | ||
|
||
Console.WriteLine("Clean up the firewall rule."); | ||
FirewallRulesManager.RemoveAllBridgeFirewallRules("CoreWCFPerfService"); | ||
} | ||
|
||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => | ||
WebHost.CreateDefaultBuilder(args) | ||
.UseKestrel(options => | ||
{ | ||
options.ListenLocalhost(8080); | ||
options.Listen(IPAddress.Loopback, 8443, listenOptions => | ||
{ | ||
listenOptions.UseHttps(); | ||
} | ||
); | ||
}) | ||
.UseNetTcp(8808) | ||
.UseStartup<Startup>(); | ||
|
||
public class Startup | ||
{ | ||
public void ConfigureServices(IServiceCollection services) | ||
{ | ||
services.AddServiceModelServices(); | ||
} | ||
|
||
public void Configure(IApplicationBuilder app) | ||
{ | ||
WSHttpBinding serverBinding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential); | ||
serverBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName; | ||
app.UseServiceModel(builder => | ||
{ | ||
builder.AddService<SayHello>(); | ||
builder.AddServiceEndpoint<SayHello, ISayHello>(new BasicHttpBinding(), "/WCFCorePerf/TestService.svc/BasicHttp"); | ||
builder.AddServiceEndpoint<SayHello, ISayHello>(new NetTcpBinding(SecurityMode.None), "/WCFCorePerf/TestService.svc/NetTcp"); | ||
builder.AddServiceEndpoint<SayHello, ISayHello>(serverBinding, "/WCFCorePerf/TestService.svc/WSHttp"); | ||
Action<ServiceHostBase> serviceHost = host => ChangeHostBehavior(host); | ||
builder.ConfigureServiceHostBase<SayHello>(serviceHost); | ||
}); | ||
} | ||
|
||
public void ChangeHostBehavior(ServiceHostBase host) | ||
{ | ||
var srvCredentials = new CoreWCF.Description.ServiceCredentials(); | ||
srvCredentials.UserNameAuthentication.UserNamePasswordValidationMode | ||
= CoreWCF.Security.UserNamePasswordValidationMode.Custom; | ||
srvCredentials.UserNameAuthentication.CustomUserNamePasswordValidator | ||
= new MyCustomValidator(); | ||
host.Description.Behaviors.Add(srvCredentials); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace WCFCorePerfService | ||
{ | ||
public class SayHello : ISayHello | ||
{ | ||
public Task<string> HelloAsync(string name) | ||
{ | ||
return Task.FromResult(name); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<configuration> | ||
<packageSources> | ||
<add key="corewcf" value="https://pkgs.dev.azure.com/dotnet/CoreWCF/_packaging/CoreWCF/nuget/v3/index.json" /> | ||
</packageSources> | ||
<disabledPackageSources /> | ||
</configuration> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
| ||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.3.32714.290 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoreWCFPerfService", "CoreWCFPerfService\CoreWCFPerfService.csproj", "{35B05C6A-9FF0-4A9C-9BBE-E88963416022}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WCFCorePerfClient", "WCFCorePerfClient\WCFCorePerfClient.csproj", "{D9001454-F77C-4053-B4AE-34342351FD49}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{35B05C6A-9FF0-4A9C-9BBE-E88963416022}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{35B05C6A-9FF0-4A9C-9BBE-E88963416022}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{35B05C6A-9FF0-4A9C-9BBE-E88963416022}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{35B05C6A-9FF0-4A9C-9BBE-E88963416022}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{D9001454-F77C-4053-B4AE-34342351FD49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{D9001454-F77C-4053-B4AE-34342351FD49}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{D9001454-F77C-4053-B4AE-34342351FD49}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{D9001454-F77C-4053-B4AE-34342351FD49}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {BD5D3AEC-A9AB-412C-A41B-A410030B454A} | ||
EndGlobalSection | ||
EndGlobal |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System.ServiceModel; | ||
using System.Threading.Tasks; | ||
|
||
namespace WCFCorePerfClient | ||
{ | ||
[ServiceContract] | ||
public interface ISayHello | ||
{ | ||
[OperationContract] | ||
Task<string> HelloAsync(string name); | ||
|
||
[OperationContract] | ||
string Hello(string name); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the Sdk
""Microsoft.NET.Sdk.Web"
and remove the package reference to Microsoft.AspNetCoreThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If change to "Microsoft.NET.Sdk.Web", visualstudio will throw IndexOutOfRangeException exception