开发具有插件架构的 Wpf 应用程序

作者:微信公众号:【架构师老卢】
7-11 18:45
25

概述:创建新式 WPF 应用程序涉及混合可靠的体系结构模式和框架,以确保可维护性、可伸缩性和灵活性。本文讨论如何使用 MVVM(Model-View-ViewModel)模式、用于数据库集成的 EF Core、插件体系结构和用于依赖项注入的 Autofac 来开发 WPF 应用程序。一个关键的重点是实施一个强大的用户管理系统,包括身份验证、授权和角色管理。此外,我们还将探索使用事件聚合器和共享服务提供商的插件之间的通信,并在主窗口中演示插件版本控制和加载。架构概述我们应用程序的主要组件包括:MVVM 模式:UI 和业务逻辑之间的关注点分离。EF Core:数据库访问和管理。插件架构:通过动态加载的插

创建新式 WPF 应用程序涉及混合可靠的体系结构模式和框架,以确保可维护性、可伸缩性和灵活性。本文讨论如何使用 MVVM(Model-View-ViewModel)模式、用于数据库集成的 EF Core、插件体系结构和用于依赖项注入的 Autofac 来开发 WPF 应用程序。一个关键的重点是实施一个强大的用户管理系统,包括身份验证、授权和角色管理。此外,我们还将探索使用事件聚合器和共享服务提供商的插件之间的通信,并在主窗口中演示插件版本控制和加载。

架构概述

我们应用程序的主要组件包括:

  1. MVVM 模式:UI 和业务逻辑之间的关注点分离。
  2. EF Core:数据库访问和管理。
  3. 插件架构:通过动态加载的插件实现可扩展性。
  4. Autofac:依赖注入管理。
  5. 事件聚合器和共享服务提供商:促进插件之间的通信。

实现主应用程序

使用 Autofac 配置依赖关系注入

Autofac使我们能够以灵活且可扩展的方式管理依赖项。下面是 DI 容器的示例配置:

public class Bootstrapper
{
    public IContainer Bootstrap()
    {
        var builder = new ContainerBuilder();

        // Register MVVM components
        builder.RegisterType<MainViewModel>().AsSelf();
        builder.RegisterType<MainWindow>().AsSelf();

        // Register EF Core DbContext
        builder.RegisterType<AppDbContext>().AsSelf().InstancePerLifetimeScope();

        // Register Plugin Loader
        builder.RegisterType<PluginLoader>().As<IPluginLoader>();

        // Register Event Aggregator
        builder.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance();

        // Register AuthService
        builder.RegisterType<AuthService>().As<IAuthService>().InstancePerLifetimeScope();

        return builder.Build();
    }
}

加载插件并显示登录页面

该应用程序在启动期间加载插件并显示一个简单的登录页面。插件的加载方式如下:

public interface IPlugin
{
    void Initialize(IContainer container);
}

public class PluginLoader : IPluginLoader
{
    private readonly IContainer _container;

    public PluginLoader(IContainer container)
    {
        _container = container;
    }

    public void LoadPlugins(string path)
    {
        var pluginAssemblies = Directory.GetFiles(path, "*.dll")
                                         .Select(Assembly.LoadFrom);
        foreach (var assembly in pluginAssemblies)
        {
            var pluginTypes = assembly.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract);
            foreach (var pluginType in pluginTypes)
            {
                var plugin = (IPlugin)Activator.CreateInstance(pluginType);
                plugin.Initialize(_container);
            }
        }
    }
}

为了显示登陆页面,我们确保 MainWindow 设置正确:

public partial class MainWindow : Window
{
    private readonly IPluginLoader _pluginLoader;

    public MainWindow(IPluginLoader pluginLoader)
    {
        InitializeComponent();
        _pluginLoader = pluginLoader;
        Loaded += OnLoaded;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        _pluginLoader.LoadPlugins("Plugins");
        // Display landing page content
        DataContext = new MainViewModel();
    }
}

实施用户管理

用于用户管理的数据模型

我们首先定义用户、角色及其关系的数据模型:

public class User  
{  
    public int Id { get; set; }  
    public string Username { get; set; }  
    public string PasswordHash { get; set; }  
    public ICollection<UserRole> UserRoles { get; set; }  
}  
  
public class Role  
{  
    public int Id { get; set; }  
    public string Name { get; set; }  
    public ICollection<UserRole> UserRoles { get; set; }  
}  
  
public class UserRole  
{  
    public int UserId { get; set; }  
    public User User { get; set; }  
    public int RoleId { get; set; }  
    public Role Role { get; set; }  
}

身份验证和授权服务

AuthService 处理身份验证和授权:

public interface IAuthService
{
    User Authenticate(string username, string password);
    bool Authorize(User user, string role);
}

public class AuthService : IAuthService
{
    private readonly AppDbContext _context;

    public AuthService(AppDbContext context)
    {
        _context = context;
    }

    public User Authenticate(string username, string password)
    {
        var user = _context.Users.Include(u => u.UserRoles).ThenInclude(ur => ur.Role)
                                 .FirstOrDefault(u => u.Username == username);
        if (user == null || !VerifyPassword(user.PasswordHash, password))
        {
            return null;
        }
        return user;
    }

    public bool Authorize(User user, string role)
    {
        return user.UserRoles.Any(ur => ur.Role.Name == role);
    }

    private bool VerifyPassword(string hashedPassword, string password)
    {
        // Implement password verification logic here
        return true;
    }
}

插件与事件聚合器的通信

事件聚合器

事件聚合器有助于插件之间的解耦通信:

public interface IEventAggregator
{
    void Publish<TEvent>(TEvent eventToPublish);
    void Subscribe<TEvent>(Action<TEvent> eventHandler);
}

public class EventAggregator : IEventAggregator
{
    private readonly ConcurrentDictionary<Type, List<object>> _subscribers = new();

    public void Publish<TEvent>(TEvent eventToPublish)
    {
        if (_subscribers.TryGetValue(typeof(TEvent), out var handlers))
        {
            foreach (var handler in handlers.OfType<Action<TEvent>>())
            {
                handler(eventToPublish);
            }
        }
    }

    public void Subscribe<TEvent>(Action<TEvent> eventHandler)
    {
        _subscribers.AddOrUpdate(
            typeof(TEvent),
            _ => new List<object> { eventHandler },
            (_, handlers) => { handlers.Add(eventHandler); return handlers; }
        );
    }
}

插件版本控制和加载

插件元数据和版本检查

为了确保插件兼容,我们实施了版本检查:

public interface IPluginMetadata
{
    string Name { get; }
    Version Version { get; }
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PluginAttribute : Attribute, IPluginMetadata
{
    public string Name { get; }
    public Version Version { get; }

    public PluginAttribute(string name, string version)
    {
        Name = name;
        Version = Version.Parse(version);
    }
}

public class PluginLoader : IPluginLoader
{
    private readonly IContainer _container;

    public PluginLoader(IContainer container)
    {
        _container = container;
    }

    public void LoadPlugins(string path)
    {
        var pluginAssemblies = Directory.GetFiles(path, "*.dll")
                                         .Select(Assembly.LoadFrom);
        foreach (var assembly in pluginAssemblies)
        {
            var pluginTypes = assembly.GetTypes()
                                      .Where(t => typeof(IPlugin).IsAssignableFrom(t) && 
                                                  t.GetCustomAttribute<PluginAttribute>() != null);
            foreach (var pluginType in pluginTypes)
            {
                var metadata = pluginType.GetCustomAttribute<PluginAttribute>();
                if (IsCompatible(metadata))
                {
                    var plugin = (IPlugin)Activator.CreateInstance(pluginType);
                    plugin.Initialize(_container);
                }
            }
        }
    }

    private bool IsCompatible(IPluginMetadata metadata)
    {
        // Implement compatibility check logic here
        return true;
    }
}

上述体系结构为开发模块化和可扩展的 WPF 应用程序奠定了坚实的基础。通过集成 MVVM 模式、EF Core、插件架构和 Autofac,应用程序变得高度可维护且面向未来。实施全面的用户管理系统,以及线程安全的插件通信,确保了可用性和可靠性。精心规划的插件版本控制策略可保持应用程序的兼容性和可扩展性。

阅读排行