How I add log 4 net for MAUI application vs 2022 v 17.2 - log4net

How I add log 4 net for MAUI application vs 2022 v 17.2 ?
In Worker service I used this code:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.UseSystemd()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
})
.ConfigureLogging((hostingContext, logging) =>
{
var assembly = Assembly.GetAssembly(typeof(Program));
var pathToConfig = Path.Combine(
hostingContext.HostingEnvironment.ContentRootPath
, "Logger/log4net.config");
var logManager = new AppLogManager(pathToConfig, assembly);
logging.AddLog4Net(new Log4NetProviderOptions
{
ExternalConfigurationSetup = true
});
});

Related

Azure SignalR Service Connection string

Trying to create a POC for azure signalr service. I found the github samples, which appeared to have some solid examples. I chose this one. Basically, my problem is that when I run the code locally, works like a champ with the localhost url, but when I try to run using an Azure SignalR Service using a url that I copied from azure portal keys which is in this format: Endpoint=<service_endpoint>;AccessKey=<access_key>;, I get an error stating that "Invalid URI: The URI scheme is not valid.". How do I transform the url from what I copy from keys and use it to connect to a signalr service?
class Program
{
private const string DefaultHubEndpoint = "Endpoint=http://someFakesrsname.service.signlar.net;AccsssKey=thisseemslikeagoodaccesskeytouseformyquestion";//"http://localhost:5000/ManagementSampleHub";
private const string Target = "Target";
private const string DefaultUser = "User";
static void Main(string[] args)
{
var app = new CommandLineApplication();
app.FullName = "Azure SignalR Management Sample: SignalR Client Tool";
app.HelpOption("--help");
var hubEndpointOption = app.Option("-h|--hubEndpoint", $"Set hub endpoint. Default value: {DefaultHubEndpoint}", CommandOptionType.SingleValue, true);
var userIdOption = app.Option("-u|--userIdList", "Set user ID list", CommandOptionType.MultipleValue, true);
app.OnExecute(async () =>
{
var hubEndpoint = hubEndpointOption.Value() ?? DefaultHubEndpoint;
var userIds = userIdOption.Values != null && userIdOption.Values.Count > 0 ? userIdOption.Values : new List<string>() { "User" };
Console.WriteLine("hubEndpoint: " + hubEndpoint);
Console.WriteLine("DefaultHubEndpoint: " + DefaultHubEndpoint);
foreach (var userId in userIds)
{
Console.WriteLine("UserId: " + userId);
}
var connections = (from userId in userIds
select CreateHubConnection(hubEndpoint, userId)).ToList();
await Task.WhenAll(from conn in connections
select conn.StartAsync());
Console.WriteLine($"{connections.Count} Client(s) started...");
Console.ReadLine();
await Task.WhenAll(from conn in connections
select conn.StopAsync());
return 0;
});
app.Execute(args);
}
static HubConnection CreateHubConnection(string hubEndpoint, string userId)
{
var url = hubEndpoint.TrimEnd('/') + $"?user={userId}";
var connection = new HubConnectionBuilder().WithUrl(url).Build();
connection.On(Target, (string message) =>
{
Console.WriteLine($"{userId}: gets message from service: '{message}'");
});
connection.Closed += async ex =>
{
Console.WriteLine(ex);
Environment.Exit(1);
};
return connection;
}
}
enter code here

Aspnetcore Correlation failed when facebook or google login and Invalid token when confirm email

I've done migration of my app to aspnetcore and now I do have random issue with validation tokens.
1. Issue is that randomly users receive
An error was encountered while handling the remote login. Correlation
failed.
The problem is that if I go and test it my self it works.
Second problem is that when user receive Email confirmation token and click link from email they will get
invalid token
so they can't confirm email.
Firstly I thought issue is with UseCookiePolicy but I've disabled it.
Startup.cs
namespace Flymark.Online.Web
{
public class Startup
{
private readonly IHostingEnvironment _env;
public Startup(IHostingEnvironment env)
{
_env = env;
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Configure SnapshotCollector from application settings
services.Configure<SnapshotCollectorConfiguration>(
Configuration.GetSection(nameof(SnapshotCollectorConfiguration)));
// Add SnapshotCollector telemetry processor.
services.AddSingleton<ITelemetryProcessorFactory>(sp => new SnapshotCollectorTelemetryProcessorFactory(sp));
services.AddApplicationInsightsTelemetryProcessor<TelemetryFilter>();
services.AddSingleton<ITelemetryInitializer, AppInsightsInitializer>();
services.AddCors();
var decompressionOptions = new RequestDecompressionOptions();
decompressionOptions.UseDefaults();
services.AddRequestDecompression(decompressionOptions);
FlymarkAppSettings.Init(Configuration, _env.EnvironmentName);
var storageUri = new Uri(Configuration.GetValue<string>("Flymark:DataProtectionStorageUrl"));
//Get a reference to a container to use for the sample code, and create it if it does not exist.
var container = new CloudBlobClient(storageUri).GetContainerReference("data-protection");
services.AddDataProtection()
.SetApplicationName("Flymark.Online")
.PersistKeysToAzureBlobStorage(container, "data-protection.xml");
services.AddDetection();
services.AddAutoMapper();
services.AddWebMarkupMin(
options =>
{
options.AllowMinificationInDevelopmentEnvironment = true;
options.AllowCompressionInDevelopmentEnvironment = true;
})
.AddHtmlMinification(o =>
{
o.ExcludedPages = new List<IUrlMatcher>
{
new WildcardUrlMatcher("/scripts/*")
};
o.MinificationSettings.AttributeQuotesRemovalMode = HtmlAttributeQuotesRemovalMode.KeepQuotes;
o.MinificationSettings.EmptyTagRenderMode = HtmlEmptyTagRenderMode.NoSlash;
o.MinificationSettings.RemoveOptionalEndTags = false;
})
.AddXmlMinification()
.AddHttpCompression();
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.Lax;
});
services
.AddScoped<UserStore<ApplicationUser, IdentityRole<int>, FlymarkContext, int, IdentityUserClaim<int>,
IdentityUserRole<int>, IdentityUserLogin<int>, IdentityUserToken<int>, IdentityRoleClaim<int>>,
ApplicationUserStore>();
services.AddScoped<UserManager<ApplicationUser>, FlymarkUserManager>();
services.AddScoped<RoleManager<IdentityRole<int>>, ApplicationRoleManager>();
services.AddScoped<SignInManager<ApplicationUser>, ApplicationSignInManager>();
services
.AddScoped<RoleStore<IdentityRole<int>, FlymarkContext, int, IdentityUserRole<int>,
IdentityRoleClaim<int>>, ApplicationRoleStore>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddIdentity<ApplicationUser, IdentityRole<int>>(
o =>
{
o.User.RequireUniqueEmail = true;
})
.AddUserStore<ApplicationUserStore>()
.AddUserManager<FlymarkUserManager>()
.AddRoleStore<ApplicationRoleStore>()
.AddRoleManager<ApplicationRoleManager>()
.AddSignInManager<ApplicationSignInManager>()
.AddClaimsPrincipalFactory<FlymarkClaimsPrincipalFactory>()
.AddDefaultTokenProviders();
services.AddSingleton<ILoggerFactory, LoggerFactory>(sp =>
new LoggerFactory(
sp.GetRequiredService<IEnumerable<ILoggerProvider>>(),
sp.GetRequiredService<IOptionsMonitor<LoggerFilterOptions>>()
)
);
services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; });
services.AddMemoryCache();
services.AddSingleton<IEmailSender, FlymarkEmailSender>();
services.AddMvc(o =>
{
o.Conventions.Add(new FlymarkAsyncConvention());
o.AllowValidatingTopLevelNodes = false;
o.AllowEmptyInputInBodyModelBinding = true;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(opt =>
{
opt.SerializerSettings.DateFormatString = "dd/MM/yyyy";
opt.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
var resolver = opt.SerializerSettings.ContractResolver;
if (resolver == null) return;
if (resolver is DefaultContractResolver res) res.NamingStrategy = null;
});
services.Configure<IdentityOptions>(options =>
{
// Default Password settings.
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
options.Lockout.MaxFailedAccessAttempts = 20;
});
services
.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(OAuthValidationDefaults.AuthenticationScheme,
IdentityConstants.ApplicationScheme)
.RequireAuthenticatedUser()
.Build();
});
services.AddAuthentication()
.AddExternalAuthProviders(Configuration)
.AddFlymarkOpenIdConnectServer()
.AddOAuthValidation(OAuthValidationDefaults.AuthenticationScheme);
services.Configure<SecurityStampValidatorOptions>(options =>
{
// This is the key to control how often validation takes place
options.ValidationInterval = TimeSpan.FromMinutes(15);
});
services.ConfigureApplicationCookie(config =>
{
config.LoginPath = "/Identity/Account/LogIn";
config.AccessDeniedPath = "/Identity/Account/LogIn";
config.SlidingExpiration = true;
config.Events.OnRedirectToLogin = OnRedirectToLoginAsync;
});
}
private Task OnRedirectToLoginAsync(RedirectContext<CookieAuthenticationOptions> context)
{
if (context.HttpContext.Request.Path.Value.Contains("/api"))
context.Response.StatusCode = 401;
else
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
}
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
//builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterModule(new FlymarkDalDiModule
{
Configuration = Configuration
});
builder.RegisterModule(new DbDiModule(FlymarkAppSettings.Instance.DbContextConnection,
FlymarkAppSettings.Instance.StorageConnectionString));
builder.RegisterModule<FlymarkWebDiModule>();
}
private CultureInfo CreateCulture(string key)
{
return new CultureInfo(key)
{
NumberFormat = {NumberDecimalSeparator = "."},
DateTimeFormat = {ShortDatePattern = "dd/MM/yyyy"}
};
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory, IMapper mapper)
{
#if DEBUG
mapper.ConfigurationProvider.AssertConfigurationIsValid();
#endif
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = context =>
{
context.Context.Response.Headers.Add("Cache-Control", "no-cache, no-store");
context.Context.Response.Headers.Add("Expires", "-1");
}
});
}
else
{
app.UseExceptionHandler("/Error/Error500");
app.UseStaticFiles();
}
app.UseCors(builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowCredentials()
.SetPreflightMaxAge(TimeSpan.FromMinutes(5))
.AllowAnyHeader();
});
app.UseRequestDecompression();
app.UseLegacyTokenContentTypeFixMiddleware();
var supportedCultures = new[]
{
CreateCulture("en"),
CreateCulture("ru"),
CreateCulture("uk")
};
app.UseFlymarkExceptionMiddleware();
app.UseCookiePolicy();
app
.UseAuthentication()
.UseDomainMiddleware()
.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
})
.UseWebMarkupMin();
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
{
//Re-execute the request so the user gets the error page
var originalPath = ctx.Request.Path.Value;
ctx.Items["originalPath"] = originalPath;
ctx.Request.Path = "/error/error404";
await next();
}
});
app
.UseMvc(routes =>
{
routes.MapRoute(
"areaRoute",
"{area:exists}/{controller=Dashboard}/{action=Index}/{id?}");
routes.MapRoute(
"default",
"{controller=Home}/{action=Index}/{id?}");
});
}
}
}
I am generating url for email confirmation like this:
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Page("/Account/ConfirmEmail",
null,
new {userId = user.Id, code = code.ToBase64String()},
returnDomainUrl.Scheme,
returnDomainUrl.Host);
I also thought that it could be an angularjs (I still have it on my page) but its not loaded at /signin-facebook since its handled by middleware.
I think issue is somehwere with dataprotection since I am getting them in login and confirmation email
I also tried to base 64 email token, but it wont help in addition I think that url is encoded automatically by Page.Url
Finally after weeks of investigations I found an issue.
When user register I will send email and sms, then user goes and confirm sms, which will trigger update of security stamp. Then later if user click confirm email and it fails because security stamp is not the same as in a token
So moving sending confirmation email after phone number is confirmed. Solved half of my problem.
Most probably the tokens validation failed because the tokens are generated in a domain and being validated in another domain.
In ASP.Net this can be solved by having the same machineKey in both domains web.config files.
For ASP.Net Core you can replace the machineKey as described here so you have the same cryptographic settings in both of domains.
see: Replace the ASP.NET machineKey in ASP.NET Core

How to profile many connections with ServiceStack.MiniProfiler?

After registering my connections, I want to profile them. With the code below, I only profile the main connection (guepard).
public static IDbConnectionFactory RegisterConnections(this Container self, bool enableProfiler)
{
var dbFactory = new OrmLiteConnectionFactory(ConfigurationManager.ConnectionStrings["guepard"].ConnectionString, SqlServer2008Dialect.Provider);
self.Register<IDbConnectionFactory>(
c =>
{
var cs = ConfigurationManager.ConnectionStrings;
dbFactory.RegisterConnection("gecko-log", cs["gecko-log"].ConnectionString, SqlServerDialect.Provider);
dbFactory.RegisterConnection("ksmpro", cs["ksmpro"].ConnectionString, SqlServer2012Dialect.Provider);
dbFactory.RegisterConnection("gestion-stock", cs["gestion-stock"].ConnectionString, SqlServerDialect.Provider);
dbFactory.RegisterConnection("planning", cs["planning"].ConnectionString, SqlServerDialect.Provider);
dbFactory.RegisterConnection("febus", cs["febus"].ConnectionString, SqlServerDialect.Provider);
if (enableProfiler)
dbFactory.ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current);
return dbFactory;
}
);
return dbFactory;
}
I don't know how to profile each connection.
Thank you for your time.
You can either register an OrmLiteConnectionFactory with the ConnectionFilter, e.g:
dbFactory.RegisterConnection("gecko-log",
new OrmLiteConnectionFactory(cs["gecko-log"].ConnectionString,
SqlServerDialect.Provider,
setGlobalDialectProvider: false) {
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
}
);
Or go through each NamedConnection factory after registering them to set the ConnectionFilter, e.g:
OrmLiteConnectionFactory.NamedConnections.Values
.Each(f => f.ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current));

MassTransit Consumer not getting called

In the following sample program (using MassTransit, Azure ServiceBus), I am able to send messages to the queue, but my Receive Endpoint/Consumer does not seems to get the message. What am I doing wrong here? (Simple publish and a handler example given in this link(http://masstransit-project.com/MassTransit/quickstart.html) works fine!)
static async Task MainAsync(string[] args)
{
var bus = Bus.Factory.CreateUsingAzureServiceBus(cfg =>
{
var serviceUri = ServiceBusEnvironment.CreateServiceUri("sb", "{sb}", "{sb-name}");
var host = cfg.Host(serviceUri, h =>
{
h.OperationTimeout = TimeSpan.FromSeconds(5);
h.TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
"RootManageSharedAccessKey",
"{key}");
h.TransportType = TransportType.NetMessaging;
});
cfg.ReceiveEndpoint(host, "test_queue", ep =>
{
ep.Consumer<SayHelloCommandConsumer>();
});
});
bus.Start();
await SendAHello(bus);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
bus.Stop();
}
private static async Task SendAHello(IBusControl bus)
{
var sendToUri = new Uri("queue-end-point-address");
var endPoint = await bus.GetSendEndpoint(sendToUri);
await endPoint.Send<ISayHello>( new
{
Message = "Hello there !"
});
}
}
public class SayHelloCommandConsumer : IConsumer<ISayHello>
{
public Task Consume(ConsumeContext<ISayHello> context)
{
var command = context.Message;
return Console.Out.WriteLineAsync($"Recieved a message {command}");
}
}
public interface ISayHello
{
string Message { get; set; }
}
}
The queue address looked suspect, and it seems like you've corrected it.

Configure ConnectionFilter for a Named Connection

Given the following OrmLite configuration from the documentation, what is the best way to configure the ConnectionFilter for each of the the named connections?
var dbFactory = new OrmLiteConnectionFactory(
"Data Source=host;Initial Catalog=RobotsMaster;Integrated Security=SSPI", //Connection String
SqlServerDialect.Provider);
dbFactory.Run(db => db.CreateTable<MasterRecord>(overwrite:false));
NoOfShards.Times(i => {
var namedShard = "robots-shard" + i;
dbFactory.RegisterConnection(namedShard,
"~/App_Data/{0}.sqlite".Fmt(shardId).MapAbsolutePath(), //Connection String
SqliteDialect.Provider);
dbFactory.OpenDbConnection(namedShard).Run(db => db.CreateTable<Robot>(overwrite:false));
});
Currently, I am using this instead of RegisterConnection.
OrmLiteConnectionFactory.NamedConnections[namedShard] = new OrmLiteConnectionFactory("~/App_Data/{0}.sqlite".Fmt(shardId).MapAbsolutePath(), true, SqliteDialect.Provider, true) {
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
};
Could we change RegisterConnection to something like
public void RegisterConnection(string connectionKey, string connectionString, IOrmLiteDialectProvider dialectProvider, bool autoDisposeConnection = true)
{
RegisterConnection(connectionKey, new OrmLiteConnectionFactory(connectionString, autoDisposeConnection, dialectProvider, autoDisposeConnection));
}
public void RegisterConnection(string connectionKey, OrmLiteConnectionFactory ormLiteConnectionFactory)
{
NamedConnections[connectionKey] = ormLiteConnectionFactory;
}
Submitted a patch to ServiceStack.OrmLite. https://github.com/ServiceStack/ServiceStack.OrmLite/pull/212

Resources