@@ -4,10 +4,7 @@ using System.Linq; | |||
using System.Threading.Tasks; | |||
using Microsoft.AspNetCore.Builder; | |||
using Microsoft.AspNetCore.Hosting; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.Extensions.Options; | |||
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. | |||
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(); | |||
} | |||
@@ -24,6 +39,8 @@ namespace Sample.RabbitMQ.PostgreSql | |||
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | |||
{ | |||
app.UseMvc(); | |||
app.UseCap(); | |||
} | |||
} | |||
} |
@@ -1,6 +1,5 @@ | |||
using Microsoft.AspNetCore.Builder; | |||
using Microsoft.AspNetCore.Hosting; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Logging; | |||
using Sample.RabbitMQ.SqlServer.Services; | |||
@@ -26,7 +25,7 @@ namespace Sample.RabbitMQ.SqlServer | |||
z.UserName = "admin"; | |||
z.Password = "123123"; | |||
}); | |||
x.UseDashboard(); | |||
x.UseDashboard(d => { d.StatsPollingInterval = 1000000; }); | |||
x.UseDiscovery(d => | |||
{ | |||
d.DiscoveryServerHostName = "localhost"; | |||
@@ -48,8 +47,6 @@ namespace Sample.RabbitMQ.SqlServer | |||
app.UseMvc(); | |||
app.UseCap(); | |||
app.UseCapDashboard(); | |||
} | |||
} | |||
} |
@@ -26,24 +26,18 @@ namespace Microsoft.AspNetCore.Builder | |||
CheckRequirement(app); | |||
var provider = app.ApplicationServices; | |||
var bootstrapper = provider.GetRequiredService<IBootstrapper>(); | |||
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; | |||
} | |||
@@ -25,49 +25,44 @@ namespace DotNetCore.CAP | |||
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 pathMatch = discoveryOptions.MatchPath; | |||
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); | |||
} | |||
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); | |||
} | |||
var stringContent = await response.Content.ReadAsStringAsync(); | |||
var content = await response.Content.ReadAsByteArrayAsync(); | |||
AddHeaderIfDoesntExist(context, | |||
AddHeaderIfDoesntExist(context, | |||
new KeyValuePair<string, IEnumerable<string>>("Content-Length", new[] { content.Length.ToString() })); | |||
context.Response.OnStarting(state => | |||
@@ -128,7 +135,7 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy | |||
DownstreamRequest.RequestUri = uriBuilder.Uri; | |||
} | |||
private static void AddHeaderIfDoesntExist(HttpContext context, | |||
private static void AddHeaderIfDoesntExist(HttpContext context, | |||
KeyValuePair<string, IEnumerable<string>> httpResponseHeader) | |||
{ | |||
if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key)) | |||
@@ -42,7 +42,7 @@ namespace DotNetCore.CAP.Dashboard | |||
} | |||
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 now = DateTime.Now; | |||
var retries = ++message.Retries; | |||
if (retries >= retryBehavior.RetryCount) | |||
{ | |||