惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
Security Archives - TechRepublic
Security Archives - TechRepublic
Security Latest
Security Latest
K
Kaspersky official blog
P
Palo Alto Networks Blog
T
Threat Research - Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tor Project blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
A
Arctic Wolf
NISL@THU
NISL@THU
GbyAI
GbyAI
腾讯CDC
罗磊的独立博客
Simon Willison's Weblog
Simon Willison's Weblog
Scott Helme
Scott Helme
S
SegmentFault 最新的问题
Cyberwarzone
Cyberwarzone
Jina AI
Jina AI
S
Schneier on Security
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
博客园 - 【当耐特】
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Spread Privacy
Spread Privacy
C
CXSECURITY Database RSS Feed - CXSecurity.com
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Register - Security
The Register - Security
C
Cybersecurity and Infrastructure Security Agency CISA
L
Lohrmann on Cybersecurity
V
Vulnerabilities – Threatpost
G
GRAHAM CLULEY
P
Proofpoint News Feed
Cisco Talos Blog
Cisco Talos Blog
博客园_首页
雷峰网
雷峰网
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
V2EX - 技术
V2EX - 技术
O
OpenAI News
博客园 - 司徒正美
S
Security @ Cisco Blogs
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
博客园 - 叶小钗
Vercel News
Vercel News
AI
AI
博客园 - 聂微东
Webroot Blog
Webroot Blog
J
Java Code Geeks

博客园 - ddrsql

从“黑盒”到“全景”:在.NET中拥抱OpenTelemetry与SigNoz的可观测工具 关于git分支堆叠 记录团队使用git合并代码丢失 记一次对老服务改造 国产麒麟(Kylin-Server-10)系统无外网环境安装docker vue3学习之axios、mockjs、nswag vue3学习之tabler组件Layout布局 vue3学习之BootstrapVueNext Framework升级到Core以及Dapper支持达梦数据库 Avalonia中使用EF增删改查DM数据库 Linux中使用原生Wpf之Avalonia WPF通过wine适配统信uos系统 单体仓库下通过helm优雅的将微服务部署到k8s DevOps 前端项目(angular、vue、react)打包静态资源生成一份Docker镜像支持部署不同环境 VS使用IIS调试(非附加进程).net core、.net framework程序 k8s集群通过nginx-ingress做tcp、udp 4层网络转发 DevOps .net core Jenkins持续集成Linux、Docker、K8S swaggerui集成oauth implicit redis cluster集群web管理工具 relumin
Avalonia集成Prism与Abp
ddrsql · 2023-03-05 · via 博客园 - ddrsql

使用到到相关组件

Avalonia 版本 11.0.0-preview5

UI皮肤 Material.Avalonia具体内容可以点进去看

Prism.Avalonia

aspnetboilerplate 版本 7.3.0

效果

解决方案目录结构

示例地址 由于module目录下有些类库非直接引用到启动项需要生成整个解决方案后运行。

Avalonia启动项UCompany.UProject.Wpf中使用appsettings.json配置文件以及UserSecrets

通过ConfigurationBuilder读取配置信息

var builder = new ConfigurationBuilder()
    .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddUserSecrets(typeof(App).Assembly);

Configuration.DefaultNameOrConnectionString = builder.Build().GetConnectionString("Default");

添加UserSecrets启动项csproj文件PropertyGroup节点中会多出如下配置

<UserSecretsId>2f1ac190-35e0-4261-828d-f28c3b746de9</UserSecretsId>

Avalonia启动项UCompany.UProject.Wpf集成Abp以及Serilog

本示例中使用abp版本7.3.0

var services = new ServiceCollection();
            services.CreateSeriLog(builder.Build())
                .UseSeriLog(SerilogCreatorExtensions.logger);
            IocManager.IocContainer.AddFacility<LoggingFacility>(f => f.LogUsing(new SerilogFactory(SerilogCreatorExtensions.logger)));

WindsorRegistrationHelper.CreateServiceProvider(IocManager.IocContainer, services);

使用到EF部分需要记录日志将IOC中SerilogFactory替换原有Microsoft.Extensions.Logging.ILoggerFactory

        Configuration.Modules.AbpEfCore().AddDbContext<PlatformDbContext>(options =>
        {
#if DEBUG
            var loggerFactory = IocManager.IocContainer.Resolve<ILoggerFactory>();
                options.DbContextOptions.UseLoggerFactory(loggerFactory);
                options.DbContextOptions.EnableSensitiveDataLogging(); // 记录SQL的参数值
#endif
            //...
        });

SerilogCreatorExtensions

public static class SerilogCreatorExtensions
{
    public static Serilog.ILogger logger;
    public static Serilog.Core.Logger CreateSerilog(this IConfigurationRoot configuration)
    {
        return BuildSerilogConfiguration(configuration).CreateLogger();
    }
    private static LoggerConfiguration BuildSerilogConfiguration(IConfiguration configuration)
    {
        // 默认读取 configuration 中 "Serilog" 节点下的配置
        var loggerConfiguration = new LoggerConfiguration();
        SetSerilogConfiguration(loggerConfiguration, configuration);
        return loggerConfiguration;
    }
    public static void SetSerilogConfiguration(LoggerConfiguration loggerConfiguration, IConfiguration configuration)
    {
        // 默认读取 configuration 中 "Serilog" 节点下的配置
        loggerConfiguration.ReadFrom.Configuration(configuration)
            .Enrich.WithExceptionDetails()
            .Enrich.WithExceptionDetails(new DestructuringOptionsBuilder()
                .WithDefaultDestructurers()
                .WithDestructurers(new[] { new DbUpdateExceptionDestructurer() })
            )
            .Enrich.FromLogContext()
            .MinimumLevel.Debug()//最小记录级别
            .WriteTo.Console();
        var logPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Logs", "logs.txt");
        loggerConfiguration.WriteTo.File(logPath, rollingInterval: RollingInterval.Day, shared: true);
    }
    public static IServiceCollection CreateSeriLog(this IServiceCollection collection, IConfigurationRoot configuration)
    {
        if (logger == null)
        {
            logger = BuildSerilogConfiguration(configuration).CreateLogger();
        }
        return collection;
    }

    public static IServiceCollection UseSeriLog(this IServiceCollection collection, Serilog.ILogger logger = null,
        bool dispose = false, LoggerProviderCollection providers = null)
    {
        if (providers != null)
        {
            collection.AddSingleton<ILoggerFactory>(services =>
            {
                var factory = new SerilogLoggerFactory(logger, dispose, providers);

                foreach (var provider in services.GetServices<ILoggerProvider>())
                    factory.AddProvider(provider);

                return factory;
            });
        }
        else
        {
            collection.AddSingleton<ILoggerFactory>(services => new SerilogLoggerFactory(logger, dispose));
        }
        ConfigureServices(collection, logger);

        return collection;
    }

    static void ConfigureServices(IServiceCollection collection, Serilog.ILogger logger)
    {
        if (collection == null) throw new ArgumentNullException(nameof(collection));

        if (logger != null)
        {
            collection.AddSingleton(logger);
        }
    }
}

appsettings.json配置

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "Microsoft": "Information",
        "System": "Information"
      }
    }
  },
  "ConnectionStrings": {
    "Default": "Data Source=192.168.1.1;Database=avawpf;uid=root;pwd=root;charset=utf8mb4;Allow User Variables=true;"
  }
}

Abp模块加载

protected void OnStartup()
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    //var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"\xx-path");
    //_bootstrapper.PlugInSources.AddFolder(path);
    _bootstrapper.Initialize();
    watch.Stop();
    TimeSpan timeSpan = watch.Elapsed;
    Console.WriteLine("执行时间:{0}(毫秒)", timeSpan.TotalMilliseconds);
}

加载耗时

ViewModel中调用AppService

本来是打算弄一个Prism.CastleWindsor扩展就能统一IOC容器,但是使用后有些prism的Factory相关类型注入存在问题(纯属本人对Castle.Windsor使用上没有弄透彻)

最后暂时通过IocManager获取IOC实例,由于Prims(Prism.DryIoc.Avalonia)与Abp(Castle.Windsor)中使用IOC不一样故使用如下方式。

private readonly ITodoItemAppService _todoItemAppService = IocManager.Instance.Resolve<ITodoItemAppService>();

如果需要使用job也可以借助Quartz实现

集成Prism

基本和原先prism使用基本上没什么区别

App.xaml.cs

public class App : PrismApplication
{
    public static bool IsSingleViewLifetime =>
        Environment.GetCommandLineArgs()
            .Any(a => a == "--fbdev" || a == "--drm");

    public static AppBuilder BuildAvaloniaApp() =>
        AppBuilder
            .Configure<App>()
            .UsePlatformDetect();

    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
        base.Initialize();              // <-- Required
    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        // Register Services
        // Views - Generic
        // Views - Region Navigation
    }

    protected override AvaloniaObject CreateShell()
    {
        if (IsSingleViewLifetime)
            return Container.Resolve<MainControl>(); // For Linux Framebuffer or DRM
        else
            return Container.Resolve<MainWindow>();
    }

    protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
    {
        // Register modules
    }

    /// <summary>Called after <seealso cref="Initialize"/>.</summary>
    protected override void OnInitialized()
    {
      // Register initial Views to Region.
    }
}