@@ -4,10 +4,7 @@ using System.Linq; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Microsoft.AspNetCore.Builder; | using Microsoft.AspNetCore.Builder; | ||||
using Microsoft.AspNetCore.Hosting; | using Microsoft.AspNetCore.Hosting; | ||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.Options; | |||||
namespace Sample.RabbitMQ.PostgreSql | namespace Sample.RabbitMQ.PostgreSql | ||||
{ | { | ||||
@@ -16,7 +13,25 @@ namespace Sample.RabbitMQ.PostgreSql | |||||
// This method gets called by the runtime. Use this method to add services to the container. | // This method gets called by the runtime. Use this method to add services to the container. | ||||
public void ConfigureServices(IServiceCollection services) | public void ConfigureServices(IServiceCollection services) | ||||
{ | { | ||||
services.AddCap(x => | |||||
{ | |||||
x.UseEntityFramework<AppDbContext>(); | |||||
x.UseRabbitMQ(z => | |||||
{ | |||||
z.HostName = "192.168.2.206"; | |||||
z.UserName = "admin"; | |||||
z.Password = "123123"; | |||||
}); | |||||
x.UseDashboard(); | |||||
x.UseDiscovery(d => | |||||
{ | |||||
d.DiscoveryServerHostName = "localhost"; | |||||
d.DiscoveryServerProt = 8500; | |||||
d.CurrentNodeHostName = "localhost"; | |||||
d.CurrentNodePort = 5800; | |||||
d.NodeName = "CAP一号节点"; | |||||
}); | |||||
}); | |||||
services.AddMvc(); | services.AddMvc(); | ||||
} | } | ||||
@@ -24,6 +39,8 @@ namespace Sample.RabbitMQ.PostgreSql | |||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | public void Configure(IApplicationBuilder app, IHostingEnvironment env) | ||||
{ | { | ||||
app.UseMvc(); | app.UseMvc(); | ||||
app.UseCap(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,6 +1,5 @@ | |||||
using Microsoft.AspNetCore.Builder; | using Microsoft.AspNetCore.Builder; | ||||
using Microsoft.AspNetCore.Hosting; | using Microsoft.AspNetCore.Hosting; | ||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||
using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||
using Sample.RabbitMQ.SqlServer.Services; | using Sample.RabbitMQ.SqlServer.Services; | ||||
@@ -26,7 +25,7 @@ namespace Sample.RabbitMQ.SqlServer | |||||
z.UserName = "admin"; | z.UserName = "admin"; | ||||
z.Password = "123123"; | z.Password = "123123"; | ||||
}); | }); | ||||
x.UseDashboard(); | |||||
x.UseDashboard(d => { d.StatsPollingInterval = 1000000; }); | |||||
x.UseDiscovery(d => | x.UseDiscovery(d => | ||||
{ | { | ||||
d.DiscoveryServerHostName = "localhost"; | d.DiscoveryServerHostName = "localhost"; | ||||
@@ -48,8 +47,6 @@ namespace Sample.RabbitMQ.SqlServer | |||||
app.UseMvc(); | app.UseMvc(); | ||||
app.UseCap(); | app.UseCap(); | ||||
app.UseCapDashboard(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -26,24 +26,18 @@ namespace Microsoft.AspNetCore.Builder | |||||
CheckRequirement(app); | CheckRequirement(app); | ||||
var provider = app.ApplicationServices; | var provider = app.ApplicationServices; | ||||
var bootstrapper = provider.GetRequiredService<IBootstrapper>(); | var bootstrapper = provider.GetRequiredService<IBootstrapper>(); | ||||
bootstrapper.BootstrapAsync(); | bootstrapper.BootstrapAsync(); | ||||
return app; | |||||
} | |||||
///<summary> | |||||
/// Enables cap dashboard for the current application | |||||
/// </summary> | |||||
/// <param name="app">The <see cref="IApplicationBuilder"/> instance this method extends.</param> | |||||
/// <returns>The <see cref="IApplicationBuilder"/> instance this method extends.</returns> | |||||
public static IApplicationBuilder UseCapDashboard(this IApplicationBuilder app) | |||||
{ | |||||
if (app == null) throw new ArgumentNullException(nameof(app)); | |||||
CheckRequirement(app); | |||||
app.UseMiddleware<GatewayProxyMiddleware>(); | |||||
app.UseMiddleware<DashboardMiddleware>(); | |||||
if (provider.GetService<DashboardOptions>() != null) | |||||
{ | |||||
if (provider.GetService<DiscoveryOptions>() != null) | |||||
{ | |||||
app.UseMiddleware<GatewayProxyMiddleware>(); | |||||
} | |||||
app.UseMiddleware<DashboardMiddleware>(); | |||||
} | |||||
return app; | return app; | ||||
} | } | ||||
@@ -25,49 +25,44 @@ namespace DotNetCore.CAP | |||||
public Task Invoke(HttpContext context) | public Task Invoke(HttpContext context) | ||||
{ | { | ||||
if (context.Request.Path.StartsWithSegments(_options.PathMatch, | |||||
out var matchedPath, out var remainingPath)) | |||||
if (!context.Request.Path.StartsWithSegments(_options.PathMatch, | |||||
out var matchedPath, out var remainingPath)) return _next(context); | |||||
// Update the path | |||||
var path = context.Request.Path; | |||||
var pathBase = context.Request.PathBase; | |||||
context.Request.PathBase = pathBase.Add(matchedPath); | |||||
context.Request.Path = remainingPath; | |||||
try | |||||
{ | { | ||||
// Update the path | |||||
var path = context.Request.Path; | |||||
var pathBase = context.Request.PathBase; | |||||
context.Request.PathBase = pathBase.Add(matchedPath); | |||||
context.Request.Path = remainingPath; | |||||
var dashboardContext = new CapDashboardContext(_storage, _options, context); | |||||
var findResult = _routes.FindDispatcher(context.Request.Path.Value); | |||||
try | |||||
if (findResult == null) | |||||
{ | { | ||||
var dashboardContext = new CapDashboardContext(_storage, _options, context); | |||||
var findResult = _routes.FindDispatcher(context.Request.Path.Value); | |||||
if (findResult == null) | |||||
{ | |||||
return _next.Invoke(context); | |||||
} | |||||
return _next.Invoke(context); | |||||
} | |||||
if (_options.Authorization.Any(filter => !filter.Authorize(dashboardContext))) | |||||
{ | |||||
var isAuthenticated = context.User?.Identity?.IsAuthenticated; | |||||
if (_options.Authorization.Any(filter => !filter.Authorize(dashboardContext))) | |||||
{ | |||||
var isAuthenticated = context.User?.Identity?.IsAuthenticated; | |||||
context.Response.StatusCode = isAuthenticated == true | |||||
? (int)HttpStatusCode.Forbidden | |||||
: (int)HttpStatusCode.Unauthorized; | |||||
context.Response.StatusCode = isAuthenticated == true | |||||
? (int)HttpStatusCode.Forbidden | |||||
: (int)HttpStatusCode.Unauthorized; | |||||
return Task.CompletedTask; | |||||
} | |||||
return Task.CompletedTask; | |||||
} | |||||
dashboardContext.UriMatch = findResult.Item2; | |||||
dashboardContext.UriMatch = findResult.Item2; | |||||
return findResult.Item1.Dispatch(dashboardContext); | |||||
} | |||||
finally | |||||
{ | |||||
context.Request.PathBase = pathBase; | |||||
context.Request.Path = path; | |||||
} | |||||
return findResult.Item1.Dispatch(dashboardContext); | |||||
} | } | ||||
else | |||||
finally | |||||
{ | { | ||||
return _next(context); | |||||
context.Request.PathBase = pathBase; | |||||
context.Request.Path = path; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -46,40 +46,48 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy | |||||
var request = context.Request; | var request = context.Request; | ||||
var pathMatch = discoveryOptions.MatchPath; | var pathMatch = discoveryOptions.MatchPath; | ||||
var isCapRequest = request.Path.StartsWithSegments(new PathString(pathMatch)); | var isCapRequest = request.Path.StartsWithSegments(new PathString(pathMatch)); | ||||
var isSwitchNode = request.Cookies.TryGetValue(NodeCookieName, out string requestNodeId); | |||||
var isCurrentNode = discoveryOptions.NodeId.ToString() == requestNodeId; | |||||
if (!isCapRequest || !isSwitchNode || isCurrentNode) | |||||
if (!isCapRequest) | |||||
{ | { | ||||
await _next.Invoke(context); | await _next.Invoke(context); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
_logger.LogDebug("started calling gateway proxy middleware"); | |||||
//For performance reasons, we need to put this functionality in the else | |||||
var isSwitchNode = request.Cookies.TryGetValue(NodeCookieName, out string requestNodeId); | |||||
var isCurrentNode = discoveryOptions.NodeId.ToString() == requestNodeId; | |||||
var isNodesPage = request.Path.StartsWithSegments(new PathString(pathMatch + "/nodes")); | |||||
if (TryGetRemoteNode(requestNodeId, out Node node)) | |||||
if (!isSwitchNode || isCurrentNode || isNodesPage) | |||||
{ | |||||
await _next.Invoke(context); | |||||
} | |||||
else | |||||
{ | { | ||||
try | |||||
_logger.LogDebug("started calling gateway proxy middleware"); | |||||
if (TryGetRemoteNode(requestNodeId, out Node node)) | |||||
{ | { | ||||
DownstreamRequest = await _requestMapper.Map(request); | |||||
try | |||||
{ | |||||
DownstreamRequest = await _requestMapper.Map(request); | |||||
SetDownStreamRequestUri(node, request.Path.Value); | |||||
SetDownStreamRequestUri(node, request.Path.Value); | |||||
var response = await _requester.GetResponse(DownstreamRequest); | |||||
var response = await _requester.GetResponse(DownstreamRequest); | |||||
await SetResponseOnHttpContext(context, response); | |||||
await SetResponseOnHttpContext(context, response); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
_logger.LogError(ex.Message); | |||||
} | |||||
} | } | ||||
catch(Exception ex) | |||||
else | |||||
{ | { | ||||
_logger.LogError(ex.Message); | |||||
context.Response.Cookies.Delete(NodeCookieName); | |||||
await _next.Invoke(context); | |||||
} | } | ||||
} | } | ||||
else | |||||
{ | |||||
context.Response.Cookies.Delete(NodeCookieName); | |||||
await _next.Invoke(context); | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -90,10 +98,9 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy | |||||
AddHeaderIfDoesntExist(context, httpResponseHeader); | AddHeaderIfDoesntExist(context, httpResponseHeader); | ||||
} | } | ||||
var stringContent = await response.Content.ReadAsStringAsync(); | |||||
var content = await response.Content.ReadAsByteArrayAsync(); | var content = await response.Content.ReadAsByteArrayAsync(); | ||||
AddHeaderIfDoesntExist(context, | |||||
AddHeaderIfDoesntExist(context, | |||||
new KeyValuePair<string, IEnumerable<string>>("Content-Length", new[] { content.Length.ToString() })); | new KeyValuePair<string, IEnumerable<string>>("Content-Length", new[] { content.Length.ToString() })); | ||||
context.Response.OnStarting(state => | context.Response.OnStarting(state => | ||||
@@ -128,7 +135,7 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy | |||||
DownstreamRequest.RequestUri = uriBuilder.Uri; | DownstreamRequest.RequestUri = uriBuilder.Uri; | ||||
} | } | ||||
private static void AddHeaderIfDoesntExist(HttpContext context, | |||||
private static void AddHeaderIfDoesntExist(HttpContext context, | |||||
KeyValuePair<string, IEnumerable<string>> httpResponseHeader) | KeyValuePair<string, IEnumerable<string>> httpResponseHeader) | ||||
{ | { | ||||
if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key)) | if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key)) | ||||
@@ -42,7 +42,7 @@ namespace DotNetCore.CAP.Dashboard | |||||
} | } | ||||
context.Response.ContentType = "application/json"; | context.Response.ContentType = "application/json"; | ||||
await context.Response.WriteAsync(serialized); | |||||
await context.Response.WriteAsync(serialized ?? string.Empty); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -124,7 +124,6 @@ namespace DotNetCore.CAP | |||||
{ | { | ||||
var retryBehavior = RetryBehavior.DefaultRetry; | var retryBehavior = RetryBehavior.DefaultRetry; | ||||
var now = DateTime.Now; | |||||
var retries = ++message.Retries; | var retries = ++message.Retries; | ||||
if (retries >= retryBehavior.RetryCount) | if (retries >= retryBehavior.RetryCount) | ||||
{ | { | ||||