Base solution for your next web application

Activities of "GarethWright"

Prerequisites

  • What is your product version? 9.0.1
  • What is your product type (Angular or MVC)? ANGULAR
  • What is product framework type (.net framework or .net core)? .NetCore

Console app gets a token successfully but returns 401 Unauthorised when connecting to the api endpoint from a remote ip. Works fine if connecting via localhost. I think this may be something to do with IdentityServer being configured to use .AddDeveloperSigninCredentials but I have no idea how I would configure this to work in a multi tenant environment where the host is at https://api.{tenant_name}.domain.com

.net core Angular Single Project 9.0.1

This works fine locally but when publishing to IIS any deep link i.e /account/login returns a 404.

It should all as the provided

app.Use(async (context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) { context.Request.Path = "/index.html"; await next(); 
            
            } });

should handle those 404s

namespace PROJECT.Web.Startup { public class Startup { private const string DefaultCorsPolicyName = "localhost";

    private readonly IConfigurationRoot _appConfiguration;
    private readonly IWebHostEnvironment _hostingEnvironment;

    public Startup(IWebHostEnvironment env)
    {
        _hostingEnvironment = env;
        _appConfiguration = env.GetAppConfiguration();
    }

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        //MVC
        services.AddControllersWithViews(options =>
        {
            options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
        }).AddNewtonsoftJson();

        services.AddSignalR();

        //Configure CORS for angular2 UI
        services.AddCors(options =>
        {
            options.AddPolicy(DefaultCorsPolicyName, builder =>
            {
                //App:CorsOrigins in appsettings.json can contain more than one address with splitted by comma.
                builder
                    .WithOrigins(
                        // App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
                        _appConfiguration["App:CorsOrigins"]
                            .Split(",", StringSplitOptions.RemoveEmptyEntries)
                            .Select(o => o.RemovePostFix("/"))
                            .ToArray()
                    )
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });

        if (bool.Parse(_appConfiguration["KestrelServer:IsEnabled"]))
        {
            ConfigureKestrel(services);
        }

        IdentityRegistrar.Register(services);
        AuthConfigurer.Configure(services, _appConfiguration);

        //Identity server
        if (bool.Parse(_appConfiguration["IdentityServer:IsEnabled"]))
        {
            IdentityServerRegistrar.Register(services, _appConfiguration, options =>
                 options.UserInteraction = new UserInteractionOptions()
                 {
                     LoginUrl = "/UI/Login",
                     LogoutUrl = "/UI/LogOut",
                     ErrorUrl = "/Error"
                 });
        }

        if (WebConsts.SwaggerUiEnabled)
        {
            //Swagger - Enable this line and the related lines in Configure method to enable swagger UI
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo() { Title = "inteliProCS API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);
                options.ParameterFilter<SwaggerEnumParameterFilter>();
                options.SchemaFilter<SwaggerEnumSchemaFilter>();
                options.OperationFilter<SwaggerOperationIdFilter>();
                options.OperationFilter<SwaggerOperationFilter>();
                options.CustomDefaultSchemaIdSelector();
            }).AddSwaggerGenNewtonsoftSupport();
        }

        //Recaptcha
        services.AddreCAPTCHAV3(x =>
        {
            x.SiteKey = _appConfiguration["Recaptcha:SiteKey"];
            x.SiteSecret = _appConfiguration["Recaptcha:SecretKey"];
        });

        if (WebConsts.HangfireDashboardEnabled)
        {

            //Hangfire(Enable to use Hangfire instead of default job manager)
            services.AddHangfire(config =>
            {
                config.UseSqlServerStorage(_appConfiguration.GetConnectionString("Default"));

            });
        }

        if (WebConsts.GraphQL.Enabled)
        {
            services.AddAndConfigureGraphQL();
        }

        if (bool.Parse(_appConfiguration["HealthChecks:HealthChecksEnabled"]))
        {
            services.AddAbpZeroHealthCheck();

            var healthCheckUISection = _appConfiguration.GetSection("HealthChecks")?.GetSection("HealthChecksUI");

            if (bool.Parse(healthCheckUISection["HealthChecksUIEnabled"]))
            {
                services.Configure<HealthChecksUISettings>(settings =>
                {
                    healthCheckUISection.Bind(settings, c => c.BindNonPublicProperties = true);
                });
                services.AddHealthChecksUI();
            }
        }

        //Configure Abp and Dependency Injection
        return services.AddAbp<inteliProCSWebHostModule>(options =>
        {
            //Configure Log4Net logging
            options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                f => f.UseAbpLog4Net().WithConfig(_hostingEnvironment.IsDevelopment()
                        ? "log4net.config"
                        : "log4net.Production.config")
            );

            options.PlugInSources.AddFolder(Path.Combine(_hostingEnvironment.WebRootPath, "Plugins"), SearchOption.AllDirectories);
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
    {
        //Initializes ABP framework.
        app.UseAbp(options =>
        {
            options.UseAbpRequestLocalization = false; //used below: UseAbpRequestLocalization
        });

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseStatusCodePagesWithRedirects("~/Error?statusCode={0}");
            app.UseExceptionHandler("/Error");
        }

        app.Use(async (context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) { context.Request.Path = "/index.html"; await next(); 
        
        } });
      // app.UseDefaultFiles(new DefaultFilesOptions { DefaultFileNames = new List<string> { "index.html" }});
       app.UseStaticFiles();
       app.UseRouting();

        app.UseCors(DefaultCorsPolicyName); //Enable CORS!

        app.UseAuthentication();
        app.UseJwtTokenMiddleware();

        if (bool.Parse(_appConfiguration["IdentityServer:IsEnabled"]))
        {
            app.UseJwtTokenMiddleware("IdentityBearer");
            app.UseIdentityServer();
        }

        app.UseAuthorization();

        using (var scope = app.ApplicationServices.CreateScope())
        {
            if (scope.ServiceProvider.GetService<DatabaseCheckHelper>().Exist(_appConfiguration["ConnectionStrings:Default"]))
            {
                app.UseAbpRequestLocalization();
            }
        }

        if (WebConsts.HangfireDashboardEnabled)
        {
            //Hangfire dashboard &server(Enable to use Hangfire instead of default job manager)
            app.UseHangfireDashboard(WebConsts.HangfireDashboardEndPoint, new DashboardOptions
            {

                // Authorization = new[] { new AbpHangfireAuthorizationFilter(AppPermissions.Pages_Administration_HangfireDashboard) }
            });

            var options = new BackgroundJobServerOptions
            {
                Queues = new[] { "WindowsService", "default" }
            };
            app.UseHangfireServer(options);


            RecurringJob.AddOrUpdate<IHangFireNotificationAppService>("Daily CSCS/ ECS Card Check", dd => dd.CheckCSCSECSCardValid(), Cron.Daily(8));
            RecurringJob.AddOrUpdate<IHangFireAppService>("Check access revocation", dd => dd.CheckForAccessRevocation(), "*/5 * * * *");
            RecurringJob.AddOrUpdate<IHangFireAppService>("Monthly Co2Report", mm => mm.MonthlyCo2ReportJob(), Cron.Daily(21));
            RecurringJob.AddOrUpdate<IHangFireAppService>("Weekly Co2Report", ww => ww.WeeklyCo2ReportJob(), Cron.Weekly(DayOfWeek.Friday, 21));
            RecurringJob.AddOrUpdate<IHangFireAppService>("Daily Co2Report", dd => dd.DailyCo2ReportJob(), Cron.Daily(21));
            RecurringJob.AddOrUpdate<IHangFireAppService>("Get Job Request", rs => rs.GetJobRequestResult(), "*/20 * * * *");
            RecurringJob.AddOrUpdate<IHangFireNotificationAppService>
                ("Send Warning Notification", r => r.SendNotificationForHangFire(),
                "*/10 * * * *");

         
        }

        if (bool.Parse(_appConfiguration["Payment:Stripe:IsActive"]))
        {
            StripeConfiguration.ApiKey = _appConfiguration["Payment:Stripe:SecretKey"];
        }

       

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<AbpCommonHub>("/signalr");
            endpoints.MapHub<ChatHub>("/signalr-chat");

            endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
            endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");

            if (bool.Parse(_appConfiguration["HealthChecks:HealthChecksEnabled"]))
            {
                endpoints.MapHealthChecks("/health", new HealthCheckOptions()
                {
                    Predicate = _ => true,
                    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
                });
            }
        });

        if (bool.Parse(_appConfiguration["HealthChecks:HealthChecksEnabled"]))
        {
            if (bool.Parse(_appConfiguration["HealthChecks:HealthChecksUI:HealthChecksUIEnabled"]))
            {
                app.UseHealthChecksUI();
            }
        }

        if (WebConsts.SwaggerUiEnabled)
        {
            // Enable middleware to serve generated Swagger as a JSON endpoint
            app.UseSwagger();
            // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)

            app.UseSwaggerUI(options =>
            {
                options.SwaggerEndpoint(_appConfiguration["App:SwaggerEndPoint"], "API V1");
                options.IndexStream = () => Assembly.GetExecutingAssembly()
                    .GetManifestResourceStream("inteliProCS.Web.wwwroot.swagger.ui.index.html");
                options.InjectBaseUrl(_appConfiguration["App:ServerRootAddress"]);
            }); //URL: /swagger
        }
    }

    private void ConfigureKestrel(IServiceCollection services)
    {
        services.Configure<Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions>(options =>
        {
            options.Listen(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 443),
                listenOptions =>
                {
                    var certPassword = _appConfiguration.GetValue<string>("Kestrel:Certificates:Default:Password");
                    var certPath = _appConfiguration.GetValue<string>("Kestrel:Certificates:Default:Path");
                    var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath, certPassword);
                    listenOptions.UseHttps(new HttpsConnectionAdapterOptions()
                    {
                        ServerCertificate = cert
                    });
                });
        });
    }
}

}

I tried the web.config

This doesn't work either

.netCore

If issue related with ABP Framework

Latest

I'm trying to integrate with GoCardless to add Direct Debit Payments for memberships. They sent a webhook when payments are complete and I need to add the following to a controller to process that event.

[HttpPost]
       
        [AllowAnonymous]
        public async Task<StatusCodeResult> WebhookEvent()
        
            {
    var requestBody = HttpContext.Request.Body;
    requestBody.Seek(0, System.IO.SeekOrigin.Begin);
    var requestJson = new StreamReader(requestBody).ReadToEnd();

    // We recommend storing your webhook endpoint secret in an environment variable
    // for security
    var secret = AppConsts.GoCardlesssSandBoxToken;
    var signature = Request.Headers["Webhook-Signature"];

    try
    {
        // Webhooks can contain many events. In a real implementation, you should handle
        // the processing of each event asychronously to avoid timing out here.
        // You could check whether you've processed the event before (by recording the event
        // ID when you process it) and retrieve the associated resource to ensure that you have
        // the most up-to-date information about it.
        foreach (GoCardless.Resources.Event whevent in WebhookParser.Parse(requestJson, secret, signature))
        {
            // To keep this example simple, we're only handling Mandate events
            if (whevent.ResourceType == GoCardless.Resources.EventResourceType.Mandates)
            {
                switch (whevent.Action)
                {
                    case "created":
                        Console.WriteLine($"Mandate {whevent.Links.Mandate} has been created, yay!");
                        break;
                    case "cancelled":
                        Console.WriteLine($"Oh no, mandate {whevent.Links.Mandate} was cancelled!");
                        break;
                    default:
                        Console.WriteLine($"{whevent.Links.Mandate} has been {whevent.Action}");
                        break;
                }
            }
            else
            {
                Console.WriteLine($"No method to handle {whevent.ResourceType} events yet");
            }
        }

        return new StatusCodeResult((int)HttpStatusCode.OK);

    }
    catch (InvalidSignatureException e)
    {
        return new BadRequestResult();
    }
}

I've added to the MVC controller but I keep getting 302 redirected to login page. I can't figure out why as I've added the [AllowAnonymous] Attribute. I've also tried the [abpAllowAnonymous] attribute with no success.

  • What is your product version?
  • 9.0.2
  • What is your product type (Angular or MVC)?
  • Angular (Integrated)
  • What is product framework type (.net framework or .net core)?
  • .netCore

I've downloaded the latest 9.2.0...how does one go about updating my project?

Language is set to English UK and date set to 2020-07-13 in datepicker.

Date saved is 2020-07-12 because it is not accounting for daylight savings time.

More worrying is that on updating the entity all the date fields are changed to the previous day.

I think this is because if the language is 'en' it just returns the promise without checking any locale specifics like DST. <br>

static registerNgxBootstrapDatePickerLocales(): Promise {
if (abp.localization.currentLanguage.name === 'en') {
return Promise.resolve(true);
}

I have a requirement whereby the aspnet zero site is running on a local server in single tenent mode and the same application is also available in multitenant online.

i would like to have the tenent site online sync changes from the local install and webhooks seem to be a viable option for doing so.

Has anyone used webhooks in this way?

I downloaded with the merged project, but in hindsight could do with them seperate? The downloader does not let me do this, can you facilitate?

Showing 1 to 7 of 7 entries